diff --git a/.github/ISSUE_TEMPLATE/01_bug.yaml b/.github/ISSUE_TEMPLATE/01_bug.yaml deleted file mode 100644 index d5b392d327..0000000000 --- a/.github/ISSUE_TEMPLATE/01_bug.yaml +++ /dev/null @@ -1,39 +0,0 @@ -name: Bug Report -description: Something is not working -labels: [bug] -body: - - type: textarea - id: description - attributes: - label: Description - placeholder: Please include steps to reproduce your issue, provide example code snippets if possible - validations: - required: true - - type: textarea - id: expected - attributes: - label: Expected Behaviour - placeholder: What did you expect to happen instead - validations: - required: true - - type: input - id: fpm-version - attributes: - label: Version of fpm - placeholder: 0.4.0, 04da9a1ce99e8fce1abdb7eb9a2073f3188038ea, ... - validations: - required: true - - type: input - id: platform - attributes: - label: Platform and Architecture - placeholder: MacOS/ARM, Windows, OpenBSD, ... - validations: - required: true - - type: textarea - id: additional - attributes: - label: Additional Information - placeholder: Further relevant context, i.e. links to other issues - validations: - required: false diff --git a/.github/ISSUE_TEMPLATE/02_packaging.yaml b/.github/ISSUE_TEMPLATE/02_packaging.yaml deleted file mode 100644 index a552afd229..0000000000 --- a/.github/ISSUE_TEMPLATE/02_packaging.yaml +++ /dev/null @@ -1,32 +0,0 @@ -name: Packaging Issue -description: Porting or packaging a project to fpm -labels: [packaging] -body: - - type: input - id: project - attributes: - label: Upstream Project - placeholder: URL for the upstream project - validations: - required: true - - type: textarea - id: description - attributes: - label: Description - placeholder: Please describe the issue with porting or packaging a project with fpm - validations: - required: true - - type: input - id: fpm-version - attributes: - label: Version of fpm - placeholder: 0.4.0, 04da9a1ce99e8fce1abdb7eb9a2073f3188038ea, ... - validations: - required: true - - type: textarea - id: additional - attributes: - label: Additional Information - placeholder: Further relevant context, i.e. links to other issues - validations: - required: false diff --git a/.github/ISSUE_TEMPLATE/03_feature.yaml b/.github/ISSUE_TEMPLATE/03_feature.yaml deleted file mode 100644 index 679cc5b315..0000000000 --- a/.github/ISSUE_TEMPLATE/03_feature.yaml +++ /dev/null @@ -1,28 +0,0 @@ -name: Feature request -description: An idea for a new feature -labels: [enhancement] -body: - - type: textarea - id: description - attributes: - label: Description - placeholder: | - Please describe the feature, please provide examples - Use codefences (```) to add literal codeblocks for examples - validations: - required: true - - type: textarea - id: solution - attributes: - label: Possible Solution - placeholder: | - Please describe possible solutions or currently available workarounds if available. - validations: - required: false - - type: textarea - id: additional - attributes: - label: Additional Information - placeholder: Further relevant context, i.e. links to other issues - validations: - required: false diff --git a/.github/ISSUE_TEMPLATE/04_specification.yaml b/.github/ISSUE_TEMPLATE/04_specification.yaml deleted file mode 100644 index cf4b5780bd..0000000000 --- a/.github/ISSUE_TEMPLATE/04_specification.yaml +++ /dev/null @@ -1,42 +0,0 @@ -name: Specification Proposal -description: Suggestion for extending the package manifest, command line interface, ... -labels: [specification] -body: - - type: textarea - id: motivation - attributes: - label: Motivation - placeholder: | - What is the purpose of this proposal. Please provide usage examples for the new functionality as well. - validations: - required: true - - type: textarea - id: description - attributes: - label: Specification - placeholder: | - Please provide possible realisations of this proposal, i.e. an example how this would work in the manifest. - - Use code fences to provide the example. - - ```toml - [extra] - fpm = "feature" - ``` - validations: - required: true - - type: textarea - id: prior-art - attributes: - label: Prior Art - placeholder: | - Include links and references to other package manager or build systems if available. - validations: - required: false - - type: textarea - id: additional - attributes: - label: Additional Information - placeholder: Further relevant context, i.e. links to other issues - validations: - required: false diff --git a/.github/ISSUE_TEMPLATE/05_free.md b/.github/ISSUE_TEMPLATE/05_free.md deleted file mode 100644 index 4447767ff3..0000000000 --- a/.github/ISSUE_TEMPLATE/05_free.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -name: Free Form -about: If the topic doesn't fit anything above and is not suitable for the lists below ---- diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml deleted file mode 100644 index e6b20a20e1..0000000000 --- a/.github/ISSUE_TEMPLATE/config.yml +++ /dev/null @@ -1,10 +0,0 @@ -contact_links: - - name: Fpm discussion board - url: https://github.com/fortran-lang/fpm/discussions - about: Discussion about fpm related topics - - name: Fortran-lang discourse - url: https://fortran-lang.discourse.group/ - about: Discussion about all things Fortran - - name: Fortran-lang mailing list - url: https://groups.io/g/fortran-lang - about: Mailinglist for the Fortran language diff --git a/.github/actions/setup-intel/action.yml b/.github/actions/setup-intel/action.yml deleted file mode 100644 index 458e926d3a..0000000000 --- a/.github/actions/setup-intel/action.yml +++ /dev/null @@ -1,122 +0,0 @@ -name: 'Setup Intel oneAPI Environment' -description: 'Sets up Intel oneAPI C++, Fortran compilers and MPI on Windows or Ubuntu runners.' - -inputs: - os: - description: 'Operating system of the runner. Must contain "windows" or "ubuntu".' - required: true - type: string - - version: - description: 'Intel oneAPI installer version for Ubuntu (e.g. 2024.1.0).' - required: false - default: '2024.1.0' - type: string - -runs: - using: "composite" - steps: - - name: (Windows) Setup VS Build environment - if: contains(inputs.os, 'windows') - uses: seanmiddleditch/gha-setup-vsdevenv@v4 - - - name: (Windows) Retrieve and Install Intel toolchain - if: contains(inputs.os, 'windows') - shell: pwsh - run: | - $tempDir = "C:\TEMP\intel_install" - New-Item -ItemType Directory -Force -Path $tempDir - cd $tempDir - $installerName = "w_HPCKit_p_2023.0.0.25931_offline.exe" # Consider using inputs.intel_version_windows if added - $installerUrl = "https://registrationcenter-download.intel.com/akdlm/irc_nas/19085/$installerName" - Write-Host "Downloading Intel oneAPI installer..." - curl.exe --output $installerName --url $installerUrl --retry 5 --retry-delay 5 -L # Added -L for potential redirects - Write-Host "Extracting installer..." - Start-Process -FilePath ".\$installerName" -ArgumentList "-s -x -f oneAPI --log extract.log" -Wait -NoNewWindow - Remove-Item ".\$installerName" -Force - Write-Host "Installing oneAPI components..." - # Install C++, Fortran, and MPI development tools silently - Start-Process -FilePath ".\oneAPI\bootstrapper.exe" -ArgumentList "-s --action install --eula=accept --components=""intel.oneapi.win.cpp-compiler:intel.oneapi.win.ifort-compiler:intel.oneapi.win.mpi.devel"" -p=NEED_VS2017_INTEGRATION=0 -p=NEED_VS2019_INTEGRATION=0 -p=NEED_VS2022_INTEGRATION=0 --log-dir=." -Wait -NoNewWindow - Write-Host "Cleaning up extracted files..." - Remove-Item ".\oneAPI" -Force -Recurse - cd .. - Remove-Item $tempDir -Force -Recurse - - - name: (Windows) Test that OneAPI is installed - if: contains(inputs.os, 'windows') - shell: pwsh - run: | - $setvarsPath = "C:\Program Files (x86)\Intel\oneAPI\setvars.bat" - $compilerVarsPath = "C:\Program Files (x86)\Intel\oneAPI\compiler\latest\env\vars.bat" - if (-not (Test-Path -Path $setvarsPath -PathType Leaf)) { - Write-Error "Intel oneAPI setvars.bat not found at $setvarsPath" - exit 1 - } - if (-not (Test-Path -Path $compilerVarsPath -PathType Leaf)) { - Write-Warning "Intel oneAPI compiler vars.bat not found at $compilerVarsPath. MPI might still work." - # Depending on requirements, you might want to 'exit 1' here too - } - Write-Host "Intel oneAPI installation paths verified." - - - name: (Windows) Load OneAPI environment variables - if: contains(inputs.os, 'windows') - shell: cmd - run: | - call "C:\Program Files (x86)\Intel\oneAPI\setvars.bat" > NUL - echo "Setting Intel environment variables..." - echo "PATH=%PATH%" >> %GITHUB_ENV% - echo "INCLUDE=%INCLUDE%" >> %GITHUB_ENV% - echo "LIB=%LIB%" >> %GITHUB_ENV% - REM Add any other specific vars if needed, e.g., for MPI - echo "I_MPI_ROOT=%I_MPI_ROOT%" >> %GITHUB_ENV% - echo "FI_PROVIDER_PATH=%FI_PROVIDER_PATH%" >> %GITHUB_ENV% - echo "MPI_BIN=%MPI_BIN%" >> %GITHUB_ENV% - - # --- Ubuntu Intel Setup --- - - name: (Ubuntu) Install prerequisites and Intel GPG key - if: contains(inputs.os, 'ubuntu') - shell: bash - run: | - sudo apt-get update -y -qq - sudo apt-get install -y -qq gpg wget ca-certificates curl gpg-agent software-properties-common - wget -O- https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB | gpg --dearmor | sudo tee /usr/share/keyrings/oneapi-archive-keyring.gpg > /dev/null - - - name: (Ubuntu) Add Intel oneAPI repository - if: contains(inputs.os, 'ubuntu') - shell: bash - run: | - echo "deb [signed-by=/usr/share/keyrings/oneapi-archive-keyring.gpg] https://apt.repos.intel.com/oneapi all main" | sudo tee /etc/apt/sources.list.d/oneAPI.list - sudo apt-get update -y -qq - - - name: (Ubuntu) Install Intel oneAPI Compilers using fortran-lang action - if: contains(inputs.os, 'ubuntu') - uses: fortran-lang/setup-fortran@v1 - with: - compiler: intel - version: ${{ inputs.version }} - - - name: (Ubuntu) Install Intel oneAPI MPI and build dependencies - if: contains(inputs.os, 'ubuntu') - shell: bash - run: | - # Install MPI devel package and common build tools - # The compilers (icc, ifort) should already be installed by setup-fortran action - sudo apt-get install -y -q intel-oneapi-mpi-devel intel-oneapi-mkl ninja-build cmake libcurl4-gnutls-dev - - - name: (Ubuntu) Source oneAPI environment and add to GITHUB_ENV - if: contains(inputs.os, 'ubuntu') - shell: bash - run: | - # Source the main setvars script to set up the environment for this step - # Use --force as we might be in a non-interactive shell - source /opt/intel/oneapi/setvars.sh --force > /dev/null 2>&1 - echo "Sourced setvars.sh. Adding key variables to GITHUB_ENV..." - # Explicitly add key variables to GITHUB_ENV for subsequent steps - echo "PATH=$PATH" >> $GITHUB_ENV - echo "LD_LIBRARY_PATH=$LD_LIBRARY_PATH" >> $GITHUB_ENV - echo "LIBRARY_PATH=$LIBRARY_PATH" >> $GITHUB_ENV - echo "CPATH=$CPATH" >> $GITHUB_ENV - echo "CMPLR_ROOT=$CMPLR_ROOT" >> $GITHUB_ENV # Example compiler root - echo "MPI_ROOT=$MPI_ROOT" >> $GITHUB_ENV # MPI root (check actual variable name if needed, e.g., I_MPI_ROOT) - echo "I_MPI_ROOT=$I_MPI_ROOT" >> $GITHUB_ENV # Common variable name for Intel MPI root - echo "FI_PROVIDER_PATH=$FI_PROVIDER_PATH" >> $GITHUB_ENV # Often needed for MPI diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index 8ac6b8c498..0000000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,6 +0,0 @@ -version: 2 -updates: - - package-ecosystem: "github-actions" - directory: "/" - schedule: - interval: "monthly" diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml deleted file mode 100644 index 3a8e515a80..0000000000 --- a/.github/workflows/CI.yml +++ /dev/null @@ -1,327 +0,0 @@ -name: CI - -on: - push: - pull_request: - release: - types: [published] - -env: - CI: "ON" # We can detect this in the build system and other vendors implement it - HOMEBREW_NO_ANALYTICS: "ON" # Make Homebrew installation a little quicker - HOMEBREW_NO_AUTO_UPDATE: "ON" - HOMEBREW_NO_BOTTLE_SOURCE_FALLBACK: "ON" - HOMEBREW_NO_GITHUB_API: "ON" - HOMEBREW_NO_INSTALL_CLEANUP: "ON" - -jobs: - - build: - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest, macos-13, windows-latest] - toolchain: - - {compiler: gcc, version: 10} - - {compiler: gcc, version: 11} - - {compiler: gcc, version: 12} - - {compiler: gcc, version: 13} - - {compiler: gcc, version: 14} - - {compiler: intel, version: 2025.1} - exclude: - - os: macos-13 # No Intel on MacOS anymore since 2024 - toolchain: {compiler: intel, version: '2025.1'} - - os: windows-latest # Doesn't pass build and tests yet - toolchain: {compiler: intel, version: '2025.1'} - - os: windows-latest # gcc 14 not available on Windows yet - toolchain: {compiler: gcc, version: 14} - include: - - os: ubuntu-latest - os-arch: linux-x86_64 - release-flags: --flag '--static -g -fbacktrace -O3' - - os: macos-13 - os-arch: macos-x86_64 - release-flags: --flag '-g -fbacktrace -O3' - - os: windows-latest - os-arch: windows-x86_64 - release-flags: --flag '--static -g -fbacktrace -O3' - exe: .exe - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Setup Fortran compiler - uses: fortran-lang/setup-fortran@v1.6.3 - id: setup-fortran - with: - compiler: ${{ matrix.toolchain.compiler }} - version: ${{ matrix.toolchain.version }} - - # Phase 1: Bootstrap fpm with existing version - - name: Install fpm - uses: fortran-lang/setup-fpm@v7 - with: - fpm-version: 'v0.8.0' - - # Backport gfortran shared libraries to version 10 folder. This is necessary because the macOS release of fpm - # 0.10.0 used for bootstrapping has these paths hardcoded in the executable. - - name: MacOS patch libgfortran - if: contains(matrix.os, 'macos') && !contains(matrix.toolchain.version, '10') - run: | - which gfortran-${{ matrix.toolchain.version }} - which gfortran - mkdir /usr/local/opt/gcc@10 - mkdir /usr/local/opt/gcc@10/lib - mkdir /usr/local/opt/gcc@10/lib/gcc - mkdir /usr/local/opt/gcc@10/lib/gcc/10 - mkdir /usr/local/lib/gcc/10 - ln -fs /usr/local/opt/gcc@${{ matrix.toolchain.version }}/lib/gcc/${{ matrix.toolchain.version }}/libquadmath.0.dylib /usr/local/opt/gcc@10/lib/gcc/10/libquadmath.0.dylib - ln -fs /usr/local/opt/gcc@${{ matrix.toolchain.version }}/lib/gcc/${{ matrix.toolchain.version }}/libgfortran.5.dylib /usr/local/opt/gcc@10/lib/gcc/10/libgfortran.5.dylib - ln -fs /usr/local/lib/gcc/${{ matrix.toolchain.version }}/libgcc_s.1.dylib /usr/local/lib/gcc/10/libgcc_s.1.dylib - - # gcc and g++ will point to clang/clang++: use versioned alias for fpm - - name: MacOS patch C and C++ compilers - if: contains(matrix.os, 'macos') - run: | - echo "CC=gcc-${{ matrix.toolchain.version }}" >> $GITHUB_ENV - echo "FPM_CC=gcc-${{ matrix.toolchain.version }}" >> $GITHUB_ENV - echo "CXX=g++-${{ matrix.toolchain.version }}" >> $GITHUB_ENV - echo "FPM_CXX=g++-${{ matrix.toolchain.version }}" >> $GITHUB_ENV - echo "FPM_LDFLAGS=-lstdc++" >> $GITHUB_ENV - - - name: Remove fpm from path - shell: bash - run: | - mv $(which fpm) fpm-bootstrap${{ matrix.exe }} - echo "BOOTSTRAP=$PWD/fpm-bootstrap" >> $GITHUB_ENV - - - name: Build Fortran fpm (bootstrap) - shell: bash - run: | - ${{ env.BOOTSTRAP }} build - - - name: Run Fortran fpm (bootstrap) - shell: bash - run: | - ${{ env.BOOTSTRAP }} run - ${{ env.BOOTSTRAP }} run -- --version - ${{ env.BOOTSTRAP }} run -- --help - - - name: Test Fortran fpm (bootstrap) - shell: bash - run: | - ${{ env.BOOTSTRAP }} test - - - name: Install Fortran fpm (bootstrap) - shell: bash - run: | - ${{ env.BOOTSTRAP }} install - - # Phase 2: Bootstrap fpm with itself - - name: Replace bootstrapping version - shell: bash - run: | - ${{ env.BOOTSTRAP }} run --runner cp -- fpm-debug${{ matrix.exe }} - rm -v ${{ env.BOOTSTRAP }} - echo "FPM=$PWD/fpm-debug" >> $GITHUB_ENV - - - name: Get version (normal) - if: github.event_name != 'release' - shell: bash - run: | - VERSION=$(git rev-parse --short HEAD) - echo "VERSION=$VERSION" >> $GITHUB_ENV - - - name: Get version (release) - if: github.event_name == 'release' - shell: bash - run: | - VERSION=$(echo ${{ github.ref }} | cut -dv -f2) - echo "VERSION=$VERSION" >> $GITHUB_ENV - FPM_VERSION=$(${{ env.FPM }} --version | grep -o '${{ env.REGEX }}') - [ "$VERSION" = "$FPM_VERSION" ] - env: - REGEX: '[0-9]\{1,4\}\.[0-9]\{1,4\}\.[0-9]\{1,4\}' - - - name: Build Fortran fpm - shell: bash - run: | - ${{ env.FPM }} build ${{ matrix.release-flags }} - - - name: Run Fortran fpm - shell: bash - run: | - ${{ env.FPM }} run ${{ matrix.release-flags }} - ${{ env.FPM }} run ${{ matrix.release-flags }} -- --version - ${{ env.FPM }} run ${{ matrix.release-flags }} -- --help - - - name: Test Fortran fpm - shell: bash - run: | - ${{ env.FPM }} test ${{ matrix.release-flags }} - - - name: Install Fortran fpm - shell: bash - run: | - ${{ env.FPM }} install ${{ matrix.release-flags }} - - - name: Package release version - shell: bash - run: | - ${{ env.FPM }} run ${{ matrix.release-flags }} --runner cp -- ${{ env.EXE }} - rm -v ${{ env.FPM }} - echo "FPM_RELEASE=${{ env.EXE }}" >> $GITHUB_ENV - env: - EXE: fpm-${{ env.VERSION }}-${{ matrix.os-arch }}-gcc-${{ matrix.toolchain.version }}${{ matrix.exe }} - - - name: Run release version - shell: bash - run: | - ci/run_tests.sh "$PWD/${{ env.FPM_RELEASE }}" - - - name: Upload artifact - uses: actions/upload-artifact@v4 - with: - name: ${{ env.FPM_RELEASE }} - path: ${{ env.FPM_RELEASE }} - - - make-installer: - if: ${{ github.event_name == 'release' && contains(github.ref, 'v') || github.event_name == 'push' }} - runs-on: windows-latest - needs: - - build - strategy: - fail-fast: false - matrix: - gcc_v: [11,12,13] - - steps: - - uses: actions/checkout@v4 - - - name: Download Artifacts - uses: actions/download-artifact@v4 - with: - path: ${{ github.workspace }} - pattern: fpm-*-windows-*-gcc-${{ matrix.gcc_v }}.exe - - - name: Get version (normal) - if: github.event_name != 'release' - shell: bash - run: | - VERSION=$(git rev-parse --short HEAD) - echo "VERSION=$VERSION" >> $GITHUB_ENV - - - name: Get version (release) - if: github.event_name == 'release' - shell: bash - run: | - VERSION=$(echo ${{ github.ref }} | cut -dv -f2) - echo "VERSION=$VERSION" >> $GITHUB_ENV - env: - REGEX: '[0-9]\{1,4\}\.[0-9]\{1,4\}\.[0-9]\{1,4\}' - - - name: Setup MinGW (MSYS2) - uses: msys2/setup-msys2@v2 - with: - msystem: MINGW64 - update: false - install: >- - wget - unzip - - - name: Fetch Windows executable - shell: msys2 {0} - run: | - cp fpm-*/fpm-*-windows-*-gcc-${{ matrix.gcc_v }}.exe ./ci/fpm.exe - - - name: Fetch Git for Windows - shell: msys2 {0} - run: | - cd ./ci - wget ${{ env.git_download }} -O MinGit.zip - unzip MinGit.zip -d MinGit - env: - git_download: "https://github.com/git-for-windows/git/releases/download/v2.33.1.windows.1/MinGit-2.33.1-64-bit.zip" - - - name: Fetch EnVar Plugin for NSIS - shell: msys2 {0} - run: | - cd ./ci - wget ${{ env.envar_download }} -O EnVar-Plugin.zip - mkdir EnVar_plugin - unzip EnVar-Plugin.zip -d EnVar_plugin - env: - envar_download: "https://github.com/GsNSIS/EnVar/releases/download/v0.3.1/EnVar-Plugin.zip" - - - name: Generate installer - run: | - cd ./ci - makensis fpm-installer.nsi - move fpm-installer.exe fpm-installer-${{ env.VERSION }}-gcc-${{ matrix.gcc_v }}.exe - - - name: Upload artifact - uses: actions/upload-artifact@v4 - with: - name: fpm-installer-gcc-${{ matrix.gcc_v }} - path: ci/fpm-installer-${{ env.VERSION }}-gcc-${{ matrix.gcc_v }}.exe - - upload-artifacts: - if: ${{ github.event_name == 'release' && contains(github.ref, 'v') || github.event_name == 'push' }} - runs-on: ubuntu-latest - needs: - - build - - make-installer - - steps: - - id: deploy-on-push - if: ${{ github.event_name == 'push' }} - run: - echo "::set-output name=result::${{ env.DEPLOY_BRANCH }}" - env: - DEPLOY_BRANCH: ${{ secrets.DEPLOY_BRANCH && contains(github.ref, secrets.DEPLOY_BRANCH) && 1 || 0 }} - - - uses: actions/checkout@v4 - if: ${{ github.event_name == 'push' }} - - - name: Download Artifacts - uses: actions/download-artifact@v4 - with: - path: fpm-cd-artifacts - pattern: 'fpm-*-gcc-12*' - merge-multiple: true - - - name: Normalize file names for continuous delivery - if: ${{ github.event_name == 'push' }} - run: | - cd fpm-cd-artifacts - for output in fpm-*; do - mv -v $(basename $output) $(basename $output | sed -E '${{ env.replace }}') - done - env: - replace: 's/-([0-9]+\.[0-9]+\.[0-9]+-[0-9]+-g)?[0-9a-f]+//' - - - name: Create SHA256 checksums - run: | - cd fpm-cd-artifacts - for output in fpm-*; do - sha256sum $(basename "$output") | tee $(basename "$output").sha256 - done - - - name: Move/Create continuous tag - if: ${{ github.event_name == 'push' && steps.deploy-on-push.outputs.result != 0 }} - run: | - git tag --force 'current' ${{ github.sha }} - git push --tags --force - - - name: Upload assets - uses: svenstaro/upload-release-action@v2 - if: ${{ github.event_name == 'release' || steps.deploy-on-push.outputs.result != 0 }} - with: - repo_token: ${{ secrets.GITHUB_TOKEN }} - file: fpm-cd-artifacts/* - file_glob: true - tag: ${{ github.event_name == 'release' && github.ref || 'current'}} - overwrite: true diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml deleted file mode 100644 index fe364018e5..0000000000 --- a/.github/workflows/docs.yml +++ /dev/null @@ -1,24 +0,0 @@ -name: docs - -on: [push, pull_request] - -jobs: - build-and-deploy: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 - with: - python-version: '3.x' - - name: Install dependencies - run: pip install ford - - name: Build Documentation - run: ford docs.md - - uses: JamesIves/github-pages-deploy-action@v4.7.3 - if: github.event_name == 'push' && github.repository == 'fortran-lang/fpm' && ( startsWith( github.ref, 'refs/tags/' ) || github.ref == 'refs/heads/main' ) - with: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - BRANCH: gh-pages - FOLDER: fpm-doc - CLEAN: true - diff --git a/.github/workflows/meta.yml b/.github/workflows/meta.yml deleted file mode 100644 index 095da46563..0000000000 --- a/.github/workflows/meta.yml +++ /dev/null @@ -1,340 +0,0 @@ -name: metapackage-tests - -on: - # On push, only run if any of the metapackage files has changed - push: - paths: - - 'src/*meta*.f90' - - 'src/fpm/*meta*.f90' - - 'src/fpm/manifest/*meta*.f90' - - 'src/ci/meta_tests.sh' - - 'src/.github/workflows/meta.yml' - # Always run on PR or release - pull_request: - release: - types: [published] - # Allow manual triggering - workflow_dispatch: - -env: - CI: "ON" # We can detect this in the build system and other vendors implement it - HOMEBREW_NO_ANALYTICS: 1 # Make Homebrew installation a little quicker - HOMEBREW_NO_AUTO_UPDATE: 1 - HOMEBREW_NO_BOTTLE_SOURCE_FALLBACK: 1 - HOMEBREW_NO_GITHUB_API: 1 - HOMEBREW_NO_INSTALL_CLEANUP: 1 - HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK: 1 - -jobs: - - build: - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - include: - - os: ubuntu-latest - mpi: openmpi - - os: ubuntu-latest - mpi: mpich - - os: macos-13 - mpi: openmpi - - os: macos-13 - mpi: mpich - - os: ubuntu-latest - mpi: intel - intel_version: "2024.1.0" - - os: ubuntu-latest - mpi: intel - intel_version: "2025.0" - - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: (Ubuntu/macOS) setup gcc version - if: contains(matrix.os,'ubuntu') || contains(matrix.os,'macos') - run: | - echo "GCC_V=14" >> $GITHUB_ENV - - - name: (Windows) Install MSYS2 - uses: msys2/setup-msys2@v2 - if: contains(matrix.os,'windows') && contains(matrix.mpi,'msmpi') - with: - msystem: MINGW64 - update: true - install: >- - git - base-devel - wget - unzip - curl - hdf5 - netcdf - netcdf-fortran - - - name: (Ubuntu) Install gfortran - if: contains(matrix.os,'ubuntu') - run: | - sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-${GCC_V} 100 \ - --slave /usr/bin/gfortran gfortran /usr/bin/gfortran-${GCC_V} \ - --slave /usr/bin/gcov gcov /usr/bin/gcov-${GCC_V} - - - name: (Ubuntu) Install OpenMPI - if: contains(matrix.os,'ubuntu') && contains(matrix.mpi,'openmpi') - run: | - sudo apt-get update - sudo apt install -y -q openmpi-bin libopenmpi-dev hwloc fabric libhdf5-dev \ - libhdf5-fortran-102 libnetcdf-dev libnetcdff-dev libopenblas-dev - - - name: (Ubuntu) Install MPICH - if: contains(matrix.os,'ubuntu') && contains(matrix.mpi,'mpich') - run: | - sudo apt-get update - sudo apt install -y -q mpich hwloc fabric libhdf5-dev libhdf5-fortran-102 \ - libnetcdf-dev libnetcdff-dev libopenblas-dev - - # Intel - - name: Setup Intel Environment - if: contains(matrix.mpi, 'intel') - uses: ./.github/actions/setup-intel - with: - os: ${{ matrix.os }} - version: ${{ matrix.intel_version }} - - - name: (Ubuntu) Build and Install HDF5 from source - if: contains(matrix.os, 'ubuntu') && contains(matrix.mpi, 'intel') - # Needs checkout if source code isn't available, adjust if needed - # Ensure compilers are available from the previous step's environment setup - shell: bash - run: | - # Source again just in case shell context is lost (shouldn't be, but safer) - source /opt/intel/oneapi/setvars.sh --force - # Download HDF5 - curl -O -L https://github.com/HDFGroup/hdf5/archive/refs/tags/snapshot-1.14.tar.gz - tar zxf snapshot-1.14.tar.gz - cd hdf5-snapshot-1.14 - # Configure HDF5 with Intel compilers - cmake -B build -DCMAKE_Fortran_COMPILER=ifx -DCMAKE_C_COMPILER=icx -DCMAKE_CXX_COMPILER=icpx -DHDF5_BUILD_FORTRAN=ON -DCMAKE_INSTALL_PREFIX=/usr - cd build - make -j $(nproc) - sudo make install - cd ../.. # Go back to workspace directory - rm -rf hdf5-snapshot-1.14 snapshot-1.14.tar.gz # Clean up - - - name: (Ubuntu) Build and Install NetCDF-C from source - if: contains(matrix.os, 'ubuntu') && contains(matrix.mpi, 'intel') - shell: bash - run: | - source /opt/intel/oneapi/setvars.sh --force - # Download NetCDF-C - curl -L https://github.com/Unidata/netcdf-c/archive/refs/tags/v4.9.2.tar.gz -o - | tar xz - cd netcdf-c-4.9.2 - # Configure NetCDF-C with Intel Compilers, referencing installed HDF5 - # Set CC/CXX/FC explicitly in environment for configure script - export CC=icx CXX=icpx FC=ifx - ./configure --prefix=/usr --enable-netcdf-4 --with-hdf5=/usr - make -j $(nproc) - sudo make install - cd .. # Go back to workspace directory - rm -rf netcdf-c-4.9.2 # Clean up - - - name: (Ubuntu) Build and Install NetCDF-Fortran from source - if: contains(matrix.os, 'ubuntu') && contains(matrix.mpi, 'intel') - shell: bash - run: | - source /opt/intel/oneapi/setvars.sh --force - # Download NetCDF-Fortran - curl -L https://github.com/Unidata/netcdf-fortran/archive/refs/tags/v4.6.1.tar.gz -o - | tar xz - cd netcdf-fortran-4.6.1 - # Configure NetCDF-Fortran with Intel Compilers using CMake - cmake -B build -DCMAKE_Fortran_COMPILER=ifx -DCMAKE_C_COMPILER=icx -DCMAKE_CXX_COMPILER=icpx -DCMAKE_INSTALL_PREFIX=/usr - cd build - make -j $(nproc) - sudo make install - cd ../.. # Go back to workspace directory - rm -rf netcdf-fortran-4.6.1 # Clean up - - - name: (Windows) Put MSYS2_MinGW64 on PATH - if: contains(matrix.os,'windows') && (!contains(matrix.mpi,'intel')) - # there is not yet an environment variable for this path from msys2/setup-msys2 - run: echo "${{ runner.temp }}/msys64/mingw64/bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - - - name: (Windows) download MS-MPI setup (SDK is from MSYS2) - if: contains(matrix.os,'windows') && contains(matrix.mpi,'msmpi') - # run: curl -L -O https://github.com/microsoft/Microsoft-MPI/releases/download/v10.1.2/msmpisetup.exe 10.1.1 - run: curl -L -O https://download.microsoft.com/download/a/5/2/a5207ca5-1203-491a-8fb8-906fd68ae623/msmpisetup.exe # 10.1.2 - - - name: (Windows) Install mpiexec.exe (-force needed to bypass GUI on headless) - if: contains(matrix.os,'windows') && contains(matrix.mpi,'msmpi') - run: .\msmpisetup.exe -unattend -force - - - name: (Windows) test that mpiexec.exe exists - if: contains(matrix.os,'windows') && contains(matrix.mpi,'msmpi') - # can't use MSMPI_BIN as Actions doesn't update PATH from msmpisetup.exe - run: Test-Path "C:\Program Files\Microsoft MPI\Bin\mpiexec.exe" -PathType leaf - - - name: (Windows) put MSMPI_BIN on PATH (where mpiexec is) - if: contains(matrix.os,'windows') && contains(matrix.mpi,'msmpi') - run: | - echo "C:\Program Files\Microsoft MPI\Bin\" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - echo "/c/Program Files/Microsoft MPI/Bin/" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - echo "MSMPI_BIN=C:\Program Files\Microsoft MPI\Bin\" | Out-File -FilePath $env:GITHUB_ENV -Append - - - name: (Windows) Install MSYS2 msmpi package - if: contains(matrix.os,'windows') && contains(matrix.mpi,'msmpi') - shell: msys2 {0} - run: pacman --noconfirm -S mingw-w64-x86_64-msmpi - - - name: (macOS) Set up Homebrew - if: contains(matrix.os,'macos') - id: set-up-homebrew - uses: Homebrew/actions/setup-homebrew@master - - - name: (macOS) Install Homebrew gfortran - if: contains(matrix.os, 'macos') - run: | - # Only install gcc if not already available - which gfortran-${{ env.GCC_V }} || brew install gcc@${{ env.GCC_V }} - which gfortran-${{ env.GCC_V }} - which gfortran || ln -s /usr/local/bin/gfortran-${{ env.GCC_V }} /usr/local/bin/gfortran - # Backport gfortran shared libraries to version 10 folder. This is necessary because all macOS releases of fpm - # have these paths hardcoded in the executable (no PIC?). Current bootstrap version 0.8.0 has gcc-10 - mkdir /usr/local/opt/gcc@10 - mkdir /usr/local/opt/gcc@10/lib - mkdir /usr/local/opt/gcc@10/lib/gcc - mkdir /usr/local/opt/gcc@10/lib/gcc/10 - mkdir /usr/local/lib/gcc/10 - ln -fs /usr/local/opt/gcc@${{ env.GCC_V }}/lib/gcc/${{ env.GCC_V }}/libquadmath.0.dylib /usr/local/opt/gcc@10/lib/gcc/10/libquadmath.0.dylib - ln -fs /usr/local/opt/gcc@${{ env.GCC_V }}/lib/gcc/${{ env.GCC_V }}/libgfortran.5.dylib /usr/local/opt/gcc@10/lib/gcc/10/libgfortran.5.dylib - # Newer gcc versions use libgcc_s.1.1.dylib - ln -fs /usr/local/lib/gcc/${{ env.GCC_V }}/libgcc_s.1.dylib /usr/local/lib/gcc/10/libgcc_s.1.dylib || ln -fs /usr/local/lib/gcc/${{ env.GCC_V }}/libgcc_s.1.1.dylib /usr/local/lib/gcc/10/libgcc_s.1.dylib - - - name: (macOS) Install homebrew MPICH - if: contains(matrix.mpi,'mpich') && contains(matrix.os,'macos') - run: | - brew install mpich - - - name: (macOS) Install homebrew OpenMPI - if: contains(matrix.mpi,'openmpi') && contains(matrix.os,'macos') - run: | - brew install openmpi #--cc=gcc-${{ env.GCC_V }} openmpi - - - name: (macOS) Install homebrew HDF5 - if: contains(matrix.os,'macos') - run: | - brew install hdf5 - - - name: (macOS) Install homebrew NetCDF - if: contains(matrix.os,'macos') - run: | - brew install netcdf - brew install netcdf-fortran - - # Phase 1: Bootstrap fpm with existing version - - name: Install fpm - uses: fortran-lang/setup-fpm@v7 - with: - fpm-version: 'v0.8.0' - - - name: Remove fpm from path - shell: bash - run: | - mv $(which fpm) fpm-bootstrap${{ matrix.exe }} - echo "BOOTSTRAP=$PWD/fpm-bootstrap" >> $GITHUB_ENV - - - name: (macOS/Ubuntu) Use gcc/g++ instead of Clang for C/C++ / ifx to build fpm - if: contains(matrix.os,'macOS') || contains(matrix.os,'ubuntu') - shell: bash - run: | - echo "FPM_FC=gfortran-${{ env.GCC_V }}" >> $GITHUB_ENV - echo "FPM_CC=gcc-${{ env.GCC_V }}" >> $GITHUB_ENV - echo "FPM_CXX=g++-${{ env.GCC_V }}" >> $GITHUB_ENV - - - name: Build Fortran fpm (bootstrap) - shell: bash - run: | - ${{ env.BOOTSTRAP }} build - - - name: Run Fortran fpm (bootstrap) - shell: bash - run: | - ${{ env.BOOTSTRAP }} run - ${{ env.BOOTSTRAP }} run -- --version - ${{ env.BOOTSTRAP }} run -- --help - - - name: Test Fortran fpm (bootstrap) - if: (!contains(matrix.mpi,'intel')) - shell: bash - run: | - ${{ env.BOOTSTRAP }} test - - - name: Install Fortran fpm (bootstrap) - shell: bash - run: | - ${{ env.BOOTSTRAP }} install - - # Phase 2: Bootstrap fpm with itself - - name: Replace bootstrapping version - shell: bash - run: | - ${{ env.BOOTSTRAP }} run --runner cp -- fpm-debug${{ matrix.exe }} - rm -v ${{ env.BOOTSTRAP }} - echo "FPM=$PWD/fpm-debug" >> $GITHUB_ENV - - - name: Get version (normal) - if: github.event_name != 'release' - shell: bash - run: | - VERSION=$(git rev-parse --short HEAD) - echo "VERSION=$VERSION" >> $GITHUB_ENV - - - name: Get version (release) - if: github.event_name == 'release' - shell: bash - run: | - VERSION=$(echo ${{ github.ref }} | cut -dv -f2) - echo "VERSION=$VERSION" >> $GITHUB_ENV - FPM_VERSION=$(${{ env.FPM }} --version | grep -o '${{ env.REGEX }}') - [ "$VERSION" = "$FPM_VERSION" ] - env: - REGEX: '[0-9]\{1,4\}\.[0-9]\{1,4\}\.[0-9]\{1,4\}' - - - name: Build Fortran fpm - shell: bash - run: | - ${{ env.FPM }} build ${{ matrix.release-flags }} - - - name: Run Fortran fpm - shell: bash - run: | - ${{ env.FPM }} run ${{ matrix.release-flags }} - ${{ env.FPM }} run ${{ matrix.release-flags }} -- --version - ${{ env.FPM }} run ${{ matrix.release-flags }} -- --help - - - name: Install Fortran fpm - shell: bash - run: | - ${{ env.FPM }} install ${{ matrix.release-flags }} - - - name: Package release version - shell: bash - run: | - ${{ env.FPM }} run ${{ matrix.release-flags }} --runner cp -- ${{ env.EXE }} - rm -v ${{ env.FPM }} - echo "FPM_RELEASE=${{ env.EXE }}" >> $GITHUB_ENV - env: - EXE: fpm-${{ env.VERSION }}-${{ matrix.os-arch }}${{ matrix.exe }} - - - name: Use Intel compiler for the metapackage tests - if: contains(matrix.mpi,'intel') - shell: bash - run: | - echo "FPM_FC=ifx" >> $GITHUB_ENV - echo "FPM_CC=icx" >> $GITHUB_ENV - echo "FPM_CXX=icpx" >> $GITHUB_ENV - - - name: Run metapackage tests using the release version - shell: bash - run: | - ci/meta_tests.sh "$PWD/${{ env.FPM_RELEASE }}" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index f6d4b16286..0000000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,167 +0,0 @@ -name: Release - -on: - push: - pull_request: - release: - types: [published] - -jobs: - source-archive: - runs-on: ubuntu-latest - strategy: - fail-fast: false - matrix: - format: [zip] - env: - FORMAT: ${{ matrix.format }} - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Get version number - run: | - VERSION=$(git describe --tags --match 'v*' --always | tr -d 'v') - echo "VERSION=${VERSION}" >> $GITHUB_ENV - - - name: Create archive - run: | - echo "OUTPUT=${{ env.OUTPUT }}" >> $GITHUB_ENV - git archive --prefix ${{ env.PREFIX }} --format ${{ env.FORMAT }} HEAD > ${{ env.OUTPUT }} - env: - OUTPUT: fpm-${{ env.VERSION }}.${{ env.FORMAT }} - PREFIX: fpm-${{ env.VERSION }}/ - - - name: Upload artifact - uses: actions/upload-artifact@v4 - with: - name: ${{ env.OUTPUT }} - path: ${{ env.OUTPUT }} - - source-single-file: - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Get version number - run: | - VERSION=$(git describe --tags --match 'v*' --always | tr -d 'v') - echo "VERSION=${VERSION}" >> $GITHUB_ENV - echo ${{ env.VERSION }} - - - name: Get manifest version - run: | - MANIFEST_VERSION=$(grep version fpm.toml | head -1 | tr -d ' ' | tr -d 'version=') - echo "MANIFEST_VERSION=${MANIFEST_VERSION}" >> $GITHUB_ENV - echo ${{ env.MANIFEST_VERSION }} - - # Note: this step is meant to remove the test targets from the package manifest, - # a change in the package manifest might require to regenerate the patch file. - - name: Remove tests - run: | - patch -p1 < ./ci/single-file.patch - - - name: Install fpm - uses: fortran-lang/setup-fpm@v7 - with: - fpm-version: 'v0.8.0' - - - name: Create single file version - run: | - echo "OUTPUT=${{ env.OUTPUT }}" >> $GITHUB_ENV - echo "#define FPM_BOOTSTRAP" > fpm-${{ env.VERSION }}.F90 - # We need to pass the exact version string that a fpm build command would send - echo "#define FPM_RELEASE_VERSION ${{ env.MANIFEST_VERSION }}" >> fpm-${{ env.VERSION }}.F90 - # Intel compiler predefines "linux" and "unix" which causes inadvertent substitutions - echo "#undef linux" >> fpm-${{ env.VERSION }}.F90 - echo "#undef unix" >> fpm-${{ env.VERSION }}.F90 - fpm build --compiler ./ci/single-file-gfortran.sh - env: - OUTPUT: fpm-${{ env.VERSION }}.F90 - OMP_NUM_THREADS: 1 - - # Building the bootstrap version from the single source version is the most expensive - # step in this workflow, since we have to compile several thousand lines of source. - - name: Build single source version - run: | - echo "EXE=${{ env.BUILD_DIR }}/fpm" >> $GITHUB_ENV - mkdir ${{ env.BUILD_DIR }} - gfortran ${{ env.OUTPUT }} -J ${{ env.BUILD_DIR }} -o ${{ env.BUILD_DIR }}/fpm - env: - BUILD_DIR: build/bootstrap - - - name: Undo patch - run: | - patch -p1 -R < ./ci/single-file.patch - - - name: Build fpm with bootstrap version - run: | - ${{ env.EXE }} build - - - name: Upload artifact - uses: actions/upload-artifact@v4 - with: - name: ${{ env.OUTPUT }} - path: ${{ env.OUTPUT }} - - upload-artifacts: - if: ${{ github.event_name == 'release' && contains(github.ref, 'v') || github.event_name == 'push' }} - runs-on: ubuntu-latest - needs: - - source-archive - - source-single-file - - steps: - - id: deploy-on-push - if: ${{ github.event_name == 'push' }} - run: - echo "::set-output name=result::${{ env.DEPLOY_BRANCH }}" - env: - DEPLOY_BRANCH: ${{ secrets.DEPLOY_BRANCH && contains(github.ref, secrets.DEPLOY_BRANCH) && 1 || 0 }} - - - uses: actions/checkout@v4 - if: ${{ github.event_name == 'push' }} - - - name: Download Artifacts - uses: actions/download-artifact@v4 - with: - path: fpm-cd-artifacts - merge-multiple: true - - - name: Normalize file names for continuous delivery - if: ${{ github.event_name == 'push' }} - run: | - cd fpm-cd-artifacts - for output in fpm-*; do - mv -v $(basename $output) $(basename $output | sed -E '${{ env.replace }}') - done - env: - replace: 's/-([0-9]+\.[0-9]+\.[0-9]+-[0-9]+-g)?[0-9a-f]+//' - - - name: Create SHA256 checksums - run: | - cd fpm-cd-artifacts - for output in fpm-*; do - sha256sum $(basename "$output") | tee $(basename "$output").sha256 - done - - - name: Move/Create continuous tag - if: ${{ github.event_name == 'push' && steps.deploy-on-push.outputs.result != 0 }} - run: | - git tag --force 'current' ${{ github.sha }} - git push --tags --force - - - name: Upload assets - if: ${{ github.event_name == 'release' || steps.deploy-on-push.outputs.result != 0 }} - uses: svenstaro/upload-release-action@v2 - with: - repo_token: ${{ secrets.GITHUB_TOKEN }} - file: fpm-cd-artifacts/* - file_glob: true - tag: ${{ github.event_name == 'release' && github.ref || 'current'}} - overwrite: true diff --git a/.gitignore b/.gitignore deleted file mode 100644 index a7b1ac33f6..0000000000 --- a/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -build/* - -# Visual Studio Code -.vscode/ - -# CodeBlocks -project/ - -# Temporary files -*.swp - diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index a4a21474ac..0000000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,121 +0,0 @@ -# Contributing to the Fortran Package Manager - -Thank you for considering contributing to the Fortran Package Manager (*fpm*). -Please review and follow these guidelines to make the contribution process -simple and effective for all involved. It will help communicate that you -respect the time of the community developers. In return, the community will -help address your problem, evaluate changes, and guide you through your pull -requests. - -By contributing to *fpm*, you certify that you own or are allowed to share the -content of your contribution under the [fpm license](LICENSE). - -* [Style](#style) -* [Reporting a bug](#reporting-a-bug) -* [Suggesting a feature](#suggesting-a-feature) -* [Workflow](#workflow) -* [General guidelines](#general-guidelines) -* [For new contributors](#for-new-contributors) - -## Style - -Please follow the -[Fortran stdlib style guide](https://github.com/fortran-lang/stdlib/blob/master/STYLE_GUIDE.md) -for any Fortran code that you contribute. -This allows us to focus on substance rather than style. - -## Reporting a bug - -A bug is a *demonstrable problem* caused by the code in this repository. -Good bug reports are extremely valuable to us—thank you! - -Before opening a bug report: - -1. Check if the issue has already been reported - ([issues](https://github.com/fortran-lang/fpm/issues)). -2. Check if it is still an issue or it has been fixed? - Try to reproduce it with the latest version from the default branch. -3. Isolate the problem and create a minimal test case. - -A good bug report should include all information needed to reproduce the bug. -Please be as detailed as possible: - -1. Which version of *fpm* are you using? Please be specific. -2. What are the steps to reproduce the issue? -3. What is the expected outcome? -4. What happens instead? - -This information will help the community diagnose the issue quickly and with -minimal back-and-forth. - -## Suggesting a feature - -Before suggesting a new feature, take a moment to find out if it fits the scope -of the project, or if it has already been discussed. It is up to you to provide -a strong argument to convince the community of the benefits of this feature. -Please provide as much detail and context as possible. If applicable, include a -mocked-up snippet of what the output or behavior would look like with this -feature implemented. “Crazy”, out-of-the-box ideas are especially welcome. -It’s quite possible that we are not considering an unusually creative solution. - -## Workflow - -*fpm* is a community project. There is no one single person making final -decisions. This is the workflow that we follow: - -1. Open a [new issue](https://github.com/fortran-lang/fpm/issues/new) to - describe a bug or propose a new feature. - Refer to the earlier sections on how to write a good bug report or feature - request. -2. Discuss with the community and reach majority consensus about what should be - done about the bug or feature request. - We define “majority” loosely as 80%. - This means that at least 4 of 5 people engaged in the discussion should be - able to agree on the next step. - This allows us to have the community mostly agree while not getting stuck if - one person disagrees. - At this stage, the scope of the fix/feature, its behavior, and API if - applicable should be defined. - Only when you have community consensus on these items you should proceed to - writing code and opening a PR. - **When actively working on code towards a PR, please assign yourself to the - issue on GitHub.** - This is good collaborative practice to avoid duplicated effort and also - inform others what you are currently working on. -3. Open a new Pull Request (PR) with your contribution. - The body of the PR should at least include a bullet-point summary of the - changes, and a detailed description is encouraged. - If the PR completely addresses the issue you opened in step 1, include in - the PR description the following line: `Fixes #`. -4. Request reviewers to your PR. - For small bug fixes or documentation improvements, 1 to 2 reviewers is - sufficient. - For implementation of bigger features, request 3 to 4 or more reviewers. - Ideally, request reviewers that participated in step 2. -5. If your PR implements a feature that adds or changes the behavior of *fpm*, - your PR must also include appropriate changes to the documentation. - -This workflow can evolve and change over time as we learn how best to work -together. If you have an idea on how to improve the workflow itself, please -open an issue and we’ll discuss it. - -## General guidelines - -* A PR should implement *only one* feature or bug fix. -* Do not commit changes to files that are irrelevant to your feature or bug fix. -* Smaller PRs are better than large PRs, and will lead to a shorter review and - merge cycle -* Add tests for your feature or bug fix to be sure that it stays functional and useful -* Be open to constructive criticism and requests for improving your code. -* Again, please follow the - [Fortran stdlib style guide](https://github.com/fortran-lang/stdlib/blob/master/STYLE_GUIDE.md). - -## For new contributors - -If you have never created a pull request before, welcome :tada:. -You can learn how from -[this great tutorial](https://app.egghead.io/courses/how-to-contribute-to-an-open-source-project-on-github). - -Don’t know where to start? -You can start by looking through the list of -[open issues](https://github.com/fortran-lang/fpm/issues). diff --git a/ChangeLog.md b/ChangeLog.md deleted file mode 100644 index b6fab63b6a..0000000000 --- a/ChangeLog.md +++ /dev/null @@ -1,3 +0,0 @@ -# Changelog for fpm - -## Unreleased changes diff --git a/LICENSE b/LICENSE deleted file mode 100644 index e3f75628d6..0000000000 --- a/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2020 fpm contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/PACKAGING.md b/PACKAGING.md deleted file mode 100644 index 32bc51bfda..0000000000 --- a/PACKAGING.md +++ /dev/null @@ -1,718 +0,0 @@ -# Preparing your package for FPM - -This document describes how you need to organize your application or library for -it to successfully build with the Fortran Package Manager (*fpm*). - -* [What kind of package can fpm build?](#what-kind-of-package-can-fpm-build) -* [Example package layouts](#example-package-layouts) - - [Single program](#single-program) - - [Single-module library](#single-module-library) - - [Multi-module library](#multi-module-library) - - [Application and library](#application-and-library) - - [Multi-level library](#multi-level-library) - - [Be more explicit](#be-more-explicit) - - [Add some tests](#add-some-tests) - - [Adding dependencies](#adding-dependencies) - - [Custom build scripts](#custom-build-scripts) - -## What kind of package can fpm build? - -You can use *fpm* to build: - -* Applications (program only) -* Libraries (modules only) -* Combination of the two (programs and modules combined) - -Let’s look at some examples of different kinds of package layouts that you can -use with *fpm*. - -## Example package layouts - -This section describes some example package layouts that you can build with -*fpm*. You can use them to model the layout of your own package. - -### Single program - -Let’s start with the simplest package imaginable—a single program without -dependencies or modules. Here’s what the layout of the top-level directory -looks like: - -``` -. -├── app -│   └── main.f90 -└── fpm.toml -``` - -We have one source file (`main.f90`) in one directory (`app`). Its contents -are: - -```fortran -program main - print *, 'Hello, World!' -end program main -``` - -This program prints the usual greeting to the standard output, and nothing more. - -There’s another important file in the top-level directory, `fpm.toml`. This is -*fpm*’s configuration file specific to your package. It includes all the data -that *fpm* needs to build your app. In our simple case, it looks like this: - -```toml -name = "hello" -version = "0.1.0" -license = "MIT" -author = "Jane Programmer" -maintainer = "jane@example.com" -copyright = "2020 Jane Programmer" -``` - -The preamble includes some metadata, such as `license`, `author`, and similar, -that you may have seen in other package manager configuration files. The one -option that matters here right now is: - -```toml -name = "hello" -``` - -This line specifies the name of your package, which determines the name of the -executable file of your program. In this example, our program executable, once -built, will be called `hello`. - -Let’s now build this program using *fpm*: - -``` -$ fpm build -# gfortran (for build/debug/app/main.o) -# gfortran (for build/debug/app/hello) -``` - -On the first line, we ran `fpm build` to compile and link the application. -The latter two lines are emitted by *fpm*, and indicate which command was -executed at each build step (`gfortran`), and which files have been output -by it: object file `main.o`, and executable `hello`. - -We can now run the app with `fpm run`: - -``` -$ fpm run - Hello, World! -``` - -If your application needs to use a module internally, but you don’t intend -to build it as a library to be used in other projects, you can include the -module in your program source file as well. -For example: - -```fortran -$ cat app/main.f90 -module math_constants - real, parameter :: pi = 4 * atan(1.) -end module math_constants - -program main - use math_constants, only: pi - print *, 'Hello, World!' - print *, 'pi = ', pi -end program main -``` - -Now, run this using `fpm run`: - -``` -$ fpm run -# gfortran (for build/debug/app/main.o) -# gfortran (for build/debug/app/hello) - Hello, World! - pi = 3.14159274 -``` - -Although we have named our program `hello`, which is the same name as the -package name in `fpm.toml`, you can name it anything you want as long as it’s -permitted by the language. - -Notice that you can run `fpm run`, and if the package hasn’t been built yet, -`fpm build` will run automatically for you. This is true if the source files -have been updated since the last build. Thus, if you want to run your -application, you can skip the `fpm build` step, and go straight to `fpm run`. - -When running your application using `fpm run`, the program's exit code is -passed by *fpm* back to the operating system. So, it is possible to use Fortran -numbered `stop` and `error stop` codes to pass termination reasons back to the terminal. - -Try running the following app with `fpm run`: - -```fortran -program main - use math_constants, only: pi - - real :: angle - - read(*,*,iostat=ierr) angle - if (ierr/=0) then - stop 2 ! Not real - elseif (angle>pi) then - stop 1 - else - stop 0 - endif -end program main -``` - -and then checking that the error code matches. Note that error codes are passed to variable `$?` -on Unix/Mac systems, and to environment variable `%errorlevel%` on Windows. - -In this last example, our source file defined a `math_constants` module inside -the same source file as the main program. Let’s see how we can define an *fpm* -package that makes this module available as a library. - -### Single-module library - -The package layout for this example looks like this: - -``` -. -├── fpm.toml -└── src - └── math_constants.f90 -``` - -In this example we’ll build a simple math constants library that exports -the number pi as a parameter: - -```fortran -$ cat src/math_constants.f90 -module math_constants - real, parameter :: pi = 4 * atan(1.) -end module math_constants -``` - -and our `fpm.toml` is the same as before. - -Now use `fpm build` to build the package: - -``` -$ fpm build -# gfortran (for build/debug/library/math_constants.o build/debug/library/math_constants.mod) -# ar (for build/debug/library/math_constants.a) -ar: creating build/debug/library/math_constants.a -``` - -Based on the output of `fpm build`, *fpm* first ran `gfortran` to emit the -binary object (`math_constants.o`) and module (`math_constants.mod`) files. -Then it ran `ar` to create a static library archive `math_constants.a`. -`build/debug/library` is thus both your include and library path, should you -want to compile and link an external program with this library. - -For modules in the top-level (`src`) directory, *fpm* requires that: - -* The module has the same name as the source file. -* There is only one module per file. - -These two requirements simplify the build process for *fpm*. As Fortran -compilers emit module files (`.mod`) with the same name as the module itself -(but not the source file, `.f90`), naming the module the same as the source file -allows *fpm* to: - -* Uniquely and exactly map a source file (`.f90`) to its object (`.o`) and -module (`.mod`) files. -* Avoid conflicts with modules of the same name that could appear in dependency -packages (more on this in a bit). - -Since this is a library without executable programs, `fpm run` here does -nothing. - -In this example, our library is made of only one module. However, most -real-world libraries are likely to use multiple modules. Let’s see how you can -package your multi-module library. - -### Multi-module library - -In this example, we’ll use another module to define a 64-bit real kind -parameter and make it available in `math_constants` to define `pi` with -higher precision. To make this exercise worthwhile, we’ll define another math -constant, Euler’s number. - -Our package layout looks like this: - -``` -. -├── fpm.toml -└── src - ├── math_constants.f90 - └── type_kinds.f90 -``` - -And our source file contents are: - -```fortran -$ cat src/math_constants.f90 -module math_constants - use type_kinds, only: rk - real(rk), parameter :: pi = 4 * atan(1._rk) - real(rk), parameter :: e = exp(1._rk) -end module math_constants - -$ cat src/type_kinds.f90 -module type_kinds - use iso_fortran_env, only: real64 - integer, parameter :: rk = real64 -end module type_kinds -``` - -and there are no changes to our `fpm.toml` relative to previous examples. - -Like before, notice that the module `type_kinds` is name exactly as the -source file that contains it. -This is important. - -By now you know how to build the package: - -``` -$ fpm build -# gfortran (for build/debug/library/type_kinds.o build/debug/library/type_kinds.mod) -# gfortran (for build/debug/library/math_constants.o build/debug/library/math_constants.mod) -# ar (for build/debug/library/math_constants.a) -ar: creating build/debug/library/math_constants.a -``` - -Our build path now contains: - -``` -$ ls build/debug/library/ -math_constants.a math_constants.mod math_constants.o type_kinds.mod type_kinds.o -``` - -And the static library includes all the object files: - -``` -$ nm build/debug/library/math_constants.a - -math_constants.o: - -type_kinds.o: -``` - -The takeaways from this example are that: - -* *fpm* automatically scanned the `src` directory for any source files. -* It also resolved the dependency order between different modules. - -### Application and library - -Let’s now combine the two previous examples into one: We’ll build the math -constants library *and* an executable program that uses it. We’ll use this -program as a demo, and to verify that defining higher-precision constants from -the previous example actually worked. - -Here’s the package layout for your application + library package: - -``` -. -├── app -│   └── main.f90 -├── fpm.toml -└── src - ├── math_constants.f90 - └── type_kinds.f90 -``` - -Our `fpm.toml` remains unchanged and our executable program source file is: - -```fortran -$ cat app/main.f90 -program main - use math_constants, only: e, pi - print *, 'math_constants library demo' - print *, 'pi = ', pi - print *, 'e = ', e -end program main -``` - -Let’s go straight to running the demo program: - -``` -$ fpm run -# gfortran (for build/debug/library/type_kinds.o build/debug/library/type_kinds.mod) -# gfortran (for build/debug/library/math_constants.o build/debug/library/math_constants.mod) -# ar (for build/debug/library/math_constants.a) -ar: creating build/debug/library/math_constants.a -# gfortran (for build/debug/app/main.o) -# gfortran (for build/debug/app/math_constants) - math_constants library demo - pi = 3.1415926535897931 - e = 2.7182818284590451 -``` - -The *fpm* build + run process works as expected, and our program correctly -outputs higher-precision constants. - -So far we covered how *fpm* builds: - -* A single program -* A single-module library -* A multi-module library -* A program and a library - -However, all our modules so far have been organized in the top level source -directory. More complex libraries may organize their modules in subdirectories. -Let’s see how we can build this with *fpm*. - -### Multi-level library - -In this example, we’ll define our library as a collection of modules, two of -which are defined in a subdirectory: - -``` -. -├── app -│   └── main.f90 -├── fpm.toml -└── src - ├── math_constants - │   ├── derived.f90 - │   └── fundamental.f90 - ├── math_constants.f90 - └── type_kinds.f90 -``` - -First, `fpm.toml` and `src/type_kinds.f90` remain unchanged relative to the -previous example. - -The rest of the source files are: - -```fortran -$ cat src/math_constants.f90 -module math_constants - use math_constants_fundamental, only: e, pi - use math_constants_derived, only: half_pi, two_pi -end module math_constants - -$ cat src/math_constants/fundamental.f90 -module math_constants_fundamental - use type_kinds, only: rk - real(rk), parameter :: pi = 4 * atan(1._rk) - real(rk), parameter :: e = exp(1._rk) -end module math_constants_fundamental - -$ cat src/math_constants/derived.f90 -module math_constants_derived - use math_constants_fundamental, only: pi - use type_kinds, only: rk - real(rk), parameter :: two_pi = 2 * pi - real(rk), parameter :: half_pi = pi / 2 -end module math_constants_derived - -$ cat app/main.f90 -program main - use math_constants, only: e, pi, half_pi, two_pi - print *, 'math_constants library demo' - print *, 'pi = ', pi - print *, '2*pi = ', two_pi - print *, 'pi/2 = ', half_pi - print *, 'e = ', e -end program main -``` - -Our top-level `math_constants` module now doesn’t define the constants, but -imports them from the two modules in the subdirectory. Constants `e` and `pi` -we define in the `math_constants_fundamental` module, and `two_pi` and `half_pi` -in the `math_constants_derived` module. From the main program, we access all -the constants from the top-level module `math_constants`. - -Let’s build and run this package: - -``` -$ fpm run -# gfortran (for build/debug/library/type_kinds.o build/debug/library/type_kinds.mod) -# gfortran (for build/debug/library/math_constants_fundamental.o build/debug/library/math_constants_fundamental.mod) -# gfortran (for build/debug/library/math_constants_derived.o build/debug/library/math_constants_derived.mod) -# gfortran (for build/debug/library/math_constants.o build/debug/library/math_constants.mod) -# ar (for build/debug/library/math_constants.a) -ar: creating build/debug/library/math_constants.a -# gfortran (for build/debug/app/main.o) -# gfortran (for build/debug/app/math_constants) - math_constants library demo - pi = 3.1415926535897931 - 2*pi = 6.2831853071795862 - pi/2 = 1.5707963267948966 - e = 2.7182818284590451 -``` - -Again, *fpm* built and run the package as expected. - -Recall from an earlier example that *fpm* required the modules in the top-level -`src` directory to be named the same as their source file. This is why -`src/math_constants.f90` defines `module math_constants`. - -For modules defined in subdirectories, there’s an additional requirement: module -name must contain the path components of the directory that its source file is -in. In our case, `src/math_constants/fundamental.f90` defines the -`math_constants_fundamental` module. Likewise, `src/math_constants/derived.f90` -defines the `math_constants_derived` module. - -This rule applies generally to any number of nested directories and modules. -For example, `src/a/b/c/d.f90` must define a module called `a_b_c_d`. - -Takeaways from this example are that: - -* You can place your module source files in any levels of subdirectories inside `src`. -* The module name must include the path components and the source file name--for example, -`src/a/b/c/d.f90` must define a module called `a_b_c_d`. - -### Be more explicit - -So far we’ve let *fpm* use its defaults to determine the layout of our package. -It determined where our library sources would live, what the name of the -executable will be, and some other things. But we can be more explicit about it, -and make some changes to those things. - -Let’s look at what the `fpm.toml` file from our last example would look like if -we specified everything. - -```toml -name = "math_constants" -version = "0.1.0" -license = "MIT" -author = "Jane Programmer" -maintainer = "jane@example.com" -copyright = "2020 Jane Programmer" - -[library] -source-dir="src" - -[[ executable ]] -name="math_constants" -source-dir="app" -main="main.f90" -``` - -You can see that by making these explicit in the `fpm.toml` we are able to -change many of the settings that *fpm* used by default. We can change the -folders where our sources are stored, we can change the name of our executable, -and we can change the name of the file our program is defined in. - -### Add some tests - -*fpm* also provides support for unit testing. By default, *fpm* looks for a -program in `test/main.f90` which it will compile and execute with the command -`fpm test`. The tests are treated pretty much exactly like the executables. -Let’s define one explicitly in our `fpm.toml` file. We’ll make sure that our -definition of `pi` satisfies the property `sin(pi) == 0.0`. Here’s the -`fpm.toml` file: - -```toml -name = "math_constants" -version = "0.1.0" -license = "MIT" -author = "Jane Programmer" -maintainer = "jane@example.com" -copyright = "2020 Jane Programmer" - -[library] -source-dir="src" - -[[ executable ]] -name="math_constants" -source-dir="app" -main="main.f90" - -[[ test ]] -name="runTests" -source-dir="test" -main="main.f90" -``` - -where the contents of the `main.f90` file are - -```fortran -program main - use math_constants, only: pi - print *, "sin(pi) = ", sin(pi) -end program main -``` - -With this setup, we can run our tests. - -``` -$ fpm test -# gfortran (for build/debug/library/type_kinds.o build/debug/library/type_kinds.mod) -# gfortran (for build/debug/library/math_constants_fundamental.o build/debug/library/math_constants_fundamental.mod) -# gfortran (for build/debug/library/math_constants_derived.o build/debug/library/math_constants_derived.mod) -# gfortran (for build/debug/library/math_constants.o build/debug/library/math_constants.mod) -# ar (for build/debug/library/math_constants.a) -ar: creating build/debug/library/math_constants.a -# gfortran (for build/debug/app/main.o) -# gfortran (for build/debug/app/math_constants) -# gfortran (for build/debug/test/main.o) -# gfortran (for build/debug/test/runTests) - sin(pi) = 1.2246467991473532E-016 -``` - -### Adding dependencies - -Inevitably, you’ll want to be able to include other libraries in your project. -fpm makes this incredibly simple, by taking care of fetching and compiling your -dependencies for you. You just tell it what your dependencies are, and where to -find them. Let’s add a dependency to our library. Now our `fpm.toml` file looks -like this: - -```toml -name = "math_constants" -version = "0.1.0" -license = "MIT" -author = "Jane Programmer" -maintainer = "jane@example.com" -copyright = "2020 Jane Programmer" - -[library] -source-dir="src" - -[dependencies] -helloff = { git = "https://gitlab.com/everythingfunctional/helloff.git" } - -[[ executable ]] -name="math_constants" -source-dir="app" -main="main.f90" - -[[ test ]] -name="runTests" -source-dir="test" -main="main.f90" -``` - -Now you can use any modules from this library anywhere in your code. Just like -this: - -```fortran -program main - use helloff, only: create_greeting - use math_constants, only: e, pi, half_pi, two_pi - print *, 'math_constants library demo' - print *, 'pi = ', pi - print *, '2*pi = ', two_pi - print *, 'pi/2 = ', half_pi - print *, 'e = ', e - print *, create_greeting("fpm") -end program main -``` - -And now, `fpm run` will output the following: - -``` - math_constants library demo - pi = 3.1415926535897931 - 2*pi = 6.2831853071795862 - pi/2 = 1.5707963267948966 - e = 2.7182818284590451 - Hello, fpm! -``` - -Additionally, any users of your library will now automatically depend on your -dependencies too. So if you don’t need that dependency for the library, like in -the above example, then you can specify it for the specific executable like -below. Then fpm will still fetch and compile it when building your executable, -but users of your library won’t have to. - -```toml -name = "math_constants" -version = "0.1.0" -license = "MIT" -author = "Jane Programmer" -maintainer = "jane@example.com" -copyright = "2020 Jane Programmer" - -[library] -source-dir="src" - -[[ executable ]] -name="math_constants" -source-dir="app" -main="main.f90" -[executable.dependencies] -helloff = { git = "https://gitlab.com/everythingfunctional/helloff.git" } - -[[ test ]] -name="runTests" -source-dir="test" -main="main.f90" -``` - -You can also specify dependencies for your tests in a similar way, with -`[test.dependencies]` instead of `[executable.dependencies]`. There’s also -another option for test dependencies. The below example makes the dependencies -available for all the tests, but again your users won’t depend on these. - -```toml -name = "math_constants" -version = "0.1.0" -license = "MIT" -author = "Jane Programmer" -maintainer = "jane@example.com" -copyright = "2020 Jane Programmer" - -[library] -source-dir="src" - -[dev-dependencies] -helloff = { git = "https://gitlab.com/everythingfunctional/helloff.git" } - -[[ executable ]] -name="math_constants" -source-dir="app" -main="main.f90" - -[[ test ]] -name="runTests" -source-dir="test" -main="main.f90" -``` - -You can also be specific about which version of a dependency you’d like. You can -specify a branch to use like -`helloff = { git = "https://gitlab.com/everythingfunctional/helloff.git", branch = "master" }`, -or a tag like -`helloff = { git = "https://gitlab.com/everythingfunctional/helloff.git", tag = "v1.2.3" }`, -or even a specific commit like -`helloff = { git = "https://gitlab.com/everythingfunctional/helloff.git", rev = "a1b2c3" }`. -You can even specify the path to another folder, if for example you’ve got -another fpm package in the same repository. Like this: -`helloff = { path = "helloff" }`. Note that you should *not* specify paths -outside of your repository, or things won’t work for your users. - -### Custom build scripts - -If there is something special about your library that makes fpm unable to build -it, you can provide your own build script. fpm will then simply call your build -script to build the library. - -To specify a build script to be used, put it in the library section of your -`fpm.toml` file, like: - -```toml -[library] -source-dir="src" -build-script="my_build_script" -``` - -*fpm* will set the following environment variables to specify some parameters to -the build script: - -* `FC` – The Fortran compiler to be used. -* `FFLAGS` – The flags that should be passed to the Fortran compiler. -* `BUILD_DIR` – Where the compiled files should be placed. -* `INCLUDE_DIRS` – The folders where any dependencies can be found, space separated. -It is then the responsibility of the build script to generate the appropriate -include flags. - -Additionally, script will be called with the name of the archive (`*.a` file) -that should be produced as the command line argument. - -> Note: If the name of the build script is `Makefile` or ends with `.mk`, then -> the make program will be used to run it. Not the the archive file is explicitly -> specified as the target to be built - -> Note: All file and directory names are specified with their full canonical -> path. diff --git a/README.md b/README.md deleted file mode 100644 index 3670cede53..0000000000 --- a/README.md +++ /dev/null @@ -1,161 +0,0 @@ -

- -

- -# [Fortran Package Manager](https://fpm.fortran-lang.org/) - -Fortran Package Manager (fpm) is a package manager and build system for Fortran. -Its key goal is to improve the user experience of Fortran programmers. -It does so by making it easier to build your Fortran program or library, run the -executables, tests, and examples, and distribute it as a dependency to other -Fortran projects. -Fpm's user interface is modeled after [Rust's Cargo](https://doc.rust-lang.org/cargo/), -so if you're familiar with that tool, you will feel at home with fpm. -Fpm's long term vision is to nurture and grow the ecosystem of modern Fortran -applications and libraries. - -Fpm is an early prototype and is evolving rapidly. -You can use it to build and package your Fortran projects, as well as to use -[existing fpm packages](https://github.com/fortran-lang/fpm-registry) as dependencies. -Fpm's behavior and user interface may change as it evolves, however as fpm -matures and we enter production, we will aim to stay backwards compatible. -Please follow the [issues](https://github.com/fortran-lang/fpm/issues) to -contribute and/or stay up to date with the development. -Before opening a bug report or a feature suggestion, please read our -[Contributor Guide](CONTRIBUTING.md). You can also discuss your ideas and -queries with the community in -[fpm discussions](https://github.com/fortran-lang/fpm/discussions), -or more broadly on [Fortran-Lang Discourse](https://fortran-lang.discourse.group/). - -Fortran Package Manager is not to be confused with -[Jordan Sissel's fpm](https://github.com/jordansissel/fpm), a more general, -non-Fortran related package manager. - -**Website: ** - -## [Download](https://fpm.fortran-lang.org/install/index.html) - -Fpm is available on many platforms and through multiple package managers, see our Documentation -webpage for a list of **[All Supported Installations](https://fpm.fortran-lang.org/install/index.html)**. - -The easiest installation routes are shown below. - -### [Binary](https://github.com/fortran-lang/fpm/releases) - -Binaries for the latest stable release are available [to download](https://github.com/fortran-lang/fpm/releases/latest) for Windows, MacOS, and Linux. - -**Note:** On Linux and MacOS, you will need to enable executable permission before you can use the binary. - -_e.g._ `$ chmod u+x fpm-0.6.0-linux-x86_64` - -The binaries at the [current tag](https://github.com/fortran-lang/fpm/releases/tag/current) are updated automatically to always provide the current git version from the default branch. - -### [Conda] - -Fpm is available on [conda-forge], to add `conda-forge` to your channels use: - -```sh -conda config --add channels conda-forge -``` - -Fpm can be installed with: - -```sh -conda create -n fpm fpm -conda activate fpm -``` - -The conda package manager can be installed from [miniforge](https://github.com/conda-forge/miniforge/releases) -or from [miniconda](https://docs.conda.io/en/latest/miniconda.html). - -[Conda]: https://conda.io -[conda-forge]: https://conda-forge.org/ - -### [Homebrew](https://brew.sh/) - -The Fortran Package Manager (fpm) is available for the [Homebrew](https://brew.sh/) package manager via an additional tap. -To install fpm via brew, include the new tap and install using - -```sh -brew tap fortran-lang/fortran -brew install fpm -``` - -Binary distributions are available for MacOS 11 (Catalina) and 12 (Big Sur) for x86_64 architectures. For other platforms fpm will be built locally from source automatically. - -Fpm should be available and functional after those steps. -For more details checkout the tap [here](https://github.com/fortran-lang/homebrew-fortran). - -## [Get started](https://fpm.fortran-lang.org/tutorial/index.html) - -**Follow our [Quickstart Tutorial](https://fpm.fortran-lang.org/tutorial/hello-fpm.html) to get familiar with fpm**. - -### Start a new project - -Creating a new *fpm* project is as simple as running the command -`fpm new project_name`. This will create a new folder in your current directory -with the following contents and initialized as a git repository. - -* `fpm.toml` – with your project’s name and some default standard meta-data -* `README.md` – with your project’s name -* `.gitignore` -* `src/project_name.f90` – with a simple hello world subroutine -* `app/main.f90` (if `--app` flag used) – a program that calls the subroutine -* `test/main.f90` (if `--test` flag used) – an empty test program - -### Building your Fortran project with fpm - -*fpm* understands the basic commands: - -* `fpm build` – build your library, executables and tests -* `fpm run` – run executables -* `fpm test` – run tests -* `fpm install` - installs the executables locally - -The command `fpm run` can optionally accept the name of the specific executable -to run, as can `fpm test`; like `fpm run specific_executable`. Command line -arguments can also be passed to the executable(s) or test(s) with the option -`-- some arguments`. - -See additional instructions in the [Packaging guide](PACKAGING.md) or -the [manifest reference](https://fpm.fortran-lang.org/spec/manifest.html). - - - -## Environmental variables - -The table below lists the environment variables that control `fpm`'s choice of compilers, -compiler flags, archiver locations, and link flags, each of which can be overridden by -passing `fpm` flags also shown in the table. - -| Environment Variable | Defines | Overridden by | -| :------------------- | :-------------------- | :--------------- | -| `FPM_FC` | Fortran compiler path | `--compiler` | -| `FPM_CC` | C compiler path | `--c-compiler` | -| `FPM_CXX` | C++ compiler path | `--cxx-compiler` | -| `FPM_FFLAGS` | Fortran compiler flags| `--flag` | -| `FPM_CFLAGS` | C compiler flags | `--c-flag` | -| `FPM_CXXFLAGS` | C++ compiler flags | `--cxx-flag` | -| `FPM_AR` | Archiver path | `--archiver` | -| `FPM_LDFLAGS` | Link flags | `--link-flag` | diff --git a/ci/fpm-installer.nsi b/ci/fpm-installer.nsi deleted file mode 100644 index 0c0243b555..0000000000 --- a/ci/fpm-installer.nsi +++ /dev/null @@ -1,112 +0,0 @@ -; NSIS Installer script for the Fortran Package Manager - -; ---------------- Properties ---------------- -; Name used in installer GUI -Name "Fortran Package Manager" - -; Name for folder location and reg key -!define INSTALL_NAME "fortran-lang" - -; Installer icon -!define MUI_ICON "installer-icon.ico" - -; Compress installer -SetCompress auto - -; Always produce unicode installer -Unicode true - -; ---------------- Setup ---------------- -; Use EnVar plugin (https://nsis.sourceforge.io/EnVar_plug-in) -!addplugindir ".\EnVar_plugin\Plugins\x86-unicode" - -; Use the 'Modern' Installer UI macros -!include "MUI2.nsh" - -; Default installation folder (local) -InstallDir "$LOCALAPPDATA\${INSTALL_NAME}" - -; Get installation folder from registry if available -InstallDirRegKey HKCU "Software\${INSTALL_NAME}" "" - -; Request application privileges -RequestExecutionLevel user - - -; ---------------- Installer Pages ---------------- -!insertmacro MUI_PAGE_COMPONENTS -!insertmacro MUI_PAGE_DIRECTORY -!insertmacro MUI_PAGE_INSTFILES - - -; ---------------- Uninstaller Pages ---------------- -!insertmacro MUI_UNPAGE_CONFIRM -!insertmacro MUI_UNPAGE_INSTFILES - - -; MUI Language -!insertmacro MUI_LANGUAGE "English" - - -; ---------------- Component: Core Installation ---------------- -Section "-Core" SecCore - - SetOutPath "$INSTDIR" - - ; Store installation folder - WriteRegStr HKCU "Software\${INSTALL_NAME}" "" $INSTDIR - - ; Create uninstaller - WriteUninstaller "$INSTDIR\Uninstall.exe" - - ; Add to path - EnVar::SetHKCU - EnVar::AddValue "PATH" "$INSTDIR\fpm" - EnVar::AddValue "PATH" "$INSTDIR\MinGit\mingw64\bin" - -SectionEnd - - -; ---------------- Component: fpm ---------------- -Section "FPM" SecFPM - - SetOutPath "$INSTDIR\fpm" - - File "fpm.exe" - -SectionEnd - - -; ---------------- Component: Git ---------------- -Section "Git for Windows" SecGit - - SetOutPath "$INSTDIR" - - File /r "MinGit" - -SectionEnd - - -; ---------------- Uninstaller ---------------- -Section "Uninstall" - - RMDir /r "$INSTDIR" - - DeleteRegKey /ifempty HKCU "Software\${INSTALL_NAME}" - - EnVar::SetHKCU - EnVar::DeleteValue "PATH" "$INSTDIR\fpm" - EnVar::DeleteValue "PATH" "$INSTDIR\MinGit\mingw64\bin" - -SectionEnd - - -; ---------------- Component description Strings (EN) ---------------- -LangString DESC_SecFPM ${LANG_ENGLISH} "The Fortran Package Manager" -LangString DESC_SecGit ${LANG_ENGLISH} "Git version control (required for FPM)" - - -!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN - !insertmacro MUI_DESCRIPTION_TEXT ${SecFPM} $(DESC_SecFPM) - !insertmacro MUI_DESCRIPTION_TEXT ${SecGit} $(DESC_SecGit) -!insertmacro MUI_FUNCTION_DESCRIPTION_END diff --git a/ci/meta_tests.sh b/ci/meta_tests.sh deleted file mode 100755 index 6c1754e491..0000000000 --- a/ci/meta_tests.sh +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/env bash -set -ex - -# *********************** -# This script tests all example packages using any metapackage/system dependencies -# *********************** - -cd "$(dirname $0)/.." - -if [ "$1" ]; then - fpm="$1" -else - fpm=fpm -fi - -# Build example packages -pushd example_packages/ -rm -rf ./*/build - -pushd metapackage_openmp -"$fpm" build --verbose -"$fpm" run --verbose -popd - -pushd metapackage_stdlib -"$fpm" build --verbose -"$fpm" run --verbose -popd - -pushd metapackage_minpack -"$fpm" build --verbose -"$fpm" run --verbose -popd - -pushd metapackage_mpi -"$fpm" build --verbose -"$fpm" run --verbose -popd - -pushd metapackage_mpi_c -"$fpm" build --verbose -"$fpm" run --verbose -popd - -pushd metapackage_hdf5 -"$fpm" build --verbose -"$fpm" run --verbose -popd - -pushd metapackage_netcdf -"$fpm" build --verbose -"$fpm" run --verbose -popd - -pushd metapackage_blas -"$fpm" build --verbose -"$fpm" run --verbose -popd - -pushd metapackage_stdlib_extblas -"$fpm" build --verbose -"$fpm" run --verbose -popd - -# Cleanup -rm -rf ./*/build diff --git a/ci/run_tests.sh b/ci/run_tests.sh deleted file mode 100755 index 0260743f16..0000000000 --- a/ci/run_tests.sh +++ /dev/null @@ -1,348 +0,0 @@ -#!/usr/bin/env bash -set -ex - -cd "$(dirname $0)/.." - -if [ "$1" ]; then - fpm="$1" -else - fpm=fpm -fi - -# Build example packages -pushd example_packages/ -rm -rf ./*/build - -dir=hello_world -"$fpm" -C $dir build -"$fpm" -C $dir run --target hello_world -"$fpm" -C $dir/app run - -pushd hello_fpm -"$fpm" build -"$fpm" run --target hello_fpm -popd - -pushd circular_test -"$fpm" build -popd - -pushd circular_example -"$fpm" build -popd - -pushd nonintrinsic -"$fpm" build -popd - -pushd hello_complex -"$fpm" build -"$fpm" test -"$fpm" run --target say_Hello -"$fpm" run --target say_goodbye -"$fpm" test --target greet_test -"$fpm" test --target farewell_test -popd - -pushd hello_complex_2 -"$fpm" build -"$fpm" run --target say_hello_world -"$fpm" run --target say_goodbye -"$fpm" test --target greet_test -"$fpm" test --target farewell_test -popd - -pushd with_examples -"$fpm" build -"$fpm" run --example --target demo-prog -"$fpm" run --target demo-prog -popd - -pushd many_examples - -"$fpm" run --example --all -test -e demo1.txt -test -e demo2.txt -popd - -# Test building individual targets -pushd many_targets -cases=( "1" "2" "3" ) -targets=( "run" "example" "test" ) -cmdrun=( "run --target" "run --example" "test --target" ) -for j in {0..2} -do - for i in {0..2} - do - rm -f *.txt - this=${cases[$i]} - others=${cases[@]/$this} - filename=${targets[$j]}$this - echo "$filename" - "$fpm" ${cmdrun[$j]} $filename - test -e $filename.txt - # non-i-th tests should not have run - for k in ${others[@]} - do - test ! -e ${targets[$k]}$k.txt - done - done -done - -# Test building all targets and with runner -if [[ "$(which time)" ]]; then -targets=( "run" "run --example" "test" ) -names=( "run" "example" "test" ) -cmdrun=( " " " --runner time" ) -for j in {0..2} -do - for i in {0..1} - do - rm -f *.txt - "$fpm" ${targets[$j]}${cmdrun[$i]} - # all targets should have run - for k in ${cases[@]} - do - test -e ${names[$j]}$k.txt - done - done -done -fi -popd - - -pushd auto_discovery_off -"$fpm" build -"$fpm" run --target auto_discovery_off -"$fpm" test --target my_test -test ! -x ./build/gfortran_*/app/unused -test ! -x ./build/gfortran_*/test/unused_test -popd - -pushd auto_with_nondefault_main -"$fpm" build -"$fpm" install --prefix=./installed -test -x ./installed/bin/non_default_name -popd - -pushd tree_shake -"$fpm" build -"$fpm" run -"$fpm" test -test ! -e ./build/gfortran_*/tree_shake/src_farewell_m.f90.o -test ! -e ./build/gfortran_*/tree_shake/src_farewell_m.f90.o.log -popd - -pushd submodule_tree_shake -"$fpm" run -test ! -e ./build/gfortran_*/submodule_tree_shake/src_parent_unused.f90.o -test ! -e ./build/gfortran_*/submodule_tree_shake/src_parent_unused.f90.o.log -test ! -e ./build/gfortran_*/submodule_tree_shake/src_child_unused.f90.o -test ! -e ./build/gfortran_*/submodule_tree_shake/src_child_unused.f90.o.log -popd - -pushd version_file -"$fpm" build -"$fpm" run -popd - -pushd with_c -"$fpm" build -"$fpm" run --target with_c -popd - -pushd submodules -"$fpm" build -popd - -pushd app_with_submodule -"$fpm" run --all -popd - -pushd program_with_module -"$fpm" build -"$fpm" run --target Program_with_module -popd - -pushd link_executable -"$fpm" build -"$fpm" run --target gomp_test -popd - -pushd fortran_includes -"$fpm" build -popd - -pushd c_includes -"$fpm" build -popd - -pushd c_header_only -"$fpm" build -popd - -pushd c_main -"$fpm" run -popd - -pushd c_main_preprocess -"$fpm" build --c-flag "-DVAL" -popd - -pushd app_with_c -"$fpm" run -popd - -pushd hello_fpm_path -"$fpm" run -popd - -pushd preprocess_cpp -"$fpm" build -popd - -pushd preprocess_cpp_c -"$fpm" run -popd - -pushd preprocess_cpp_deps -"$fpm" build -popd - -pushd preprocess_cpp_suffix -"$fpm" run -popd - -pushd preprocess_per_dependency -"$fpm" run -popd - -pushd preprocess_hello -"$fpm" build -popd - -pushd fpm_test_exe_issues -"$fpm" build -popd - -pushd cpp_files -"$fpm" test -popd - -# Test Fortran features -for feature in free-form fixed-form implicit-typing implicit-external -do - pushd $feature - "$fpm" run - popd -done - -# Test app exit codes -pushd fpm_test_exit_code -"$fpm" build - -# odd number -> success! -EXIT_CODE=0 -"$fpm" run -- 1 || EXIT_CODE=$? -test $EXIT_CODE -eq 0 - -# even number -> error 3 -EXIT_CODE=0 -"$fpm" run -- 512 || EXIT_CODE=$? -test $EXIT_CODE -eq 3 - -# even number -> error 3 -EXIT_CODE=0 -"$fpm" run -- 0 || EXIT_CODE=$? -test $EXIT_CODE -eq 3 - -# not an integer -> error 2 -EXIT_CODE=0 -"$fpm" run -- 3.1415 || EXIT_CODE=$? -if [[ "$FPM_FC" == "ifx" ]]; then - test $EXIT_CODE -eq 0 # ifx does not return error code on non-integer input -else - test $EXIT_CODE -eq 2 -fi - -# not a number -> error 2 -EXIT_CODE=0 -"$fpm" run -- notanumber || EXIT_CODE=$? -test $EXIT_CODE -eq 2 - -# no arguments -> error 1 -EXIT_CODE=0 -"$fpm" run || EXIT_CODE=$? -test $EXIT_CODE -eq 1 -popd - -# test dependency priority -pushd dependency_priority - -# first build should run OK -EXIT_CODE=0 -"$fpm" run || EXIT_CODE=$? -test $EXIT_CODE -eq 0 - -"$fpm" build --verbose - -# Build again, should update nothing -"$fpm" build --verbose > build.log -if [[ -n "$(grep Update build.log)" ]]; then - echo "Some dependencies were updated that should not be"; - exit 1; -fi - -# Request update --clean, should update all dependencies -"$fpm" update --clean --verbose > update.log -if [[ -z "$(grep Update update.log)" ]]; then - echo "No updated dependencies after 'fpm update --clean'"; - exit 1; -fi - -# Test that no files are lost during multiple `install`s -# including overwriting the same install -"$fpm" install --prefix a -"$fpm" install --prefix a -"$fpm" install --prefix a -"$fpm" install --prefix b -"$fpm" install --prefix c - -popd - -# Test shared library dependencies -pushd shared_lib -"$fpm" build || EXIT_CODE=$? -test $EXIT_CODE -eq 0 -popd - -pushd shared_lib_extra -"$fpm" build || EXIT_CODE=$? -test $EXIT_CODE -eq 0 -popd - -pushd shared_lib_empty -"$fpm" build -"$fpm" run -"$fpm" test -popd - -pushd static_lib_empty -"$fpm" build -"$fpm" run -"$fpm" test -popd - -pushd shared_app_only -"$fpm" test || EXIT_CODE=$? -test $EXIT_CODE -eq 0 -popd - -# Static library dependencies -pushd static_app_only -"$fpm" test || EXIT_CODE=$? -test $EXIT_CODE -eq 0 -popd - -# Cleanup -rm -rf ./*/build diff --git a/ci/single-file-gfortran.sh b/ci/single-file-gfortran.sh deleted file mode 100755 index 904c7f8af5..0000000000 --- a/ci/single-file-gfortran.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash - -output="${OUTPUT:-fpm-single-file.F90}" - -args=("$@") -file=$(printf "%s\n" "${args[@]}" | grep -P '^.+\.[fF]90$') -if [ $? = 0 ]; then - echo " + Appending source file '$file' to '${output}'" - cat $file >> "${output}" -fi -exec gfortran "${args[@]}" diff --git a/ci/single-file.patch b/ci/single-file.patch deleted file mode 100644 index 9817638dd3..0000000000 --- a/ci/single-file.patch +++ /dev/null @@ -1,30 +0,0 @@ -diff --git a/fpm.toml b/fpm.toml -index 51faa0e9..273e8e0e 100644 ---- a/fpm.toml -+++ b/fpm.toml -@@ -17,23 +17,5 @@ M_CLI2.rev = "7264878cdb1baff7323cc48596d829ccfe7751b8" - jonquil.git = "https://github.com/toml-f/jonquil" - jonquil.rev = "05d30818bb12fb877226ce284b9a3a41b971a889" - --[[test]] --name = "cli-test" --source-dir = "test/cli_test" --main = "cli_test.f90" -- --[[test]] --name = "new-test" --source-dir = "test/new_test" --main = "new_test.f90" -- --[[test]] --name = "fpm-test" --source-dir = "test/fpm_test" --main = "main.f90" -- --[[test]] --name = "help-test" --source-dir = "test/help_test" --main = "help_test.f90" -- -+[build] -+auto-tests = false diff --git a/css/brands.css b/css/brands.css new file mode 100644 index 0000000000..8ae2f76285 --- /dev/null +++ b/css/brands.css @@ -0,0 +1,1609 @@ +/*! + * Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + * Copyright 2024 Fonticons, Inc. + */ +:root, :host { + --fa-style-family-brands: 'Font Awesome 6 Brands'; + --fa-font-brands: normal 400 1em/1 'Font Awesome 6 Brands'; } + +@font-face { + font-family: 'Font Awesome 6 Brands'; + font-style: normal; + font-weight: 400; + font-display: block; + src: url("../webfonts/fa-brands-400.woff2") format("woff2"), url("../webfonts/fa-brands-400.ttf") format("truetype"); } + +.fab, +.fa-brands { + font-weight: 400; } + +.fa-monero { + --fa: "\f3d0"; } + +.fa-hooli { + --fa: "\f427"; } + +.fa-yelp { + --fa: "\f1e9"; } + +.fa-cc-visa { + --fa: "\f1f0"; } + +.fa-lastfm { + --fa: "\f202"; } + +.fa-shopware { + --fa: "\f5b5"; } + +.fa-creative-commons-nc { + --fa: "\f4e8"; } + +.fa-aws { + --fa: "\f375"; } + +.fa-redhat { + --fa: "\f7bc"; } + +.fa-yoast { + --fa: "\f2b1"; } + +.fa-cloudflare { + --fa: "\e07d"; } + +.fa-ups { + --fa: "\f7e0"; } + +.fa-pixiv { + --fa: "\e640"; } + +.fa-wpexplorer { + --fa: "\f2de"; } + +.fa-dyalog { + --fa: "\f399"; } + +.fa-bity { + --fa: "\f37a"; } + +.fa-stackpath { + --fa: "\f842"; } + +.fa-buysellads { + --fa: "\f20d"; } + +.fa-first-order { + --fa: "\f2b0"; } + +.fa-modx { + --fa: "\f285"; } + +.fa-guilded { + --fa: "\e07e"; } + +.fa-vnv { + --fa: "\f40b"; } + +.fa-square-js { + --fa: "\f3b9"; } + +.fa-js-square { + --fa: "\f3b9"; } + +.fa-microsoft { + --fa: "\f3ca"; } + +.fa-qq { + --fa: "\f1d6"; } + +.fa-orcid { + --fa: "\f8d2"; } + +.fa-java { + --fa: "\f4e4"; } + +.fa-invision { + --fa: "\f7b0"; } + +.fa-creative-commons-pd-alt { + --fa: "\f4ed"; } + +.fa-centercode { + --fa: "\f380"; } + +.fa-glide-g { + --fa: "\f2a6"; } + +.fa-drupal { + --fa: "\f1a9"; } + +.fa-jxl { + --fa: "\e67b"; } + +.fa-dart-lang { + --fa: "\e693"; } + +.fa-hire-a-helper { + --fa: "\f3b0"; } + +.fa-creative-commons-by { + --fa: "\f4e7"; } + +.fa-unity { + --fa: "\e049"; } + +.fa-whmcs { + --fa: "\f40d"; } + +.fa-rocketchat { + --fa: "\f3e8"; } + +.fa-vk { + --fa: "\f189"; } + +.fa-untappd { + --fa: "\f405"; } + +.fa-mailchimp { + --fa: "\f59e"; } + +.fa-css3-alt { + --fa: "\f38b"; } + +.fa-square-reddit { + --fa: "\f1a2"; } + +.fa-reddit-square { + --fa: "\f1a2"; } + +.fa-vimeo-v { + --fa: "\f27d"; } + +.fa-contao { + --fa: "\f26d"; } + +.fa-square-font-awesome { + --fa: "\e5ad"; } + +.fa-deskpro { + --fa: "\f38f"; } + +.fa-brave { + --fa: "\e63c"; } + +.fa-sistrix { + --fa: "\f3ee"; } + +.fa-square-instagram { + --fa: "\e055"; } + +.fa-instagram-square { + --fa: "\e055"; } + +.fa-battle-net { + --fa: "\f835"; } + +.fa-the-red-yeti { + --fa: "\f69d"; } + +.fa-square-hacker-news { + --fa: "\f3af"; } + +.fa-hacker-news-square { + --fa: "\f3af"; } + +.fa-edge { + --fa: "\f282"; } + +.fa-threads { + --fa: "\e618"; } + +.fa-napster { + --fa: "\f3d2"; } + +.fa-square-snapchat { + --fa: "\f2ad"; } + +.fa-snapchat-square { + --fa: "\f2ad"; } + +.fa-google-plus-g { + --fa: "\f0d5"; } + +.fa-artstation { + --fa: "\f77a"; } + +.fa-markdown { + --fa: "\f60f"; } + +.fa-sourcetree { + --fa: "\f7d3"; } + +.fa-google-plus { + --fa: "\f2b3"; } + +.fa-diaspora { + --fa: "\f791"; } + +.fa-foursquare { + --fa: "\f180"; } + +.fa-stack-overflow { + --fa: "\f16c"; } + +.fa-github-alt { + --fa: "\f113"; } + +.fa-phoenix-squadron { + --fa: "\f511"; } + +.fa-pagelines { + --fa: "\f18c"; } + +.fa-algolia { + --fa: "\f36c"; } + +.fa-red-river { + --fa: "\f3e3"; } + +.fa-creative-commons-sa { + --fa: "\f4ef"; } + +.fa-safari { + --fa: "\f267"; } + +.fa-google { + --fa: "\f1a0"; } + +.fa-square-font-awesome-stroke { + --fa: "\f35c"; } + +.fa-font-awesome-alt { + --fa: "\f35c"; } + +.fa-atlassian { + --fa: "\f77b"; } + +.fa-linkedin-in { + --fa: "\f0e1"; } + +.fa-digital-ocean { + --fa: "\f391"; } + +.fa-nimblr { + --fa: "\f5a8"; } + +.fa-chromecast { + --fa: "\f838"; } + +.fa-evernote { + --fa: "\f839"; } + +.fa-hacker-news { + --fa: "\f1d4"; } + +.fa-creative-commons-sampling { + --fa: "\f4f0"; } + +.fa-adversal { + --fa: "\f36a"; } + +.fa-creative-commons { + --fa: "\f25e"; } + +.fa-watchman-monitoring { + --fa: "\e087"; } + +.fa-fonticons { + --fa: "\f280"; } + +.fa-weixin { + --fa: "\f1d7"; } + +.fa-shirtsinbulk { + --fa: "\f214"; } + +.fa-codepen { + --fa: "\f1cb"; } + +.fa-git-alt { + --fa: "\f841"; } + +.fa-lyft { + --fa: "\f3c3"; } + +.fa-rev { + --fa: "\f5b2"; } + +.fa-windows { + --fa: "\f17a"; } + +.fa-wizards-of-the-coast { + --fa: "\f730"; } + +.fa-square-viadeo { + --fa: "\f2aa"; } + +.fa-viadeo-square { + --fa: "\f2aa"; } + +.fa-meetup { + --fa: "\f2e0"; } + +.fa-centos { + --fa: "\f789"; } + +.fa-adn { + --fa: "\f170"; } + +.fa-cloudsmith { + --fa: "\f384"; } + +.fa-opensuse { + --fa: "\e62b"; } + +.fa-pied-piper-alt { + --fa: "\f1a8"; } + +.fa-square-dribbble { + --fa: "\f397"; } + +.fa-dribbble-square { + --fa: "\f397"; } + +.fa-codiepie { + --fa: "\f284"; } + +.fa-node { + --fa: "\f419"; } + +.fa-mix { + --fa: "\f3cb"; } + +.fa-steam { + --fa: "\f1b6"; } + +.fa-cc-apple-pay { + --fa: "\f416"; } + +.fa-scribd { + --fa: "\f28a"; } + +.fa-debian { + --fa: "\e60b"; } + +.fa-openid { + --fa: "\f19b"; } + +.fa-instalod { + --fa: "\e081"; } + +.fa-files-pinwheel { + --fa: "\e69f"; } + +.fa-expeditedssl { + --fa: "\f23e"; } + +.fa-sellcast { + --fa: "\f2da"; } + +.fa-square-twitter { + --fa: "\f081"; } + +.fa-twitter-square { + --fa: "\f081"; } + +.fa-r-project { + --fa: "\f4f7"; } + +.fa-delicious { + --fa: "\f1a5"; } + +.fa-freebsd { + --fa: "\f3a4"; } + +.fa-vuejs { + --fa: "\f41f"; } + +.fa-accusoft { + --fa: "\f369"; } + +.fa-ioxhost { + --fa: "\f208"; } + +.fa-fonticons-fi { + --fa: "\f3a2"; } + +.fa-app-store { + --fa: "\f36f"; } + +.fa-cc-mastercard { + --fa: "\f1f1"; } + +.fa-itunes-note { + --fa: "\f3b5"; } + +.fa-golang { + --fa: "\e40f"; } + +.fa-kickstarter { + --fa: "\f3bb"; } + +.fa-square-kickstarter { + --fa: "\f3bb"; } + +.fa-grav { + --fa: "\f2d6"; } + +.fa-weibo { + --fa: "\f18a"; } + +.fa-uncharted { + --fa: "\e084"; } + +.fa-firstdraft { + --fa: "\f3a1"; } + +.fa-square-youtube { + --fa: "\f431"; } + +.fa-youtube-square { + --fa: "\f431"; } + +.fa-wikipedia-w { + --fa: "\f266"; } + +.fa-wpressr { + --fa: "\f3e4"; } + +.fa-rendact { + --fa: "\f3e4"; } + +.fa-angellist { + --fa: "\f209"; } + +.fa-galactic-republic { + --fa: "\f50c"; } + +.fa-nfc-directional { + --fa: "\e530"; } + +.fa-skype { + --fa: "\f17e"; } + +.fa-joget { + --fa: "\f3b7"; } + +.fa-fedora { + --fa: "\f798"; } + +.fa-stripe-s { + --fa: "\f42a"; } + +.fa-meta { + --fa: "\e49b"; } + +.fa-laravel { + --fa: "\f3bd"; } + +.fa-hotjar { + --fa: "\f3b1"; } + +.fa-bluetooth-b { + --fa: "\f294"; } + +.fa-square-letterboxd { + --fa: "\e62e"; } + +.fa-sticker-mule { + --fa: "\f3f7"; } + +.fa-creative-commons-zero { + --fa: "\f4f3"; } + +.fa-hips { + --fa: "\f452"; } + +.fa-css { + --fa: "\e6a2"; } + +.fa-behance { + --fa: "\f1b4"; } + +.fa-reddit { + --fa: "\f1a1"; } + +.fa-discord { + --fa: "\f392"; } + +.fa-chrome { + --fa: "\f268"; } + +.fa-app-store-ios { + --fa: "\f370"; } + +.fa-cc-discover { + --fa: "\f1f2"; } + +.fa-wpbeginner { + --fa: "\f297"; } + +.fa-confluence { + --fa: "\f78d"; } + +.fa-shoelace { + --fa: "\e60c"; } + +.fa-mdb { + --fa: "\f8ca"; } + +.fa-dochub { + --fa: "\f394"; } + +.fa-accessible-icon { + --fa: "\f368"; } + +.fa-ebay { + --fa: "\f4f4"; } + +.fa-amazon { + --fa: "\f270"; } + +.fa-unsplash { + --fa: "\e07c"; } + +.fa-yarn { + --fa: "\f7e3"; } + +.fa-square-steam { + --fa: "\f1b7"; } + +.fa-steam-square { + --fa: "\f1b7"; } + +.fa-500px { + --fa: "\f26e"; } + +.fa-square-vimeo { + --fa: "\f194"; } + +.fa-vimeo-square { + --fa: "\f194"; } + +.fa-asymmetrik { + --fa: "\f372"; } + +.fa-font-awesome { + --fa: "\f2b4"; } + +.fa-font-awesome-flag { + --fa: "\f2b4"; } + +.fa-font-awesome-logo-full { + --fa: "\f2b4"; } + +.fa-gratipay { + --fa: "\f184"; } + +.fa-apple { + --fa: "\f179"; } + +.fa-hive { + --fa: "\e07f"; } + +.fa-gitkraken { + --fa: "\f3a6"; } + +.fa-keybase { + --fa: "\f4f5"; } + +.fa-apple-pay { + --fa: "\f415"; } + +.fa-padlet { + --fa: "\e4a0"; } + +.fa-amazon-pay { + --fa: "\f42c"; } + +.fa-square-github { + --fa: "\f092"; } + +.fa-github-square { + --fa: "\f092"; } + +.fa-stumbleupon { + --fa: "\f1a4"; } + +.fa-fedex { + --fa: "\f797"; } + +.fa-phoenix-framework { + --fa: "\f3dc"; } + +.fa-shopify { + --fa: "\e057"; } + +.fa-neos { + --fa: "\f612"; } + +.fa-square-threads { + --fa: "\e619"; } + +.fa-hackerrank { + --fa: "\f5f7"; } + +.fa-researchgate { + --fa: "\f4f8"; } + +.fa-swift { + --fa: "\f8e1"; } + +.fa-angular { + --fa: "\f420"; } + +.fa-speakap { + --fa: "\f3f3"; } + +.fa-angrycreative { + --fa: "\f36e"; } + +.fa-y-combinator { + --fa: "\f23b"; } + +.fa-empire { + --fa: "\f1d1"; } + +.fa-envira { + --fa: "\f299"; } + +.fa-google-scholar { + --fa: "\e63b"; } + +.fa-square-gitlab { + --fa: "\e5ae"; } + +.fa-gitlab-square { + --fa: "\e5ae"; } + +.fa-studiovinari { + --fa: "\f3f8"; } + +.fa-pied-piper { + --fa: "\f2ae"; } + +.fa-wordpress { + --fa: "\f19a"; } + +.fa-product-hunt { + --fa: "\f288"; } + +.fa-firefox { + --fa: "\f269"; } + +.fa-linode { + --fa: "\f2b8"; } + +.fa-goodreads { + --fa: "\f3a8"; } + +.fa-square-odnoklassniki { + --fa: "\f264"; } + +.fa-odnoklassniki-square { + --fa: "\f264"; } + +.fa-jsfiddle { + --fa: "\f1cc"; } + +.fa-sith { + --fa: "\f512"; } + +.fa-themeisle { + --fa: "\f2b2"; } + +.fa-page4 { + --fa: "\f3d7"; } + +.fa-hashnode { + --fa: "\e499"; } + +.fa-react { + --fa: "\f41b"; } + +.fa-cc-paypal { + --fa: "\f1f4"; } + +.fa-squarespace { + --fa: "\f5be"; } + +.fa-cc-stripe { + --fa: "\f1f5"; } + +.fa-creative-commons-share { + --fa: "\f4f2"; } + +.fa-bitcoin { + --fa: "\f379"; } + +.fa-keycdn { + --fa: "\f3ba"; } + +.fa-opera { + --fa: "\f26a"; } + +.fa-itch-io { + --fa: "\f83a"; } + +.fa-umbraco { + --fa: "\f8e8"; } + +.fa-galactic-senate { + --fa: "\f50d"; } + +.fa-ubuntu { + --fa: "\f7df"; } + +.fa-draft2digital { + --fa: "\f396"; } + +.fa-stripe { + --fa: "\f429"; } + +.fa-houzz { + --fa: "\f27c"; } + +.fa-gg { + --fa: "\f260"; } + +.fa-dhl { + --fa: "\f790"; } + +.fa-square-pinterest { + --fa: "\f0d3"; } + +.fa-pinterest-square { + --fa: "\f0d3"; } + +.fa-xing { + --fa: "\f168"; } + +.fa-blackberry { + --fa: "\f37b"; } + +.fa-creative-commons-pd { + --fa: "\f4ec"; } + +.fa-playstation { + --fa: "\f3df"; } + +.fa-quinscape { + --fa: "\f459"; } + +.fa-less { + --fa: "\f41d"; } + +.fa-blogger-b { + --fa: "\f37d"; } + +.fa-opencart { + --fa: "\f23d"; } + +.fa-vine { + --fa: "\f1ca"; } + +.fa-signal-messenger { + --fa: "\e663"; } + +.fa-paypal { + --fa: "\f1ed"; } + +.fa-gitlab { + --fa: "\f296"; } + +.fa-typo3 { + --fa: "\f42b"; } + +.fa-reddit-alien { + --fa: "\f281"; } + +.fa-yahoo { + --fa: "\f19e"; } + +.fa-dailymotion { + --fa: "\e052"; } + +.fa-affiliatetheme { + --fa: "\f36b"; } + +.fa-pied-piper-pp { + --fa: "\f1a7"; } + +.fa-bootstrap { + --fa: "\f836"; } + +.fa-odnoklassniki { + --fa: "\f263"; } + +.fa-nfc-symbol { + --fa: "\e531"; } + +.fa-mintbit { + --fa: "\e62f"; } + +.fa-ethereum { + --fa: "\f42e"; } + +.fa-speaker-deck { + --fa: "\f83c"; } + +.fa-creative-commons-nc-eu { + --fa: "\f4e9"; } + +.fa-patreon { + --fa: "\f3d9"; } + +.fa-avianex { + --fa: "\f374"; } + +.fa-ello { + --fa: "\f5f1"; } + +.fa-gofore { + --fa: "\f3a7"; } + +.fa-bimobject { + --fa: "\f378"; } + +.fa-brave-reverse { + --fa: "\e63d"; } + +.fa-facebook-f { + --fa: "\f39e"; } + +.fa-square-google-plus { + --fa: "\f0d4"; } + +.fa-google-plus-square { + --fa: "\f0d4"; } + +.fa-web-awesome { + --fa: "\e682"; } + +.fa-mandalorian { + --fa: "\f50f"; } + +.fa-first-order-alt { + --fa: "\f50a"; } + +.fa-osi { + --fa: "\f41a"; } + +.fa-google-wallet { + --fa: "\f1ee"; } + +.fa-d-and-d-beyond { + --fa: "\f6ca"; } + +.fa-periscope { + --fa: "\f3da"; } + +.fa-fulcrum { + --fa: "\f50b"; } + +.fa-cloudscale { + --fa: "\f383"; } + +.fa-forumbee { + --fa: "\f211"; } + +.fa-mizuni { + --fa: "\f3cc"; } + +.fa-schlix { + --fa: "\f3ea"; } + +.fa-square-xing { + --fa: "\f169"; } + +.fa-xing-square { + --fa: "\f169"; } + +.fa-bandcamp { + --fa: "\f2d5"; } + +.fa-wpforms { + --fa: "\f298"; } + +.fa-cloudversify { + --fa: "\f385"; } + +.fa-usps { + --fa: "\f7e1"; } + +.fa-megaport { + --fa: "\f5a3"; } + +.fa-magento { + --fa: "\f3c4"; } + +.fa-spotify { + --fa: "\f1bc"; } + +.fa-optin-monster { + --fa: "\f23c"; } + +.fa-fly { + --fa: "\f417"; } + +.fa-square-bluesky { + --fa: "\e6a3"; } + +.fa-aviato { + --fa: "\f421"; } + +.fa-itunes { + --fa: "\f3b4"; } + +.fa-cuttlefish { + --fa: "\f38c"; } + +.fa-blogger { + --fa: "\f37c"; } + +.fa-flickr { + --fa: "\f16e"; } + +.fa-viber { + --fa: "\f409"; } + +.fa-soundcloud { + --fa: "\f1be"; } + +.fa-digg { + --fa: "\f1a6"; } + +.fa-tencent-weibo { + --fa: "\f1d5"; } + +.fa-letterboxd { + --fa: "\e62d"; } + +.fa-symfony { + --fa: "\f83d"; } + +.fa-maxcdn { + --fa: "\f136"; } + +.fa-etsy { + --fa: "\f2d7"; } + +.fa-facebook-messenger { + --fa: "\f39f"; } + +.fa-audible { + --fa: "\f373"; } + +.fa-think-peaks { + --fa: "\f731"; } + +.fa-bilibili { + --fa: "\e3d9"; } + +.fa-erlang { + --fa: "\f39d"; } + +.fa-x-twitter { + --fa: "\e61b"; } + +.fa-cotton-bureau { + --fa: "\f89e"; } + +.fa-dashcube { + --fa: "\f210"; } + +.fa-42-group { + --fa: "\e080"; } + +.fa-innosoft { + --fa: "\e080"; } + +.fa-stack-exchange { + --fa: "\f18d"; } + +.fa-elementor { + --fa: "\f430"; } + +.fa-square-pied-piper { + --fa: "\e01e"; } + +.fa-pied-piper-square { + --fa: "\e01e"; } + +.fa-creative-commons-nd { + --fa: "\f4eb"; } + +.fa-palfed { + --fa: "\f3d8"; } + +.fa-superpowers { + --fa: "\f2dd"; } + +.fa-resolving { + --fa: "\f3e7"; } + +.fa-xbox { + --fa: "\f412"; } + +.fa-square-web-awesome-stroke { + --fa: "\e684"; } + +.fa-searchengin { + --fa: "\f3eb"; } + +.fa-tiktok { + --fa: "\e07b"; } + +.fa-square-facebook { + --fa: "\f082"; } + +.fa-facebook-square { + --fa: "\f082"; } + +.fa-renren { + --fa: "\f18b"; } + +.fa-linux { + --fa: "\f17c"; } + +.fa-glide { + --fa: "\f2a5"; } + +.fa-linkedin { + --fa: "\f08c"; } + +.fa-hubspot { + --fa: "\f3b2"; } + +.fa-deploydog { + --fa: "\f38e"; } + +.fa-twitch { + --fa: "\f1e8"; } + +.fa-flutter { + --fa: "\e694"; } + +.fa-ravelry { + --fa: "\f2d9"; } + +.fa-mixer { + --fa: "\e056"; } + +.fa-square-lastfm { + --fa: "\f203"; } + +.fa-lastfm-square { + --fa: "\f203"; } + +.fa-vimeo { + --fa: "\f40a"; } + +.fa-mendeley { + --fa: "\f7b3"; } + +.fa-uniregistry { + --fa: "\f404"; } + +.fa-figma { + --fa: "\f799"; } + +.fa-creative-commons-remix { + --fa: "\f4ee"; } + +.fa-cc-amazon-pay { + --fa: "\f42d"; } + +.fa-dropbox { + --fa: "\f16b"; } + +.fa-instagram { + --fa: "\f16d"; } + +.fa-cmplid { + --fa: "\e360"; } + +.fa-upwork { + --fa: "\e641"; } + +.fa-facebook { + --fa: "\f09a"; } + +.fa-gripfire { + --fa: "\f3ac"; } + +.fa-jedi-order { + --fa: "\f50e"; } + +.fa-uikit { + --fa: "\f403"; } + +.fa-fort-awesome-alt { + --fa: "\f3a3"; } + +.fa-phabricator { + --fa: "\f3db"; } + +.fa-ussunnah { + --fa: "\f407"; } + +.fa-earlybirds { + --fa: "\f39a"; } + +.fa-trade-federation { + --fa: "\f513"; } + +.fa-autoprefixer { + --fa: "\f41c"; } + +.fa-whatsapp { + --fa: "\f232"; } + +.fa-square-upwork { + --fa: "\e67c"; } + +.fa-slideshare { + --fa: "\f1e7"; } + +.fa-google-play { + --fa: "\f3ab"; } + +.fa-viadeo { + --fa: "\f2a9"; } + +.fa-line { + --fa: "\f3c0"; } + +.fa-google-drive { + --fa: "\f3aa"; } + +.fa-servicestack { + --fa: "\f3ec"; } + +.fa-simplybuilt { + --fa: "\f215"; } + +.fa-bitbucket { + --fa: "\f171"; } + +.fa-imdb { + --fa: "\f2d8"; } + +.fa-deezer { + --fa: "\e077"; } + +.fa-raspberry-pi { + --fa: "\f7bb"; } + +.fa-jira { + --fa: "\f7b1"; } + +.fa-docker { + --fa: "\f395"; } + +.fa-screenpal { + --fa: "\e570"; } + +.fa-bluetooth { + --fa: "\f293"; } + +.fa-gitter { + --fa: "\f426"; } + +.fa-d-and-d { + --fa: "\f38d"; } + +.fa-microblog { + --fa: "\e01a"; } + +.fa-cc-diners-club { + --fa: "\f24c"; } + +.fa-gg-circle { + --fa: "\f261"; } + +.fa-pied-piper-hat { + --fa: "\f4e5"; } + +.fa-kickstarter-k { + --fa: "\f3bc"; } + +.fa-yandex { + --fa: "\f413"; } + +.fa-readme { + --fa: "\f4d5"; } + +.fa-html5 { + --fa: "\f13b"; } + +.fa-sellsy { + --fa: "\f213"; } + +.fa-square-web-awesome { + --fa: "\e683"; } + +.fa-sass { + --fa: "\f41e"; } + +.fa-wirsindhandwerk { + --fa: "\e2d0"; } + +.fa-wsh { + --fa: "\e2d0"; } + +.fa-buromobelexperte { + --fa: "\f37f"; } + +.fa-salesforce { + --fa: "\f83b"; } + +.fa-octopus-deploy { + --fa: "\e082"; } + +.fa-medapps { + --fa: "\f3c6"; } + +.fa-ns8 { + --fa: "\f3d5"; } + +.fa-pinterest-p { + --fa: "\f231"; } + +.fa-apper { + --fa: "\f371"; } + +.fa-fort-awesome { + --fa: "\f286"; } + +.fa-waze { + --fa: "\f83f"; } + +.fa-bluesky { + --fa: "\e671"; } + +.fa-cc-jcb { + --fa: "\f24b"; } + +.fa-snapchat { + --fa: "\f2ab"; } + +.fa-snapchat-ghost { + --fa: "\f2ab"; } + +.fa-fantasy-flight-games { + --fa: "\f6dc"; } + +.fa-rust { + --fa: "\e07a"; } + +.fa-wix { + --fa: "\f5cf"; } + +.fa-square-behance { + --fa: "\f1b5"; } + +.fa-behance-square { + --fa: "\f1b5"; } + +.fa-supple { + --fa: "\f3f9"; } + +.fa-webflow { + --fa: "\e65c"; } + +.fa-rebel { + --fa: "\f1d0"; } + +.fa-css3 { + --fa: "\f13c"; } + +.fa-staylinked { + --fa: "\f3f5"; } + +.fa-kaggle { + --fa: "\f5fa"; } + +.fa-space-awesome { + --fa: "\e5ac"; } + +.fa-deviantart { + --fa: "\f1bd"; } + +.fa-cpanel { + --fa: "\f388"; } + +.fa-goodreads-g { + --fa: "\f3a9"; } + +.fa-square-git { + --fa: "\f1d2"; } + +.fa-git-square { + --fa: "\f1d2"; } + +.fa-square-tumblr { + --fa: "\f174"; } + +.fa-tumblr-square { + --fa: "\f174"; } + +.fa-trello { + --fa: "\f181"; } + +.fa-creative-commons-nc-jp { + --fa: "\f4ea"; } + +.fa-get-pocket { + --fa: "\f265"; } + +.fa-perbyte { + --fa: "\e083"; } + +.fa-grunt { + --fa: "\f3ad"; } + +.fa-weebly { + --fa: "\f5cc"; } + +.fa-connectdevelop { + --fa: "\f20e"; } + +.fa-leanpub { + --fa: "\f212"; } + +.fa-black-tie { + --fa: "\f27e"; } + +.fa-themeco { + --fa: "\f5c6"; } + +.fa-python { + --fa: "\f3e2"; } + +.fa-android { + --fa: "\f17b"; } + +.fa-bots { + --fa: "\e340"; } + +.fa-free-code-camp { + --fa: "\f2c5"; } + +.fa-hornbill { + --fa: "\f592"; } + +.fa-js { + --fa: "\f3b8"; } + +.fa-ideal { + --fa: "\e013"; } + +.fa-git { + --fa: "\f1d3"; } + +.fa-dev { + --fa: "\f6cc"; } + +.fa-sketch { + --fa: "\f7c6"; } + +.fa-yandex-international { + --fa: "\f414"; } + +.fa-cc-amex { + --fa: "\f1f3"; } + +.fa-uber { + --fa: "\f402"; } + +.fa-github { + --fa: "\f09b"; } + +.fa-php { + --fa: "\f457"; } + +.fa-alipay { + --fa: "\f642"; } + +.fa-youtube { + --fa: "\f167"; } + +.fa-skyatlas { + --fa: "\f216"; } + +.fa-firefox-browser { + --fa: "\e007"; } + +.fa-replyd { + --fa: "\f3e6"; } + +.fa-suse { + --fa: "\f7d6"; } + +.fa-jenkins { + --fa: "\f3b6"; } + +.fa-twitter { + --fa: "\f099"; } + +.fa-rockrms { + --fa: "\f3e9"; } + +.fa-pinterest { + --fa: "\f0d2"; } + +.fa-buffer { + --fa: "\f837"; } + +.fa-npm { + --fa: "\f3d4"; } + +.fa-yammer { + --fa: "\f840"; } + +.fa-btc { + --fa: "\f15a"; } + +.fa-dribbble { + --fa: "\f17d"; } + +.fa-stumbleupon-circle { + --fa: "\f1a3"; } + +.fa-internet-explorer { + --fa: "\f26b"; } + +.fa-stubber { + --fa: "\e5c7"; } + +.fa-telegram { + --fa: "\f2c6"; } + +.fa-telegram-plane { + --fa: "\f2c6"; } + +.fa-old-republic { + --fa: "\f510"; } + +.fa-odysee { + --fa: "\e5c6"; } + +.fa-square-whatsapp { + --fa: "\f40c"; } + +.fa-whatsapp-square { + --fa: "\f40c"; } + +.fa-node-js { + --fa: "\f3d3"; } + +.fa-edge-legacy { + --fa: "\e078"; } + +.fa-slack { + --fa: "\f198"; } + +.fa-slack-hash { + --fa: "\f198"; } + +.fa-medrt { + --fa: "\f3c8"; } + +.fa-usb { + --fa: "\f287"; } + +.fa-tumblr { + --fa: "\f173"; } + +.fa-vaadin { + --fa: "\f408"; } + +.fa-quora { + --fa: "\f2c4"; } + +.fa-square-x-twitter { + --fa: "\e61a"; } + +.fa-reacteurope { + --fa: "\f75d"; } + +.fa-medium { + --fa: "\f23a"; } + +.fa-medium-m { + --fa: "\f23a"; } + +.fa-amilia { + --fa: "\f36d"; } + +.fa-mixcloud { + --fa: "\f289"; } + +.fa-flipboard { + --fa: "\f44d"; } + +.fa-viacoin { + --fa: "\f237"; } + +.fa-critical-role { + --fa: "\f6c9"; } + +.fa-sitrox { + --fa: "\e44a"; } + +.fa-discourse { + --fa: "\f393"; } + +.fa-joomla { + --fa: "\f1aa"; } + +.fa-mastodon { + --fa: "\f4f6"; } + +.fa-airbnb { + --fa: "\f834"; } + +.fa-wolf-pack-battalion { + --fa: "\f514"; } + +.fa-buy-n-large { + --fa: "\f8a6"; } + +.fa-gulp { + --fa: "\f3ae"; } + +.fa-creative-commons-sampling-plus { + --fa: "\f4f1"; } + +.fa-strava { + --fa: "\f428"; } + +.fa-ember { + --fa: "\f423"; } + +.fa-canadian-maple-leaf { + --fa: "\f785"; } + +.fa-teamspeak { + --fa: "\f4f9"; } + +.fa-pushed { + --fa: "\f3e1"; } + +.fa-wordpress-simple { + --fa: "\f411"; } + +.fa-nutritionix { + --fa: "\f3d6"; } + +.fa-wodu { + --fa: "\e088"; } + +.fa-google-pay { + --fa: "\e079"; } + +.fa-intercom { + --fa: "\f7af"; } + +.fa-zhihu { + --fa: "\f63f"; } + +.fa-korvue { + --fa: "\f42f"; } + +.fa-pix { + --fa: "\e43a"; } + +.fa-steam-symbol { + --fa: "\f3f6"; } diff --git a/css/brands.min.css b/css/brands.min.css new file mode 100644 index 0000000000..7aa3689f59 --- /dev/null +++ b/css/brands.min.css @@ -0,0 +1,6 @@ +/*! + * Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + * Copyright 2024 Fonticons, Inc. + */ +:host,:root{--fa-style-family-brands:"Font Awesome 6 Brands";--fa-font-brands:normal 400 1em/1 "Font Awesome 6 Brands"}@font-face{font-family:"Font Awesome 6 Brands";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.ttf) format("truetype")}.fa-brands,.fab{font-weight:400}.fa-monero{--fa:"\f3d0"}.fa-hooli{--fa:"\f427"}.fa-yelp{--fa:"\f1e9"}.fa-cc-visa{--fa:"\f1f0"}.fa-lastfm{--fa:"\f202"}.fa-shopware{--fa:"\f5b5"}.fa-creative-commons-nc{--fa:"\f4e8"}.fa-aws{--fa:"\f375"}.fa-redhat{--fa:"\f7bc"}.fa-yoast{--fa:"\f2b1"}.fa-cloudflare{--fa:"\e07d"}.fa-ups{--fa:"\f7e0"}.fa-pixiv{--fa:"\e640"}.fa-wpexplorer{--fa:"\f2de"}.fa-dyalog{--fa:"\f399"}.fa-bity{--fa:"\f37a"}.fa-stackpath{--fa:"\f842"}.fa-buysellads{--fa:"\f20d"}.fa-first-order{--fa:"\f2b0"}.fa-modx{--fa:"\f285"}.fa-guilded{--fa:"\e07e"}.fa-vnv{--fa:"\f40b"}.fa-js-square,.fa-square-js{--fa:"\f3b9"}.fa-microsoft{--fa:"\f3ca"}.fa-qq{--fa:"\f1d6"}.fa-orcid{--fa:"\f8d2"}.fa-java{--fa:"\f4e4"}.fa-invision{--fa:"\f7b0"}.fa-creative-commons-pd-alt{--fa:"\f4ed"}.fa-centercode{--fa:"\f380"}.fa-glide-g{--fa:"\f2a6"}.fa-drupal{--fa:"\f1a9"}.fa-jxl{--fa:"\e67b"}.fa-dart-lang{--fa:"\e693"}.fa-hire-a-helper{--fa:"\f3b0"}.fa-creative-commons-by{--fa:"\f4e7"}.fa-unity{--fa:"\e049"}.fa-whmcs{--fa:"\f40d"}.fa-rocketchat{--fa:"\f3e8"}.fa-vk{--fa:"\f189"}.fa-untappd{--fa:"\f405"}.fa-mailchimp{--fa:"\f59e"}.fa-css3-alt{--fa:"\f38b"}.fa-reddit-square,.fa-square-reddit{--fa:"\f1a2"}.fa-vimeo-v{--fa:"\f27d"}.fa-contao{--fa:"\f26d"}.fa-square-font-awesome{--fa:"\e5ad"}.fa-deskpro{--fa:"\f38f"}.fa-brave{--fa:"\e63c"}.fa-sistrix{--fa:"\f3ee"}.fa-instagram-square,.fa-square-instagram{--fa:"\e055"}.fa-battle-net{--fa:"\f835"}.fa-the-red-yeti{--fa:"\f69d"}.fa-hacker-news-square,.fa-square-hacker-news{--fa:"\f3af"}.fa-edge{--fa:"\f282"}.fa-threads{--fa:"\e618"}.fa-napster{--fa:"\f3d2"}.fa-snapchat-square,.fa-square-snapchat{--fa:"\f2ad"}.fa-google-plus-g{--fa:"\f0d5"}.fa-artstation{--fa:"\f77a"}.fa-markdown{--fa:"\f60f"}.fa-sourcetree{--fa:"\f7d3"}.fa-google-plus{--fa:"\f2b3"}.fa-diaspora{--fa:"\f791"}.fa-foursquare{--fa:"\f180"}.fa-stack-overflow{--fa:"\f16c"}.fa-github-alt{--fa:"\f113"}.fa-phoenix-squadron{--fa:"\f511"}.fa-pagelines{--fa:"\f18c"}.fa-algolia{--fa:"\f36c"}.fa-red-river{--fa:"\f3e3"}.fa-creative-commons-sa{--fa:"\f4ef"}.fa-safari{--fa:"\f267"}.fa-google{--fa:"\f1a0"}.fa-font-awesome-alt,.fa-square-font-awesome-stroke{--fa:"\f35c"}.fa-atlassian{--fa:"\f77b"}.fa-linkedin-in{--fa:"\f0e1"}.fa-digital-ocean{--fa:"\f391"}.fa-nimblr{--fa:"\f5a8"}.fa-chromecast{--fa:"\f838"}.fa-evernote{--fa:"\f839"}.fa-hacker-news{--fa:"\f1d4"}.fa-creative-commons-sampling{--fa:"\f4f0"}.fa-adversal{--fa:"\f36a"}.fa-creative-commons{--fa:"\f25e"}.fa-watchman-monitoring{--fa:"\e087"}.fa-fonticons{--fa:"\f280"}.fa-weixin{--fa:"\f1d7"}.fa-shirtsinbulk{--fa:"\f214"}.fa-codepen{--fa:"\f1cb"}.fa-git-alt{--fa:"\f841"}.fa-lyft{--fa:"\f3c3"}.fa-rev{--fa:"\f5b2"}.fa-windows{--fa:"\f17a"}.fa-wizards-of-the-coast{--fa:"\f730"}.fa-square-viadeo,.fa-viadeo-square{--fa:"\f2aa"}.fa-meetup{--fa:"\f2e0"}.fa-centos{--fa:"\f789"}.fa-adn{--fa:"\f170"}.fa-cloudsmith{--fa:"\f384"}.fa-opensuse{--fa:"\e62b"}.fa-pied-piper-alt{--fa:"\f1a8"}.fa-dribbble-square,.fa-square-dribbble{--fa:"\f397"}.fa-codiepie{--fa:"\f284"}.fa-node{--fa:"\f419"}.fa-mix{--fa:"\f3cb"}.fa-steam{--fa:"\f1b6"}.fa-cc-apple-pay{--fa:"\f416"}.fa-scribd{--fa:"\f28a"}.fa-debian{--fa:"\e60b"}.fa-openid{--fa:"\f19b"}.fa-instalod{--fa:"\e081"}.fa-files-pinwheel{--fa:"\e69f"}.fa-expeditedssl{--fa:"\f23e"}.fa-sellcast{--fa:"\f2da"}.fa-square-twitter,.fa-twitter-square{--fa:"\f081"}.fa-r-project{--fa:"\f4f7"}.fa-delicious{--fa:"\f1a5"}.fa-freebsd{--fa:"\f3a4"}.fa-vuejs{--fa:"\f41f"}.fa-accusoft{--fa:"\f369"}.fa-ioxhost{--fa:"\f208"}.fa-fonticons-fi{--fa:"\f3a2"}.fa-app-store{--fa:"\f36f"}.fa-cc-mastercard{--fa:"\f1f1"}.fa-itunes-note{--fa:"\f3b5"}.fa-golang{--fa:"\e40f"}.fa-kickstarter,.fa-square-kickstarter{--fa:"\f3bb"}.fa-grav{--fa:"\f2d6"}.fa-weibo{--fa:"\f18a"}.fa-uncharted{--fa:"\e084"}.fa-firstdraft{--fa:"\f3a1"}.fa-square-youtube,.fa-youtube-square{--fa:"\f431"}.fa-wikipedia-w{--fa:"\f266"}.fa-rendact,.fa-wpressr{--fa:"\f3e4"}.fa-angellist{--fa:"\f209"}.fa-galactic-republic{--fa:"\f50c"}.fa-nfc-directional{--fa:"\e530"}.fa-skype{--fa:"\f17e"}.fa-joget{--fa:"\f3b7"}.fa-fedora{--fa:"\f798"}.fa-stripe-s{--fa:"\f42a"}.fa-meta{--fa:"\e49b"}.fa-laravel{--fa:"\f3bd"}.fa-hotjar{--fa:"\f3b1"}.fa-bluetooth-b{--fa:"\f294"}.fa-square-letterboxd{--fa:"\e62e"}.fa-sticker-mule{--fa:"\f3f7"}.fa-creative-commons-zero{--fa:"\f4f3"}.fa-hips{--fa:"\f452"}.fa-css{--fa:"\e6a2"}.fa-behance{--fa:"\f1b4"}.fa-reddit{--fa:"\f1a1"}.fa-discord{--fa:"\f392"}.fa-chrome{--fa:"\f268"}.fa-app-store-ios{--fa:"\f370"}.fa-cc-discover{--fa:"\f1f2"}.fa-wpbeginner{--fa:"\f297"}.fa-confluence{--fa:"\f78d"}.fa-shoelace{--fa:"\e60c"}.fa-mdb{--fa:"\f8ca"}.fa-dochub{--fa:"\f394"}.fa-accessible-icon{--fa:"\f368"}.fa-ebay{--fa:"\f4f4"}.fa-amazon{--fa:"\f270"}.fa-unsplash{--fa:"\e07c"}.fa-yarn{--fa:"\f7e3"}.fa-square-steam,.fa-steam-square{--fa:"\f1b7"}.fa-500px{--fa:"\f26e"}.fa-square-vimeo,.fa-vimeo-square{--fa:"\f194"}.fa-asymmetrik{--fa:"\f372"}.fa-font-awesome,.fa-font-awesome-flag,.fa-font-awesome-logo-full{--fa:"\f2b4"}.fa-gratipay{--fa:"\f184"}.fa-apple{--fa:"\f179"}.fa-hive{--fa:"\e07f"}.fa-gitkraken{--fa:"\f3a6"}.fa-keybase{--fa:"\f4f5"}.fa-apple-pay{--fa:"\f415"}.fa-padlet{--fa:"\e4a0"}.fa-amazon-pay{--fa:"\f42c"}.fa-github-square,.fa-square-github{--fa:"\f092"}.fa-stumbleupon{--fa:"\f1a4"}.fa-fedex{--fa:"\f797"}.fa-phoenix-framework{--fa:"\f3dc"}.fa-shopify{--fa:"\e057"}.fa-neos{--fa:"\f612"}.fa-square-threads{--fa:"\e619"}.fa-hackerrank{--fa:"\f5f7"}.fa-researchgate{--fa:"\f4f8"}.fa-swift{--fa:"\f8e1"}.fa-angular{--fa:"\f420"}.fa-speakap{--fa:"\f3f3"}.fa-angrycreative{--fa:"\f36e"}.fa-y-combinator{--fa:"\f23b"}.fa-empire{--fa:"\f1d1"}.fa-envira{--fa:"\f299"}.fa-google-scholar{--fa:"\e63b"}.fa-gitlab-square,.fa-square-gitlab{--fa:"\e5ae"}.fa-studiovinari{--fa:"\f3f8"}.fa-pied-piper{--fa:"\f2ae"}.fa-wordpress{--fa:"\f19a"}.fa-product-hunt{--fa:"\f288"}.fa-firefox{--fa:"\f269"}.fa-linode{--fa:"\f2b8"}.fa-goodreads{--fa:"\f3a8"}.fa-odnoklassniki-square,.fa-square-odnoklassniki{--fa:"\f264"}.fa-jsfiddle{--fa:"\f1cc"}.fa-sith{--fa:"\f512"}.fa-themeisle{--fa:"\f2b2"}.fa-page4{--fa:"\f3d7"}.fa-hashnode{--fa:"\e499"}.fa-react{--fa:"\f41b"}.fa-cc-paypal{--fa:"\f1f4"}.fa-squarespace{--fa:"\f5be"}.fa-cc-stripe{--fa:"\f1f5"}.fa-creative-commons-share{--fa:"\f4f2"}.fa-bitcoin{--fa:"\f379"}.fa-keycdn{--fa:"\f3ba"}.fa-opera{--fa:"\f26a"}.fa-itch-io{--fa:"\f83a"}.fa-umbraco{--fa:"\f8e8"}.fa-galactic-senate{--fa:"\f50d"}.fa-ubuntu{--fa:"\f7df"}.fa-draft2digital{--fa:"\f396"}.fa-stripe{--fa:"\f429"}.fa-houzz{--fa:"\f27c"}.fa-gg{--fa:"\f260"}.fa-dhl{--fa:"\f790"}.fa-pinterest-square,.fa-square-pinterest{--fa:"\f0d3"}.fa-xing{--fa:"\f168"}.fa-blackberry{--fa:"\f37b"}.fa-creative-commons-pd{--fa:"\f4ec"}.fa-playstation{--fa:"\f3df"}.fa-quinscape{--fa:"\f459"}.fa-less{--fa:"\f41d"}.fa-blogger-b{--fa:"\f37d"}.fa-opencart{--fa:"\f23d"}.fa-vine{--fa:"\f1ca"}.fa-signal-messenger{--fa:"\e663"}.fa-paypal{--fa:"\f1ed"}.fa-gitlab{--fa:"\f296"}.fa-typo3{--fa:"\f42b"}.fa-reddit-alien{--fa:"\f281"}.fa-yahoo{--fa:"\f19e"}.fa-dailymotion{--fa:"\e052"}.fa-affiliatetheme{--fa:"\f36b"}.fa-pied-piper-pp{--fa:"\f1a7"}.fa-bootstrap{--fa:"\f836"}.fa-odnoklassniki{--fa:"\f263"}.fa-nfc-symbol{--fa:"\e531"}.fa-mintbit{--fa:"\e62f"}.fa-ethereum{--fa:"\f42e"}.fa-speaker-deck{--fa:"\f83c"}.fa-creative-commons-nc-eu{--fa:"\f4e9"}.fa-patreon{--fa:"\f3d9"}.fa-avianex{--fa:"\f374"}.fa-ello{--fa:"\f5f1"}.fa-gofore{--fa:"\f3a7"}.fa-bimobject{--fa:"\f378"}.fa-brave-reverse{--fa:"\e63d"}.fa-facebook-f{--fa:"\f39e"}.fa-google-plus-square,.fa-square-google-plus{--fa:"\f0d4"}.fa-web-awesome{--fa:"\e682"}.fa-mandalorian{--fa:"\f50f"}.fa-first-order-alt{--fa:"\f50a"}.fa-osi{--fa:"\f41a"}.fa-google-wallet{--fa:"\f1ee"}.fa-d-and-d-beyond{--fa:"\f6ca"}.fa-periscope{--fa:"\f3da"}.fa-fulcrum{--fa:"\f50b"}.fa-cloudscale{--fa:"\f383"}.fa-forumbee{--fa:"\f211"}.fa-mizuni{--fa:"\f3cc"}.fa-schlix{--fa:"\f3ea"}.fa-square-xing,.fa-xing-square{--fa:"\f169"}.fa-bandcamp{--fa:"\f2d5"}.fa-wpforms{--fa:"\f298"}.fa-cloudversify{--fa:"\f385"}.fa-usps{--fa:"\f7e1"}.fa-megaport{--fa:"\f5a3"}.fa-magento{--fa:"\f3c4"}.fa-spotify{--fa:"\f1bc"}.fa-optin-monster{--fa:"\f23c"}.fa-fly{--fa:"\f417"}.fa-square-bluesky{--fa:"\e6a3"}.fa-aviato{--fa:"\f421"}.fa-itunes{--fa:"\f3b4"}.fa-cuttlefish{--fa:"\f38c"}.fa-blogger{--fa:"\f37c"}.fa-flickr{--fa:"\f16e"}.fa-viber{--fa:"\f409"}.fa-soundcloud{--fa:"\f1be"}.fa-digg{--fa:"\f1a6"}.fa-tencent-weibo{--fa:"\f1d5"}.fa-letterboxd{--fa:"\e62d"}.fa-symfony{--fa:"\f83d"}.fa-maxcdn{--fa:"\f136"}.fa-etsy{--fa:"\f2d7"}.fa-facebook-messenger{--fa:"\f39f"}.fa-audible{--fa:"\f373"}.fa-think-peaks{--fa:"\f731"}.fa-bilibili{--fa:"\e3d9"}.fa-erlang{--fa:"\f39d"}.fa-x-twitter{--fa:"\e61b"}.fa-cotton-bureau{--fa:"\f89e"}.fa-dashcube{--fa:"\f210"}.fa-42-group,.fa-innosoft{--fa:"\e080"}.fa-stack-exchange{--fa:"\f18d"}.fa-elementor{--fa:"\f430"}.fa-pied-piper-square,.fa-square-pied-piper{--fa:"\e01e"}.fa-creative-commons-nd{--fa:"\f4eb"}.fa-palfed{--fa:"\f3d8"}.fa-superpowers{--fa:"\f2dd"}.fa-resolving{--fa:"\f3e7"}.fa-xbox{--fa:"\f412"}.fa-square-web-awesome-stroke{--fa:"\e684"}.fa-searchengin{--fa:"\f3eb"}.fa-tiktok{--fa:"\e07b"}.fa-facebook-square,.fa-square-facebook{--fa:"\f082"}.fa-renren{--fa:"\f18b"}.fa-linux{--fa:"\f17c"}.fa-glide{--fa:"\f2a5"}.fa-linkedin{--fa:"\f08c"}.fa-hubspot{--fa:"\f3b2"}.fa-deploydog{--fa:"\f38e"}.fa-twitch{--fa:"\f1e8"}.fa-flutter{--fa:"\e694"}.fa-ravelry{--fa:"\f2d9"}.fa-mixer{--fa:"\e056"}.fa-lastfm-square,.fa-square-lastfm{--fa:"\f203"}.fa-vimeo{--fa:"\f40a"}.fa-mendeley{--fa:"\f7b3"}.fa-uniregistry{--fa:"\f404"}.fa-figma{--fa:"\f799"}.fa-creative-commons-remix{--fa:"\f4ee"}.fa-cc-amazon-pay{--fa:"\f42d"}.fa-dropbox{--fa:"\f16b"}.fa-instagram{--fa:"\f16d"}.fa-cmplid{--fa:"\e360"}.fa-upwork{--fa:"\e641"}.fa-facebook{--fa:"\f09a"}.fa-gripfire{--fa:"\f3ac"}.fa-jedi-order{--fa:"\f50e"}.fa-uikit{--fa:"\f403"}.fa-fort-awesome-alt{--fa:"\f3a3"}.fa-phabricator{--fa:"\f3db"}.fa-ussunnah{--fa:"\f407"}.fa-earlybirds{--fa:"\f39a"}.fa-trade-federation{--fa:"\f513"}.fa-autoprefixer{--fa:"\f41c"}.fa-whatsapp{--fa:"\f232"}.fa-square-upwork{--fa:"\e67c"}.fa-slideshare{--fa:"\f1e7"}.fa-google-play{--fa:"\f3ab"}.fa-viadeo{--fa:"\f2a9"}.fa-line{--fa:"\f3c0"}.fa-google-drive{--fa:"\f3aa"}.fa-servicestack{--fa:"\f3ec"}.fa-simplybuilt{--fa:"\f215"}.fa-bitbucket{--fa:"\f171"}.fa-imdb{--fa:"\f2d8"}.fa-deezer{--fa:"\e077"}.fa-raspberry-pi{--fa:"\f7bb"}.fa-jira{--fa:"\f7b1"}.fa-docker{--fa:"\f395"}.fa-screenpal{--fa:"\e570"}.fa-bluetooth{--fa:"\f293"}.fa-gitter{--fa:"\f426"}.fa-d-and-d{--fa:"\f38d"}.fa-microblog{--fa:"\e01a"}.fa-cc-diners-club{--fa:"\f24c"}.fa-gg-circle{--fa:"\f261"}.fa-pied-piper-hat{--fa:"\f4e5"}.fa-kickstarter-k{--fa:"\f3bc"}.fa-yandex{--fa:"\f413"}.fa-readme{--fa:"\f4d5"}.fa-html5{--fa:"\f13b"}.fa-sellsy{--fa:"\f213"}.fa-square-web-awesome{--fa:"\e683"}.fa-sass{--fa:"\f41e"}.fa-wirsindhandwerk,.fa-wsh{--fa:"\e2d0"}.fa-buromobelexperte{--fa:"\f37f"}.fa-salesforce{--fa:"\f83b"}.fa-octopus-deploy{--fa:"\e082"}.fa-medapps{--fa:"\f3c6"}.fa-ns8{--fa:"\f3d5"}.fa-pinterest-p{--fa:"\f231"}.fa-apper{--fa:"\f371"}.fa-fort-awesome{--fa:"\f286"}.fa-waze{--fa:"\f83f"}.fa-bluesky{--fa:"\e671"}.fa-cc-jcb{--fa:"\f24b"}.fa-snapchat,.fa-snapchat-ghost{--fa:"\f2ab"}.fa-fantasy-flight-games{--fa:"\f6dc"}.fa-rust{--fa:"\e07a"}.fa-wix{--fa:"\f5cf"}.fa-behance-square,.fa-square-behance{--fa:"\f1b5"}.fa-supple{--fa:"\f3f9"}.fa-webflow{--fa:"\e65c"}.fa-rebel{--fa:"\f1d0"}.fa-css3{--fa:"\f13c"}.fa-staylinked{--fa:"\f3f5"}.fa-kaggle{--fa:"\f5fa"}.fa-space-awesome{--fa:"\e5ac"}.fa-deviantart{--fa:"\f1bd"}.fa-cpanel{--fa:"\f388"}.fa-goodreads-g{--fa:"\f3a9"}.fa-git-square,.fa-square-git{--fa:"\f1d2"}.fa-square-tumblr,.fa-tumblr-square{--fa:"\f174"}.fa-trello{--fa:"\f181"}.fa-creative-commons-nc-jp{--fa:"\f4ea"}.fa-get-pocket{--fa:"\f265"}.fa-perbyte{--fa:"\e083"}.fa-grunt{--fa:"\f3ad"}.fa-weebly{--fa:"\f5cc"}.fa-connectdevelop{--fa:"\f20e"}.fa-leanpub{--fa:"\f212"}.fa-black-tie{--fa:"\f27e"}.fa-themeco{--fa:"\f5c6"}.fa-python{--fa:"\f3e2"}.fa-android{--fa:"\f17b"}.fa-bots{--fa:"\e340"}.fa-free-code-camp{--fa:"\f2c5"}.fa-hornbill{--fa:"\f592"}.fa-js{--fa:"\f3b8"}.fa-ideal{--fa:"\e013"}.fa-git{--fa:"\f1d3"}.fa-dev{--fa:"\f6cc"}.fa-sketch{--fa:"\f7c6"}.fa-yandex-international{--fa:"\f414"}.fa-cc-amex{--fa:"\f1f3"}.fa-uber{--fa:"\f402"}.fa-github{--fa:"\f09b"}.fa-php{--fa:"\f457"}.fa-alipay{--fa:"\f642"}.fa-youtube{--fa:"\f167"}.fa-skyatlas{--fa:"\f216"}.fa-firefox-browser{--fa:"\e007"}.fa-replyd{--fa:"\f3e6"}.fa-suse{--fa:"\f7d6"}.fa-jenkins{--fa:"\f3b6"}.fa-twitter{--fa:"\f099"}.fa-rockrms{--fa:"\f3e9"}.fa-pinterest{--fa:"\f0d2"}.fa-buffer{--fa:"\f837"}.fa-npm{--fa:"\f3d4"}.fa-yammer{--fa:"\f840"}.fa-btc{--fa:"\f15a"}.fa-dribbble{--fa:"\f17d"}.fa-stumbleupon-circle{--fa:"\f1a3"}.fa-internet-explorer{--fa:"\f26b"}.fa-stubber{--fa:"\e5c7"}.fa-telegram,.fa-telegram-plane{--fa:"\f2c6"}.fa-old-republic{--fa:"\f510"}.fa-odysee{--fa:"\e5c6"}.fa-square-whatsapp,.fa-whatsapp-square{--fa:"\f40c"}.fa-node-js{--fa:"\f3d3"}.fa-edge-legacy{--fa:"\e078"}.fa-slack,.fa-slack-hash{--fa:"\f198"}.fa-medrt{--fa:"\f3c8"}.fa-usb{--fa:"\f287"}.fa-tumblr{--fa:"\f173"}.fa-vaadin{--fa:"\f408"}.fa-quora{--fa:"\f2c4"}.fa-square-x-twitter{--fa:"\e61a"}.fa-reacteurope{--fa:"\f75d"}.fa-medium,.fa-medium-m{--fa:"\f23a"}.fa-amilia{--fa:"\f36d"}.fa-mixcloud{--fa:"\f289"}.fa-flipboard{--fa:"\f44d"}.fa-viacoin{--fa:"\f237"}.fa-critical-role{--fa:"\f6c9"}.fa-sitrox{--fa:"\e44a"}.fa-discourse{--fa:"\f393"}.fa-joomla{--fa:"\f1aa"}.fa-mastodon{--fa:"\f4f6"}.fa-airbnb{--fa:"\f834"}.fa-wolf-pack-battalion{--fa:"\f514"}.fa-buy-n-large{--fa:"\f8a6"}.fa-gulp{--fa:"\f3ae"}.fa-creative-commons-sampling-plus{--fa:"\f4f1"}.fa-strava{--fa:"\f428"}.fa-ember{--fa:"\f423"}.fa-canadian-maple-leaf{--fa:"\f785"}.fa-teamspeak{--fa:"\f4f9"}.fa-pushed{--fa:"\f3e1"}.fa-wordpress-simple{--fa:"\f411"}.fa-nutritionix{--fa:"\f3d6"}.fa-wodu{--fa:"\e088"}.fa-google-pay{--fa:"\e079"}.fa-intercom{--fa:"\f7af"}.fa-zhihu{--fa:"\f63f"}.fa-korvue{--fa:"\f42f"}.fa-pix{--fa:"\e43a"}.fa-steam-symbol{--fa:"\f3f6"} \ No newline at end of file diff --git a/css/fontawesome.css b/css/fontawesome.css new file mode 100644 index 0000000000..a9b2ec89b2 --- /dev/null +++ b/css/fontawesome.css @@ -0,0 +1,6243 @@ +/*! + * Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + * Copyright 2024 Fonticons, Inc. + */ +.fa { + font-family: var(--fa-style-family, "Font Awesome 6 Free"); + font-weight: var(--fa-style, 900); } + +.fas, +.far, +.fab, +.fa-solid, +.fa-regular, +.fa-brands, +.fa { + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + display: var(--fa-display, inline-block); + font-style: normal; + font-variant: normal; + line-height: 1; + text-rendering: auto; } + +.fas::before, +.far::before, +.fab::before, +.fa-solid::before, +.fa-regular::before, +.fa-brands::before, +.fa::before { + content: var(--fa); } + +.fa-classic, +.fas, +.fa-solid, +.far, +.fa-regular { + font-family: 'Font Awesome 6 Free'; } + +.fa-brands, +.fab { + font-family: 'Font Awesome 6 Brands'; } + +.fa-1x { + font-size: 1em; } + +.fa-2x { + font-size: 2em; } + +.fa-3x { + font-size: 3em; } + +.fa-4x { + font-size: 4em; } + +.fa-5x { + font-size: 5em; } + +.fa-6x { + font-size: 6em; } + +.fa-7x { + font-size: 7em; } + +.fa-8x { + font-size: 8em; } + +.fa-9x { + font-size: 9em; } + +.fa-10x { + font-size: 10em; } + +.fa-2xs { + font-size: 0.625em; + line-height: 0.1em; + vertical-align: 0.225em; } + +.fa-xs { + font-size: 0.75em; + line-height: 0.08333em; + vertical-align: 0.125em; } + +.fa-sm { + font-size: 0.875em; + line-height: 0.07143em; + vertical-align: 0.05357em; } + +.fa-lg { + font-size: 1.25em; + line-height: 0.05em; + vertical-align: -0.075em; } + +.fa-xl { + font-size: 1.5em; + line-height: 0.04167em; + vertical-align: -0.125em; } + +.fa-2xl { + font-size: 2em; + line-height: 0.03125em; + vertical-align: -0.1875em; } + +.fa-fw { + text-align: center; + width: 1.25em; } + +.fa-ul { + list-style-type: none; + margin-left: var(--fa-li-margin, 2.5em); + padding-left: 0; } + .fa-ul > li { + position: relative; } + +.fa-li { + left: calc(-1 * var(--fa-li-width, 2em)); + position: absolute; + text-align: center; + width: var(--fa-li-width, 2em); + line-height: inherit; } + +.fa-border { + border-color: var(--fa-border-color, #eee); + border-radius: var(--fa-border-radius, 0.1em); + border-style: var(--fa-border-style, solid); + border-width: var(--fa-border-width, 0.08em); + padding: var(--fa-border-padding, 0.2em 0.25em 0.15em); } + +.fa-pull-left { + float: left; + margin-right: var(--fa-pull-margin, 0.3em); } + +.fa-pull-right { + float: right; + margin-left: var(--fa-pull-margin, 0.3em); } + +.fa-beat { + animation-name: fa-beat; + animation-delay: var(--fa-animation-delay, 0s); + animation-direction: var(--fa-animation-direction, normal); + animation-duration: var(--fa-animation-duration, 1s); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-timing-function: var(--fa-animation-timing, ease-in-out); } + +.fa-bounce { + animation-name: fa-bounce; + animation-delay: var(--fa-animation-delay, 0s); + animation-direction: var(--fa-animation-direction, normal); + animation-duration: var(--fa-animation-duration, 1s); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.28, 0.84, 0.42, 1)); } + +.fa-fade { + animation-name: fa-fade; + animation-delay: var(--fa-animation-delay, 0s); + animation-direction: var(--fa-animation-direction, normal); + animation-duration: var(--fa-animation-duration, 1s); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1)); } + +.fa-beat-fade { + animation-name: fa-beat-fade; + animation-delay: var(--fa-animation-delay, 0s); + animation-direction: var(--fa-animation-direction, normal); + animation-duration: var(--fa-animation-duration, 1s); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-timing-function: var(--fa-animation-timing, cubic-bezier(0.4, 0, 0.6, 1)); } + +.fa-flip { + animation-name: fa-flip; + animation-delay: var(--fa-animation-delay, 0s); + animation-direction: var(--fa-animation-direction, normal); + animation-duration: var(--fa-animation-duration, 1s); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-timing-function: var(--fa-animation-timing, ease-in-out); } + +.fa-shake { + animation-name: fa-shake; + animation-delay: var(--fa-animation-delay, 0s); + animation-direction: var(--fa-animation-direction, normal); + animation-duration: var(--fa-animation-duration, 1s); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-timing-function: var(--fa-animation-timing, linear); } + +.fa-spin { + animation-name: fa-spin; + animation-delay: var(--fa-animation-delay, 0s); + animation-direction: var(--fa-animation-direction, normal); + animation-duration: var(--fa-animation-duration, 2s); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-timing-function: var(--fa-animation-timing, linear); } + +.fa-spin-reverse { + --fa-animation-direction: reverse; } + +.fa-pulse, +.fa-spin-pulse { + animation-name: fa-spin; + animation-direction: var(--fa-animation-direction, normal); + animation-duration: var(--fa-animation-duration, 1s); + animation-iteration-count: var(--fa-animation-iteration-count, infinite); + animation-timing-function: var(--fa-animation-timing, steps(8)); } + +@media (prefers-reduced-motion: reduce) { + .fa-beat, + .fa-bounce, + .fa-fade, + .fa-beat-fade, + .fa-flip, + .fa-pulse, + .fa-shake, + .fa-spin, + .fa-spin-pulse { + animation-delay: -1ms; + animation-duration: 1ms; + animation-iteration-count: 1; + transition-delay: 0s; + transition-duration: 0s; } } + +@keyframes fa-beat { + 0%, 90% { + transform: scale(1); } + 45% { + transform: scale(var(--fa-beat-scale, 1.25)); } } + +@keyframes fa-bounce { + 0% { + transform: scale(1, 1) translateY(0); } + 10% { + transform: scale(var(--fa-bounce-start-scale-x, 1.1), var(--fa-bounce-start-scale-y, 0.9)) translateY(0); } + 30% { + transform: scale(var(--fa-bounce-jump-scale-x, 0.9), var(--fa-bounce-jump-scale-y, 1.1)) translateY(var(--fa-bounce-height, -0.5em)); } + 50% { + transform: scale(var(--fa-bounce-land-scale-x, 1.05), var(--fa-bounce-land-scale-y, 0.95)) translateY(0); } + 57% { + transform: scale(1, 1) translateY(var(--fa-bounce-rebound, -0.125em)); } + 64% { + transform: scale(1, 1) translateY(0); } + 100% { + transform: scale(1, 1) translateY(0); } } + +@keyframes fa-fade { + 50% { + opacity: var(--fa-fade-opacity, 0.4); } } + +@keyframes fa-beat-fade { + 0%, 100% { + opacity: var(--fa-beat-fade-opacity, 0.4); + transform: scale(1); } + 50% { + opacity: 1; + transform: scale(var(--fa-beat-fade-scale, 1.125)); } } + +@keyframes fa-flip { + 50% { + transform: rotate3d(var(--fa-flip-x, 0), var(--fa-flip-y, 1), var(--fa-flip-z, 0), var(--fa-flip-angle, -180deg)); } } + +@keyframes fa-shake { + 0% { + transform: rotate(-15deg); } + 4% { + transform: rotate(15deg); } + 8%, 24% { + transform: rotate(-18deg); } + 12%, 28% { + transform: rotate(18deg); } + 16% { + transform: rotate(-22deg); } + 20% { + transform: rotate(22deg); } + 32% { + transform: rotate(-12deg); } + 36% { + transform: rotate(12deg); } + 40%, 100% { + transform: rotate(0deg); } } + +@keyframes fa-spin { + 0% { + transform: rotate(0deg); } + 100% { + transform: rotate(360deg); } } + +.fa-rotate-90 { + transform: rotate(90deg); } + +.fa-rotate-180 { + transform: rotate(180deg); } + +.fa-rotate-270 { + transform: rotate(270deg); } + +.fa-flip-horizontal { + transform: scale(-1, 1); } + +.fa-flip-vertical { + transform: scale(1, -1); } + +.fa-flip-both, +.fa-flip-horizontal.fa-flip-vertical { + transform: scale(-1, -1); } + +.fa-rotate-by { + transform: rotate(var(--fa-rotate-angle, 0)); } + +.fa-stack { + display: inline-block; + height: 2em; + line-height: 2em; + position: relative; + vertical-align: middle; + width: 2.5em; } + +.fa-stack-1x, +.fa-stack-2x { + left: 0; + position: absolute; + text-align: center; + width: 100%; + z-index: var(--fa-stack-z-index, auto); } + +.fa-stack-1x { + line-height: inherit; } + +.fa-stack-2x { + font-size: 2em; } + +.fa-inverse { + color: var(--fa-inverse, #fff); } + +/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen +readers do not read off random characters that represent icons */ + +.fa-0 { + --fa: "\30"; } + +.fa-1 { + --fa: "\31"; } + +.fa-2 { + --fa: "\32"; } + +.fa-3 { + --fa: "\33"; } + +.fa-4 { + --fa: "\34"; } + +.fa-5 { + --fa: "\35"; } + +.fa-6 { + --fa: "\36"; } + +.fa-7 { + --fa: "\37"; } + +.fa-8 { + --fa: "\38"; } + +.fa-9 { + --fa: "\39"; } + +.fa-fill-drip { + --fa: "\f576"; } + +.fa-arrows-to-circle { + --fa: "\e4bd"; } + +.fa-circle-chevron-right { + --fa: "\f138"; } + +.fa-chevron-circle-right { + --fa: "\f138"; } + +.fa-at { + --fa: "\40"; } + +.fa-trash-can { + --fa: "\f2ed"; } + +.fa-trash-alt { + --fa: "\f2ed"; } + +.fa-text-height { + --fa: "\f034"; } + +.fa-user-xmark { + --fa: "\f235"; } + +.fa-user-times { + --fa: "\f235"; } + +.fa-stethoscope { + --fa: "\f0f1"; } + +.fa-message { + --fa: "\f27a"; } + +.fa-comment-alt { + --fa: "\f27a"; } + +.fa-info { + --fa: "\f129"; } + +.fa-down-left-and-up-right-to-center { + --fa: "\f422"; } + +.fa-compress-alt { + --fa: "\f422"; } + +.fa-explosion { + --fa: "\e4e9"; } + +.fa-file-lines { + --fa: "\f15c"; } + +.fa-file-alt { + --fa: "\f15c"; } + +.fa-file-text { + --fa: "\f15c"; } + +.fa-wave-square { + --fa: "\f83e"; } + +.fa-ring { + --fa: "\f70b"; } + +.fa-building-un { + --fa: "\e4d9"; } + +.fa-dice-three { + --fa: "\f527"; } + +.fa-calendar-days { + --fa: "\f073"; } + +.fa-calendar-alt { + --fa: "\f073"; } + +.fa-anchor-circle-check { + --fa: "\e4aa"; } + +.fa-building-circle-arrow-right { + --fa: "\e4d1"; } + +.fa-volleyball { + --fa: "\f45f"; } + +.fa-volleyball-ball { + --fa: "\f45f"; } + +.fa-arrows-up-to-line { + --fa: "\e4c2"; } + +.fa-sort-down { + --fa: "\f0dd"; } + +.fa-sort-desc { + --fa: "\f0dd"; } + +.fa-circle-minus { + --fa: "\f056"; } + +.fa-minus-circle { + --fa: "\f056"; } + +.fa-door-open { + --fa: "\f52b"; } + +.fa-right-from-bracket { + --fa: "\f2f5"; } + +.fa-sign-out-alt { + --fa: "\f2f5"; } + +.fa-atom { + --fa: "\f5d2"; } + +.fa-soap { + --fa: "\e06e"; } + +.fa-icons { + --fa: "\f86d"; } + +.fa-heart-music-camera-bolt { + --fa: "\f86d"; } + +.fa-microphone-lines-slash { + --fa: "\f539"; } + +.fa-microphone-alt-slash { + --fa: "\f539"; } + +.fa-bridge-circle-check { + --fa: "\e4c9"; } + +.fa-pump-medical { + --fa: "\e06a"; } + +.fa-fingerprint { + --fa: "\f577"; } + +.fa-hand-point-right { + --fa: "\f0a4"; } + +.fa-magnifying-glass-location { + --fa: "\f689"; } + +.fa-search-location { + --fa: "\f689"; } + +.fa-forward-step { + --fa: "\f051"; } + +.fa-step-forward { + --fa: "\f051"; } + +.fa-face-smile-beam { + --fa: "\f5b8"; } + +.fa-smile-beam { + --fa: "\f5b8"; } + +.fa-flag-checkered { + --fa: "\f11e"; } + +.fa-football { + --fa: "\f44e"; } + +.fa-football-ball { + --fa: "\f44e"; } + +.fa-school-circle-exclamation { + --fa: "\e56c"; } + +.fa-crop { + --fa: "\f125"; } + +.fa-angles-down { + --fa: "\f103"; } + +.fa-angle-double-down { + --fa: "\f103"; } + +.fa-users-rectangle { + --fa: "\e594"; } + +.fa-people-roof { + --fa: "\e537"; } + +.fa-people-line { + --fa: "\e534"; } + +.fa-beer-mug-empty { + --fa: "\f0fc"; } + +.fa-beer { + --fa: "\f0fc"; } + +.fa-diagram-predecessor { + --fa: "\e477"; } + +.fa-arrow-up-long { + --fa: "\f176"; } + +.fa-long-arrow-up { + --fa: "\f176"; } + +.fa-fire-flame-simple { + --fa: "\f46a"; } + +.fa-burn { + --fa: "\f46a"; } + +.fa-person { + --fa: "\f183"; } + +.fa-male { + --fa: "\f183"; } + +.fa-laptop { + --fa: "\f109"; } + +.fa-file-csv { + --fa: "\f6dd"; } + +.fa-menorah { + --fa: "\f676"; } + +.fa-truck-plane { + --fa: "\e58f"; } + +.fa-record-vinyl { + --fa: "\f8d9"; } + +.fa-face-grin-stars { + --fa: "\f587"; } + +.fa-grin-stars { + --fa: "\f587"; } + +.fa-bong { + --fa: "\f55c"; } + +.fa-spaghetti-monster-flying { + --fa: "\f67b"; } + +.fa-pastafarianism { + --fa: "\f67b"; } + +.fa-arrow-down-up-across-line { + --fa: "\e4af"; } + +.fa-spoon { + --fa: "\f2e5"; } + +.fa-utensil-spoon { + --fa: "\f2e5"; } + +.fa-jar-wheat { + --fa: "\e517"; } + +.fa-envelopes-bulk { + --fa: "\f674"; } + +.fa-mail-bulk { + --fa: "\f674"; } + +.fa-file-circle-exclamation { + --fa: "\e4eb"; } + +.fa-circle-h { + --fa: "\f47e"; } + +.fa-hospital-symbol { + --fa: "\f47e"; } + +.fa-pager { + --fa: "\f815"; } + +.fa-address-book { + --fa: "\f2b9"; } + +.fa-contact-book { + --fa: "\f2b9"; } + +.fa-strikethrough { + --fa: "\f0cc"; } + +.fa-k { + --fa: "\4b"; } + +.fa-landmark-flag { + --fa: "\e51c"; } + +.fa-pencil { + --fa: "\f303"; } + +.fa-pencil-alt { + --fa: "\f303"; } + +.fa-backward { + --fa: "\f04a"; } + +.fa-caret-right { + --fa: "\f0da"; } + +.fa-comments { + --fa: "\f086"; } + +.fa-paste { + --fa: "\f0ea"; } + +.fa-file-clipboard { + --fa: "\f0ea"; } + +.fa-code-pull-request { + --fa: "\e13c"; } + +.fa-clipboard-list { + --fa: "\f46d"; } + +.fa-truck-ramp-box { + --fa: "\f4de"; } + +.fa-truck-loading { + --fa: "\f4de"; } + +.fa-user-check { + --fa: "\f4fc"; } + +.fa-vial-virus { + --fa: "\e597"; } + +.fa-sheet-plastic { + --fa: "\e571"; } + +.fa-blog { + --fa: "\f781"; } + +.fa-user-ninja { + --fa: "\f504"; } + +.fa-person-arrow-up-from-line { + --fa: "\e539"; } + +.fa-scroll-torah { + --fa: "\f6a0"; } + +.fa-torah { + --fa: "\f6a0"; } + +.fa-broom-ball { + --fa: "\f458"; } + +.fa-quidditch { + --fa: "\f458"; } + +.fa-quidditch-broom-ball { + --fa: "\f458"; } + +.fa-toggle-off { + --fa: "\f204"; } + +.fa-box-archive { + --fa: "\f187"; } + +.fa-archive { + --fa: "\f187"; } + +.fa-person-drowning { + --fa: "\e545"; } + +.fa-arrow-down-9-1 { + --fa: "\f886"; } + +.fa-sort-numeric-desc { + --fa: "\f886"; } + +.fa-sort-numeric-down-alt { + --fa: "\f886"; } + +.fa-face-grin-tongue-squint { + --fa: "\f58a"; } + +.fa-grin-tongue-squint { + --fa: "\f58a"; } + +.fa-spray-can { + --fa: "\f5bd"; } + +.fa-truck-monster { + --fa: "\f63b"; } + +.fa-w { + --fa: "\57"; } + +.fa-earth-africa { + --fa: "\f57c"; } + +.fa-globe-africa { + --fa: "\f57c"; } + +.fa-rainbow { + --fa: "\f75b"; } + +.fa-circle-notch { + --fa: "\f1ce"; } + +.fa-tablet-screen-button { + --fa: "\f3fa"; } + +.fa-tablet-alt { + --fa: "\f3fa"; } + +.fa-paw { + --fa: "\f1b0"; } + +.fa-cloud { + --fa: "\f0c2"; } + +.fa-trowel-bricks { + --fa: "\e58a"; } + +.fa-face-flushed { + --fa: "\f579"; } + +.fa-flushed { + --fa: "\f579"; } + +.fa-hospital-user { + --fa: "\f80d"; } + +.fa-tent-arrow-left-right { + --fa: "\e57f"; } + +.fa-gavel { + --fa: "\f0e3"; } + +.fa-legal { + --fa: "\f0e3"; } + +.fa-binoculars { + --fa: "\f1e5"; } + +.fa-microphone-slash { + --fa: "\f131"; } + +.fa-box-tissue { + --fa: "\e05b"; } + +.fa-motorcycle { + --fa: "\f21c"; } + +.fa-bell-concierge { + --fa: "\f562"; } + +.fa-concierge-bell { + --fa: "\f562"; } + +.fa-pen-ruler { + --fa: "\f5ae"; } + +.fa-pencil-ruler { + --fa: "\f5ae"; } + +.fa-people-arrows { + --fa: "\e068"; } + +.fa-people-arrows-left-right { + --fa: "\e068"; } + +.fa-mars-and-venus-burst { + --fa: "\e523"; } + +.fa-square-caret-right { + --fa: "\f152"; } + +.fa-caret-square-right { + --fa: "\f152"; } + +.fa-scissors { + --fa: "\f0c4"; } + +.fa-cut { + --fa: "\f0c4"; } + +.fa-sun-plant-wilt { + --fa: "\e57a"; } + +.fa-toilets-portable { + --fa: "\e584"; } + +.fa-hockey-puck { + --fa: "\f453"; } + +.fa-table { + --fa: "\f0ce"; } + +.fa-magnifying-glass-arrow-right { + --fa: "\e521"; } + +.fa-tachograph-digital { + --fa: "\f566"; } + +.fa-digital-tachograph { + --fa: "\f566"; } + +.fa-users-slash { + --fa: "\e073"; } + +.fa-clover { + --fa: "\e139"; } + +.fa-reply { + --fa: "\f3e5"; } + +.fa-mail-reply { + --fa: "\f3e5"; } + +.fa-star-and-crescent { + --fa: "\f699"; } + +.fa-house-fire { + --fa: "\e50c"; } + +.fa-square-minus { + --fa: "\f146"; } + +.fa-minus-square { + --fa: "\f146"; } + +.fa-helicopter { + --fa: "\f533"; } + +.fa-compass { + --fa: "\f14e"; } + +.fa-square-caret-down { + --fa: "\f150"; } + +.fa-caret-square-down { + --fa: "\f150"; } + +.fa-file-circle-question { + --fa: "\e4ef"; } + +.fa-laptop-code { + --fa: "\f5fc"; } + +.fa-swatchbook { + --fa: "\f5c3"; } + +.fa-prescription-bottle { + --fa: "\f485"; } + +.fa-bars { + --fa: "\f0c9"; } + +.fa-navicon { + --fa: "\f0c9"; } + +.fa-people-group { + --fa: "\e533"; } + +.fa-hourglass-end { + --fa: "\f253"; } + +.fa-hourglass-3 { + --fa: "\f253"; } + +.fa-heart-crack { + --fa: "\f7a9"; } + +.fa-heart-broken { + --fa: "\f7a9"; } + +.fa-square-up-right { + --fa: "\f360"; } + +.fa-external-link-square-alt { + --fa: "\f360"; } + +.fa-face-kiss-beam { + --fa: "\f597"; } + +.fa-kiss-beam { + --fa: "\f597"; } + +.fa-film { + --fa: "\f008"; } + +.fa-ruler-horizontal { + --fa: "\f547"; } + +.fa-people-robbery { + --fa: "\e536"; } + +.fa-lightbulb { + --fa: "\f0eb"; } + +.fa-caret-left { + --fa: "\f0d9"; } + +.fa-circle-exclamation { + --fa: "\f06a"; } + +.fa-exclamation-circle { + --fa: "\f06a"; } + +.fa-school-circle-xmark { + --fa: "\e56d"; } + +.fa-arrow-right-from-bracket { + --fa: "\f08b"; } + +.fa-sign-out { + --fa: "\f08b"; } + +.fa-circle-chevron-down { + --fa: "\f13a"; } + +.fa-chevron-circle-down { + --fa: "\f13a"; } + +.fa-unlock-keyhole { + --fa: "\f13e"; } + +.fa-unlock-alt { + --fa: "\f13e"; } + +.fa-cloud-showers-heavy { + --fa: "\f740"; } + +.fa-headphones-simple { + --fa: "\f58f"; } + +.fa-headphones-alt { + --fa: "\f58f"; } + +.fa-sitemap { + --fa: "\f0e8"; } + +.fa-circle-dollar-to-slot { + --fa: "\f4b9"; } + +.fa-donate { + --fa: "\f4b9"; } + +.fa-memory { + --fa: "\f538"; } + +.fa-road-spikes { + --fa: "\e568"; } + +.fa-fire-burner { + --fa: "\e4f1"; } + +.fa-flag { + --fa: "\f024"; } + +.fa-hanukiah { + --fa: "\f6e6"; } + +.fa-feather { + --fa: "\f52d"; } + +.fa-volume-low { + --fa: "\f027"; } + +.fa-volume-down { + --fa: "\f027"; } + +.fa-comment-slash { + --fa: "\f4b3"; } + +.fa-cloud-sun-rain { + --fa: "\f743"; } + +.fa-compress { + --fa: "\f066"; } + +.fa-wheat-awn { + --fa: "\e2cd"; } + +.fa-wheat-alt { + --fa: "\e2cd"; } + +.fa-ankh { + --fa: "\f644"; } + +.fa-hands-holding-child { + --fa: "\e4fa"; } + +.fa-asterisk { + --fa: "\2a"; } + +.fa-square-check { + --fa: "\f14a"; } + +.fa-check-square { + --fa: "\f14a"; } + +.fa-peseta-sign { + --fa: "\e221"; } + +.fa-heading { + --fa: "\f1dc"; } + +.fa-header { + --fa: "\f1dc"; } + +.fa-ghost { + --fa: "\f6e2"; } + +.fa-list { + --fa: "\f03a"; } + +.fa-list-squares { + --fa: "\f03a"; } + +.fa-square-phone-flip { + --fa: "\f87b"; } + +.fa-phone-square-alt { + --fa: "\f87b"; } + +.fa-cart-plus { + --fa: "\f217"; } + +.fa-gamepad { + --fa: "\f11b"; } + +.fa-circle-dot { + --fa: "\f192"; } + +.fa-dot-circle { + --fa: "\f192"; } + +.fa-face-dizzy { + --fa: "\f567"; } + +.fa-dizzy { + --fa: "\f567"; } + +.fa-egg { + --fa: "\f7fb"; } + +.fa-house-medical-circle-xmark { + --fa: "\e513"; } + +.fa-campground { + --fa: "\f6bb"; } + +.fa-folder-plus { + --fa: "\f65e"; } + +.fa-futbol { + --fa: "\f1e3"; } + +.fa-futbol-ball { + --fa: "\f1e3"; } + +.fa-soccer-ball { + --fa: "\f1e3"; } + +.fa-paintbrush { + --fa: "\f1fc"; } + +.fa-paint-brush { + --fa: "\f1fc"; } + +.fa-lock { + --fa: "\f023"; } + +.fa-gas-pump { + --fa: "\f52f"; } + +.fa-hot-tub-person { + --fa: "\f593"; } + +.fa-hot-tub { + --fa: "\f593"; } + +.fa-map-location { + --fa: "\f59f"; } + +.fa-map-marked { + --fa: "\f59f"; } + +.fa-house-flood-water { + --fa: "\e50e"; } + +.fa-tree { + --fa: "\f1bb"; } + +.fa-bridge-lock { + --fa: "\e4cc"; } + +.fa-sack-dollar { + --fa: "\f81d"; } + +.fa-pen-to-square { + --fa: "\f044"; } + +.fa-edit { + --fa: "\f044"; } + +.fa-car-side { + --fa: "\f5e4"; } + +.fa-share-nodes { + --fa: "\f1e0"; } + +.fa-share-alt { + --fa: "\f1e0"; } + +.fa-heart-circle-minus { + --fa: "\e4ff"; } + +.fa-hourglass-half { + --fa: "\f252"; } + +.fa-hourglass-2 { + --fa: "\f252"; } + +.fa-microscope { + --fa: "\f610"; } + +.fa-sink { + --fa: "\e06d"; } + +.fa-bag-shopping { + --fa: "\f290"; } + +.fa-shopping-bag { + --fa: "\f290"; } + +.fa-arrow-down-z-a { + --fa: "\f881"; } + +.fa-sort-alpha-desc { + --fa: "\f881"; } + +.fa-sort-alpha-down-alt { + --fa: "\f881"; } + +.fa-mitten { + --fa: "\f7b5"; } + +.fa-person-rays { + --fa: "\e54d"; } + +.fa-users { + --fa: "\f0c0"; } + +.fa-eye-slash { + --fa: "\f070"; } + +.fa-flask-vial { + --fa: "\e4f3"; } + +.fa-hand { + --fa: "\f256"; } + +.fa-hand-paper { + --fa: "\f256"; } + +.fa-om { + --fa: "\f679"; } + +.fa-worm { + --fa: "\e599"; } + +.fa-house-circle-xmark { + --fa: "\e50b"; } + +.fa-plug { + --fa: "\f1e6"; } + +.fa-chevron-up { + --fa: "\f077"; } + +.fa-hand-spock { + --fa: "\f259"; } + +.fa-stopwatch { + --fa: "\f2f2"; } + +.fa-face-kiss { + --fa: "\f596"; } + +.fa-kiss { + --fa: "\f596"; } + +.fa-bridge-circle-xmark { + --fa: "\e4cb"; } + +.fa-face-grin-tongue { + --fa: "\f589"; } + +.fa-grin-tongue { + --fa: "\f589"; } + +.fa-chess-bishop { + --fa: "\f43a"; } + +.fa-face-grin-wink { + --fa: "\f58c"; } + +.fa-grin-wink { + --fa: "\f58c"; } + +.fa-ear-deaf { + --fa: "\f2a4"; } + +.fa-deaf { + --fa: "\f2a4"; } + +.fa-deafness { + --fa: "\f2a4"; } + +.fa-hard-of-hearing { + --fa: "\f2a4"; } + +.fa-road-circle-check { + --fa: "\e564"; } + +.fa-dice-five { + --fa: "\f523"; } + +.fa-square-rss { + --fa: "\f143"; } + +.fa-rss-square { + --fa: "\f143"; } + +.fa-land-mine-on { + --fa: "\e51b"; } + +.fa-i-cursor { + --fa: "\f246"; } + +.fa-stamp { + --fa: "\f5bf"; } + +.fa-stairs { + --fa: "\e289"; } + +.fa-i { + --fa: "\49"; } + +.fa-hryvnia-sign { + --fa: "\f6f2"; } + +.fa-hryvnia { + --fa: "\f6f2"; } + +.fa-pills { + --fa: "\f484"; } + +.fa-face-grin-wide { + --fa: "\f581"; } + +.fa-grin-alt { + --fa: "\f581"; } + +.fa-tooth { + --fa: "\f5c9"; } + +.fa-v { + --fa: "\56"; } + +.fa-bangladeshi-taka-sign { + --fa: "\e2e6"; } + +.fa-bicycle { + --fa: "\f206"; } + +.fa-staff-snake { + --fa: "\e579"; } + +.fa-rod-asclepius { + --fa: "\e579"; } + +.fa-rod-snake { + --fa: "\e579"; } + +.fa-staff-aesculapius { + --fa: "\e579"; } + +.fa-head-side-cough-slash { + --fa: "\e062"; } + +.fa-truck-medical { + --fa: "\f0f9"; } + +.fa-ambulance { + --fa: "\f0f9"; } + +.fa-wheat-awn-circle-exclamation { + --fa: "\e598"; } + +.fa-snowman { + --fa: "\f7d0"; } + +.fa-mortar-pestle { + --fa: "\f5a7"; } + +.fa-road-barrier { + --fa: "\e562"; } + +.fa-school { + --fa: "\f549"; } + +.fa-igloo { + --fa: "\f7ae"; } + +.fa-joint { + --fa: "\f595"; } + +.fa-angle-right { + --fa: "\f105"; } + +.fa-horse { + --fa: "\f6f0"; } + +.fa-q { + --fa: "\51"; } + +.fa-g { + --fa: "\47"; } + +.fa-notes-medical { + --fa: "\f481"; } + +.fa-temperature-half { + --fa: "\f2c9"; } + +.fa-temperature-2 { + --fa: "\f2c9"; } + +.fa-thermometer-2 { + --fa: "\f2c9"; } + +.fa-thermometer-half { + --fa: "\f2c9"; } + +.fa-dong-sign { + --fa: "\e169"; } + +.fa-capsules { + --fa: "\f46b"; } + +.fa-poo-storm { + --fa: "\f75a"; } + +.fa-poo-bolt { + --fa: "\f75a"; } + +.fa-face-frown-open { + --fa: "\f57a"; } + +.fa-frown-open { + --fa: "\f57a"; } + +.fa-hand-point-up { + --fa: "\f0a6"; } + +.fa-money-bill { + --fa: "\f0d6"; } + +.fa-bookmark { + --fa: "\f02e"; } + +.fa-align-justify { + --fa: "\f039"; } + +.fa-umbrella-beach { + --fa: "\f5ca"; } + +.fa-helmet-un { + --fa: "\e503"; } + +.fa-bullseye { + --fa: "\f140"; } + +.fa-bacon { + --fa: "\f7e5"; } + +.fa-hand-point-down { + --fa: "\f0a7"; } + +.fa-arrow-up-from-bracket { + --fa: "\e09a"; } + +.fa-folder { + --fa: "\f07b"; } + +.fa-folder-blank { + --fa: "\f07b"; } + +.fa-file-waveform { + --fa: "\f478"; } + +.fa-file-medical-alt { + --fa: "\f478"; } + +.fa-radiation { + --fa: "\f7b9"; } + +.fa-chart-simple { + --fa: "\e473"; } + +.fa-mars-stroke { + --fa: "\f229"; } + +.fa-vial { + --fa: "\f492"; } + +.fa-gauge { + --fa: "\f624"; } + +.fa-dashboard { + --fa: "\f624"; } + +.fa-gauge-med { + --fa: "\f624"; } + +.fa-tachometer-alt-average { + --fa: "\f624"; } + +.fa-wand-magic-sparkles { + --fa: "\e2ca"; } + +.fa-magic-wand-sparkles { + --fa: "\e2ca"; } + +.fa-e { + --fa: "\45"; } + +.fa-pen-clip { + --fa: "\f305"; } + +.fa-pen-alt { + --fa: "\f305"; } + +.fa-bridge-circle-exclamation { + --fa: "\e4ca"; } + +.fa-user { + --fa: "\f007"; } + +.fa-school-circle-check { + --fa: "\e56b"; } + +.fa-dumpster { + --fa: "\f793"; } + +.fa-van-shuttle { + --fa: "\f5b6"; } + +.fa-shuttle-van { + --fa: "\f5b6"; } + +.fa-building-user { + --fa: "\e4da"; } + +.fa-square-caret-left { + --fa: "\f191"; } + +.fa-caret-square-left { + --fa: "\f191"; } + +.fa-highlighter { + --fa: "\f591"; } + +.fa-key { + --fa: "\f084"; } + +.fa-bullhorn { + --fa: "\f0a1"; } + +.fa-globe { + --fa: "\f0ac"; } + +.fa-synagogue { + --fa: "\f69b"; } + +.fa-person-half-dress { + --fa: "\e548"; } + +.fa-road-bridge { + --fa: "\e563"; } + +.fa-location-arrow { + --fa: "\f124"; } + +.fa-c { + --fa: "\43"; } + +.fa-tablet-button { + --fa: "\f10a"; } + +.fa-building-lock { + --fa: "\e4d6"; } + +.fa-pizza-slice { + --fa: "\f818"; } + +.fa-money-bill-wave { + --fa: "\f53a"; } + +.fa-chart-area { + --fa: "\f1fe"; } + +.fa-area-chart { + --fa: "\f1fe"; } + +.fa-house-flag { + --fa: "\e50d"; } + +.fa-person-circle-minus { + --fa: "\e540"; } + +.fa-ban { + --fa: "\f05e"; } + +.fa-cancel { + --fa: "\f05e"; } + +.fa-camera-rotate { + --fa: "\e0d8"; } + +.fa-spray-can-sparkles { + --fa: "\f5d0"; } + +.fa-air-freshener { + --fa: "\f5d0"; } + +.fa-star { + --fa: "\f005"; } + +.fa-repeat { + --fa: "\f363"; } + +.fa-cross { + --fa: "\f654"; } + +.fa-box { + --fa: "\f466"; } + +.fa-venus-mars { + --fa: "\f228"; } + +.fa-arrow-pointer { + --fa: "\f245"; } + +.fa-mouse-pointer { + --fa: "\f245"; } + +.fa-maximize { + --fa: "\f31e"; } + +.fa-expand-arrows-alt { + --fa: "\f31e"; } + +.fa-charging-station { + --fa: "\f5e7"; } + +.fa-shapes { + --fa: "\f61f"; } + +.fa-triangle-circle-square { + --fa: "\f61f"; } + +.fa-shuffle { + --fa: "\f074"; } + +.fa-random { + --fa: "\f074"; } + +.fa-person-running { + --fa: "\f70c"; } + +.fa-running { + --fa: "\f70c"; } + +.fa-mobile-retro { + --fa: "\e527"; } + +.fa-grip-lines-vertical { + --fa: "\f7a5"; } + +.fa-spider { + --fa: "\f717"; } + +.fa-hands-bound { + --fa: "\e4f9"; } + +.fa-file-invoice-dollar { + --fa: "\f571"; } + +.fa-plane-circle-exclamation { + --fa: "\e556"; } + +.fa-x-ray { + --fa: "\f497"; } + +.fa-spell-check { + --fa: "\f891"; } + +.fa-slash { + --fa: "\f715"; } + +.fa-computer-mouse { + --fa: "\f8cc"; } + +.fa-mouse { + --fa: "\f8cc"; } + +.fa-arrow-right-to-bracket { + --fa: "\f090"; } + +.fa-sign-in { + --fa: "\f090"; } + +.fa-shop-slash { + --fa: "\e070"; } + +.fa-store-alt-slash { + --fa: "\e070"; } + +.fa-server { + --fa: "\f233"; } + +.fa-virus-covid-slash { + --fa: "\e4a9"; } + +.fa-shop-lock { + --fa: "\e4a5"; } + +.fa-hourglass-start { + --fa: "\f251"; } + +.fa-hourglass-1 { + --fa: "\f251"; } + +.fa-blender-phone { + --fa: "\f6b6"; } + +.fa-building-wheat { + --fa: "\e4db"; } + +.fa-person-breastfeeding { + --fa: "\e53a"; } + +.fa-right-to-bracket { + --fa: "\f2f6"; } + +.fa-sign-in-alt { + --fa: "\f2f6"; } + +.fa-venus { + --fa: "\f221"; } + +.fa-passport { + --fa: "\f5ab"; } + +.fa-thumbtack-slash { + --fa: "\e68f"; } + +.fa-thumb-tack-slash { + --fa: "\e68f"; } + +.fa-heart-pulse { + --fa: "\f21e"; } + +.fa-heartbeat { + --fa: "\f21e"; } + +.fa-people-carry-box { + --fa: "\f4ce"; } + +.fa-people-carry { + --fa: "\f4ce"; } + +.fa-temperature-high { + --fa: "\f769"; } + +.fa-microchip { + --fa: "\f2db"; } + +.fa-crown { + --fa: "\f521"; } + +.fa-weight-hanging { + --fa: "\f5cd"; } + +.fa-xmarks-lines { + --fa: "\e59a"; } + +.fa-file-prescription { + --fa: "\f572"; } + +.fa-weight-scale { + --fa: "\f496"; } + +.fa-weight { + --fa: "\f496"; } + +.fa-user-group { + --fa: "\f500"; } + +.fa-user-friends { + --fa: "\f500"; } + +.fa-arrow-up-a-z { + --fa: "\f15e"; } + +.fa-sort-alpha-up { + --fa: "\f15e"; } + +.fa-chess-knight { + --fa: "\f441"; } + +.fa-face-laugh-squint { + --fa: "\f59b"; } + +.fa-laugh-squint { + --fa: "\f59b"; } + +.fa-wheelchair { + --fa: "\f193"; } + +.fa-circle-arrow-up { + --fa: "\f0aa"; } + +.fa-arrow-circle-up { + --fa: "\f0aa"; } + +.fa-toggle-on { + --fa: "\f205"; } + +.fa-person-walking { + --fa: "\f554"; } + +.fa-walking { + --fa: "\f554"; } + +.fa-l { + --fa: "\4c"; } + +.fa-fire { + --fa: "\f06d"; } + +.fa-bed-pulse { + --fa: "\f487"; } + +.fa-procedures { + --fa: "\f487"; } + +.fa-shuttle-space { + --fa: "\f197"; } + +.fa-space-shuttle { + --fa: "\f197"; } + +.fa-face-laugh { + --fa: "\f599"; } + +.fa-laugh { + --fa: "\f599"; } + +.fa-folder-open { + --fa: "\f07c"; } + +.fa-heart-circle-plus { + --fa: "\e500"; } + +.fa-code-fork { + --fa: "\e13b"; } + +.fa-city { + --fa: "\f64f"; } + +.fa-microphone-lines { + --fa: "\f3c9"; } + +.fa-microphone-alt { + --fa: "\f3c9"; } + +.fa-pepper-hot { + --fa: "\f816"; } + +.fa-unlock { + --fa: "\f09c"; } + +.fa-colon-sign { + --fa: "\e140"; } + +.fa-headset { + --fa: "\f590"; } + +.fa-store-slash { + --fa: "\e071"; } + +.fa-road-circle-xmark { + --fa: "\e566"; } + +.fa-user-minus { + --fa: "\f503"; } + +.fa-mars-stroke-up { + --fa: "\f22a"; } + +.fa-mars-stroke-v { + --fa: "\f22a"; } + +.fa-champagne-glasses { + --fa: "\f79f"; } + +.fa-glass-cheers { + --fa: "\f79f"; } + +.fa-clipboard { + --fa: "\f328"; } + +.fa-house-circle-exclamation { + --fa: "\e50a"; } + +.fa-file-arrow-up { + --fa: "\f574"; } + +.fa-file-upload { + --fa: "\f574"; } + +.fa-wifi { + --fa: "\f1eb"; } + +.fa-wifi-3 { + --fa: "\f1eb"; } + +.fa-wifi-strong { + --fa: "\f1eb"; } + +.fa-bath { + --fa: "\f2cd"; } + +.fa-bathtub { + --fa: "\f2cd"; } + +.fa-underline { + --fa: "\f0cd"; } + +.fa-user-pen { + --fa: "\f4ff"; } + +.fa-user-edit { + --fa: "\f4ff"; } + +.fa-signature { + --fa: "\f5b7"; } + +.fa-stroopwafel { + --fa: "\f551"; } + +.fa-bold { + --fa: "\f032"; } + +.fa-anchor-lock { + --fa: "\e4ad"; } + +.fa-building-ngo { + --fa: "\e4d7"; } + +.fa-manat-sign { + --fa: "\e1d5"; } + +.fa-not-equal { + --fa: "\f53e"; } + +.fa-border-top-left { + --fa: "\f853"; } + +.fa-border-style { + --fa: "\f853"; } + +.fa-map-location-dot { + --fa: "\f5a0"; } + +.fa-map-marked-alt { + --fa: "\f5a0"; } + +.fa-jedi { + --fa: "\f669"; } + +.fa-square-poll-vertical { + --fa: "\f681"; } + +.fa-poll { + --fa: "\f681"; } + +.fa-mug-hot { + --fa: "\f7b6"; } + +.fa-car-battery { + --fa: "\f5df"; } + +.fa-battery-car { + --fa: "\f5df"; } + +.fa-gift { + --fa: "\f06b"; } + +.fa-dice-two { + --fa: "\f528"; } + +.fa-chess-queen { + --fa: "\f445"; } + +.fa-glasses { + --fa: "\f530"; } + +.fa-chess-board { + --fa: "\f43c"; } + +.fa-building-circle-check { + --fa: "\e4d2"; } + +.fa-person-chalkboard { + --fa: "\e53d"; } + +.fa-mars-stroke-right { + --fa: "\f22b"; } + +.fa-mars-stroke-h { + --fa: "\f22b"; } + +.fa-hand-back-fist { + --fa: "\f255"; } + +.fa-hand-rock { + --fa: "\f255"; } + +.fa-square-caret-up { + --fa: "\f151"; } + +.fa-caret-square-up { + --fa: "\f151"; } + +.fa-cloud-showers-water { + --fa: "\e4e4"; } + +.fa-chart-bar { + --fa: "\f080"; } + +.fa-bar-chart { + --fa: "\f080"; } + +.fa-hands-bubbles { + --fa: "\e05e"; } + +.fa-hands-wash { + --fa: "\e05e"; } + +.fa-less-than-equal { + --fa: "\f537"; } + +.fa-train { + --fa: "\f238"; } + +.fa-eye-low-vision { + --fa: "\f2a8"; } + +.fa-low-vision { + --fa: "\f2a8"; } + +.fa-crow { + --fa: "\f520"; } + +.fa-sailboat { + --fa: "\e445"; } + +.fa-window-restore { + --fa: "\f2d2"; } + +.fa-square-plus { + --fa: "\f0fe"; } + +.fa-plus-square { + --fa: "\f0fe"; } + +.fa-torii-gate { + --fa: "\f6a1"; } + +.fa-frog { + --fa: "\f52e"; } + +.fa-bucket { + --fa: "\e4cf"; } + +.fa-image { + --fa: "\f03e"; } + +.fa-microphone { + --fa: "\f130"; } + +.fa-cow { + --fa: "\f6c8"; } + +.fa-caret-up { + --fa: "\f0d8"; } + +.fa-screwdriver { + --fa: "\f54a"; } + +.fa-folder-closed { + --fa: "\e185"; } + +.fa-house-tsunami { + --fa: "\e515"; } + +.fa-square-nfi { + --fa: "\e576"; } + +.fa-arrow-up-from-ground-water { + --fa: "\e4b5"; } + +.fa-martini-glass { + --fa: "\f57b"; } + +.fa-glass-martini-alt { + --fa: "\f57b"; } + +.fa-square-binary { + --fa: "\e69b"; } + +.fa-rotate-left { + --fa: "\f2ea"; } + +.fa-rotate-back { + --fa: "\f2ea"; } + +.fa-rotate-backward { + --fa: "\f2ea"; } + +.fa-undo-alt { + --fa: "\f2ea"; } + +.fa-table-columns { + --fa: "\f0db"; } + +.fa-columns { + --fa: "\f0db"; } + +.fa-lemon { + --fa: "\f094"; } + +.fa-head-side-mask { + --fa: "\e063"; } + +.fa-handshake { + --fa: "\f2b5"; } + +.fa-gem { + --fa: "\f3a5"; } + +.fa-dolly { + --fa: "\f472"; } + +.fa-dolly-box { + --fa: "\f472"; } + +.fa-smoking { + --fa: "\f48d"; } + +.fa-minimize { + --fa: "\f78c"; } + +.fa-compress-arrows-alt { + --fa: "\f78c"; } + +.fa-monument { + --fa: "\f5a6"; } + +.fa-snowplow { + --fa: "\f7d2"; } + +.fa-angles-right { + --fa: "\f101"; } + +.fa-angle-double-right { + --fa: "\f101"; } + +.fa-cannabis { + --fa: "\f55f"; } + +.fa-circle-play { + --fa: "\f144"; } + +.fa-play-circle { + --fa: "\f144"; } + +.fa-tablets { + --fa: "\f490"; } + +.fa-ethernet { + --fa: "\f796"; } + +.fa-euro-sign { + --fa: "\f153"; } + +.fa-eur { + --fa: "\f153"; } + +.fa-euro { + --fa: "\f153"; } + +.fa-chair { + --fa: "\f6c0"; } + +.fa-circle-check { + --fa: "\f058"; } + +.fa-check-circle { + --fa: "\f058"; } + +.fa-circle-stop { + --fa: "\f28d"; } + +.fa-stop-circle { + --fa: "\f28d"; } + +.fa-compass-drafting { + --fa: "\f568"; } + +.fa-drafting-compass { + --fa: "\f568"; } + +.fa-plate-wheat { + --fa: "\e55a"; } + +.fa-icicles { + --fa: "\f7ad"; } + +.fa-person-shelter { + --fa: "\e54f"; } + +.fa-neuter { + --fa: "\f22c"; } + +.fa-id-badge { + --fa: "\f2c1"; } + +.fa-marker { + --fa: "\f5a1"; } + +.fa-face-laugh-beam { + --fa: "\f59a"; } + +.fa-laugh-beam { + --fa: "\f59a"; } + +.fa-helicopter-symbol { + --fa: "\e502"; } + +.fa-universal-access { + --fa: "\f29a"; } + +.fa-circle-chevron-up { + --fa: "\f139"; } + +.fa-chevron-circle-up { + --fa: "\f139"; } + +.fa-lari-sign { + --fa: "\e1c8"; } + +.fa-volcano { + --fa: "\f770"; } + +.fa-person-walking-dashed-line-arrow-right { + --fa: "\e553"; } + +.fa-sterling-sign { + --fa: "\f154"; } + +.fa-gbp { + --fa: "\f154"; } + +.fa-pound-sign { + --fa: "\f154"; } + +.fa-viruses { + --fa: "\e076"; } + +.fa-square-person-confined { + --fa: "\e577"; } + +.fa-user-tie { + --fa: "\f508"; } + +.fa-arrow-down-long { + --fa: "\f175"; } + +.fa-long-arrow-down { + --fa: "\f175"; } + +.fa-tent-arrow-down-to-line { + --fa: "\e57e"; } + +.fa-certificate { + --fa: "\f0a3"; } + +.fa-reply-all { + --fa: "\f122"; } + +.fa-mail-reply-all { + --fa: "\f122"; } + +.fa-suitcase { + --fa: "\f0f2"; } + +.fa-person-skating { + --fa: "\f7c5"; } + +.fa-skating { + --fa: "\f7c5"; } + +.fa-filter-circle-dollar { + --fa: "\f662"; } + +.fa-funnel-dollar { + --fa: "\f662"; } + +.fa-camera-retro { + --fa: "\f083"; } + +.fa-circle-arrow-down { + --fa: "\f0ab"; } + +.fa-arrow-circle-down { + --fa: "\f0ab"; } + +.fa-file-import { + --fa: "\f56f"; } + +.fa-arrow-right-to-file { + --fa: "\f56f"; } + +.fa-square-arrow-up-right { + --fa: "\f14c"; } + +.fa-external-link-square { + --fa: "\f14c"; } + +.fa-box-open { + --fa: "\f49e"; } + +.fa-scroll { + --fa: "\f70e"; } + +.fa-spa { + --fa: "\f5bb"; } + +.fa-location-pin-lock { + --fa: "\e51f"; } + +.fa-pause { + --fa: "\f04c"; } + +.fa-hill-avalanche { + --fa: "\e507"; } + +.fa-temperature-empty { + --fa: "\f2cb"; } + +.fa-temperature-0 { + --fa: "\f2cb"; } + +.fa-thermometer-0 { + --fa: "\f2cb"; } + +.fa-thermometer-empty { + --fa: "\f2cb"; } + +.fa-bomb { + --fa: "\f1e2"; } + +.fa-registered { + --fa: "\f25d"; } + +.fa-address-card { + --fa: "\f2bb"; } + +.fa-contact-card { + --fa: "\f2bb"; } + +.fa-vcard { + --fa: "\f2bb"; } + +.fa-scale-unbalanced-flip { + --fa: "\f516"; } + +.fa-balance-scale-right { + --fa: "\f516"; } + +.fa-subscript { + --fa: "\f12c"; } + +.fa-diamond-turn-right { + --fa: "\f5eb"; } + +.fa-directions { + --fa: "\f5eb"; } + +.fa-burst { + --fa: "\e4dc"; } + +.fa-house-laptop { + --fa: "\e066"; } + +.fa-laptop-house { + --fa: "\e066"; } + +.fa-face-tired { + --fa: "\f5c8"; } + +.fa-tired { + --fa: "\f5c8"; } + +.fa-money-bills { + --fa: "\e1f3"; } + +.fa-smog { + --fa: "\f75f"; } + +.fa-crutch { + --fa: "\f7f7"; } + +.fa-cloud-arrow-up { + --fa: "\f0ee"; } + +.fa-cloud-upload { + --fa: "\f0ee"; } + +.fa-cloud-upload-alt { + --fa: "\f0ee"; } + +.fa-palette { + --fa: "\f53f"; } + +.fa-arrows-turn-right { + --fa: "\e4c0"; } + +.fa-vest { + --fa: "\e085"; } + +.fa-ferry { + --fa: "\e4ea"; } + +.fa-arrows-down-to-people { + --fa: "\e4b9"; } + +.fa-seedling { + --fa: "\f4d8"; } + +.fa-sprout { + --fa: "\f4d8"; } + +.fa-left-right { + --fa: "\f337"; } + +.fa-arrows-alt-h { + --fa: "\f337"; } + +.fa-boxes-packing { + --fa: "\e4c7"; } + +.fa-circle-arrow-left { + --fa: "\f0a8"; } + +.fa-arrow-circle-left { + --fa: "\f0a8"; } + +.fa-group-arrows-rotate { + --fa: "\e4f6"; } + +.fa-bowl-food { + --fa: "\e4c6"; } + +.fa-candy-cane { + --fa: "\f786"; } + +.fa-arrow-down-wide-short { + --fa: "\f160"; } + +.fa-sort-amount-asc { + --fa: "\f160"; } + +.fa-sort-amount-down { + --fa: "\f160"; } + +.fa-cloud-bolt { + --fa: "\f76c"; } + +.fa-thunderstorm { + --fa: "\f76c"; } + +.fa-text-slash { + --fa: "\f87d"; } + +.fa-remove-format { + --fa: "\f87d"; } + +.fa-face-smile-wink { + --fa: "\f4da"; } + +.fa-smile-wink { + --fa: "\f4da"; } + +.fa-file-word { + --fa: "\f1c2"; } + +.fa-file-powerpoint { + --fa: "\f1c4"; } + +.fa-arrows-left-right { + --fa: "\f07e"; } + +.fa-arrows-h { + --fa: "\f07e"; } + +.fa-house-lock { + --fa: "\e510"; } + +.fa-cloud-arrow-down { + --fa: "\f0ed"; } + +.fa-cloud-download { + --fa: "\f0ed"; } + +.fa-cloud-download-alt { + --fa: "\f0ed"; } + +.fa-children { + --fa: "\e4e1"; } + +.fa-chalkboard { + --fa: "\f51b"; } + +.fa-blackboard { + --fa: "\f51b"; } + +.fa-user-large-slash { + --fa: "\f4fa"; } + +.fa-user-alt-slash { + --fa: "\f4fa"; } + +.fa-envelope-open { + --fa: "\f2b6"; } + +.fa-handshake-simple-slash { + --fa: "\e05f"; } + +.fa-handshake-alt-slash { + --fa: "\e05f"; } + +.fa-mattress-pillow { + --fa: "\e525"; } + +.fa-guarani-sign { + --fa: "\e19a"; } + +.fa-arrows-rotate { + --fa: "\f021"; } + +.fa-refresh { + --fa: "\f021"; } + +.fa-sync { + --fa: "\f021"; } + +.fa-fire-extinguisher { + --fa: "\f134"; } + +.fa-cruzeiro-sign { + --fa: "\e152"; } + +.fa-greater-than-equal { + --fa: "\f532"; } + +.fa-shield-halved { + --fa: "\f3ed"; } + +.fa-shield-alt { + --fa: "\f3ed"; } + +.fa-book-atlas { + --fa: "\f558"; } + +.fa-atlas { + --fa: "\f558"; } + +.fa-virus { + --fa: "\e074"; } + +.fa-envelope-circle-check { + --fa: "\e4e8"; } + +.fa-layer-group { + --fa: "\f5fd"; } + +.fa-arrows-to-dot { + --fa: "\e4be"; } + +.fa-archway { + --fa: "\f557"; } + +.fa-heart-circle-check { + --fa: "\e4fd"; } + +.fa-house-chimney-crack { + --fa: "\f6f1"; } + +.fa-house-damage { + --fa: "\f6f1"; } + +.fa-file-zipper { + --fa: "\f1c6"; } + +.fa-file-archive { + --fa: "\f1c6"; } + +.fa-square { + --fa: "\f0c8"; } + +.fa-martini-glass-empty { + --fa: "\f000"; } + +.fa-glass-martini { + --fa: "\f000"; } + +.fa-couch { + --fa: "\f4b8"; } + +.fa-cedi-sign { + --fa: "\e0df"; } + +.fa-italic { + --fa: "\f033"; } + +.fa-table-cells-column-lock { + --fa: "\e678"; } + +.fa-church { + --fa: "\f51d"; } + +.fa-comments-dollar { + --fa: "\f653"; } + +.fa-democrat { + --fa: "\f747"; } + +.fa-z { + --fa: "\5a"; } + +.fa-person-skiing { + --fa: "\f7c9"; } + +.fa-skiing { + --fa: "\f7c9"; } + +.fa-road-lock { + --fa: "\e567"; } + +.fa-a { + --fa: "\41"; } + +.fa-temperature-arrow-down { + --fa: "\e03f"; } + +.fa-temperature-down { + --fa: "\e03f"; } + +.fa-feather-pointed { + --fa: "\f56b"; } + +.fa-feather-alt { + --fa: "\f56b"; } + +.fa-p { + --fa: "\50"; } + +.fa-snowflake { + --fa: "\f2dc"; } + +.fa-newspaper { + --fa: "\f1ea"; } + +.fa-rectangle-ad { + --fa: "\f641"; } + +.fa-ad { + --fa: "\f641"; } + +.fa-circle-arrow-right { + --fa: "\f0a9"; } + +.fa-arrow-circle-right { + --fa: "\f0a9"; } + +.fa-filter-circle-xmark { + --fa: "\e17b"; } + +.fa-locust { + --fa: "\e520"; } + +.fa-sort { + --fa: "\f0dc"; } + +.fa-unsorted { + --fa: "\f0dc"; } + +.fa-list-ol { + --fa: "\f0cb"; } + +.fa-list-1-2 { + --fa: "\f0cb"; } + +.fa-list-numeric { + --fa: "\f0cb"; } + +.fa-person-dress-burst { + --fa: "\e544"; } + +.fa-money-check-dollar { + --fa: "\f53d"; } + +.fa-money-check-alt { + --fa: "\f53d"; } + +.fa-vector-square { + --fa: "\f5cb"; } + +.fa-bread-slice { + --fa: "\f7ec"; } + +.fa-language { + --fa: "\f1ab"; } + +.fa-face-kiss-wink-heart { + --fa: "\f598"; } + +.fa-kiss-wink-heart { + --fa: "\f598"; } + +.fa-filter { + --fa: "\f0b0"; } + +.fa-question { + --fa: "\3f"; } + +.fa-file-signature { + --fa: "\f573"; } + +.fa-up-down-left-right { + --fa: "\f0b2"; } + +.fa-arrows-alt { + --fa: "\f0b2"; } + +.fa-house-chimney-user { + --fa: "\e065"; } + +.fa-hand-holding-heart { + --fa: "\f4be"; } + +.fa-puzzle-piece { + --fa: "\f12e"; } + +.fa-money-check { + --fa: "\f53c"; } + +.fa-star-half-stroke { + --fa: "\f5c0"; } + +.fa-star-half-alt { + --fa: "\f5c0"; } + +.fa-code { + --fa: "\f121"; } + +.fa-whiskey-glass { + --fa: "\f7a0"; } + +.fa-glass-whiskey { + --fa: "\f7a0"; } + +.fa-building-circle-exclamation { + --fa: "\e4d3"; } + +.fa-magnifying-glass-chart { + --fa: "\e522"; } + +.fa-arrow-up-right-from-square { + --fa: "\f08e"; } + +.fa-external-link { + --fa: "\f08e"; } + +.fa-cubes-stacked { + --fa: "\e4e6"; } + +.fa-won-sign { + --fa: "\f159"; } + +.fa-krw { + --fa: "\f159"; } + +.fa-won { + --fa: "\f159"; } + +.fa-virus-covid { + --fa: "\e4a8"; } + +.fa-austral-sign { + --fa: "\e0a9"; } + +.fa-f { + --fa: "\46"; } + +.fa-leaf { + --fa: "\f06c"; } + +.fa-road { + --fa: "\f018"; } + +.fa-taxi { + --fa: "\f1ba"; } + +.fa-cab { + --fa: "\f1ba"; } + +.fa-person-circle-plus { + --fa: "\e541"; } + +.fa-chart-pie { + --fa: "\f200"; } + +.fa-pie-chart { + --fa: "\f200"; } + +.fa-bolt-lightning { + --fa: "\e0b7"; } + +.fa-sack-xmark { + --fa: "\e56a"; } + +.fa-file-excel { + --fa: "\f1c3"; } + +.fa-file-contract { + --fa: "\f56c"; } + +.fa-fish-fins { + --fa: "\e4f2"; } + +.fa-building-flag { + --fa: "\e4d5"; } + +.fa-face-grin-beam { + --fa: "\f582"; } + +.fa-grin-beam { + --fa: "\f582"; } + +.fa-object-ungroup { + --fa: "\f248"; } + +.fa-poop { + --fa: "\f619"; } + +.fa-location-pin { + --fa: "\f041"; } + +.fa-map-marker { + --fa: "\f041"; } + +.fa-kaaba { + --fa: "\f66b"; } + +.fa-toilet-paper { + --fa: "\f71e"; } + +.fa-helmet-safety { + --fa: "\f807"; } + +.fa-hard-hat { + --fa: "\f807"; } + +.fa-hat-hard { + --fa: "\f807"; } + +.fa-eject { + --fa: "\f052"; } + +.fa-circle-right { + --fa: "\f35a"; } + +.fa-arrow-alt-circle-right { + --fa: "\f35a"; } + +.fa-plane-circle-check { + --fa: "\e555"; } + +.fa-face-rolling-eyes { + --fa: "\f5a5"; } + +.fa-meh-rolling-eyes { + --fa: "\f5a5"; } + +.fa-object-group { + --fa: "\f247"; } + +.fa-chart-line { + --fa: "\f201"; } + +.fa-line-chart { + --fa: "\f201"; } + +.fa-mask-ventilator { + --fa: "\e524"; } + +.fa-arrow-right { + --fa: "\f061"; } + +.fa-signs-post { + --fa: "\f277"; } + +.fa-map-signs { + --fa: "\f277"; } + +.fa-cash-register { + --fa: "\f788"; } + +.fa-person-circle-question { + --fa: "\e542"; } + +.fa-h { + --fa: "\48"; } + +.fa-tarp { + --fa: "\e57b"; } + +.fa-screwdriver-wrench { + --fa: "\f7d9"; } + +.fa-tools { + --fa: "\f7d9"; } + +.fa-arrows-to-eye { + --fa: "\e4bf"; } + +.fa-plug-circle-bolt { + --fa: "\e55b"; } + +.fa-heart { + --fa: "\f004"; } + +.fa-mars-and-venus { + --fa: "\f224"; } + +.fa-house-user { + --fa: "\e1b0"; } + +.fa-home-user { + --fa: "\e1b0"; } + +.fa-dumpster-fire { + --fa: "\f794"; } + +.fa-house-crack { + --fa: "\e3b1"; } + +.fa-martini-glass-citrus { + --fa: "\f561"; } + +.fa-cocktail { + --fa: "\f561"; } + +.fa-face-surprise { + --fa: "\f5c2"; } + +.fa-surprise { + --fa: "\f5c2"; } + +.fa-bottle-water { + --fa: "\e4c5"; } + +.fa-circle-pause { + --fa: "\f28b"; } + +.fa-pause-circle { + --fa: "\f28b"; } + +.fa-toilet-paper-slash { + --fa: "\e072"; } + +.fa-apple-whole { + --fa: "\f5d1"; } + +.fa-apple-alt { + --fa: "\f5d1"; } + +.fa-kitchen-set { + --fa: "\e51a"; } + +.fa-r { + --fa: "\52"; } + +.fa-temperature-quarter { + --fa: "\f2ca"; } + +.fa-temperature-1 { + --fa: "\f2ca"; } + +.fa-thermometer-1 { + --fa: "\f2ca"; } + +.fa-thermometer-quarter { + --fa: "\f2ca"; } + +.fa-cube { + --fa: "\f1b2"; } + +.fa-bitcoin-sign { + --fa: "\e0b4"; } + +.fa-shield-dog { + --fa: "\e573"; } + +.fa-solar-panel { + --fa: "\f5ba"; } + +.fa-lock-open { + --fa: "\f3c1"; } + +.fa-elevator { + --fa: "\e16d"; } + +.fa-money-bill-transfer { + --fa: "\e528"; } + +.fa-money-bill-trend-up { + --fa: "\e529"; } + +.fa-house-flood-water-circle-arrow-right { + --fa: "\e50f"; } + +.fa-square-poll-horizontal { + --fa: "\f682"; } + +.fa-poll-h { + --fa: "\f682"; } + +.fa-circle { + --fa: "\f111"; } + +.fa-backward-fast { + --fa: "\f049"; } + +.fa-fast-backward { + --fa: "\f049"; } + +.fa-recycle { + --fa: "\f1b8"; } + +.fa-user-astronaut { + --fa: "\f4fb"; } + +.fa-plane-slash { + --fa: "\e069"; } + +.fa-trademark { + --fa: "\f25c"; } + +.fa-basketball { + --fa: "\f434"; } + +.fa-basketball-ball { + --fa: "\f434"; } + +.fa-satellite-dish { + --fa: "\f7c0"; } + +.fa-circle-up { + --fa: "\f35b"; } + +.fa-arrow-alt-circle-up { + --fa: "\f35b"; } + +.fa-mobile-screen-button { + --fa: "\f3cd"; } + +.fa-mobile-alt { + --fa: "\f3cd"; } + +.fa-volume-high { + --fa: "\f028"; } + +.fa-volume-up { + --fa: "\f028"; } + +.fa-users-rays { + --fa: "\e593"; } + +.fa-wallet { + --fa: "\f555"; } + +.fa-clipboard-check { + --fa: "\f46c"; } + +.fa-file-audio { + --fa: "\f1c7"; } + +.fa-burger { + --fa: "\f805"; } + +.fa-hamburger { + --fa: "\f805"; } + +.fa-wrench { + --fa: "\f0ad"; } + +.fa-bugs { + --fa: "\e4d0"; } + +.fa-rupee-sign { + --fa: "\f156"; } + +.fa-rupee { + --fa: "\f156"; } + +.fa-file-image { + --fa: "\f1c5"; } + +.fa-circle-question { + --fa: "\f059"; } + +.fa-question-circle { + --fa: "\f059"; } + +.fa-plane-departure { + --fa: "\f5b0"; } + +.fa-handshake-slash { + --fa: "\e060"; } + +.fa-book-bookmark { + --fa: "\e0bb"; } + +.fa-code-branch { + --fa: "\f126"; } + +.fa-hat-cowboy { + --fa: "\f8c0"; } + +.fa-bridge { + --fa: "\e4c8"; } + +.fa-phone-flip { + --fa: "\f879"; } + +.fa-phone-alt { + --fa: "\f879"; } + +.fa-truck-front { + --fa: "\e2b7"; } + +.fa-cat { + --fa: "\f6be"; } + +.fa-anchor-circle-exclamation { + --fa: "\e4ab"; } + +.fa-truck-field { + --fa: "\e58d"; } + +.fa-route { + --fa: "\f4d7"; } + +.fa-clipboard-question { + --fa: "\e4e3"; } + +.fa-panorama { + --fa: "\e209"; } + +.fa-comment-medical { + --fa: "\f7f5"; } + +.fa-teeth-open { + --fa: "\f62f"; } + +.fa-file-circle-minus { + --fa: "\e4ed"; } + +.fa-tags { + --fa: "\f02c"; } + +.fa-wine-glass { + --fa: "\f4e3"; } + +.fa-forward-fast { + --fa: "\f050"; } + +.fa-fast-forward { + --fa: "\f050"; } + +.fa-face-meh-blank { + --fa: "\f5a4"; } + +.fa-meh-blank { + --fa: "\f5a4"; } + +.fa-square-parking { + --fa: "\f540"; } + +.fa-parking { + --fa: "\f540"; } + +.fa-house-signal { + --fa: "\e012"; } + +.fa-bars-progress { + --fa: "\f828"; } + +.fa-tasks-alt { + --fa: "\f828"; } + +.fa-faucet-drip { + --fa: "\e006"; } + +.fa-cart-flatbed { + --fa: "\f474"; } + +.fa-dolly-flatbed { + --fa: "\f474"; } + +.fa-ban-smoking { + --fa: "\f54d"; } + +.fa-smoking-ban { + --fa: "\f54d"; } + +.fa-terminal { + --fa: "\f120"; } + +.fa-mobile-button { + --fa: "\f10b"; } + +.fa-house-medical-flag { + --fa: "\e514"; } + +.fa-basket-shopping { + --fa: "\f291"; } + +.fa-shopping-basket { + --fa: "\f291"; } + +.fa-tape { + --fa: "\f4db"; } + +.fa-bus-simple { + --fa: "\f55e"; } + +.fa-bus-alt { + --fa: "\f55e"; } + +.fa-eye { + --fa: "\f06e"; } + +.fa-face-sad-cry { + --fa: "\f5b3"; } + +.fa-sad-cry { + --fa: "\f5b3"; } + +.fa-audio-description { + --fa: "\f29e"; } + +.fa-person-military-to-person { + --fa: "\e54c"; } + +.fa-file-shield { + --fa: "\e4f0"; } + +.fa-user-slash { + --fa: "\f506"; } + +.fa-pen { + --fa: "\f304"; } + +.fa-tower-observation { + --fa: "\e586"; } + +.fa-file-code { + --fa: "\f1c9"; } + +.fa-signal { + --fa: "\f012"; } + +.fa-signal-5 { + --fa: "\f012"; } + +.fa-signal-perfect { + --fa: "\f012"; } + +.fa-bus { + --fa: "\f207"; } + +.fa-heart-circle-xmark { + --fa: "\e501"; } + +.fa-house-chimney { + --fa: "\e3af"; } + +.fa-home-lg { + --fa: "\e3af"; } + +.fa-window-maximize { + --fa: "\f2d0"; } + +.fa-face-frown { + --fa: "\f119"; } + +.fa-frown { + --fa: "\f119"; } + +.fa-prescription { + --fa: "\f5b1"; } + +.fa-shop { + --fa: "\f54f"; } + +.fa-store-alt { + --fa: "\f54f"; } + +.fa-floppy-disk { + --fa: "\f0c7"; } + +.fa-save { + --fa: "\f0c7"; } + +.fa-vihara { + --fa: "\f6a7"; } + +.fa-scale-unbalanced { + --fa: "\f515"; } + +.fa-balance-scale-left { + --fa: "\f515"; } + +.fa-sort-up { + --fa: "\f0de"; } + +.fa-sort-asc { + --fa: "\f0de"; } + +.fa-comment-dots { + --fa: "\f4ad"; } + +.fa-commenting { + --fa: "\f4ad"; } + +.fa-plant-wilt { + --fa: "\e5aa"; } + +.fa-diamond { + --fa: "\f219"; } + +.fa-face-grin-squint { + --fa: "\f585"; } + +.fa-grin-squint { + --fa: "\f585"; } + +.fa-hand-holding-dollar { + --fa: "\f4c0"; } + +.fa-hand-holding-usd { + --fa: "\f4c0"; } + +.fa-chart-diagram { + --fa: "\e695"; } + +.fa-bacterium { + --fa: "\e05a"; } + +.fa-hand-pointer { + --fa: "\f25a"; } + +.fa-drum-steelpan { + --fa: "\f56a"; } + +.fa-hand-scissors { + --fa: "\f257"; } + +.fa-hands-praying { + --fa: "\f684"; } + +.fa-praying-hands { + --fa: "\f684"; } + +.fa-arrow-rotate-right { + --fa: "\f01e"; } + +.fa-arrow-right-rotate { + --fa: "\f01e"; } + +.fa-arrow-rotate-forward { + --fa: "\f01e"; } + +.fa-redo { + --fa: "\f01e"; } + +.fa-biohazard { + --fa: "\f780"; } + +.fa-location-crosshairs { + --fa: "\f601"; } + +.fa-location { + --fa: "\f601"; } + +.fa-mars-double { + --fa: "\f227"; } + +.fa-child-dress { + --fa: "\e59c"; } + +.fa-users-between-lines { + --fa: "\e591"; } + +.fa-lungs-virus { + --fa: "\e067"; } + +.fa-face-grin-tears { + --fa: "\f588"; } + +.fa-grin-tears { + --fa: "\f588"; } + +.fa-phone { + --fa: "\f095"; } + +.fa-calendar-xmark { + --fa: "\f273"; } + +.fa-calendar-times { + --fa: "\f273"; } + +.fa-child-reaching { + --fa: "\e59d"; } + +.fa-head-side-virus { + --fa: "\e064"; } + +.fa-user-gear { + --fa: "\f4fe"; } + +.fa-user-cog { + --fa: "\f4fe"; } + +.fa-arrow-up-1-9 { + --fa: "\f163"; } + +.fa-sort-numeric-up { + --fa: "\f163"; } + +.fa-door-closed { + --fa: "\f52a"; } + +.fa-shield-virus { + --fa: "\e06c"; } + +.fa-dice-six { + --fa: "\f526"; } + +.fa-mosquito-net { + --fa: "\e52c"; } + +.fa-file-fragment { + --fa: "\e697"; } + +.fa-bridge-water { + --fa: "\e4ce"; } + +.fa-person-booth { + --fa: "\f756"; } + +.fa-text-width { + --fa: "\f035"; } + +.fa-hat-wizard { + --fa: "\f6e8"; } + +.fa-pen-fancy { + --fa: "\f5ac"; } + +.fa-person-digging { + --fa: "\f85e"; } + +.fa-digging { + --fa: "\f85e"; } + +.fa-trash { + --fa: "\f1f8"; } + +.fa-gauge-simple { + --fa: "\f629"; } + +.fa-gauge-simple-med { + --fa: "\f629"; } + +.fa-tachometer-average { + --fa: "\f629"; } + +.fa-book-medical { + --fa: "\f7e6"; } + +.fa-poo { + --fa: "\f2fe"; } + +.fa-quote-right { + --fa: "\f10e"; } + +.fa-quote-right-alt { + --fa: "\f10e"; } + +.fa-shirt { + --fa: "\f553"; } + +.fa-t-shirt { + --fa: "\f553"; } + +.fa-tshirt { + --fa: "\f553"; } + +.fa-cubes { + --fa: "\f1b3"; } + +.fa-divide { + --fa: "\f529"; } + +.fa-tenge-sign { + --fa: "\f7d7"; } + +.fa-tenge { + --fa: "\f7d7"; } + +.fa-headphones { + --fa: "\f025"; } + +.fa-hands-holding { + --fa: "\f4c2"; } + +.fa-hands-clapping { + --fa: "\e1a8"; } + +.fa-republican { + --fa: "\f75e"; } + +.fa-arrow-left { + --fa: "\f060"; } + +.fa-person-circle-xmark { + --fa: "\e543"; } + +.fa-ruler { + --fa: "\f545"; } + +.fa-align-left { + --fa: "\f036"; } + +.fa-dice-d6 { + --fa: "\f6d1"; } + +.fa-restroom { + --fa: "\f7bd"; } + +.fa-j { + --fa: "\4a"; } + +.fa-users-viewfinder { + --fa: "\e595"; } + +.fa-file-video { + --fa: "\f1c8"; } + +.fa-up-right-from-square { + --fa: "\f35d"; } + +.fa-external-link-alt { + --fa: "\f35d"; } + +.fa-table-cells { + --fa: "\f00a"; } + +.fa-th { + --fa: "\f00a"; } + +.fa-file-pdf { + --fa: "\f1c1"; } + +.fa-book-bible { + --fa: "\f647"; } + +.fa-bible { + --fa: "\f647"; } + +.fa-o { + --fa: "\4f"; } + +.fa-suitcase-medical { + --fa: "\f0fa"; } + +.fa-medkit { + --fa: "\f0fa"; } + +.fa-user-secret { + --fa: "\f21b"; } + +.fa-otter { + --fa: "\f700"; } + +.fa-person-dress { + --fa: "\f182"; } + +.fa-female { + --fa: "\f182"; } + +.fa-comment-dollar { + --fa: "\f651"; } + +.fa-business-time { + --fa: "\f64a"; } + +.fa-briefcase-clock { + --fa: "\f64a"; } + +.fa-table-cells-large { + --fa: "\f009"; } + +.fa-th-large { + --fa: "\f009"; } + +.fa-book-tanakh { + --fa: "\f827"; } + +.fa-tanakh { + --fa: "\f827"; } + +.fa-phone-volume { + --fa: "\f2a0"; } + +.fa-volume-control-phone { + --fa: "\f2a0"; } + +.fa-hat-cowboy-side { + --fa: "\f8c1"; } + +.fa-clipboard-user { + --fa: "\f7f3"; } + +.fa-child { + --fa: "\f1ae"; } + +.fa-lira-sign { + --fa: "\f195"; } + +.fa-satellite { + --fa: "\f7bf"; } + +.fa-plane-lock { + --fa: "\e558"; } + +.fa-tag { + --fa: "\f02b"; } + +.fa-comment { + --fa: "\f075"; } + +.fa-cake-candles { + --fa: "\f1fd"; } + +.fa-birthday-cake { + --fa: "\f1fd"; } + +.fa-cake { + --fa: "\f1fd"; } + +.fa-envelope { + --fa: "\f0e0"; } + +.fa-angles-up { + --fa: "\f102"; } + +.fa-angle-double-up { + --fa: "\f102"; } + +.fa-paperclip { + --fa: "\f0c6"; } + +.fa-arrow-right-to-city { + --fa: "\e4b3"; } + +.fa-ribbon { + --fa: "\f4d6"; } + +.fa-lungs { + --fa: "\f604"; } + +.fa-arrow-up-9-1 { + --fa: "\f887"; } + +.fa-sort-numeric-up-alt { + --fa: "\f887"; } + +.fa-litecoin-sign { + --fa: "\e1d3"; } + +.fa-border-none { + --fa: "\f850"; } + +.fa-circle-nodes { + --fa: "\e4e2"; } + +.fa-parachute-box { + --fa: "\f4cd"; } + +.fa-indent { + --fa: "\f03c"; } + +.fa-truck-field-un { + --fa: "\e58e"; } + +.fa-hourglass { + --fa: "\f254"; } + +.fa-hourglass-empty { + --fa: "\f254"; } + +.fa-mountain { + --fa: "\f6fc"; } + +.fa-user-doctor { + --fa: "\f0f0"; } + +.fa-user-md { + --fa: "\f0f0"; } + +.fa-circle-info { + --fa: "\f05a"; } + +.fa-info-circle { + --fa: "\f05a"; } + +.fa-cloud-meatball { + --fa: "\f73b"; } + +.fa-camera { + --fa: "\f030"; } + +.fa-camera-alt { + --fa: "\f030"; } + +.fa-square-virus { + --fa: "\e578"; } + +.fa-meteor { + --fa: "\f753"; } + +.fa-car-on { + --fa: "\e4dd"; } + +.fa-sleigh { + --fa: "\f7cc"; } + +.fa-arrow-down-1-9 { + --fa: "\f162"; } + +.fa-sort-numeric-asc { + --fa: "\f162"; } + +.fa-sort-numeric-down { + --fa: "\f162"; } + +.fa-hand-holding-droplet { + --fa: "\f4c1"; } + +.fa-hand-holding-water { + --fa: "\f4c1"; } + +.fa-water { + --fa: "\f773"; } + +.fa-calendar-check { + --fa: "\f274"; } + +.fa-braille { + --fa: "\f2a1"; } + +.fa-prescription-bottle-medical { + --fa: "\f486"; } + +.fa-prescription-bottle-alt { + --fa: "\f486"; } + +.fa-landmark { + --fa: "\f66f"; } + +.fa-truck { + --fa: "\f0d1"; } + +.fa-crosshairs { + --fa: "\f05b"; } + +.fa-person-cane { + --fa: "\e53c"; } + +.fa-tent { + --fa: "\e57d"; } + +.fa-vest-patches { + --fa: "\e086"; } + +.fa-check-double { + --fa: "\f560"; } + +.fa-arrow-down-a-z { + --fa: "\f15d"; } + +.fa-sort-alpha-asc { + --fa: "\f15d"; } + +.fa-sort-alpha-down { + --fa: "\f15d"; } + +.fa-money-bill-wheat { + --fa: "\e52a"; } + +.fa-cookie { + --fa: "\f563"; } + +.fa-arrow-rotate-left { + --fa: "\f0e2"; } + +.fa-arrow-left-rotate { + --fa: "\f0e2"; } + +.fa-arrow-rotate-back { + --fa: "\f0e2"; } + +.fa-arrow-rotate-backward { + --fa: "\f0e2"; } + +.fa-undo { + --fa: "\f0e2"; } + +.fa-hard-drive { + --fa: "\f0a0"; } + +.fa-hdd { + --fa: "\f0a0"; } + +.fa-face-grin-squint-tears { + --fa: "\f586"; } + +.fa-grin-squint-tears { + --fa: "\f586"; } + +.fa-dumbbell { + --fa: "\f44b"; } + +.fa-rectangle-list { + --fa: "\f022"; } + +.fa-list-alt { + --fa: "\f022"; } + +.fa-tarp-droplet { + --fa: "\e57c"; } + +.fa-house-medical-circle-check { + --fa: "\e511"; } + +.fa-person-skiing-nordic { + --fa: "\f7ca"; } + +.fa-skiing-nordic { + --fa: "\f7ca"; } + +.fa-calendar-plus { + --fa: "\f271"; } + +.fa-plane-arrival { + --fa: "\f5af"; } + +.fa-circle-left { + --fa: "\f359"; } + +.fa-arrow-alt-circle-left { + --fa: "\f359"; } + +.fa-train-subway { + --fa: "\f239"; } + +.fa-subway { + --fa: "\f239"; } + +.fa-chart-gantt { + --fa: "\e0e4"; } + +.fa-indian-rupee-sign { + --fa: "\e1bc"; } + +.fa-indian-rupee { + --fa: "\e1bc"; } + +.fa-inr { + --fa: "\e1bc"; } + +.fa-crop-simple { + --fa: "\f565"; } + +.fa-crop-alt { + --fa: "\f565"; } + +.fa-money-bill-1 { + --fa: "\f3d1"; } + +.fa-money-bill-alt { + --fa: "\f3d1"; } + +.fa-left-long { + --fa: "\f30a"; } + +.fa-long-arrow-alt-left { + --fa: "\f30a"; } + +.fa-dna { + --fa: "\f471"; } + +.fa-virus-slash { + --fa: "\e075"; } + +.fa-minus { + --fa: "\f068"; } + +.fa-subtract { + --fa: "\f068"; } + +.fa-chess { + --fa: "\f439"; } + +.fa-arrow-left-long { + --fa: "\f177"; } + +.fa-long-arrow-left { + --fa: "\f177"; } + +.fa-plug-circle-check { + --fa: "\e55c"; } + +.fa-street-view { + --fa: "\f21d"; } + +.fa-franc-sign { + --fa: "\e18f"; } + +.fa-volume-off { + --fa: "\f026"; } + +.fa-hands-asl-interpreting { + --fa: "\f2a3"; } + +.fa-american-sign-language-interpreting { + --fa: "\f2a3"; } + +.fa-asl-interpreting { + --fa: "\f2a3"; } + +.fa-hands-american-sign-language-interpreting { + --fa: "\f2a3"; } + +.fa-gear { + --fa: "\f013"; } + +.fa-cog { + --fa: "\f013"; } + +.fa-droplet-slash { + --fa: "\f5c7"; } + +.fa-tint-slash { + --fa: "\f5c7"; } + +.fa-mosque { + --fa: "\f678"; } + +.fa-mosquito { + --fa: "\e52b"; } + +.fa-star-of-david { + --fa: "\f69a"; } + +.fa-person-military-rifle { + --fa: "\e54b"; } + +.fa-cart-shopping { + --fa: "\f07a"; } + +.fa-shopping-cart { + --fa: "\f07a"; } + +.fa-vials { + --fa: "\f493"; } + +.fa-plug-circle-plus { + --fa: "\e55f"; } + +.fa-place-of-worship { + --fa: "\f67f"; } + +.fa-grip-vertical { + --fa: "\f58e"; } + +.fa-hexagon-nodes { + --fa: "\e699"; } + +.fa-arrow-turn-up { + --fa: "\f148"; } + +.fa-level-up { + --fa: "\f148"; } + +.fa-u { + --fa: "\55"; } + +.fa-square-root-variable { + --fa: "\f698"; } + +.fa-square-root-alt { + --fa: "\f698"; } + +.fa-clock { + --fa: "\f017"; } + +.fa-clock-four { + --fa: "\f017"; } + +.fa-backward-step { + --fa: "\f048"; } + +.fa-step-backward { + --fa: "\f048"; } + +.fa-pallet { + --fa: "\f482"; } + +.fa-faucet { + --fa: "\e005"; } + +.fa-baseball-bat-ball { + --fa: "\f432"; } + +.fa-s { + --fa: "\53"; } + +.fa-timeline { + --fa: "\e29c"; } + +.fa-keyboard { + --fa: "\f11c"; } + +.fa-caret-down { + --fa: "\f0d7"; } + +.fa-house-chimney-medical { + --fa: "\f7f2"; } + +.fa-clinic-medical { + --fa: "\f7f2"; } + +.fa-temperature-three-quarters { + --fa: "\f2c8"; } + +.fa-temperature-3 { + --fa: "\f2c8"; } + +.fa-thermometer-3 { + --fa: "\f2c8"; } + +.fa-thermometer-three-quarters { + --fa: "\f2c8"; } + +.fa-mobile-screen { + --fa: "\f3cf"; } + +.fa-mobile-android-alt { + --fa: "\f3cf"; } + +.fa-plane-up { + --fa: "\e22d"; } + +.fa-piggy-bank { + --fa: "\f4d3"; } + +.fa-battery-half { + --fa: "\f242"; } + +.fa-battery-3 { + --fa: "\f242"; } + +.fa-mountain-city { + --fa: "\e52e"; } + +.fa-coins { + --fa: "\f51e"; } + +.fa-khanda { + --fa: "\f66d"; } + +.fa-sliders { + --fa: "\f1de"; } + +.fa-sliders-h { + --fa: "\f1de"; } + +.fa-folder-tree { + --fa: "\f802"; } + +.fa-network-wired { + --fa: "\f6ff"; } + +.fa-map-pin { + --fa: "\f276"; } + +.fa-hamsa { + --fa: "\f665"; } + +.fa-cent-sign { + --fa: "\e3f5"; } + +.fa-flask { + --fa: "\f0c3"; } + +.fa-person-pregnant { + --fa: "\e31e"; } + +.fa-wand-sparkles { + --fa: "\f72b"; } + +.fa-ellipsis-vertical { + --fa: "\f142"; } + +.fa-ellipsis-v { + --fa: "\f142"; } + +.fa-ticket { + --fa: "\f145"; } + +.fa-power-off { + --fa: "\f011"; } + +.fa-right-long { + --fa: "\f30b"; } + +.fa-long-arrow-alt-right { + --fa: "\f30b"; } + +.fa-flag-usa { + --fa: "\f74d"; } + +.fa-laptop-file { + --fa: "\e51d"; } + +.fa-tty { + --fa: "\f1e4"; } + +.fa-teletype { + --fa: "\f1e4"; } + +.fa-diagram-next { + --fa: "\e476"; } + +.fa-person-rifle { + --fa: "\e54e"; } + +.fa-house-medical-circle-exclamation { + --fa: "\e512"; } + +.fa-closed-captioning { + --fa: "\f20a"; } + +.fa-person-hiking { + --fa: "\f6ec"; } + +.fa-hiking { + --fa: "\f6ec"; } + +.fa-venus-double { + --fa: "\f226"; } + +.fa-images { + --fa: "\f302"; } + +.fa-calculator { + --fa: "\f1ec"; } + +.fa-people-pulling { + --fa: "\e535"; } + +.fa-n { + --fa: "\4e"; } + +.fa-cable-car { + --fa: "\f7da"; } + +.fa-tram { + --fa: "\f7da"; } + +.fa-cloud-rain { + --fa: "\f73d"; } + +.fa-building-circle-xmark { + --fa: "\e4d4"; } + +.fa-ship { + --fa: "\f21a"; } + +.fa-arrows-down-to-line { + --fa: "\e4b8"; } + +.fa-download { + --fa: "\f019"; } + +.fa-face-grin { + --fa: "\f580"; } + +.fa-grin { + --fa: "\f580"; } + +.fa-delete-left { + --fa: "\f55a"; } + +.fa-backspace { + --fa: "\f55a"; } + +.fa-eye-dropper { + --fa: "\f1fb"; } + +.fa-eye-dropper-empty { + --fa: "\f1fb"; } + +.fa-eyedropper { + --fa: "\f1fb"; } + +.fa-file-circle-check { + --fa: "\e5a0"; } + +.fa-forward { + --fa: "\f04e"; } + +.fa-mobile { + --fa: "\f3ce"; } + +.fa-mobile-android { + --fa: "\f3ce"; } + +.fa-mobile-phone { + --fa: "\f3ce"; } + +.fa-face-meh { + --fa: "\f11a"; } + +.fa-meh { + --fa: "\f11a"; } + +.fa-align-center { + --fa: "\f037"; } + +.fa-book-skull { + --fa: "\f6b7"; } + +.fa-book-dead { + --fa: "\f6b7"; } + +.fa-id-card { + --fa: "\f2c2"; } + +.fa-drivers-license { + --fa: "\f2c2"; } + +.fa-outdent { + --fa: "\f03b"; } + +.fa-dedent { + --fa: "\f03b"; } + +.fa-heart-circle-exclamation { + --fa: "\e4fe"; } + +.fa-house { + --fa: "\f015"; } + +.fa-home { + --fa: "\f015"; } + +.fa-home-alt { + --fa: "\f015"; } + +.fa-home-lg-alt { + --fa: "\f015"; } + +.fa-calendar-week { + --fa: "\f784"; } + +.fa-laptop-medical { + --fa: "\f812"; } + +.fa-b { + --fa: "\42"; } + +.fa-file-medical { + --fa: "\f477"; } + +.fa-dice-one { + --fa: "\f525"; } + +.fa-kiwi-bird { + --fa: "\f535"; } + +.fa-arrow-right-arrow-left { + --fa: "\f0ec"; } + +.fa-exchange { + --fa: "\f0ec"; } + +.fa-rotate-right { + --fa: "\f2f9"; } + +.fa-redo-alt { + --fa: "\f2f9"; } + +.fa-rotate-forward { + --fa: "\f2f9"; } + +.fa-utensils { + --fa: "\f2e7"; } + +.fa-cutlery { + --fa: "\f2e7"; } + +.fa-arrow-up-wide-short { + --fa: "\f161"; } + +.fa-sort-amount-up { + --fa: "\f161"; } + +.fa-mill-sign { + --fa: "\e1ed"; } + +.fa-bowl-rice { + --fa: "\e2eb"; } + +.fa-skull { + --fa: "\f54c"; } + +.fa-tower-broadcast { + --fa: "\f519"; } + +.fa-broadcast-tower { + --fa: "\f519"; } + +.fa-truck-pickup { + --fa: "\f63c"; } + +.fa-up-long { + --fa: "\f30c"; } + +.fa-long-arrow-alt-up { + --fa: "\f30c"; } + +.fa-stop { + --fa: "\f04d"; } + +.fa-code-merge { + --fa: "\f387"; } + +.fa-upload { + --fa: "\f093"; } + +.fa-hurricane { + --fa: "\f751"; } + +.fa-mound { + --fa: "\e52d"; } + +.fa-toilet-portable { + --fa: "\e583"; } + +.fa-compact-disc { + --fa: "\f51f"; } + +.fa-file-arrow-down { + --fa: "\f56d"; } + +.fa-file-download { + --fa: "\f56d"; } + +.fa-caravan { + --fa: "\f8ff"; } + +.fa-shield-cat { + --fa: "\e572"; } + +.fa-bolt { + --fa: "\f0e7"; } + +.fa-zap { + --fa: "\f0e7"; } + +.fa-glass-water { + --fa: "\e4f4"; } + +.fa-oil-well { + --fa: "\e532"; } + +.fa-vault { + --fa: "\e2c5"; } + +.fa-mars { + --fa: "\f222"; } + +.fa-toilet { + --fa: "\f7d8"; } + +.fa-plane-circle-xmark { + --fa: "\e557"; } + +.fa-yen-sign { + --fa: "\f157"; } + +.fa-cny { + --fa: "\f157"; } + +.fa-jpy { + --fa: "\f157"; } + +.fa-rmb { + --fa: "\f157"; } + +.fa-yen { + --fa: "\f157"; } + +.fa-ruble-sign { + --fa: "\f158"; } + +.fa-rouble { + --fa: "\f158"; } + +.fa-rub { + --fa: "\f158"; } + +.fa-ruble { + --fa: "\f158"; } + +.fa-sun { + --fa: "\f185"; } + +.fa-guitar { + --fa: "\f7a6"; } + +.fa-face-laugh-wink { + --fa: "\f59c"; } + +.fa-laugh-wink { + --fa: "\f59c"; } + +.fa-horse-head { + --fa: "\f7ab"; } + +.fa-bore-hole { + --fa: "\e4c3"; } + +.fa-industry { + --fa: "\f275"; } + +.fa-circle-down { + --fa: "\f358"; } + +.fa-arrow-alt-circle-down { + --fa: "\f358"; } + +.fa-arrows-turn-to-dots { + --fa: "\e4c1"; } + +.fa-florin-sign { + --fa: "\e184"; } + +.fa-arrow-down-short-wide { + --fa: "\f884"; } + +.fa-sort-amount-desc { + --fa: "\f884"; } + +.fa-sort-amount-down-alt { + --fa: "\f884"; } + +.fa-less-than { + --fa: "\3c"; } + +.fa-angle-down { + --fa: "\f107"; } + +.fa-car-tunnel { + --fa: "\e4de"; } + +.fa-head-side-cough { + --fa: "\e061"; } + +.fa-grip-lines { + --fa: "\f7a4"; } + +.fa-thumbs-down { + --fa: "\f165"; } + +.fa-user-lock { + --fa: "\f502"; } + +.fa-arrow-right-long { + --fa: "\f178"; } + +.fa-long-arrow-right { + --fa: "\f178"; } + +.fa-anchor-circle-xmark { + --fa: "\e4ac"; } + +.fa-ellipsis { + --fa: "\f141"; } + +.fa-ellipsis-h { + --fa: "\f141"; } + +.fa-chess-pawn { + --fa: "\f443"; } + +.fa-kit-medical { + --fa: "\f479"; } + +.fa-first-aid { + --fa: "\f479"; } + +.fa-person-through-window { + --fa: "\e5a9"; } + +.fa-toolbox { + --fa: "\f552"; } + +.fa-hands-holding-circle { + --fa: "\e4fb"; } + +.fa-bug { + --fa: "\f188"; } + +.fa-credit-card { + --fa: "\f09d"; } + +.fa-credit-card-alt { + --fa: "\f09d"; } + +.fa-car { + --fa: "\f1b9"; } + +.fa-automobile { + --fa: "\f1b9"; } + +.fa-hand-holding-hand { + --fa: "\e4f7"; } + +.fa-book-open-reader { + --fa: "\f5da"; } + +.fa-book-reader { + --fa: "\f5da"; } + +.fa-mountain-sun { + --fa: "\e52f"; } + +.fa-arrows-left-right-to-line { + --fa: "\e4ba"; } + +.fa-dice-d20 { + --fa: "\f6cf"; } + +.fa-truck-droplet { + --fa: "\e58c"; } + +.fa-file-circle-xmark { + --fa: "\e5a1"; } + +.fa-temperature-arrow-up { + --fa: "\e040"; } + +.fa-temperature-up { + --fa: "\e040"; } + +.fa-medal { + --fa: "\f5a2"; } + +.fa-bed { + --fa: "\f236"; } + +.fa-square-h { + --fa: "\f0fd"; } + +.fa-h-square { + --fa: "\f0fd"; } + +.fa-podcast { + --fa: "\f2ce"; } + +.fa-temperature-full { + --fa: "\f2c7"; } + +.fa-temperature-4 { + --fa: "\f2c7"; } + +.fa-thermometer-4 { + --fa: "\f2c7"; } + +.fa-thermometer-full { + --fa: "\f2c7"; } + +.fa-bell { + --fa: "\f0f3"; } + +.fa-superscript { + --fa: "\f12b"; } + +.fa-plug-circle-xmark { + --fa: "\e560"; } + +.fa-star-of-life { + --fa: "\f621"; } + +.fa-phone-slash { + --fa: "\f3dd"; } + +.fa-paint-roller { + --fa: "\f5aa"; } + +.fa-handshake-angle { + --fa: "\f4c4"; } + +.fa-hands-helping { + --fa: "\f4c4"; } + +.fa-location-dot { + --fa: "\f3c5"; } + +.fa-map-marker-alt { + --fa: "\f3c5"; } + +.fa-file { + --fa: "\f15b"; } + +.fa-greater-than { + --fa: "\3e"; } + +.fa-person-swimming { + --fa: "\f5c4"; } + +.fa-swimmer { + --fa: "\f5c4"; } + +.fa-arrow-down { + --fa: "\f063"; } + +.fa-droplet { + --fa: "\f043"; } + +.fa-tint { + --fa: "\f043"; } + +.fa-eraser { + --fa: "\f12d"; } + +.fa-earth-americas { + --fa: "\f57d"; } + +.fa-earth { + --fa: "\f57d"; } + +.fa-earth-america { + --fa: "\f57d"; } + +.fa-globe-americas { + --fa: "\f57d"; } + +.fa-person-burst { + --fa: "\e53b"; } + +.fa-dove { + --fa: "\f4ba"; } + +.fa-battery-empty { + --fa: "\f244"; } + +.fa-battery-0 { + --fa: "\f244"; } + +.fa-socks { + --fa: "\f696"; } + +.fa-inbox { + --fa: "\f01c"; } + +.fa-section { + --fa: "\e447"; } + +.fa-gauge-high { + --fa: "\f625"; } + +.fa-tachometer-alt { + --fa: "\f625"; } + +.fa-tachometer-alt-fast { + --fa: "\f625"; } + +.fa-envelope-open-text { + --fa: "\f658"; } + +.fa-hospital { + --fa: "\f0f8"; } + +.fa-hospital-alt { + --fa: "\f0f8"; } + +.fa-hospital-wide { + --fa: "\f0f8"; } + +.fa-wine-bottle { + --fa: "\f72f"; } + +.fa-chess-rook { + --fa: "\f447"; } + +.fa-bars-staggered { + --fa: "\f550"; } + +.fa-reorder { + --fa: "\f550"; } + +.fa-stream { + --fa: "\f550"; } + +.fa-dharmachakra { + --fa: "\f655"; } + +.fa-hotdog { + --fa: "\f80f"; } + +.fa-person-walking-with-cane { + --fa: "\f29d"; } + +.fa-blind { + --fa: "\f29d"; } + +.fa-drum { + --fa: "\f569"; } + +.fa-ice-cream { + --fa: "\f810"; } + +.fa-heart-circle-bolt { + --fa: "\e4fc"; } + +.fa-fax { + --fa: "\f1ac"; } + +.fa-paragraph { + --fa: "\f1dd"; } + +.fa-check-to-slot { + --fa: "\f772"; } + +.fa-vote-yea { + --fa: "\f772"; } + +.fa-star-half { + --fa: "\f089"; } + +.fa-boxes-stacked { + --fa: "\f468"; } + +.fa-boxes { + --fa: "\f468"; } + +.fa-boxes-alt { + --fa: "\f468"; } + +.fa-link { + --fa: "\f0c1"; } + +.fa-chain { + --fa: "\f0c1"; } + +.fa-ear-listen { + --fa: "\f2a2"; } + +.fa-assistive-listening-systems { + --fa: "\f2a2"; } + +.fa-tree-city { + --fa: "\e587"; } + +.fa-play { + --fa: "\f04b"; } + +.fa-font { + --fa: "\f031"; } + +.fa-table-cells-row-lock { + --fa: "\e67a"; } + +.fa-rupiah-sign { + --fa: "\e23d"; } + +.fa-magnifying-glass { + --fa: "\f002"; } + +.fa-search { + --fa: "\f002"; } + +.fa-table-tennis-paddle-ball { + --fa: "\f45d"; } + +.fa-ping-pong-paddle-ball { + --fa: "\f45d"; } + +.fa-table-tennis { + --fa: "\f45d"; } + +.fa-person-dots-from-line { + --fa: "\f470"; } + +.fa-diagnoses { + --fa: "\f470"; } + +.fa-trash-can-arrow-up { + --fa: "\f82a"; } + +.fa-trash-restore-alt { + --fa: "\f82a"; } + +.fa-naira-sign { + --fa: "\e1f6"; } + +.fa-cart-arrow-down { + --fa: "\f218"; } + +.fa-walkie-talkie { + --fa: "\f8ef"; } + +.fa-file-pen { + --fa: "\f31c"; } + +.fa-file-edit { + --fa: "\f31c"; } + +.fa-receipt { + --fa: "\f543"; } + +.fa-square-pen { + --fa: "\f14b"; } + +.fa-pen-square { + --fa: "\f14b"; } + +.fa-pencil-square { + --fa: "\f14b"; } + +.fa-suitcase-rolling { + --fa: "\f5c1"; } + +.fa-person-circle-exclamation { + --fa: "\e53f"; } + +.fa-chevron-down { + --fa: "\f078"; } + +.fa-battery-full { + --fa: "\f240"; } + +.fa-battery { + --fa: "\f240"; } + +.fa-battery-5 { + --fa: "\f240"; } + +.fa-skull-crossbones { + --fa: "\f714"; } + +.fa-code-compare { + --fa: "\e13a"; } + +.fa-list-ul { + --fa: "\f0ca"; } + +.fa-list-dots { + --fa: "\f0ca"; } + +.fa-school-lock { + --fa: "\e56f"; } + +.fa-tower-cell { + --fa: "\e585"; } + +.fa-down-long { + --fa: "\f309"; } + +.fa-long-arrow-alt-down { + --fa: "\f309"; } + +.fa-ranking-star { + --fa: "\e561"; } + +.fa-chess-king { + --fa: "\f43f"; } + +.fa-person-harassing { + --fa: "\e549"; } + +.fa-brazilian-real-sign { + --fa: "\e46c"; } + +.fa-landmark-dome { + --fa: "\f752"; } + +.fa-landmark-alt { + --fa: "\f752"; } + +.fa-arrow-up { + --fa: "\f062"; } + +.fa-tv { + --fa: "\f26c"; } + +.fa-television { + --fa: "\f26c"; } + +.fa-tv-alt { + --fa: "\f26c"; } + +.fa-shrimp { + --fa: "\e448"; } + +.fa-list-check { + --fa: "\f0ae"; } + +.fa-tasks { + --fa: "\f0ae"; } + +.fa-jug-detergent { + --fa: "\e519"; } + +.fa-circle-user { + --fa: "\f2bd"; } + +.fa-user-circle { + --fa: "\f2bd"; } + +.fa-user-shield { + --fa: "\f505"; } + +.fa-wind { + --fa: "\f72e"; } + +.fa-car-burst { + --fa: "\f5e1"; } + +.fa-car-crash { + --fa: "\f5e1"; } + +.fa-y { + --fa: "\59"; } + +.fa-person-snowboarding { + --fa: "\f7ce"; } + +.fa-snowboarding { + --fa: "\f7ce"; } + +.fa-truck-fast { + --fa: "\f48b"; } + +.fa-shipping-fast { + --fa: "\f48b"; } + +.fa-fish { + --fa: "\f578"; } + +.fa-user-graduate { + --fa: "\f501"; } + +.fa-circle-half-stroke { + --fa: "\f042"; } + +.fa-adjust { + --fa: "\f042"; } + +.fa-clapperboard { + --fa: "\e131"; } + +.fa-circle-radiation { + --fa: "\f7ba"; } + +.fa-radiation-alt { + --fa: "\f7ba"; } + +.fa-baseball { + --fa: "\f433"; } + +.fa-baseball-ball { + --fa: "\f433"; } + +.fa-jet-fighter-up { + --fa: "\e518"; } + +.fa-diagram-project { + --fa: "\f542"; } + +.fa-project-diagram { + --fa: "\f542"; } + +.fa-copy { + --fa: "\f0c5"; } + +.fa-volume-xmark { + --fa: "\f6a9"; } + +.fa-volume-mute { + --fa: "\f6a9"; } + +.fa-volume-times { + --fa: "\f6a9"; } + +.fa-hand-sparkles { + --fa: "\e05d"; } + +.fa-grip { + --fa: "\f58d"; } + +.fa-grip-horizontal { + --fa: "\f58d"; } + +.fa-share-from-square { + --fa: "\f14d"; } + +.fa-share-square { + --fa: "\f14d"; } + +.fa-child-combatant { + --fa: "\e4e0"; } + +.fa-child-rifle { + --fa: "\e4e0"; } + +.fa-gun { + --fa: "\e19b"; } + +.fa-square-phone { + --fa: "\f098"; } + +.fa-phone-square { + --fa: "\f098"; } + +.fa-plus { + --fa: "\2b"; } + +.fa-add { + --fa: "\2b"; } + +.fa-expand { + --fa: "\f065"; } + +.fa-computer { + --fa: "\e4e5"; } + +.fa-xmark { + --fa: "\f00d"; } + +.fa-close { + --fa: "\f00d"; } + +.fa-multiply { + --fa: "\f00d"; } + +.fa-remove { + --fa: "\f00d"; } + +.fa-times { + --fa: "\f00d"; } + +.fa-arrows-up-down-left-right { + --fa: "\f047"; } + +.fa-arrows { + --fa: "\f047"; } + +.fa-chalkboard-user { + --fa: "\f51c"; } + +.fa-chalkboard-teacher { + --fa: "\f51c"; } + +.fa-peso-sign { + --fa: "\e222"; } + +.fa-building-shield { + --fa: "\e4d8"; } + +.fa-baby { + --fa: "\f77c"; } + +.fa-users-line { + --fa: "\e592"; } + +.fa-quote-left { + --fa: "\f10d"; } + +.fa-quote-left-alt { + --fa: "\f10d"; } + +.fa-tractor { + --fa: "\f722"; } + +.fa-trash-arrow-up { + --fa: "\f829"; } + +.fa-trash-restore { + --fa: "\f829"; } + +.fa-arrow-down-up-lock { + --fa: "\e4b0"; } + +.fa-lines-leaning { + --fa: "\e51e"; } + +.fa-ruler-combined { + --fa: "\f546"; } + +.fa-copyright { + --fa: "\f1f9"; } + +.fa-equals { + --fa: "\3d"; } + +.fa-blender { + --fa: "\f517"; } + +.fa-teeth { + --fa: "\f62e"; } + +.fa-shekel-sign { + --fa: "\f20b"; } + +.fa-ils { + --fa: "\f20b"; } + +.fa-shekel { + --fa: "\f20b"; } + +.fa-sheqel { + --fa: "\f20b"; } + +.fa-sheqel-sign { + --fa: "\f20b"; } + +.fa-map { + --fa: "\f279"; } + +.fa-rocket { + --fa: "\f135"; } + +.fa-photo-film { + --fa: "\f87c"; } + +.fa-photo-video { + --fa: "\f87c"; } + +.fa-folder-minus { + --fa: "\f65d"; } + +.fa-hexagon-nodes-bolt { + --fa: "\e69a"; } + +.fa-store { + --fa: "\f54e"; } + +.fa-arrow-trend-up { + --fa: "\e098"; } + +.fa-plug-circle-minus { + --fa: "\e55e"; } + +.fa-sign-hanging { + --fa: "\f4d9"; } + +.fa-sign { + --fa: "\f4d9"; } + +.fa-bezier-curve { + --fa: "\f55b"; } + +.fa-bell-slash { + --fa: "\f1f6"; } + +.fa-tablet { + --fa: "\f3fb"; } + +.fa-tablet-android { + --fa: "\f3fb"; } + +.fa-school-flag { + --fa: "\e56e"; } + +.fa-fill { + --fa: "\f575"; } + +.fa-angle-up { + --fa: "\f106"; } + +.fa-drumstick-bite { + --fa: "\f6d7"; } + +.fa-holly-berry { + --fa: "\f7aa"; } + +.fa-chevron-left { + --fa: "\f053"; } + +.fa-bacteria { + --fa: "\e059"; } + +.fa-hand-lizard { + --fa: "\f258"; } + +.fa-notdef { + --fa: "\e1fe"; } + +.fa-disease { + --fa: "\f7fa"; } + +.fa-briefcase-medical { + --fa: "\f469"; } + +.fa-genderless { + --fa: "\f22d"; } + +.fa-chevron-right { + --fa: "\f054"; } + +.fa-retweet { + --fa: "\f079"; } + +.fa-car-rear { + --fa: "\f5de"; } + +.fa-car-alt { + --fa: "\f5de"; } + +.fa-pump-soap { + --fa: "\e06b"; } + +.fa-video-slash { + --fa: "\f4e2"; } + +.fa-battery-quarter { + --fa: "\f243"; } + +.fa-battery-2 { + --fa: "\f243"; } + +.fa-radio { + --fa: "\f8d7"; } + +.fa-baby-carriage { + --fa: "\f77d"; } + +.fa-carriage-baby { + --fa: "\f77d"; } + +.fa-traffic-light { + --fa: "\f637"; } + +.fa-thermometer { + --fa: "\f491"; } + +.fa-vr-cardboard { + --fa: "\f729"; } + +.fa-hand-middle-finger { + --fa: "\f806"; } + +.fa-percent { + --fa: "\25"; } + +.fa-percentage { + --fa: "\25"; } + +.fa-truck-moving { + --fa: "\f4df"; } + +.fa-glass-water-droplet { + --fa: "\e4f5"; } + +.fa-display { + --fa: "\e163"; } + +.fa-face-smile { + --fa: "\f118"; } + +.fa-smile { + --fa: "\f118"; } + +.fa-thumbtack { + --fa: "\f08d"; } + +.fa-thumb-tack { + --fa: "\f08d"; } + +.fa-trophy { + --fa: "\f091"; } + +.fa-person-praying { + --fa: "\f683"; } + +.fa-pray { + --fa: "\f683"; } + +.fa-hammer { + --fa: "\f6e3"; } + +.fa-hand-peace { + --fa: "\f25b"; } + +.fa-rotate { + --fa: "\f2f1"; } + +.fa-sync-alt { + --fa: "\f2f1"; } + +.fa-spinner { + --fa: "\f110"; } + +.fa-robot { + --fa: "\f544"; } + +.fa-peace { + --fa: "\f67c"; } + +.fa-gears { + --fa: "\f085"; } + +.fa-cogs { + --fa: "\f085"; } + +.fa-warehouse { + --fa: "\f494"; } + +.fa-arrow-up-right-dots { + --fa: "\e4b7"; } + +.fa-splotch { + --fa: "\f5bc"; } + +.fa-face-grin-hearts { + --fa: "\f584"; } + +.fa-grin-hearts { + --fa: "\f584"; } + +.fa-dice-four { + --fa: "\f524"; } + +.fa-sim-card { + --fa: "\f7c4"; } + +.fa-transgender { + --fa: "\f225"; } + +.fa-transgender-alt { + --fa: "\f225"; } + +.fa-mercury { + --fa: "\f223"; } + +.fa-arrow-turn-down { + --fa: "\f149"; } + +.fa-level-down { + --fa: "\f149"; } + +.fa-person-falling-burst { + --fa: "\e547"; } + +.fa-award { + --fa: "\f559"; } + +.fa-ticket-simple { + --fa: "\f3ff"; } + +.fa-ticket-alt { + --fa: "\f3ff"; } + +.fa-building { + --fa: "\f1ad"; } + +.fa-angles-left { + --fa: "\f100"; } + +.fa-angle-double-left { + --fa: "\f100"; } + +.fa-qrcode { + --fa: "\f029"; } + +.fa-clock-rotate-left { + --fa: "\f1da"; } + +.fa-history { + --fa: "\f1da"; } + +.fa-face-grin-beam-sweat { + --fa: "\f583"; } + +.fa-grin-beam-sweat { + --fa: "\f583"; } + +.fa-file-export { + --fa: "\f56e"; } + +.fa-arrow-right-from-file { + --fa: "\f56e"; } + +.fa-shield { + --fa: "\f132"; } + +.fa-shield-blank { + --fa: "\f132"; } + +.fa-arrow-up-short-wide { + --fa: "\f885"; } + +.fa-sort-amount-up-alt { + --fa: "\f885"; } + +.fa-comment-nodes { + --fa: "\e696"; } + +.fa-house-medical { + --fa: "\e3b2"; } + +.fa-golf-ball-tee { + --fa: "\f450"; } + +.fa-golf-ball { + --fa: "\f450"; } + +.fa-circle-chevron-left { + --fa: "\f137"; } + +.fa-chevron-circle-left { + --fa: "\f137"; } + +.fa-house-chimney-window { + --fa: "\e00d"; } + +.fa-pen-nib { + --fa: "\f5ad"; } + +.fa-tent-arrow-turn-left { + --fa: "\e580"; } + +.fa-tents { + --fa: "\e582"; } + +.fa-wand-magic { + --fa: "\f0d0"; } + +.fa-magic { + --fa: "\f0d0"; } + +.fa-dog { + --fa: "\f6d3"; } + +.fa-carrot { + --fa: "\f787"; } + +.fa-moon { + --fa: "\f186"; } + +.fa-wine-glass-empty { + --fa: "\f5ce"; } + +.fa-wine-glass-alt { + --fa: "\f5ce"; } + +.fa-cheese { + --fa: "\f7ef"; } + +.fa-yin-yang { + --fa: "\f6ad"; } + +.fa-music { + --fa: "\f001"; } + +.fa-code-commit { + --fa: "\f386"; } + +.fa-temperature-low { + --fa: "\f76b"; } + +.fa-person-biking { + --fa: "\f84a"; } + +.fa-biking { + --fa: "\f84a"; } + +.fa-broom { + --fa: "\f51a"; } + +.fa-shield-heart { + --fa: "\e574"; } + +.fa-gopuram { + --fa: "\f664"; } + +.fa-earth-oceania { + --fa: "\e47b"; } + +.fa-globe-oceania { + --fa: "\e47b"; } + +.fa-square-xmark { + --fa: "\f2d3"; } + +.fa-times-square { + --fa: "\f2d3"; } + +.fa-xmark-square { + --fa: "\f2d3"; } + +.fa-hashtag { + --fa: "\23"; } + +.fa-up-right-and-down-left-from-center { + --fa: "\f424"; } + +.fa-expand-alt { + --fa: "\f424"; } + +.fa-oil-can { + --fa: "\f613"; } + +.fa-t { + --fa: "\54"; } + +.fa-hippo { + --fa: "\f6ed"; } + +.fa-chart-column { + --fa: "\e0e3"; } + +.fa-infinity { + --fa: "\f534"; } + +.fa-vial-circle-check { + --fa: "\e596"; } + +.fa-person-arrow-down-to-line { + --fa: "\e538"; } + +.fa-voicemail { + --fa: "\f897"; } + +.fa-fan { + --fa: "\f863"; } + +.fa-person-walking-luggage { + --fa: "\e554"; } + +.fa-up-down { + --fa: "\f338"; } + +.fa-arrows-alt-v { + --fa: "\f338"; } + +.fa-cloud-moon-rain { + --fa: "\f73c"; } + +.fa-calendar { + --fa: "\f133"; } + +.fa-trailer { + --fa: "\e041"; } + +.fa-bahai { + --fa: "\f666"; } + +.fa-haykal { + --fa: "\f666"; } + +.fa-sd-card { + --fa: "\f7c2"; } + +.fa-dragon { + --fa: "\f6d5"; } + +.fa-shoe-prints { + --fa: "\f54b"; } + +.fa-circle-plus { + --fa: "\f055"; } + +.fa-plus-circle { + --fa: "\f055"; } + +.fa-face-grin-tongue-wink { + --fa: "\f58b"; } + +.fa-grin-tongue-wink { + --fa: "\f58b"; } + +.fa-hand-holding { + --fa: "\f4bd"; } + +.fa-plug-circle-exclamation { + --fa: "\e55d"; } + +.fa-link-slash { + --fa: "\f127"; } + +.fa-chain-broken { + --fa: "\f127"; } + +.fa-chain-slash { + --fa: "\f127"; } + +.fa-unlink { + --fa: "\f127"; } + +.fa-clone { + --fa: "\f24d"; } + +.fa-person-walking-arrow-loop-left { + --fa: "\e551"; } + +.fa-arrow-up-z-a { + --fa: "\f882"; } + +.fa-sort-alpha-up-alt { + --fa: "\f882"; } + +.fa-fire-flame-curved { + --fa: "\f7e4"; } + +.fa-fire-alt { + --fa: "\f7e4"; } + +.fa-tornado { + --fa: "\f76f"; } + +.fa-file-circle-plus { + --fa: "\e494"; } + +.fa-book-quran { + --fa: "\f687"; } + +.fa-quran { + --fa: "\f687"; } + +.fa-anchor { + --fa: "\f13d"; } + +.fa-border-all { + --fa: "\f84c"; } + +.fa-face-angry { + --fa: "\f556"; } + +.fa-angry { + --fa: "\f556"; } + +.fa-cookie-bite { + --fa: "\f564"; } + +.fa-arrow-trend-down { + --fa: "\e097"; } + +.fa-rss { + --fa: "\f09e"; } + +.fa-feed { + --fa: "\f09e"; } + +.fa-draw-polygon { + --fa: "\f5ee"; } + +.fa-scale-balanced { + --fa: "\f24e"; } + +.fa-balance-scale { + --fa: "\f24e"; } + +.fa-gauge-simple-high { + --fa: "\f62a"; } + +.fa-tachometer { + --fa: "\f62a"; } + +.fa-tachometer-fast { + --fa: "\f62a"; } + +.fa-shower { + --fa: "\f2cc"; } + +.fa-desktop { + --fa: "\f390"; } + +.fa-desktop-alt { + --fa: "\f390"; } + +.fa-m { + --fa: "\4d"; } + +.fa-table-list { + --fa: "\f00b"; } + +.fa-th-list { + --fa: "\f00b"; } + +.fa-comment-sms { + --fa: "\f7cd"; } + +.fa-sms { + --fa: "\f7cd"; } + +.fa-book { + --fa: "\f02d"; } + +.fa-user-plus { + --fa: "\f234"; } + +.fa-check { + --fa: "\f00c"; } + +.fa-battery-three-quarters { + --fa: "\f241"; } + +.fa-battery-4 { + --fa: "\f241"; } + +.fa-house-circle-check { + --fa: "\e509"; } + +.fa-angle-left { + --fa: "\f104"; } + +.fa-diagram-successor { + --fa: "\e47a"; } + +.fa-truck-arrow-right { + --fa: "\e58b"; } + +.fa-arrows-split-up-and-left { + --fa: "\e4bc"; } + +.fa-hand-fist { + --fa: "\f6de"; } + +.fa-fist-raised { + --fa: "\f6de"; } + +.fa-cloud-moon { + --fa: "\f6c3"; } + +.fa-briefcase { + --fa: "\f0b1"; } + +.fa-person-falling { + --fa: "\e546"; } + +.fa-image-portrait { + --fa: "\f3e0"; } + +.fa-portrait { + --fa: "\f3e0"; } + +.fa-user-tag { + --fa: "\f507"; } + +.fa-rug { + --fa: "\e569"; } + +.fa-earth-europe { + --fa: "\f7a2"; } + +.fa-globe-europe { + --fa: "\f7a2"; } + +.fa-cart-flatbed-suitcase { + --fa: "\f59d"; } + +.fa-luggage-cart { + --fa: "\f59d"; } + +.fa-rectangle-xmark { + --fa: "\f410"; } + +.fa-rectangle-times { + --fa: "\f410"; } + +.fa-times-rectangle { + --fa: "\f410"; } + +.fa-window-close { + --fa: "\f410"; } + +.fa-baht-sign { + --fa: "\e0ac"; } + +.fa-book-open { + --fa: "\f518"; } + +.fa-book-journal-whills { + --fa: "\f66a"; } + +.fa-journal-whills { + --fa: "\f66a"; } + +.fa-handcuffs { + --fa: "\e4f8"; } + +.fa-triangle-exclamation { + --fa: "\f071"; } + +.fa-exclamation-triangle { + --fa: "\f071"; } + +.fa-warning { + --fa: "\f071"; } + +.fa-database { + --fa: "\f1c0"; } + +.fa-share { + --fa: "\f064"; } + +.fa-mail-forward { + --fa: "\f064"; } + +.fa-bottle-droplet { + --fa: "\e4c4"; } + +.fa-mask-face { + --fa: "\e1d7"; } + +.fa-hill-rockslide { + --fa: "\e508"; } + +.fa-right-left { + --fa: "\f362"; } + +.fa-exchange-alt { + --fa: "\f362"; } + +.fa-paper-plane { + --fa: "\f1d8"; } + +.fa-road-circle-exclamation { + --fa: "\e565"; } + +.fa-dungeon { + --fa: "\f6d9"; } + +.fa-align-right { + --fa: "\f038"; } + +.fa-money-bill-1-wave { + --fa: "\f53b"; } + +.fa-money-bill-wave-alt { + --fa: "\f53b"; } + +.fa-life-ring { + --fa: "\f1cd"; } + +.fa-hands { + --fa: "\f2a7"; } + +.fa-sign-language { + --fa: "\f2a7"; } + +.fa-signing { + --fa: "\f2a7"; } + +.fa-calendar-day { + --fa: "\f783"; } + +.fa-water-ladder { + --fa: "\f5c5"; } + +.fa-ladder-water { + --fa: "\f5c5"; } + +.fa-swimming-pool { + --fa: "\f5c5"; } + +.fa-arrows-up-down { + --fa: "\f07d"; } + +.fa-arrows-v { + --fa: "\f07d"; } + +.fa-face-grimace { + --fa: "\f57f"; } + +.fa-grimace { + --fa: "\f57f"; } + +.fa-wheelchair-move { + --fa: "\e2ce"; } + +.fa-wheelchair-alt { + --fa: "\e2ce"; } + +.fa-turn-down { + --fa: "\f3be"; } + +.fa-level-down-alt { + --fa: "\f3be"; } + +.fa-person-walking-arrow-right { + --fa: "\e552"; } + +.fa-square-envelope { + --fa: "\f199"; } + +.fa-envelope-square { + --fa: "\f199"; } + +.fa-dice { + --fa: "\f522"; } + +.fa-bowling-ball { + --fa: "\f436"; } + +.fa-brain { + --fa: "\f5dc"; } + +.fa-bandage { + --fa: "\f462"; } + +.fa-band-aid { + --fa: "\f462"; } + +.fa-calendar-minus { + --fa: "\f272"; } + +.fa-circle-xmark { + --fa: "\f057"; } + +.fa-times-circle { + --fa: "\f057"; } + +.fa-xmark-circle { + --fa: "\f057"; } + +.fa-gifts { + --fa: "\f79c"; } + +.fa-hotel { + --fa: "\f594"; } + +.fa-earth-asia { + --fa: "\f57e"; } + +.fa-globe-asia { + --fa: "\f57e"; } + +.fa-id-card-clip { + --fa: "\f47f"; } + +.fa-id-card-alt { + --fa: "\f47f"; } + +.fa-magnifying-glass-plus { + --fa: "\f00e"; } + +.fa-search-plus { + --fa: "\f00e"; } + +.fa-thumbs-up { + --fa: "\f164"; } + +.fa-user-clock { + --fa: "\f4fd"; } + +.fa-hand-dots { + --fa: "\f461"; } + +.fa-allergies { + --fa: "\f461"; } + +.fa-file-invoice { + --fa: "\f570"; } + +.fa-window-minimize { + --fa: "\f2d1"; } + +.fa-mug-saucer { + --fa: "\f0f4"; } + +.fa-coffee { + --fa: "\f0f4"; } + +.fa-brush { + --fa: "\f55d"; } + +.fa-file-half-dashed { + --fa: "\e698"; } + +.fa-mask { + --fa: "\f6fa"; } + +.fa-magnifying-glass-minus { + --fa: "\f010"; } + +.fa-search-minus { + --fa: "\f010"; } + +.fa-ruler-vertical { + --fa: "\f548"; } + +.fa-user-large { + --fa: "\f406"; } + +.fa-user-alt { + --fa: "\f406"; } + +.fa-train-tram { + --fa: "\e5b4"; } + +.fa-user-nurse { + --fa: "\f82f"; } + +.fa-syringe { + --fa: "\f48e"; } + +.fa-cloud-sun { + --fa: "\f6c4"; } + +.fa-stopwatch-20 { + --fa: "\e06f"; } + +.fa-square-full { + --fa: "\f45c"; } + +.fa-magnet { + --fa: "\f076"; } + +.fa-jar { + --fa: "\e516"; } + +.fa-note-sticky { + --fa: "\f249"; } + +.fa-sticky-note { + --fa: "\f249"; } + +.fa-bug-slash { + --fa: "\e490"; } + +.fa-arrow-up-from-water-pump { + --fa: "\e4b6"; } + +.fa-bone { + --fa: "\f5d7"; } + +.fa-table-cells-row-unlock { + --fa: "\e691"; } + +.fa-user-injured { + --fa: "\f728"; } + +.fa-face-sad-tear { + --fa: "\f5b4"; } + +.fa-sad-tear { + --fa: "\f5b4"; } + +.fa-plane { + --fa: "\f072"; } + +.fa-tent-arrows-down { + --fa: "\e581"; } + +.fa-exclamation { + --fa: "\21"; } + +.fa-arrows-spin { + --fa: "\e4bb"; } + +.fa-print { + --fa: "\f02f"; } + +.fa-turkish-lira-sign { + --fa: "\e2bb"; } + +.fa-try { + --fa: "\e2bb"; } + +.fa-turkish-lira { + --fa: "\e2bb"; } + +.fa-dollar-sign { + --fa: "\24"; } + +.fa-dollar { + --fa: "\24"; } + +.fa-usd { + --fa: "\24"; } + +.fa-x { + --fa: "\58"; } + +.fa-magnifying-glass-dollar { + --fa: "\f688"; } + +.fa-search-dollar { + --fa: "\f688"; } + +.fa-users-gear { + --fa: "\f509"; } + +.fa-users-cog { + --fa: "\f509"; } + +.fa-person-military-pointing { + --fa: "\e54a"; } + +.fa-building-columns { + --fa: "\f19c"; } + +.fa-bank { + --fa: "\f19c"; } + +.fa-institution { + --fa: "\f19c"; } + +.fa-museum { + --fa: "\f19c"; } + +.fa-university { + --fa: "\f19c"; } + +.fa-umbrella { + --fa: "\f0e9"; } + +.fa-trowel { + --fa: "\e589"; } + +.fa-d { + --fa: "\44"; } + +.fa-stapler { + --fa: "\e5af"; } + +.fa-masks-theater { + --fa: "\f630"; } + +.fa-theater-masks { + --fa: "\f630"; } + +.fa-kip-sign { + --fa: "\e1c4"; } + +.fa-hand-point-left { + --fa: "\f0a5"; } + +.fa-handshake-simple { + --fa: "\f4c6"; } + +.fa-handshake-alt { + --fa: "\f4c6"; } + +.fa-jet-fighter { + --fa: "\f0fb"; } + +.fa-fighter-jet { + --fa: "\f0fb"; } + +.fa-square-share-nodes { + --fa: "\f1e1"; } + +.fa-share-alt-square { + --fa: "\f1e1"; } + +.fa-barcode { + --fa: "\f02a"; } + +.fa-plus-minus { + --fa: "\e43c"; } + +.fa-video { + --fa: "\f03d"; } + +.fa-video-camera { + --fa: "\f03d"; } + +.fa-graduation-cap { + --fa: "\f19d"; } + +.fa-mortar-board { + --fa: "\f19d"; } + +.fa-hand-holding-medical { + --fa: "\e05c"; } + +.fa-person-circle-check { + --fa: "\e53e"; } + +.fa-turn-up { + --fa: "\f3bf"; } + +.fa-level-up-alt { + --fa: "\f3bf"; } + +.sr-only, +.fa-sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; } + +.sr-only-focusable:not(:focus), +.fa-sr-only-focusable:not(:focus) { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; } diff --git a/css/fontawesome.min.css b/css/fontawesome.min.css new file mode 100644 index 0000000000..4e07e306c0 --- /dev/null +++ b/css/fontawesome.min.css @@ -0,0 +1,9 @@ +/*! + * Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + * Copyright 2024 Fonticons, Inc. + */ +.fa{font-family:var(--fa-style-family,"Font Awesome 6 Free");font-weight:var(--fa-style,900)}.fa,.fa-brands,.fa-regular,.fa-solid,.fab,.far,.fas{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:var(--fa-display,inline-block);font-style:normal;font-variant:normal;line-height:1;text-rendering:auto}.fa-brands:before,.fa-regular:before,.fa-solid:before,.fa:before,.fab:before,.far:before,.fas:before{content:var(--fa)}.fa-classic,.fa-regular,.fa-solid,.far,.fas{font-family:"Font Awesome 6 Free"}.fa-brands,.fab{font-family:"Font Awesome 6 Brands"}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-2xs{font-size:.625em;line-height:.1em;vertical-align:.225em}.fa-xs{font-size:.75em;line-height:.08333em;vertical-align:.125em}.fa-sm{font-size:.875em;line-height:.07143em;vertical-align:.05357em}.fa-lg{font-size:1.25em;line-height:.05em;vertical-align:-.075em}.fa-xl{font-size:1.5em;line-height:.04167em;vertical-align:-.125em}.fa-2xl{font-size:2em;line-height:.03125em;vertical-align:-.1875em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:var(--fa-li-margin,2.5em);padding-left:0}.fa-ul>li{position:relative}.fa-li{left:calc(var(--fa-li-width, 2em)*-1);position:absolute;text-align:center;width:var(--fa-li-width,2em);line-height:inherit}.fa-border{border-radius:var(--fa-border-radius,.1em);border:var(--fa-border-width,.08em) var(--fa-border-style,solid) var(--fa-border-color,#eee);padding:var(--fa-border-padding,.2em .25em .15em)}.fa-pull-left{float:left;margin-right:var(--fa-pull-margin,.3em)}.fa-pull-right{float:right;margin-left:var(--fa-pull-margin,.3em)}.fa-beat{animation-name:fa-beat;animation-delay:var(--fa-animation-delay,0s);animation-direction:var(--fa-animation-direction,normal);animation-duration:var(--fa-animation-duration,1s);animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-timing-function:var(--fa-animation-timing,ease-in-out)}.fa-bounce{animation-name:fa-bounce;animation-delay:var(--fa-animation-delay,0s);animation-direction:var(--fa-animation-direction,normal);animation-duration:var(--fa-animation-duration,1s);animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-timing-function:var(--fa-animation-timing,cubic-bezier(.28,.84,.42,1))}.fa-fade{animation-name:fa-fade;animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-timing-function:var(--fa-animation-timing,cubic-bezier(.4,0,.6,1))}.fa-beat-fade,.fa-fade{animation-delay:var(--fa-animation-delay,0s);animation-direction:var(--fa-animation-direction,normal);animation-duration:var(--fa-animation-duration,1s)}.fa-beat-fade{animation-name:fa-beat-fade;animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-timing-function:var(--fa-animation-timing,cubic-bezier(.4,0,.6,1))}.fa-flip{animation-name:fa-flip;animation-delay:var(--fa-animation-delay,0s);animation-direction:var(--fa-animation-direction,normal);animation-duration:var(--fa-animation-duration,1s);animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-timing-function:var(--fa-animation-timing,ease-in-out)}.fa-shake{animation-name:fa-shake;animation-duration:var(--fa-animation-duration,1s);animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-timing-function:var(--fa-animation-timing,linear)}.fa-shake,.fa-spin{animation-delay:var(--fa-animation-delay,0s);animation-direction:var(--fa-animation-direction,normal)}.fa-spin{animation-name:fa-spin;animation-duration:var(--fa-animation-duration,2s);animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-timing-function:var(--fa-animation-timing,linear)}.fa-spin-reverse{--fa-animation-direction:reverse}.fa-pulse,.fa-spin-pulse{animation-name:fa-spin;animation-direction:var(--fa-animation-direction,normal);animation-duration:var(--fa-animation-duration,1s);animation-iteration-count:var(--fa-animation-iteration-count,infinite);animation-timing-function:var(--fa-animation-timing,steps(8))}@media (prefers-reduced-motion:reduce){.fa-beat,.fa-beat-fade,.fa-bounce,.fa-fade,.fa-flip,.fa-pulse,.fa-shake,.fa-spin,.fa-spin-pulse{animation-delay:-1ms;animation-duration:1ms;animation-iteration-count:1;transition-delay:0s;transition-duration:0s}}@keyframes fa-beat{0%,90%{transform:scale(1)}45%{transform:scale(var(--fa-beat-scale,1.25))}}@keyframes fa-bounce{0%{transform:scale(1) translateY(0)}10%{transform:scale(var(--fa-bounce-start-scale-x,1.1),var(--fa-bounce-start-scale-y,.9)) translateY(0)}30%{transform:scale(var(--fa-bounce-jump-scale-x,.9),var(--fa-bounce-jump-scale-y,1.1)) translateY(var(--fa-bounce-height,-.5em))}50%{transform:scale(var(--fa-bounce-land-scale-x,1.05),var(--fa-bounce-land-scale-y,.95)) translateY(0)}57%{transform:scale(1) translateY(var(--fa-bounce-rebound,-.125em))}64%{transform:scale(1) translateY(0)}to{transform:scale(1) translateY(0)}}@keyframes fa-fade{50%{opacity:var(--fa-fade-opacity,.4)}}@keyframes fa-beat-fade{0%,to{opacity:var(--fa-beat-fade-opacity,.4);transform:scale(1)}50%{opacity:1;transform:scale(var(--fa-beat-fade-scale,1.125))}}@keyframes fa-flip{50%{transform:rotate3d(var(--fa-flip-x,0),var(--fa-flip-y,1),var(--fa-flip-z,0),var(--fa-flip-angle,-180deg))}}@keyframes fa-shake{0%{transform:rotate(-15deg)}4%{transform:rotate(15deg)}8%,24%{transform:rotate(-18deg)}12%,28%{transform:rotate(18deg)}16%{transform:rotate(-22deg)}20%{transform:rotate(22deg)}32%{transform:rotate(-12deg)}36%{transform:rotate(12deg)}40%,to{transform:rotate(0deg)}}@keyframes fa-spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.fa-rotate-90{transform:rotate(90deg)}.fa-rotate-180{transform:rotate(180deg)}.fa-rotate-270{transform:rotate(270deg)}.fa-flip-horizontal{transform:scaleX(-1)}.fa-flip-vertical{transform:scaleY(-1)}.fa-flip-both,.fa-flip-horizontal.fa-flip-vertical{transform:scale(-1)}.fa-rotate-by{transform:rotate(var(--fa-rotate-angle,0))}.fa-stack{display:inline-block;height:2em;line-height:2em;position:relative;vertical-align:middle;width:2.5em}.fa-stack-1x,.fa-stack-2x{left:0;position:absolute;text-align:center;width:100%;z-index:var(--fa-stack-z-index,auto)}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:var(--fa-inverse,#fff)} + +.fa-0{--fa:"\30"}.fa-1{--fa:"\31"}.fa-2{--fa:"\32"}.fa-3{--fa:"\33"}.fa-4{--fa:"\34"}.fa-5{--fa:"\35"}.fa-6{--fa:"\36"}.fa-7{--fa:"\37"}.fa-8{--fa:"\38"}.fa-9{--fa:"\39"}.fa-fill-drip{--fa:"\f576"}.fa-arrows-to-circle{--fa:"\e4bd"}.fa-chevron-circle-right,.fa-circle-chevron-right{--fa:"\f138"}.fa-at{--fa:"\40"}.fa-trash-alt,.fa-trash-can{--fa:"\f2ed"}.fa-text-height{--fa:"\f034"}.fa-user-times,.fa-user-xmark{--fa:"\f235"}.fa-stethoscope{--fa:"\f0f1"}.fa-comment-alt,.fa-message{--fa:"\f27a"}.fa-info{--fa:"\f129"}.fa-compress-alt,.fa-down-left-and-up-right-to-center{--fa:"\f422"}.fa-explosion{--fa:"\e4e9"}.fa-file-alt,.fa-file-lines,.fa-file-text{--fa:"\f15c"}.fa-wave-square{--fa:"\f83e"}.fa-ring{--fa:"\f70b"}.fa-building-un{--fa:"\e4d9"}.fa-dice-three{--fa:"\f527"}.fa-calendar-alt,.fa-calendar-days{--fa:"\f073"}.fa-anchor-circle-check{--fa:"\e4aa"}.fa-building-circle-arrow-right{--fa:"\e4d1"}.fa-volleyball,.fa-volleyball-ball{--fa:"\f45f"}.fa-arrows-up-to-line{--fa:"\e4c2"}.fa-sort-desc,.fa-sort-down{--fa:"\f0dd"}.fa-circle-minus,.fa-minus-circle{--fa:"\f056"}.fa-door-open{--fa:"\f52b"}.fa-right-from-bracket,.fa-sign-out-alt{--fa:"\f2f5"}.fa-atom{--fa:"\f5d2"}.fa-soap{--fa:"\e06e"}.fa-heart-music-camera-bolt,.fa-icons{--fa:"\f86d"}.fa-microphone-alt-slash,.fa-microphone-lines-slash{--fa:"\f539"}.fa-bridge-circle-check{--fa:"\e4c9"}.fa-pump-medical{--fa:"\e06a"}.fa-fingerprint{--fa:"\f577"}.fa-hand-point-right{--fa:"\f0a4"}.fa-magnifying-glass-location,.fa-search-location{--fa:"\f689"}.fa-forward-step,.fa-step-forward{--fa:"\f051"}.fa-face-smile-beam,.fa-smile-beam{--fa:"\f5b8"}.fa-flag-checkered{--fa:"\f11e"}.fa-football,.fa-football-ball{--fa:"\f44e"}.fa-school-circle-exclamation{--fa:"\e56c"}.fa-crop{--fa:"\f125"}.fa-angle-double-down,.fa-angles-down{--fa:"\f103"}.fa-users-rectangle{--fa:"\e594"}.fa-people-roof{--fa:"\e537"}.fa-people-line{--fa:"\e534"}.fa-beer,.fa-beer-mug-empty{--fa:"\f0fc"}.fa-diagram-predecessor{--fa:"\e477"}.fa-arrow-up-long,.fa-long-arrow-up{--fa:"\f176"}.fa-burn,.fa-fire-flame-simple{--fa:"\f46a"}.fa-male,.fa-person{--fa:"\f183"}.fa-laptop{--fa:"\f109"}.fa-file-csv{--fa:"\f6dd"}.fa-menorah{--fa:"\f676"}.fa-truck-plane{--fa:"\e58f"}.fa-record-vinyl{--fa:"\f8d9"}.fa-face-grin-stars,.fa-grin-stars{--fa:"\f587"}.fa-bong{--fa:"\f55c"}.fa-pastafarianism,.fa-spaghetti-monster-flying{--fa:"\f67b"}.fa-arrow-down-up-across-line{--fa:"\e4af"}.fa-spoon,.fa-utensil-spoon{--fa:"\f2e5"}.fa-jar-wheat{--fa:"\e517"}.fa-envelopes-bulk,.fa-mail-bulk{--fa:"\f674"}.fa-file-circle-exclamation{--fa:"\e4eb"}.fa-circle-h,.fa-hospital-symbol{--fa:"\f47e"}.fa-pager{--fa:"\f815"}.fa-address-book,.fa-contact-book{--fa:"\f2b9"}.fa-strikethrough{--fa:"\f0cc"}.fa-k{--fa:"\4b"}.fa-landmark-flag{--fa:"\e51c"}.fa-pencil,.fa-pencil-alt{--fa:"\f303"}.fa-backward{--fa:"\f04a"}.fa-caret-right{--fa:"\f0da"}.fa-comments{--fa:"\f086"}.fa-file-clipboard,.fa-paste{--fa:"\f0ea"}.fa-code-pull-request{--fa:"\e13c"}.fa-clipboard-list{--fa:"\f46d"}.fa-truck-loading,.fa-truck-ramp-box{--fa:"\f4de"}.fa-user-check{--fa:"\f4fc"}.fa-vial-virus{--fa:"\e597"}.fa-sheet-plastic{--fa:"\e571"}.fa-blog{--fa:"\f781"}.fa-user-ninja{--fa:"\f504"}.fa-person-arrow-up-from-line{--fa:"\e539"}.fa-scroll-torah,.fa-torah{--fa:"\f6a0"}.fa-broom-ball,.fa-quidditch,.fa-quidditch-broom-ball{--fa:"\f458"}.fa-toggle-off{--fa:"\f204"}.fa-archive,.fa-box-archive{--fa:"\f187"}.fa-person-drowning{--fa:"\e545"}.fa-arrow-down-9-1,.fa-sort-numeric-desc,.fa-sort-numeric-down-alt{--fa:"\f886"}.fa-face-grin-tongue-squint,.fa-grin-tongue-squint{--fa:"\f58a"}.fa-spray-can{--fa:"\f5bd"}.fa-truck-monster{--fa:"\f63b"}.fa-w{--fa:"\57"}.fa-earth-africa,.fa-globe-africa{--fa:"\f57c"}.fa-rainbow{--fa:"\f75b"}.fa-circle-notch{--fa:"\f1ce"}.fa-tablet-alt,.fa-tablet-screen-button{--fa:"\f3fa"}.fa-paw{--fa:"\f1b0"}.fa-cloud{--fa:"\f0c2"}.fa-trowel-bricks{--fa:"\e58a"}.fa-face-flushed,.fa-flushed{--fa:"\f579"}.fa-hospital-user{--fa:"\f80d"}.fa-tent-arrow-left-right{--fa:"\e57f"}.fa-gavel,.fa-legal{--fa:"\f0e3"}.fa-binoculars{--fa:"\f1e5"}.fa-microphone-slash{--fa:"\f131"}.fa-box-tissue{--fa:"\e05b"}.fa-motorcycle{--fa:"\f21c"}.fa-bell-concierge,.fa-concierge-bell{--fa:"\f562"}.fa-pen-ruler,.fa-pencil-ruler{--fa:"\f5ae"}.fa-people-arrows,.fa-people-arrows-left-right{--fa:"\e068"}.fa-mars-and-venus-burst{--fa:"\e523"}.fa-caret-square-right,.fa-square-caret-right{--fa:"\f152"}.fa-cut,.fa-scissors{--fa:"\f0c4"}.fa-sun-plant-wilt{--fa:"\e57a"}.fa-toilets-portable{--fa:"\e584"}.fa-hockey-puck{--fa:"\f453"}.fa-table{--fa:"\f0ce"}.fa-magnifying-glass-arrow-right{--fa:"\e521"}.fa-digital-tachograph,.fa-tachograph-digital{--fa:"\f566"}.fa-users-slash{--fa:"\e073"}.fa-clover{--fa:"\e139"}.fa-mail-reply,.fa-reply{--fa:"\f3e5"}.fa-star-and-crescent{--fa:"\f699"}.fa-house-fire{--fa:"\e50c"}.fa-minus-square,.fa-square-minus{--fa:"\f146"}.fa-helicopter{--fa:"\f533"}.fa-compass{--fa:"\f14e"}.fa-caret-square-down,.fa-square-caret-down{--fa:"\f150"}.fa-file-circle-question{--fa:"\e4ef"}.fa-laptop-code{--fa:"\f5fc"}.fa-swatchbook{--fa:"\f5c3"}.fa-prescription-bottle{--fa:"\f485"}.fa-bars,.fa-navicon{--fa:"\f0c9"}.fa-people-group{--fa:"\e533"}.fa-hourglass-3,.fa-hourglass-end{--fa:"\f253"}.fa-heart-broken,.fa-heart-crack{--fa:"\f7a9"}.fa-external-link-square-alt,.fa-square-up-right{--fa:"\f360"}.fa-face-kiss-beam,.fa-kiss-beam{--fa:"\f597"}.fa-film{--fa:"\f008"}.fa-ruler-horizontal{--fa:"\f547"}.fa-people-robbery{--fa:"\e536"}.fa-lightbulb{--fa:"\f0eb"}.fa-caret-left{--fa:"\f0d9"}.fa-circle-exclamation,.fa-exclamation-circle{--fa:"\f06a"}.fa-school-circle-xmark{--fa:"\e56d"}.fa-arrow-right-from-bracket,.fa-sign-out{--fa:"\f08b"}.fa-chevron-circle-down,.fa-circle-chevron-down{--fa:"\f13a"}.fa-unlock-alt,.fa-unlock-keyhole{--fa:"\f13e"}.fa-cloud-showers-heavy{--fa:"\f740"}.fa-headphones-alt,.fa-headphones-simple{--fa:"\f58f"}.fa-sitemap{--fa:"\f0e8"}.fa-circle-dollar-to-slot,.fa-donate{--fa:"\f4b9"}.fa-memory{--fa:"\f538"}.fa-road-spikes{--fa:"\e568"}.fa-fire-burner{--fa:"\e4f1"}.fa-flag{--fa:"\f024"}.fa-hanukiah{--fa:"\f6e6"}.fa-feather{--fa:"\f52d"}.fa-volume-down,.fa-volume-low{--fa:"\f027"}.fa-comment-slash{--fa:"\f4b3"}.fa-cloud-sun-rain{--fa:"\f743"}.fa-compress{--fa:"\f066"}.fa-wheat-alt,.fa-wheat-awn{--fa:"\e2cd"}.fa-ankh{--fa:"\f644"}.fa-hands-holding-child{--fa:"\e4fa"}.fa-asterisk{--fa:"\2a"}.fa-check-square,.fa-square-check{--fa:"\f14a"}.fa-peseta-sign{--fa:"\e221"}.fa-header,.fa-heading{--fa:"\f1dc"}.fa-ghost{--fa:"\f6e2"}.fa-list,.fa-list-squares{--fa:"\f03a"}.fa-phone-square-alt,.fa-square-phone-flip{--fa:"\f87b"}.fa-cart-plus{--fa:"\f217"}.fa-gamepad{--fa:"\f11b"}.fa-circle-dot,.fa-dot-circle{--fa:"\f192"}.fa-dizzy,.fa-face-dizzy{--fa:"\f567"}.fa-egg{--fa:"\f7fb"}.fa-house-medical-circle-xmark{--fa:"\e513"}.fa-campground{--fa:"\f6bb"}.fa-folder-plus{--fa:"\f65e"}.fa-futbol,.fa-futbol-ball,.fa-soccer-ball{--fa:"\f1e3"}.fa-paint-brush,.fa-paintbrush{--fa:"\f1fc"}.fa-lock{--fa:"\f023"}.fa-gas-pump{--fa:"\f52f"}.fa-hot-tub,.fa-hot-tub-person{--fa:"\f593"}.fa-map-location,.fa-map-marked{--fa:"\f59f"}.fa-house-flood-water{--fa:"\e50e"}.fa-tree{--fa:"\f1bb"}.fa-bridge-lock{--fa:"\e4cc"}.fa-sack-dollar{--fa:"\f81d"}.fa-edit,.fa-pen-to-square{--fa:"\f044"}.fa-car-side{--fa:"\f5e4"}.fa-share-alt,.fa-share-nodes{--fa:"\f1e0"}.fa-heart-circle-minus{--fa:"\e4ff"}.fa-hourglass-2,.fa-hourglass-half{--fa:"\f252"}.fa-microscope{--fa:"\f610"}.fa-sink{--fa:"\e06d"}.fa-bag-shopping,.fa-shopping-bag{--fa:"\f290"}.fa-arrow-down-z-a,.fa-sort-alpha-desc,.fa-sort-alpha-down-alt{--fa:"\f881"}.fa-mitten{--fa:"\f7b5"}.fa-person-rays{--fa:"\e54d"}.fa-users{--fa:"\f0c0"}.fa-eye-slash{--fa:"\f070"}.fa-flask-vial{--fa:"\e4f3"}.fa-hand,.fa-hand-paper{--fa:"\f256"}.fa-om{--fa:"\f679"}.fa-worm{--fa:"\e599"}.fa-house-circle-xmark{--fa:"\e50b"}.fa-plug{--fa:"\f1e6"}.fa-chevron-up{--fa:"\f077"}.fa-hand-spock{--fa:"\f259"}.fa-stopwatch{--fa:"\f2f2"}.fa-face-kiss,.fa-kiss{--fa:"\f596"}.fa-bridge-circle-xmark{--fa:"\e4cb"}.fa-face-grin-tongue,.fa-grin-tongue{--fa:"\f589"}.fa-chess-bishop{--fa:"\f43a"}.fa-face-grin-wink,.fa-grin-wink{--fa:"\f58c"}.fa-deaf,.fa-deafness,.fa-ear-deaf,.fa-hard-of-hearing{--fa:"\f2a4"}.fa-road-circle-check{--fa:"\e564"}.fa-dice-five{--fa:"\f523"}.fa-rss-square,.fa-square-rss{--fa:"\f143"}.fa-land-mine-on{--fa:"\e51b"}.fa-i-cursor{--fa:"\f246"}.fa-stamp{--fa:"\f5bf"}.fa-stairs{--fa:"\e289"}.fa-i{--fa:"\49"}.fa-hryvnia,.fa-hryvnia-sign{--fa:"\f6f2"}.fa-pills{--fa:"\f484"}.fa-face-grin-wide,.fa-grin-alt{--fa:"\f581"}.fa-tooth{--fa:"\f5c9"}.fa-v{--fa:"\56"}.fa-bangladeshi-taka-sign{--fa:"\e2e6"}.fa-bicycle{--fa:"\f206"}.fa-rod-asclepius,.fa-rod-snake,.fa-staff-aesculapius,.fa-staff-snake{--fa:"\e579"}.fa-head-side-cough-slash{--fa:"\e062"}.fa-ambulance,.fa-truck-medical{--fa:"\f0f9"}.fa-wheat-awn-circle-exclamation{--fa:"\e598"}.fa-snowman{--fa:"\f7d0"}.fa-mortar-pestle{--fa:"\f5a7"}.fa-road-barrier{--fa:"\e562"}.fa-school{--fa:"\f549"}.fa-igloo{--fa:"\f7ae"}.fa-joint{--fa:"\f595"}.fa-angle-right{--fa:"\f105"}.fa-horse{--fa:"\f6f0"}.fa-q{--fa:"\51"}.fa-g{--fa:"\47"}.fa-notes-medical{--fa:"\f481"}.fa-temperature-2,.fa-temperature-half,.fa-thermometer-2,.fa-thermometer-half{--fa:"\f2c9"}.fa-dong-sign{--fa:"\e169"}.fa-capsules{--fa:"\f46b"}.fa-poo-bolt,.fa-poo-storm{--fa:"\f75a"}.fa-face-frown-open,.fa-frown-open{--fa:"\f57a"}.fa-hand-point-up{--fa:"\f0a6"}.fa-money-bill{--fa:"\f0d6"}.fa-bookmark{--fa:"\f02e"}.fa-align-justify{--fa:"\f039"}.fa-umbrella-beach{--fa:"\f5ca"}.fa-helmet-un{--fa:"\e503"}.fa-bullseye{--fa:"\f140"}.fa-bacon{--fa:"\f7e5"}.fa-hand-point-down{--fa:"\f0a7"}.fa-arrow-up-from-bracket{--fa:"\e09a"}.fa-folder,.fa-folder-blank{--fa:"\f07b"}.fa-file-medical-alt,.fa-file-waveform{--fa:"\f478"}.fa-radiation{--fa:"\f7b9"}.fa-chart-simple{--fa:"\e473"}.fa-mars-stroke{--fa:"\f229"}.fa-vial{--fa:"\f492"}.fa-dashboard,.fa-gauge,.fa-gauge-med,.fa-tachometer-alt-average{--fa:"\f624"}.fa-magic-wand-sparkles,.fa-wand-magic-sparkles{--fa:"\e2ca"}.fa-e{--fa:"\45"}.fa-pen-alt,.fa-pen-clip{--fa:"\f305"}.fa-bridge-circle-exclamation{--fa:"\e4ca"}.fa-user{--fa:"\f007"}.fa-school-circle-check{--fa:"\e56b"}.fa-dumpster{--fa:"\f793"}.fa-shuttle-van,.fa-van-shuttle{--fa:"\f5b6"}.fa-building-user{--fa:"\e4da"}.fa-caret-square-left,.fa-square-caret-left{--fa:"\f191"}.fa-highlighter{--fa:"\f591"}.fa-key{--fa:"\f084"}.fa-bullhorn{--fa:"\f0a1"}.fa-globe{--fa:"\f0ac"}.fa-synagogue{--fa:"\f69b"}.fa-person-half-dress{--fa:"\e548"}.fa-road-bridge{--fa:"\e563"}.fa-location-arrow{--fa:"\f124"}.fa-c{--fa:"\43"}.fa-tablet-button{--fa:"\f10a"}.fa-building-lock{--fa:"\e4d6"}.fa-pizza-slice{--fa:"\f818"}.fa-money-bill-wave{--fa:"\f53a"}.fa-area-chart,.fa-chart-area{--fa:"\f1fe"}.fa-house-flag{--fa:"\e50d"}.fa-person-circle-minus{--fa:"\e540"}.fa-ban,.fa-cancel{--fa:"\f05e"}.fa-camera-rotate{--fa:"\e0d8"}.fa-air-freshener,.fa-spray-can-sparkles{--fa:"\f5d0"}.fa-star{--fa:"\f005"}.fa-repeat{--fa:"\f363"}.fa-cross{--fa:"\f654"}.fa-box{--fa:"\f466"}.fa-venus-mars{--fa:"\f228"}.fa-arrow-pointer,.fa-mouse-pointer{--fa:"\f245"}.fa-expand-arrows-alt,.fa-maximize{--fa:"\f31e"}.fa-charging-station{--fa:"\f5e7"}.fa-shapes,.fa-triangle-circle-square{--fa:"\f61f"}.fa-random,.fa-shuffle{--fa:"\f074"}.fa-person-running,.fa-running{--fa:"\f70c"}.fa-mobile-retro{--fa:"\e527"}.fa-grip-lines-vertical{--fa:"\f7a5"}.fa-spider{--fa:"\f717"}.fa-hands-bound{--fa:"\e4f9"}.fa-file-invoice-dollar{--fa:"\f571"}.fa-plane-circle-exclamation{--fa:"\e556"}.fa-x-ray{--fa:"\f497"}.fa-spell-check{--fa:"\f891"}.fa-slash{--fa:"\f715"}.fa-computer-mouse,.fa-mouse{--fa:"\f8cc"}.fa-arrow-right-to-bracket,.fa-sign-in{--fa:"\f090"}.fa-shop-slash,.fa-store-alt-slash{--fa:"\e070"}.fa-server{--fa:"\f233"}.fa-virus-covid-slash{--fa:"\e4a9"}.fa-shop-lock{--fa:"\e4a5"}.fa-hourglass-1,.fa-hourglass-start{--fa:"\f251"}.fa-blender-phone{--fa:"\f6b6"}.fa-building-wheat{--fa:"\e4db"}.fa-person-breastfeeding{--fa:"\e53a"}.fa-right-to-bracket,.fa-sign-in-alt{--fa:"\f2f6"}.fa-venus{--fa:"\f221"}.fa-passport{--fa:"\f5ab"}.fa-thumb-tack-slash,.fa-thumbtack-slash{--fa:"\e68f"}.fa-heart-pulse,.fa-heartbeat{--fa:"\f21e"}.fa-people-carry,.fa-people-carry-box{--fa:"\f4ce"}.fa-temperature-high{--fa:"\f769"}.fa-microchip{--fa:"\f2db"}.fa-crown{--fa:"\f521"}.fa-weight-hanging{--fa:"\f5cd"}.fa-xmarks-lines{--fa:"\e59a"}.fa-file-prescription{--fa:"\f572"}.fa-weight,.fa-weight-scale{--fa:"\f496"}.fa-user-friends,.fa-user-group{--fa:"\f500"}.fa-arrow-up-a-z,.fa-sort-alpha-up{--fa:"\f15e"}.fa-chess-knight{--fa:"\f441"}.fa-face-laugh-squint,.fa-laugh-squint{--fa:"\f59b"}.fa-wheelchair{--fa:"\f193"}.fa-arrow-circle-up,.fa-circle-arrow-up{--fa:"\f0aa"}.fa-toggle-on{--fa:"\f205"}.fa-person-walking,.fa-walking{--fa:"\f554"}.fa-l{--fa:"\4c"}.fa-fire{--fa:"\f06d"}.fa-bed-pulse,.fa-procedures{--fa:"\f487"}.fa-shuttle-space,.fa-space-shuttle{--fa:"\f197"}.fa-face-laugh,.fa-laugh{--fa:"\f599"}.fa-folder-open{--fa:"\f07c"}.fa-heart-circle-plus{--fa:"\e500"}.fa-code-fork{--fa:"\e13b"}.fa-city{--fa:"\f64f"}.fa-microphone-alt,.fa-microphone-lines{--fa:"\f3c9"}.fa-pepper-hot{--fa:"\f816"}.fa-unlock{--fa:"\f09c"}.fa-colon-sign{--fa:"\e140"}.fa-headset{--fa:"\f590"}.fa-store-slash{--fa:"\e071"}.fa-road-circle-xmark{--fa:"\e566"}.fa-user-minus{--fa:"\f503"}.fa-mars-stroke-up,.fa-mars-stroke-v{--fa:"\f22a"}.fa-champagne-glasses,.fa-glass-cheers{--fa:"\f79f"}.fa-clipboard{--fa:"\f328"}.fa-house-circle-exclamation{--fa:"\e50a"}.fa-file-arrow-up,.fa-file-upload{--fa:"\f574"}.fa-wifi,.fa-wifi-3,.fa-wifi-strong{--fa:"\f1eb"}.fa-bath,.fa-bathtub{--fa:"\f2cd"}.fa-underline{--fa:"\f0cd"}.fa-user-edit,.fa-user-pen{--fa:"\f4ff"}.fa-signature{--fa:"\f5b7"}.fa-stroopwafel{--fa:"\f551"}.fa-bold{--fa:"\f032"}.fa-anchor-lock{--fa:"\e4ad"}.fa-building-ngo{--fa:"\e4d7"}.fa-manat-sign{--fa:"\e1d5"}.fa-not-equal{--fa:"\f53e"}.fa-border-style,.fa-border-top-left{--fa:"\f853"}.fa-map-location-dot,.fa-map-marked-alt{--fa:"\f5a0"}.fa-jedi{--fa:"\f669"}.fa-poll,.fa-square-poll-vertical{--fa:"\f681"}.fa-mug-hot{--fa:"\f7b6"}.fa-battery-car,.fa-car-battery{--fa:"\f5df"}.fa-gift{--fa:"\f06b"}.fa-dice-two{--fa:"\f528"}.fa-chess-queen{--fa:"\f445"}.fa-glasses{--fa:"\f530"}.fa-chess-board{--fa:"\f43c"}.fa-building-circle-check{--fa:"\e4d2"}.fa-person-chalkboard{--fa:"\e53d"}.fa-mars-stroke-h,.fa-mars-stroke-right{--fa:"\f22b"}.fa-hand-back-fist,.fa-hand-rock{--fa:"\f255"}.fa-caret-square-up,.fa-square-caret-up{--fa:"\f151"}.fa-cloud-showers-water{--fa:"\e4e4"}.fa-bar-chart,.fa-chart-bar{--fa:"\f080"}.fa-hands-bubbles,.fa-hands-wash{--fa:"\e05e"}.fa-less-than-equal{--fa:"\f537"}.fa-train{--fa:"\f238"}.fa-eye-low-vision,.fa-low-vision{--fa:"\f2a8"}.fa-crow{--fa:"\f520"}.fa-sailboat{--fa:"\e445"}.fa-window-restore{--fa:"\f2d2"}.fa-plus-square,.fa-square-plus{--fa:"\f0fe"}.fa-torii-gate{--fa:"\f6a1"}.fa-frog{--fa:"\f52e"}.fa-bucket{--fa:"\e4cf"}.fa-image{--fa:"\f03e"}.fa-microphone{--fa:"\f130"}.fa-cow{--fa:"\f6c8"}.fa-caret-up{--fa:"\f0d8"}.fa-screwdriver{--fa:"\f54a"}.fa-folder-closed{--fa:"\e185"}.fa-house-tsunami{--fa:"\e515"}.fa-square-nfi{--fa:"\e576"}.fa-arrow-up-from-ground-water{--fa:"\e4b5"}.fa-glass-martini-alt,.fa-martini-glass{--fa:"\f57b"}.fa-square-binary{--fa:"\e69b"}.fa-rotate-back,.fa-rotate-backward,.fa-rotate-left,.fa-undo-alt{--fa:"\f2ea"}.fa-columns,.fa-table-columns{--fa:"\f0db"}.fa-lemon{--fa:"\f094"}.fa-head-side-mask{--fa:"\e063"}.fa-handshake{--fa:"\f2b5"}.fa-gem{--fa:"\f3a5"}.fa-dolly,.fa-dolly-box{--fa:"\f472"}.fa-smoking{--fa:"\f48d"}.fa-compress-arrows-alt,.fa-minimize{--fa:"\f78c"}.fa-monument{--fa:"\f5a6"}.fa-snowplow{--fa:"\f7d2"}.fa-angle-double-right,.fa-angles-right{--fa:"\f101"}.fa-cannabis{--fa:"\f55f"}.fa-circle-play,.fa-play-circle{--fa:"\f144"}.fa-tablets{--fa:"\f490"}.fa-ethernet{--fa:"\f796"}.fa-eur,.fa-euro,.fa-euro-sign{--fa:"\f153"}.fa-chair{--fa:"\f6c0"}.fa-check-circle,.fa-circle-check{--fa:"\f058"}.fa-circle-stop,.fa-stop-circle{--fa:"\f28d"}.fa-compass-drafting,.fa-drafting-compass{--fa:"\f568"}.fa-plate-wheat{--fa:"\e55a"}.fa-icicles{--fa:"\f7ad"}.fa-person-shelter{--fa:"\e54f"}.fa-neuter{--fa:"\f22c"}.fa-id-badge{--fa:"\f2c1"}.fa-marker{--fa:"\f5a1"}.fa-face-laugh-beam,.fa-laugh-beam{--fa:"\f59a"}.fa-helicopter-symbol{--fa:"\e502"}.fa-universal-access{--fa:"\f29a"}.fa-chevron-circle-up,.fa-circle-chevron-up{--fa:"\f139"}.fa-lari-sign{--fa:"\e1c8"}.fa-volcano{--fa:"\f770"}.fa-person-walking-dashed-line-arrow-right{--fa:"\e553"}.fa-gbp,.fa-pound-sign,.fa-sterling-sign{--fa:"\f154"}.fa-viruses{--fa:"\e076"}.fa-square-person-confined{--fa:"\e577"}.fa-user-tie{--fa:"\f508"}.fa-arrow-down-long,.fa-long-arrow-down{--fa:"\f175"}.fa-tent-arrow-down-to-line{--fa:"\e57e"}.fa-certificate{--fa:"\f0a3"}.fa-mail-reply-all,.fa-reply-all{--fa:"\f122"}.fa-suitcase{--fa:"\f0f2"}.fa-person-skating,.fa-skating{--fa:"\f7c5"}.fa-filter-circle-dollar,.fa-funnel-dollar{--fa:"\f662"}.fa-camera-retro{--fa:"\f083"}.fa-arrow-circle-down,.fa-circle-arrow-down{--fa:"\f0ab"}.fa-arrow-right-to-file,.fa-file-import{--fa:"\f56f"}.fa-external-link-square,.fa-square-arrow-up-right{--fa:"\f14c"}.fa-box-open{--fa:"\f49e"}.fa-scroll{--fa:"\f70e"}.fa-spa{--fa:"\f5bb"}.fa-location-pin-lock{--fa:"\e51f"}.fa-pause{--fa:"\f04c"}.fa-hill-avalanche{--fa:"\e507"}.fa-temperature-0,.fa-temperature-empty,.fa-thermometer-0,.fa-thermometer-empty{--fa:"\f2cb"}.fa-bomb{--fa:"\f1e2"}.fa-registered{--fa:"\f25d"}.fa-address-card,.fa-contact-card,.fa-vcard{--fa:"\f2bb"}.fa-balance-scale-right,.fa-scale-unbalanced-flip{--fa:"\f516"}.fa-subscript{--fa:"\f12c"}.fa-diamond-turn-right,.fa-directions{--fa:"\f5eb"}.fa-burst{--fa:"\e4dc"}.fa-house-laptop,.fa-laptop-house{--fa:"\e066"}.fa-face-tired,.fa-tired{--fa:"\f5c8"}.fa-money-bills{--fa:"\e1f3"}.fa-smog{--fa:"\f75f"}.fa-crutch{--fa:"\f7f7"}.fa-cloud-arrow-up,.fa-cloud-upload,.fa-cloud-upload-alt{--fa:"\f0ee"}.fa-palette{--fa:"\f53f"}.fa-arrows-turn-right{--fa:"\e4c0"}.fa-vest{--fa:"\e085"}.fa-ferry{--fa:"\e4ea"}.fa-arrows-down-to-people{--fa:"\e4b9"}.fa-seedling,.fa-sprout{--fa:"\f4d8"}.fa-arrows-alt-h,.fa-left-right{--fa:"\f337"}.fa-boxes-packing{--fa:"\e4c7"}.fa-arrow-circle-left,.fa-circle-arrow-left{--fa:"\f0a8"}.fa-group-arrows-rotate{--fa:"\e4f6"}.fa-bowl-food{--fa:"\e4c6"}.fa-candy-cane{--fa:"\f786"}.fa-arrow-down-wide-short,.fa-sort-amount-asc,.fa-sort-amount-down{--fa:"\f160"}.fa-cloud-bolt,.fa-thunderstorm{--fa:"\f76c"}.fa-remove-format,.fa-text-slash{--fa:"\f87d"}.fa-face-smile-wink,.fa-smile-wink{--fa:"\f4da"}.fa-file-word{--fa:"\f1c2"}.fa-file-powerpoint{--fa:"\f1c4"}.fa-arrows-h,.fa-arrows-left-right{--fa:"\f07e"}.fa-house-lock{--fa:"\e510"}.fa-cloud-arrow-down,.fa-cloud-download,.fa-cloud-download-alt{--fa:"\f0ed"}.fa-children{--fa:"\e4e1"}.fa-blackboard,.fa-chalkboard{--fa:"\f51b"}.fa-user-alt-slash,.fa-user-large-slash{--fa:"\f4fa"}.fa-envelope-open{--fa:"\f2b6"}.fa-handshake-alt-slash,.fa-handshake-simple-slash{--fa:"\e05f"}.fa-mattress-pillow{--fa:"\e525"}.fa-guarani-sign{--fa:"\e19a"}.fa-arrows-rotate,.fa-refresh,.fa-sync{--fa:"\f021"}.fa-fire-extinguisher{--fa:"\f134"}.fa-cruzeiro-sign{--fa:"\e152"}.fa-greater-than-equal{--fa:"\f532"}.fa-shield-alt,.fa-shield-halved{--fa:"\f3ed"}.fa-atlas,.fa-book-atlas{--fa:"\f558"}.fa-virus{--fa:"\e074"}.fa-envelope-circle-check{--fa:"\e4e8"}.fa-layer-group{--fa:"\f5fd"}.fa-arrows-to-dot{--fa:"\e4be"}.fa-archway{--fa:"\f557"}.fa-heart-circle-check{--fa:"\e4fd"}.fa-house-chimney-crack,.fa-house-damage{--fa:"\f6f1"}.fa-file-archive,.fa-file-zipper{--fa:"\f1c6"}.fa-square{--fa:"\f0c8"}.fa-glass-martini,.fa-martini-glass-empty{--fa:"\f000"}.fa-couch{--fa:"\f4b8"}.fa-cedi-sign{--fa:"\e0df"}.fa-italic{--fa:"\f033"}.fa-table-cells-column-lock{--fa:"\e678"}.fa-church{--fa:"\f51d"}.fa-comments-dollar{--fa:"\f653"}.fa-democrat{--fa:"\f747"}.fa-z{--fa:"\5a"}.fa-person-skiing,.fa-skiing{--fa:"\f7c9"}.fa-road-lock{--fa:"\e567"}.fa-a{--fa:"\41"}.fa-temperature-arrow-down,.fa-temperature-down{--fa:"\e03f"}.fa-feather-alt,.fa-feather-pointed{--fa:"\f56b"}.fa-p{--fa:"\50"}.fa-snowflake{--fa:"\f2dc"}.fa-newspaper{--fa:"\f1ea"}.fa-ad,.fa-rectangle-ad{--fa:"\f641"}.fa-arrow-circle-right,.fa-circle-arrow-right{--fa:"\f0a9"}.fa-filter-circle-xmark{--fa:"\e17b"}.fa-locust{--fa:"\e520"}.fa-sort,.fa-unsorted{--fa:"\f0dc"}.fa-list-1-2,.fa-list-numeric,.fa-list-ol{--fa:"\f0cb"}.fa-person-dress-burst{--fa:"\e544"}.fa-money-check-alt,.fa-money-check-dollar{--fa:"\f53d"}.fa-vector-square{--fa:"\f5cb"}.fa-bread-slice{--fa:"\f7ec"}.fa-language{--fa:"\f1ab"}.fa-face-kiss-wink-heart,.fa-kiss-wink-heart{--fa:"\f598"}.fa-filter{--fa:"\f0b0"}.fa-question{--fa:"\3f"}.fa-file-signature{--fa:"\f573"}.fa-arrows-alt,.fa-up-down-left-right{--fa:"\f0b2"}.fa-house-chimney-user{--fa:"\e065"}.fa-hand-holding-heart{--fa:"\f4be"}.fa-puzzle-piece{--fa:"\f12e"}.fa-money-check{--fa:"\f53c"}.fa-star-half-alt,.fa-star-half-stroke{--fa:"\f5c0"}.fa-code{--fa:"\f121"}.fa-glass-whiskey,.fa-whiskey-glass{--fa:"\f7a0"}.fa-building-circle-exclamation{--fa:"\e4d3"}.fa-magnifying-glass-chart{--fa:"\e522"}.fa-arrow-up-right-from-square,.fa-external-link{--fa:"\f08e"}.fa-cubes-stacked{--fa:"\e4e6"}.fa-krw,.fa-won,.fa-won-sign{--fa:"\f159"}.fa-virus-covid{--fa:"\e4a8"}.fa-austral-sign{--fa:"\e0a9"}.fa-f{--fa:"\46"}.fa-leaf{--fa:"\f06c"}.fa-road{--fa:"\f018"}.fa-cab,.fa-taxi{--fa:"\f1ba"}.fa-person-circle-plus{--fa:"\e541"}.fa-chart-pie,.fa-pie-chart{--fa:"\f200"}.fa-bolt-lightning{--fa:"\e0b7"}.fa-sack-xmark{--fa:"\e56a"}.fa-file-excel{--fa:"\f1c3"}.fa-file-contract{--fa:"\f56c"}.fa-fish-fins{--fa:"\e4f2"}.fa-building-flag{--fa:"\e4d5"}.fa-face-grin-beam,.fa-grin-beam{--fa:"\f582"}.fa-object-ungroup{--fa:"\f248"}.fa-poop{--fa:"\f619"}.fa-location-pin,.fa-map-marker{--fa:"\f041"}.fa-kaaba{--fa:"\f66b"}.fa-toilet-paper{--fa:"\f71e"}.fa-hard-hat,.fa-hat-hard,.fa-helmet-safety{--fa:"\f807"}.fa-eject{--fa:"\f052"}.fa-arrow-alt-circle-right,.fa-circle-right{--fa:"\f35a"}.fa-plane-circle-check{--fa:"\e555"}.fa-face-rolling-eyes,.fa-meh-rolling-eyes{--fa:"\f5a5"}.fa-object-group{--fa:"\f247"}.fa-chart-line,.fa-line-chart{--fa:"\f201"}.fa-mask-ventilator{--fa:"\e524"}.fa-arrow-right{--fa:"\f061"}.fa-map-signs,.fa-signs-post{--fa:"\f277"}.fa-cash-register{--fa:"\f788"}.fa-person-circle-question{--fa:"\e542"}.fa-h{--fa:"\48"}.fa-tarp{--fa:"\e57b"}.fa-screwdriver-wrench,.fa-tools{--fa:"\f7d9"}.fa-arrows-to-eye{--fa:"\e4bf"}.fa-plug-circle-bolt{--fa:"\e55b"}.fa-heart{--fa:"\f004"}.fa-mars-and-venus{--fa:"\f224"}.fa-home-user,.fa-house-user{--fa:"\e1b0"}.fa-dumpster-fire{--fa:"\f794"}.fa-house-crack{--fa:"\e3b1"}.fa-cocktail,.fa-martini-glass-citrus{--fa:"\f561"}.fa-face-surprise,.fa-surprise{--fa:"\f5c2"}.fa-bottle-water{--fa:"\e4c5"}.fa-circle-pause,.fa-pause-circle{--fa:"\f28b"}.fa-toilet-paper-slash{--fa:"\e072"}.fa-apple-alt,.fa-apple-whole{--fa:"\f5d1"}.fa-kitchen-set{--fa:"\e51a"}.fa-r{--fa:"\52"}.fa-temperature-1,.fa-temperature-quarter,.fa-thermometer-1,.fa-thermometer-quarter{--fa:"\f2ca"}.fa-cube{--fa:"\f1b2"}.fa-bitcoin-sign{--fa:"\e0b4"}.fa-shield-dog{--fa:"\e573"}.fa-solar-panel{--fa:"\f5ba"}.fa-lock-open{--fa:"\f3c1"}.fa-elevator{--fa:"\e16d"}.fa-money-bill-transfer{--fa:"\e528"}.fa-money-bill-trend-up{--fa:"\e529"}.fa-house-flood-water-circle-arrow-right{--fa:"\e50f"}.fa-poll-h,.fa-square-poll-horizontal{--fa:"\f682"}.fa-circle{--fa:"\f111"}.fa-backward-fast,.fa-fast-backward{--fa:"\f049"}.fa-recycle{--fa:"\f1b8"}.fa-user-astronaut{--fa:"\f4fb"}.fa-plane-slash{--fa:"\e069"}.fa-trademark{--fa:"\f25c"}.fa-basketball,.fa-basketball-ball{--fa:"\f434"}.fa-satellite-dish{--fa:"\f7c0"}.fa-arrow-alt-circle-up,.fa-circle-up{--fa:"\f35b"}.fa-mobile-alt,.fa-mobile-screen-button{--fa:"\f3cd"}.fa-volume-high,.fa-volume-up{--fa:"\f028"}.fa-users-rays{--fa:"\e593"}.fa-wallet{--fa:"\f555"}.fa-clipboard-check{--fa:"\f46c"}.fa-file-audio{--fa:"\f1c7"}.fa-burger,.fa-hamburger{--fa:"\f805"}.fa-wrench{--fa:"\f0ad"}.fa-bugs{--fa:"\e4d0"}.fa-rupee,.fa-rupee-sign{--fa:"\f156"}.fa-file-image{--fa:"\f1c5"}.fa-circle-question,.fa-question-circle{--fa:"\f059"}.fa-plane-departure{--fa:"\f5b0"}.fa-handshake-slash{--fa:"\e060"}.fa-book-bookmark{--fa:"\e0bb"}.fa-code-branch{--fa:"\f126"}.fa-hat-cowboy{--fa:"\f8c0"}.fa-bridge{--fa:"\e4c8"}.fa-phone-alt,.fa-phone-flip{--fa:"\f879"}.fa-truck-front{--fa:"\e2b7"}.fa-cat{--fa:"\f6be"}.fa-anchor-circle-exclamation{--fa:"\e4ab"}.fa-truck-field{--fa:"\e58d"}.fa-route{--fa:"\f4d7"}.fa-clipboard-question{--fa:"\e4e3"}.fa-panorama{--fa:"\e209"}.fa-comment-medical{--fa:"\f7f5"}.fa-teeth-open{--fa:"\f62f"}.fa-file-circle-minus{--fa:"\e4ed"}.fa-tags{--fa:"\f02c"}.fa-wine-glass{--fa:"\f4e3"}.fa-fast-forward,.fa-forward-fast{--fa:"\f050"}.fa-face-meh-blank,.fa-meh-blank{--fa:"\f5a4"}.fa-parking,.fa-square-parking{--fa:"\f540"}.fa-house-signal{--fa:"\e012"}.fa-bars-progress,.fa-tasks-alt{--fa:"\f828"}.fa-faucet-drip{--fa:"\e006"}.fa-cart-flatbed,.fa-dolly-flatbed{--fa:"\f474"}.fa-ban-smoking,.fa-smoking-ban{--fa:"\f54d"}.fa-terminal{--fa:"\f120"}.fa-mobile-button{--fa:"\f10b"}.fa-house-medical-flag{--fa:"\e514"}.fa-basket-shopping,.fa-shopping-basket{--fa:"\f291"}.fa-tape{--fa:"\f4db"}.fa-bus-alt,.fa-bus-simple{--fa:"\f55e"}.fa-eye{--fa:"\f06e"}.fa-face-sad-cry,.fa-sad-cry{--fa:"\f5b3"}.fa-audio-description{--fa:"\f29e"}.fa-person-military-to-person{--fa:"\e54c"}.fa-file-shield{--fa:"\e4f0"}.fa-user-slash{--fa:"\f506"}.fa-pen{--fa:"\f304"}.fa-tower-observation{--fa:"\e586"}.fa-file-code{--fa:"\f1c9"}.fa-signal,.fa-signal-5,.fa-signal-perfect{--fa:"\f012"}.fa-bus{--fa:"\f207"}.fa-heart-circle-xmark{--fa:"\e501"}.fa-home-lg,.fa-house-chimney{--fa:"\e3af"}.fa-window-maximize{--fa:"\f2d0"}.fa-face-frown,.fa-frown{--fa:"\f119"}.fa-prescription{--fa:"\f5b1"}.fa-shop,.fa-store-alt{--fa:"\f54f"}.fa-floppy-disk,.fa-save{--fa:"\f0c7"}.fa-vihara{--fa:"\f6a7"}.fa-balance-scale-left,.fa-scale-unbalanced{--fa:"\f515"}.fa-sort-asc,.fa-sort-up{--fa:"\f0de"}.fa-comment-dots,.fa-commenting{--fa:"\f4ad"}.fa-plant-wilt{--fa:"\e5aa"}.fa-diamond{--fa:"\f219"}.fa-face-grin-squint,.fa-grin-squint{--fa:"\f585"}.fa-hand-holding-dollar,.fa-hand-holding-usd{--fa:"\f4c0"}.fa-chart-diagram{--fa:"\e695"}.fa-bacterium{--fa:"\e05a"}.fa-hand-pointer{--fa:"\f25a"}.fa-drum-steelpan{--fa:"\f56a"}.fa-hand-scissors{--fa:"\f257"}.fa-hands-praying,.fa-praying-hands{--fa:"\f684"}.fa-arrow-right-rotate,.fa-arrow-rotate-forward,.fa-arrow-rotate-right,.fa-redo{--fa:"\f01e"}.fa-biohazard{--fa:"\f780"}.fa-location,.fa-location-crosshairs{--fa:"\f601"}.fa-mars-double{--fa:"\f227"}.fa-child-dress{--fa:"\e59c"}.fa-users-between-lines{--fa:"\e591"}.fa-lungs-virus{--fa:"\e067"}.fa-face-grin-tears,.fa-grin-tears{--fa:"\f588"}.fa-phone{--fa:"\f095"}.fa-calendar-times,.fa-calendar-xmark{--fa:"\f273"}.fa-child-reaching{--fa:"\e59d"}.fa-head-side-virus{--fa:"\e064"}.fa-user-cog,.fa-user-gear{--fa:"\f4fe"}.fa-arrow-up-1-9,.fa-sort-numeric-up{--fa:"\f163"}.fa-door-closed{--fa:"\f52a"}.fa-shield-virus{--fa:"\e06c"}.fa-dice-six{--fa:"\f526"}.fa-mosquito-net{--fa:"\e52c"}.fa-file-fragment{--fa:"\e697"}.fa-bridge-water{--fa:"\e4ce"}.fa-person-booth{--fa:"\f756"}.fa-text-width{--fa:"\f035"}.fa-hat-wizard{--fa:"\f6e8"}.fa-pen-fancy{--fa:"\f5ac"}.fa-digging,.fa-person-digging{--fa:"\f85e"}.fa-trash{--fa:"\f1f8"}.fa-gauge-simple,.fa-gauge-simple-med,.fa-tachometer-average{--fa:"\f629"}.fa-book-medical{--fa:"\f7e6"}.fa-poo{--fa:"\f2fe"}.fa-quote-right,.fa-quote-right-alt{--fa:"\f10e"}.fa-shirt,.fa-t-shirt,.fa-tshirt{--fa:"\f553"}.fa-cubes{--fa:"\f1b3"}.fa-divide{--fa:"\f529"}.fa-tenge,.fa-tenge-sign{--fa:"\f7d7"}.fa-headphones{--fa:"\f025"}.fa-hands-holding{--fa:"\f4c2"}.fa-hands-clapping{--fa:"\e1a8"}.fa-republican{--fa:"\f75e"}.fa-arrow-left{--fa:"\f060"}.fa-person-circle-xmark{--fa:"\e543"}.fa-ruler{--fa:"\f545"}.fa-align-left{--fa:"\f036"}.fa-dice-d6{--fa:"\f6d1"}.fa-restroom{--fa:"\f7bd"}.fa-j{--fa:"\4a"}.fa-users-viewfinder{--fa:"\e595"}.fa-file-video{--fa:"\f1c8"}.fa-external-link-alt,.fa-up-right-from-square{--fa:"\f35d"}.fa-table-cells,.fa-th{--fa:"\f00a"}.fa-file-pdf{--fa:"\f1c1"}.fa-bible,.fa-book-bible{--fa:"\f647"}.fa-o{--fa:"\4f"}.fa-medkit,.fa-suitcase-medical{--fa:"\f0fa"}.fa-user-secret{--fa:"\f21b"}.fa-otter{--fa:"\f700"}.fa-female,.fa-person-dress{--fa:"\f182"}.fa-comment-dollar{--fa:"\f651"}.fa-briefcase-clock,.fa-business-time{--fa:"\f64a"}.fa-table-cells-large,.fa-th-large{--fa:"\f009"}.fa-book-tanakh,.fa-tanakh{--fa:"\f827"}.fa-phone-volume,.fa-volume-control-phone{--fa:"\f2a0"}.fa-hat-cowboy-side{--fa:"\f8c1"}.fa-clipboard-user{--fa:"\f7f3"}.fa-child{--fa:"\f1ae"}.fa-lira-sign{--fa:"\f195"}.fa-satellite{--fa:"\f7bf"}.fa-plane-lock{--fa:"\e558"}.fa-tag{--fa:"\f02b"}.fa-comment{--fa:"\f075"}.fa-birthday-cake,.fa-cake,.fa-cake-candles{--fa:"\f1fd"}.fa-envelope{--fa:"\f0e0"}.fa-angle-double-up,.fa-angles-up{--fa:"\f102"}.fa-paperclip{--fa:"\f0c6"}.fa-arrow-right-to-city{--fa:"\e4b3"}.fa-ribbon{--fa:"\f4d6"}.fa-lungs{--fa:"\f604"}.fa-arrow-up-9-1,.fa-sort-numeric-up-alt{--fa:"\f887"}.fa-litecoin-sign{--fa:"\e1d3"}.fa-border-none{--fa:"\f850"}.fa-circle-nodes{--fa:"\e4e2"}.fa-parachute-box{--fa:"\f4cd"}.fa-indent{--fa:"\f03c"}.fa-truck-field-un{--fa:"\e58e"}.fa-hourglass,.fa-hourglass-empty{--fa:"\f254"}.fa-mountain{--fa:"\f6fc"}.fa-user-doctor,.fa-user-md{--fa:"\f0f0"}.fa-circle-info,.fa-info-circle{--fa:"\f05a"}.fa-cloud-meatball{--fa:"\f73b"}.fa-camera,.fa-camera-alt{--fa:"\f030"}.fa-square-virus{--fa:"\e578"}.fa-meteor{--fa:"\f753"}.fa-car-on{--fa:"\e4dd"}.fa-sleigh{--fa:"\f7cc"}.fa-arrow-down-1-9,.fa-sort-numeric-asc,.fa-sort-numeric-down{--fa:"\f162"}.fa-hand-holding-droplet,.fa-hand-holding-water{--fa:"\f4c1"}.fa-water{--fa:"\f773"}.fa-calendar-check{--fa:"\f274"}.fa-braille{--fa:"\f2a1"}.fa-prescription-bottle-alt,.fa-prescription-bottle-medical{--fa:"\f486"}.fa-landmark{--fa:"\f66f"}.fa-truck{--fa:"\f0d1"}.fa-crosshairs{--fa:"\f05b"}.fa-person-cane{--fa:"\e53c"}.fa-tent{--fa:"\e57d"}.fa-vest-patches{--fa:"\e086"}.fa-check-double{--fa:"\f560"}.fa-arrow-down-a-z,.fa-sort-alpha-asc,.fa-sort-alpha-down{--fa:"\f15d"}.fa-money-bill-wheat{--fa:"\e52a"}.fa-cookie{--fa:"\f563"}.fa-arrow-left-rotate,.fa-arrow-rotate-back,.fa-arrow-rotate-backward,.fa-arrow-rotate-left,.fa-undo{--fa:"\f0e2"}.fa-hard-drive,.fa-hdd{--fa:"\f0a0"}.fa-face-grin-squint-tears,.fa-grin-squint-tears{--fa:"\f586"}.fa-dumbbell{--fa:"\f44b"}.fa-list-alt,.fa-rectangle-list{--fa:"\f022"}.fa-tarp-droplet{--fa:"\e57c"}.fa-house-medical-circle-check{--fa:"\e511"}.fa-person-skiing-nordic,.fa-skiing-nordic{--fa:"\f7ca"}.fa-calendar-plus{--fa:"\f271"}.fa-plane-arrival{--fa:"\f5af"}.fa-arrow-alt-circle-left,.fa-circle-left{--fa:"\f359"}.fa-subway,.fa-train-subway{--fa:"\f239"}.fa-chart-gantt{--fa:"\e0e4"}.fa-indian-rupee,.fa-indian-rupee-sign,.fa-inr{--fa:"\e1bc"}.fa-crop-alt,.fa-crop-simple{--fa:"\f565"}.fa-money-bill-1,.fa-money-bill-alt{--fa:"\f3d1"}.fa-left-long,.fa-long-arrow-alt-left{--fa:"\f30a"}.fa-dna{--fa:"\f471"}.fa-virus-slash{--fa:"\e075"}.fa-minus,.fa-subtract{--fa:"\f068"}.fa-chess{--fa:"\f439"}.fa-arrow-left-long,.fa-long-arrow-left{--fa:"\f177"}.fa-plug-circle-check{--fa:"\e55c"}.fa-street-view{--fa:"\f21d"}.fa-franc-sign{--fa:"\e18f"}.fa-volume-off{--fa:"\f026"}.fa-american-sign-language-interpreting,.fa-asl-interpreting,.fa-hands-american-sign-language-interpreting,.fa-hands-asl-interpreting{--fa:"\f2a3"}.fa-cog,.fa-gear{--fa:"\f013"}.fa-droplet-slash,.fa-tint-slash{--fa:"\f5c7"}.fa-mosque{--fa:"\f678"}.fa-mosquito{--fa:"\e52b"}.fa-star-of-david{--fa:"\f69a"}.fa-person-military-rifle{--fa:"\e54b"}.fa-cart-shopping,.fa-shopping-cart{--fa:"\f07a"}.fa-vials{--fa:"\f493"}.fa-plug-circle-plus{--fa:"\e55f"}.fa-place-of-worship{--fa:"\f67f"}.fa-grip-vertical{--fa:"\f58e"}.fa-hexagon-nodes{--fa:"\e699"}.fa-arrow-turn-up,.fa-level-up{--fa:"\f148"}.fa-u{--fa:"\55"}.fa-square-root-alt,.fa-square-root-variable{--fa:"\f698"}.fa-clock,.fa-clock-four{--fa:"\f017"}.fa-backward-step,.fa-step-backward{--fa:"\f048"}.fa-pallet{--fa:"\f482"}.fa-faucet{--fa:"\e005"}.fa-baseball-bat-ball{--fa:"\f432"}.fa-s{--fa:"\53"}.fa-timeline{--fa:"\e29c"}.fa-keyboard{--fa:"\f11c"}.fa-caret-down{--fa:"\f0d7"}.fa-clinic-medical,.fa-house-chimney-medical{--fa:"\f7f2"}.fa-temperature-3,.fa-temperature-three-quarters,.fa-thermometer-3,.fa-thermometer-three-quarters{--fa:"\f2c8"}.fa-mobile-android-alt,.fa-mobile-screen{--fa:"\f3cf"}.fa-plane-up{--fa:"\e22d"}.fa-piggy-bank{--fa:"\f4d3"}.fa-battery-3,.fa-battery-half{--fa:"\f242"}.fa-mountain-city{--fa:"\e52e"}.fa-coins{--fa:"\f51e"}.fa-khanda{--fa:"\f66d"}.fa-sliders,.fa-sliders-h{--fa:"\f1de"}.fa-folder-tree{--fa:"\f802"}.fa-network-wired{--fa:"\f6ff"}.fa-map-pin{--fa:"\f276"}.fa-hamsa{--fa:"\f665"}.fa-cent-sign{--fa:"\e3f5"}.fa-flask{--fa:"\f0c3"}.fa-person-pregnant{--fa:"\e31e"}.fa-wand-sparkles{--fa:"\f72b"}.fa-ellipsis-v,.fa-ellipsis-vertical{--fa:"\f142"}.fa-ticket{--fa:"\f145"}.fa-power-off{--fa:"\f011"}.fa-long-arrow-alt-right,.fa-right-long{--fa:"\f30b"}.fa-flag-usa{--fa:"\f74d"}.fa-laptop-file{--fa:"\e51d"}.fa-teletype,.fa-tty{--fa:"\f1e4"}.fa-diagram-next{--fa:"\e476"}.fa-person-rifle{--fa:"\e54e"}.fa-house-medical-circle-exclamation{--fa:"\e512"}.fa-closed-captioning{--fa:"\f20a"}.fa-hiking,.fa-person-hiking{--fa:"\f6ec"}.fa-venus-double{--fa:"\f226"}.fa-images{--fa:"\f302"}.fa-calculator{--fa:"\f1ec"}.fa-people-pulling{--fa:"\e535"}.fa-n{--fa:"\4e"}.fa-cable-car,.fa-tram{--fa:"\f7da"}.fa-cloud-rain{--fa:"\f73d"}.fa-building-circle-xmark{--fa:"\e4d4"}.fa-ship{--fa:"\f21a"}.fa-arrows-down-to-line{--fa:"\e4b8"}.fa-download{--fa:"\f019"}.fa-face-grin,.fa-grin{--fa:"\f580"}.fa-backspace,.fa-delete-left{--fa:"\f55a"}.fa-eye-dropper,.fa-eye-dropper-empty,.fa-eyedropper{--fa:"\f1fb"}.fa-file-circle-check{--fa:"\e5a0"}.fa-forward{--fa:"\f04e"}.fa-mobile,.fa-mobile-android,.fa-mobile-phone{--fa:"\f3ce"}.fa-face-meh,.fa-meh{--fa:"\f11a"}.fa-align-center{--fa:"\f037"}.fa-book-dead,.fa-book-skull{--fa:"\f6b7"}.fa-drivers-license,.fa-id-card{--fa:"\f2c2"}.fa-dedent,.fa-outdent{--fa:"\f03b"}.fa-heart-circle-exclamation{--fa:"\e4fe"}.fa-home,.fa-home-alt,.fa-home-lg-alt,.fa-house{--fa:"\f015"}.fa-calendar-week{--fa:"\f784"}.fa-laptop-medical{--fa:"\f812"}.fa-b{--fa:"\42"}.fa-file-medical{--fa:"\f477"}.fa-dice-one{--fa:"\f525"}.fa-kiwi-bird{--fa:"\f535"}.fa-arrow-right-arrow-left,.fa-exchange{--fa:"\f0ec"}.fa-redo-alt,.fa-rotate-forward,.fa-rotate-right{--fa:"\f2f9"}.fa-cutlery,.fa-utensils{--fa:"\f2e7"}.fa-arrow-up-wide-short,.fa-sort-amount-up{--fa:"\f161"}.fa-mill-sign{--fa:"\e1ed"}.fa-bowl-rice{--fa:"\e2eb"}.fa-skull{--fa:"\f54c"}.fa-broadcast-tower,.fa-tower-broadcast{--fa:"\f519"}.fa-truck-pickup{--fa:"\f63c"}.fa-long-arrow-alt-up,.fa-up-long{--fa:"\f30c"}.fa-stop{--fa:"\f04d"}.fa-code-merge{--fa:"\f387"}.fa-upload{--fa:"\f093"}.fa-hurricane{--fa:"\f751"}.fa-mound{--fa:"\e52d"}.fa-toilet-portable{--fa:"\e583"}.fa-compact-disc{--fa:"\f51f"}.fa-file-arrow-down,.fa-file-download{--fa:"\f56d"}.fa-caravan{--fa:"\f8ff"}.fa-shield-cat{--fa:"\e572"}.fa-bolt,.fa-zap{--fa:"\f0e7"}.fa-glass-water{--fa:"\e4f4"}.fa-oil-well{--fa:"\e532"}.fa-vault{--fa:"\e2c5"}.fa-mars{--fa:"\f222"}.fa-toilet{--fa:"\f7d8"}.fa-plane-circle-xmark{--fa:"\e557"}.fa-cny,.fa-jpy,.fa-rmb,.fa-yen,.fa-yen-sign{--fa:"\f157"}.fa-rouble,.fa-rub,.fa-ruble,.fa-ruble-sign{--fa:"\f158"}.fa-sun{--fa:"\f185"}.fa-guitar{--fa:"\f7a6"}.fa-face-laugh-wink,.fa-laugh-wink{--fa:"\f59c"}.fa-horse-head{--fa:"\f7ab"}.fa-bore-hole{--fa:"\e4c3"}.fa-industry{--fa:"\f275"}.fa-arrow-alt-circle-down,.fa-circle-down{--fa:"\f358"}.fa-arrows-turn-to-dots{--fa:"\e4c1"}.fa-florin-sign{--fa:"\e184"}.fa-arrow-down-short-wide,.fa-sort-amount-desc,.fa-sort-amount-down-alt{--fa:"\f884"}.fa-less-than{--fa:"\3c"}.fa-angle-down{--fa:"\f107"}.fa-car-tunnel{--fa:"\e4de"}.fa-head-side-cough{--fa:"\e061"}.fa-grip-lines{--fa:"\f7a4"}.fa-thumbs-down{--fa:"\f165"}.fa-user-lock{--fa:"\f502"}.fa-arrow-right-long,.fa-long-arrow-right{--fa:"\f178"}.fa-anchor-circle-xmark{--fa:"\e4ac"}.fa-ellipsis,.fa-ellipsis-h{--fa:"\f141"}.fa-chess-pawn{--fa:"\f443"}.fa-first-aid,.fa-kit-medical{--fa:"\f479"}.fa-person-through-window{--fa:"\e5a9"}.fa-toolbox{--fa:"\f552"}.fa-hands-holding-circle{--fa:"\e4fb"}.fa-bug{--fa:"\f188"}.fa-credit-card,.fa-credit-card-alt{--fa:"\f09d"}.fa-automobile,.fa-car{--fa:"\f1b9"}.fa-hand-holding-hand{--fa:"\e4f7"}.fa-book-open-reader,.fa-book-reader{--fa:"\f5da"}.fa-mountain-sun{--fa:"\e52f"}.fa-arrows-left-right-to-line{--fa:"\e4ba"}.fa-dice-d20{--fa:"\f6cf"}.fa-truck-droplet{--fa:"\e58c"}.fa-file-circle-xmark{--fa:"\e5a1"}.fa-temperature-arrow-up,.fa-temperature-up{--fa:"\e040"}.fa-medal{--fa:"\f5a2"}.fa-bed{--fa:"\f236"}.fa-h-square,.fa-square-h{--fa:"\f0fd"}.fa-podcast{--fa:"\f2ce"}.fa-temperature-4,.fa-temperature-full,.fa-thermometer-4,.fa-thermometer-full{--fa:"\f2c7"}.fa-bell{--fa:"\f0f3"}.fa-superscript{--fa:"\f12b"}.fa-plug-circle-xmark{--fa:"\e560"}.fa-star-of-life{--fa:"\f621"}.fa-phone-slash{--fa:"\f3dd"}.fa-paint-roller{--fa:"\f5aa"}.fa-hands-helping,.fa-handshake-angle{--fa:"\f4c4"}.fa-location-dot,.fa-map-marker-alt{--fa:"\f3c5"}.fa-file{--fa:"\f15b"}.fa-greater-than{--fa:"\3e"}.fa-person-swimming,.fa-swimmer{--fa:"\f5c4"}.fa-arrow-down{--fa:"\f063"}.fa-droplet,.fa-tint{--fa:"\f043"}.fa-eraser{--fa:"\f12d"}.fa-earth,.fa-earth-america,.fa-earth-americas,.fa-globe-americas{--fa:"\f57d"}.fa-person-burst{--fa:"\e53b"}.fa-dove{--fa:"\f4ba"}.fa-battery-0,.fa-battery-empty{--fa:"\f244"}.fa-socks{--fa:"\f696"}.fa-inbox{--fa:"\f01c"}.fa-section{--fa:"\e447"}.fa-gauge-high,.fa-tachometer-alt,.fa-tachometer-alt-fast{--fa:"\f625"}.fa-envelope-open-text{--fa:"\f658"}.fa-hospital,.fa-hospital-alt,.fa-hospital-wide{--fa:"\f0f8"}.fa-wine-bottle{--fa:"\f72f"}.fa-chess-rook{--fa:"\f447"}.fa-bars-staggered,.fa-reorder,.fa-stream{--fa:"\f550"}.fa-dharmachakra{--fa:"\f655"}.fa-hotdog{--fa:"\f80f"}.fa-blind,.fa-person-walking-with-cane{--fa:"\f29d"}.fa-drum{--fa:"\f569"}.fa-ice-cream{--fa:"\f810"}.fa-heart-circle-bolt{--fa:"\e4fc"}.fa-fax{--fa:"\f1ac"}.fa-paragraph{--fa:"\f1dd"}.fa-check-to-slot,.fa-vote-yea{--fa:"\f772"}.fa-star-half{--fa:"\f089"}.fa-boxes,.fa-boxes-alt,.fa-boxes-stacked{--fa:"\f468"}.fa-chain,.fa-link{--fa:"\f0c1"}.fa-assistive-listening-systems,.fa-ear-listen{--fa:"\f2a2"}.fa-tree-city{--fa:"\e587"}.fa-play{--fa:"\f04b"}.fa-font{--fa:"\f031"}.fa-table-cells-row-lock{--fa:"\e67a"}.fa-rupiah-sign{--fa:"\e23d"}.fa-magnifying-glass,.fa-search{--fa:"\f002"}.fa-ping-pong-paddle-ball,.fa-table-tennis,.fa-table-tennis-paddle-ball{--fa:"\f45d"}.fa-diagnoses,.fa-person-dots-from-line{--fa:"\f470"}.fa-trash-can-arrow-up,.fa-trash-restore-alt{--fa:"\f82a"}.fa-naira-sign{--fa:"\e1f6"}.fa-cart-arrow-down{--fa:"\f218"}.fa-walkie-talkie{--fa:"\f8ef"}.fa-file-edit,.fa-file-pen{--fa:"\f31c"}.fa-receipt{--fa:"\f543"}.fa-pen-square,.fa-pencil-square,.fa-square-pen{--fa:"\f14b"}.fa-suitcase-rolling{--fa:"\f5c1"}.fa-person-circle-exclamation{--fa:"\e53f"}.fa-chevron-down{--fa:"\f078"}.fa-battery,.fa-battery-5,.fa-battery-full{--fa:"\f240"}.fa-skull-crossbones{--fa:"\f714"}.fa-code-compare{--fa:"\e13a"}.fa-list-dots,.fa-list-ul{--fa:"\f0ca"}.fa-school-lock{--fa:"\e56f"}.fa-tower-cell{--fa:"\e585"}.fa-down-long,.fa-long-arrow-alt-down{--fa:"\f309"}.fa-ranking-star{--fa:"\e561"}.fa-chess-king{--fa:"\f43f"}.fa-person-harassing{--fa:"\e549"}.fa-brazilian-real-sign{--fa:"\e46c"}.fa-landmark-alt,.fa-landmark-dome{--fa:"\f752"}.fa-arrow-up{--fa:"\f062"}.fa-television,.fa-tv,.fa-tv-alt{--fa:"\f26c"}.fa-shrimp{--fa:"\e448"}.fa-list-check,.fa-tasks{--fa:"\f0ae"}.fa-jug-detergent{--fa:"\e519"}.fa-circle-user,.fa-user-circle{--fa:"\f2bd"}.fa-user-shield{--fa:"\f505"}.fa-wind{--fa:"\f72e"}.fa-car-burst,.fa-car-crash{--fa:"\f5e1"}.fa-y{--fa:"\59"}.fa-person-snowboarding,.fa-snowboarding{--fa:"\f7ce"}.fa-shipping-fast,.fa-truck-fast{--fa:"\f48b"}.fa-fish{--fa:"\f578"}.fa-user-graduate{--fa:"\f501"}.fa-adjust,.fa-circle-half-stroke{--fa:"\f042"}.fa-clapperboard{--fa:"\e131"}.fa-circle-radiation,.fa-radiation-alt{--fa:"\f7ba"}.fa-baseball,.fa-baseball-ball{--fa:"\f433"}.fa-jet-fighter-up{--fa:"\e518"}.fa-diagram-project,.fa-project-diagram{--fa:"\f542"}.fa-copy{--fa:"\f0c5"}.fa-volume-mute,.fa-volume-times,.fa-volume-xmark{--fa:"\f6a9"}.fa-hand-sparkles{--fa:"\e05d"}.fa-grip,.fa-grip-horizontal{--fa:"\f58d"}.fa-share-from-square,.fa-share-square{--fa:"\f14d"}.fa-child-combatant,.fa-child-rifle{--fa:"\e4e0"}.fa-gun{--fa:"\e19b"}.fa-phone-square,.fa-square-phone{--fa:"\f098"}.fa-add,.fa-plus{--fa:"\2b"}.fa-expand{--fa:"\f065"}.fa-computer{--fa:"\e4e5"}.fa-close,.fa-multiply,.fa-remove,.fa-times,.fa-xmark{--fa:"\f00d"}.fa-arrows,.fa-arrows-up-down-left-right{--fa:"\f047"}.fa-chalkboard-teacher,.fa-chalkboard-user{--fa:"\f51c"}.fa-peso-sign{--fa:"\e222"}.fa-building-shield{--fa:"\e4d8"}.fa-baby{--fa:"\f77c"}.fa-users-line{--fa:"\e592"}.fa-quote-left,.fa-quote-left-alt{--fa:"\f10d"}.fa-tractor{--fa:"\f722"}.fa-trash-arrow-up,.fa-trash-restore{--fa:"\f829"}.fa-arrow-down-up-lock{--fa:"\e4b0"}.fa-lines-leaning{--fa:"\e51e"}.fa-ruler-combined{--fa:"\f546"}.fa-copyright{--fa:"\f1f9"}.fa-equals{--fa:"\3d"}.fa-blender{--fa:"\f517"}.fa-teeth{--fa:"\f62e"}.fa-ils,.fa-shekel,.fa-shekel-sign,.fa-sheqel,.fa-sheqel-sign{--fa:"\f20b"}.fa-map{--fa:"\f279"}.fa-rocket{--fa:"\f135"}.fa-photo-film,.fa-photo-video{--fa:"\f87c"}.fa-folder-minus{--fa:"\f65d"}.fa-hexagon-nodes-bolt{--fa:"\e69a"}.fa-store{--fa:"\f54e"}.fa-arrow-trend-up{--fa:"\e098"}.fa-plug-circle-minus{--fa:"\e55e"}.fa-sign,.fa-sign-hanging{--fa:"\f4d9"}.fa-bezier-curve{--fa:"\f55b"}.fa-bell-slash{--fa:"\f1f6"}.fa-tablet,.fa-tablet-android{--fa:"\f3fb"}.fa-school-flag{--fa:"\e56e"}.fa-fill{--fa:"\f575"}.fa-angle-up{--fa:"\f106"}.fa-drumstick-bite{--fa:"\f6d7"}.fa-holly-berry{--fa:"\f7aa"}.fa-chevron-left{--fa:"\f053"}.fa-bacteria{--fa:"\e059"}.fa-hand-lizard{--fa:"\f258"}.fa-notdef{--fa:"\e1fe"}.fa-disease{--fa:"\f7fa"}.fa-briefcase-medical{--fa:"\f469"}.fa-genderless{--fa:"\f22d"}.fa-chevron-right{--fa:"\f054"}.fa-retweet{--fa:"\f079"}.fa-car-alt,.fa-car-rear{--fa:"\f5de"}.fa-pump-soap{--fa:"\e06b"}.fa-video-slash{--fa:"\f4e2"}.fa-battery-2,.fa-battery-quarter{--fa:"\f243"}.fa-radio{--fa:"\f8d7"}.fa-baby-carriage,.fa-carriage-baby{--fa:"\f77d"}.fa-traffic-light{--fa:"\f637"}.fa-thermometer{--fa:"\f491"}.fa-vr-cardboard{--fa:"\f729"}.fa-hand-middle-finger{--fa:"\f806"}.fa-percent,.fa-percentage{--fa:"\25"}.fa-truck-moving{--fa:"\f4df"}.fa-glass-water-droplet{--fa:"\e4f5"}.fa-display{--fa:"\e163"}.fa-face-smile,.fa-smile{--fa:"\f118"}.fa-thumb-tack,.fa-thumbtack{--fa:"\f08d"}.fa-trophy{--fa:"\f091"}.fa-person-praying,.fa-pray{--fa:"\f683"}.fa-hammer{--fa:"\f6e3"}.fa-hand-peace{--fa:"\f25b"}.fa-rotate,.fa-sync-alt{--fa:"\f2f1"}.fa-spinner{--fa:"\f110"}.fa-robot{--fa:"\f544"}.fa-peace{--fa:"\f67c"}.fa-cogs,.fa-gears{--fa:"\f085"}.fa-warehouse{--fa:"\f494"}.fa-arrow-up-right-dots{--fa:"\e4b7"}.fa-splotch{--fa:"\f5bc"}.fa-face-grin-hearts,.fa-grin-hearts{--fa:"\f584"}.fa-dice-four{--fa:"\f524"}.fa-sim-card{--fa:"\f7c4"}.fa-transgender,.fa-transgender-alt{--fa:"\f225"}.fa-mercury{--fa:"\f223"}.fa-arrow-turn-down,.fa-level-down{--fa:"\f149"}.fa-person-falling-burst{--fa:"\e547"}.fa-award{--fa:"\f559"}.fa-ticket-alt,.fa-ticket-simple{--fa:"\f3ff"}.fa-building{--fa:"\f1ad"}.fa-angle-double-left,.fa-angles-left{--fa:"\f100"}.fa-qrcode{--fa:"\f029"}.fa-clock-rotate-left,.fa-history{--fa:"\f1da"}.fa-face-grin-beam-sweat,.fa-grin-beam-sweat{--fa:"\f583"}.fa-arrow-right-from-file,.fa-file-export{--fa:"\f56e"}.fa-shield,.fa-shield-blank{--fa:"\f132"}.fa-arrow-up-short-wide,.fa-sort-amount-up-alt{--fa:"\f885"}.fa-comment-nodes{--fa:"\e696"}.fa-house-medical{--fa:"\e3b2"}.fa-golf-ball,.fa-golf-ball-tee{--fa:"\f450"}.fa-chevron-circle-left,.fa-circle-chevron-left{--fa:"\f137"}.fa-house-chimney-window{--fa:"\e00d"}.fa-pen-nib{--fa:"\f5ad"}.fa-tent-arrow-turn-left{--fa:"\e580"}.fa-tents{--fa:"\e582"}.fa-magic,.fa-wand-magic{--fa:"\f0d0"}.fa-dog{--fa:"\f6d3"}.fa-carrot{--fa:"\f787"}.fa-moon{--fa:"\f186"}.fa-wine-glass-alt,.fa-wine-glass-empty{--fa:"\f5ce"}.fa-cheese{--fa:"\f7ef"}.fa-yin-yang{--fa:"\f6ad"}.fa-music{--fa:"\f001"}.fa-code-commit{--fa:"\f386"}.fa-temperature-low{--fa:"\f76b"}.fa-biking,.fa-person-biking{--fa:"\f84a"}.fa-broom{--fa:"\f51a"}.fa-shield-heart{--fa:"\e574"}.fa-gopuram{--fa:"\f664"}.fa-earth-oceania,.fa-globe-oceania{--fa:"\e47b"}.fa-square-xmark,.fa-times-square,.fa-xmark-square{--fa:"\f2d3"}.fa-hashtag{--fa:"\23"}.fa-expand-alt,.fa-up-right-and-down-left-from-center{--fa:"\f424"}.fa-oil-can{--fa:"\f613"}.fa-t{--fa:"\54"}.fa-hippo{--fa:"\f6ed"}.fa-chart-column{--fa:"\e0e3"}.fa-infinity{--fa:"\f534"}.fa-vial-circle-check{--fa:"\e596"}.fa-person-arrow-down-to-line{--fa:"\e538"}.fa-voicemail{--fa:"\f897"}.fa-fan{--fa:"\f863"}.fa-person-walking-luggage{--fa:"\e554"}.fa-arrows-alt-v,.fa-up-down{--fa:"\f338"}.fa-cloud-moon-rain{--fa:"\f73c"}.fa-calendar{--fa:"\f133"}.fa-trailer{--fa:"\e041"}.fa-bahai,.fa-haykal{--fa:"\f666"}.fa-sd-card{--fa:"\f7c2"}.fa-dragon{--fa:"\f6d5"}.fa-shoe-prints{--fa:"\f54b"}.fa-circle-plus,.fa-plus-circle{--fa:"\f055"}.fa-face-grin-tongue-wink,.fa-grin-tongue-wink{--fa:"\f58b"}.fa-hand-holding{--fa:"\f4bd"}.fa-plug-circle-exclamation{--fa:"\e55d"}.fa-chain-broken,.fa-chain-slash,.fa-link-slash,.fa-unlink{--fa:"\f127"}.fa-clone{--fa:"\f24d"}.fa-person-walking-arrow-loop-left{--fa:"\e551"}.fa-arrow-up-z-a,.fa-sort-alpha-up-alt{--fa:"\f882"}.fa-fire-alt,.fa-fire-flame-curved{--fa:"\f7e4"}.fa-tornado{--fa:"\f76f"}.fa-file-circle-plus{--fa:"\e494"}.fa-book-quran,.fa-quran{--fa:"\f687"}.fa-anchor{--fa:"\f13d"}.fa-border-all{--fa:"\f84c"}.fa-angry,.fa-face-angry{--fa:"\f556"}.fa-cookie-bite{--fa:"\f564"}.fa-arrow-trend-down{--fa:"\e097"}.fa-feed,.fa-rss{--fa:"\f09e"}.fa-draw-polygon{--fa:"\f5ee"}.fa-balance-scale,.fa-scale-balanced{--fa:"\f24e"}.fa-gauge-simple-high,.fa-tachometer,.fa-tachometer-fast{--fa:"\f62a"}.fa-shower{--fa:"\f2cc"}.fa-desktop,.fa-desktop-alt{--fa:"\f390"}.fa-m{--fa:"\4d"}.fa-table-list,.fa-th-list{--fa:"\f00b"}.fa-comment-sms,.fa-sms{--fa:"\f7cd"}.fa-book{--fa:"\f02d"}.fa-user-plus{--fa:"\f234"}.fa-check{--fa:"\f00c"}.fa-battery-4,.fa-battery-three-quarters{--fa:"\f241"}.fa-house-circle-check{--fa:"\e509"}.fa-angle-left{--fa:"\f104"}.fa-diagram-successor{--fa:"\e47a"}.fa-truck-arrow-right{--fa:"\e58b"}.fa-arrows-split-up-and-left{--fa:"\e4bc"}.fa-fist-raised,.fa-hand-fist{--fa:"\f6de"}.fa-cloud-moon{--fa:"\f6c3"}.fa-briefcase{--fa:"\f0b1"}.fa-person-falling{--fa:"\e546"}.fa-image-portrait,.fa-portrait{--fa:"\f3e0"}.fa-user-tag{--fa:"\f507"}.fa-rug{--fa:"\e569"}.fa-earth-europe,.fa-globe-europe{--fa:"\f7a2"}.fa-cart-flatbed-suitcase,.fa-luggage-cart{--fa:"\f59d"}.fa-rectangle-times,.fa-rectangle-xmark,.fa-times-rectangle,.fa-window-close{--fa:"\f410"}.fa-baht-sign{--fa:"\e0ac"}.fa-book-open{--fa:"\f518"}.fa-book-journal-whills,.fa-journal-whills{--fa:"\f66a"}.fa-handcuffs{--fa:"\e4f8"}.fa-exclamation-triangle,.fa-triangle-exclamation,.fa-warning{--fa:"\f071"}.fa-database{--fa:"\f1c0"}.fa-mail-forward,.fa-share{--fa:"\f064"}.fa-bottle-droplet{--fa:"\e4c4"}.fa-mask-face{--fa:"\e1d7"}.fa-hill-rockslide{--fa:"\e508"}.fa-exchange-alt,.fa-right-left{--fa:"\f362"}.fa-paper-plane{--fa:"\f1d8"}.fa-road-circle-exclamation{--fa:"\e565"}.fa-dungeon{--fa:"\f6d9"}.fa-align-right{--fa:"\f038"}.fa-money-bill-1-wave,.fa-money-bill-wave-alt{--fa:"\f53b"}.fa-life-ring{--fa:"\f1cd"}.fa-hands,.fa-sign-language,.fa-signing{--fa:"\f2a7"}.fa-calendar-day{--fa:"\f783"}.fa-ladder-water,.fa-swimming-pool,.fa-water-ladder{--fa:"\f5c5"}.fa-arrows-up-down,.fa-arrows-v{--fa:"\f07d"}.fa-face-grimace,.fa-grimace{--fa:"\f57f"}.fa-wheelchair-alt,.fa-wheelchair-move{--fa:"\e2ce"}.fa-level-down-alt,.fa-turn-down{--fa:"\f3be"}.fa-person-walking-arrow-right{--fa:"\e552"}.fa-envelope-square,.fa-square-envelope{--fa:"\f199"}.fa-dice{--fa:"\f522"}.fa-bowling-ball{--fa:"\f436"}.fa-brain{--fa:"\f5dc"}.fa-band-aid,.fa-bandage{--fa:"\f462"}.fa-calendar-minus{--fa:"\f272"}.fa-circle-xmark,.fa-times-circle,.fa-xmark-circle{--fa:"\f057"}.fa-gifts{--fa:"\f79c"}.fa-hotel{--fa:"\f594"}.fa-earth-asia,.fa-globe-asia{--fa:"\f57e"}.fa-id-card-alt,.fa-id-card-clip{--fa:"\f47f"}.fa-magnifying-glass-plus,.fa-search-plus{--fa:"\f00e"}.fa-thumbs-up{--fa:"\f164"}.fa-user-clock{--fa:"\f4fd"}.fa-allergies,.fa-hand-dots{--fa:"\f461"}.fa-file-invoice{--fa:"\f570"}.fa-window-minimize{--fa:"\f2d1"}.fa-coffee,.fa-mug-saucer{--fa:"\f0f4"}.fa-brush{--fa:"\f55d"}.fa-file-half-dashed{--fa:"\e698"}.fa-mask{--fa:"\f6fa"}.fa-magnifying-glass-minus,.fa-search-minus{--fa:"\f010"}.fa-ruler-vertical{--fa:"\f548"}.fa-user-alt,.fa-user-large{--fa:"\f406"}.fa-train-tram{--fa:"\e5b4"}.fa-user-nurse{--fa:"\f82f"}.fa-syringe{--fa:"\f48e"}.fa-cloud-sun{--fa:"\f6c4"}.fa-stopwatch-20{--fa:"\e06f"}.fa-square-full{--fa:"\f45c"}.fa-magnet{--fa:"\f076"}.fa-jar{--fa:"\e516"}.fa-note-sticky,.fa-sticky-note{--fa:"\f249"}.fa-bug-slash{--fa:"\e490"}.fa-arrow-up-from-water-pump{--fa:"\e4b6"}.fa-bone{--fa:"\f5d7"}.fa-table-cells-row-unlock{--fa:"\e691"}.fa-user-injured{--fa:"\f728"}.fa-face-sad-tear,.fa-sad-tear{--fa:"\f5b4"}.fa-plane{--fa:"\f072"}.fa-tent-arrows-down{--fa:"\e581"}.fa-exclamation{--fa:"\21"}.fa-arrows-spin{--fa:"\e4bb"}.fa-print{--fa:"\f02f"}.fa-try,.fa-turkish-lira,.fa-turkish-lira-sign{--fa:"\e2bb"}.fa-dollar,.fa-dollar-sign,.fa-usd{--fa:"\24"}.fa-x{--fa:"\58"}.fa-magnifying-glass-dollar,.fa-search-dollar{--fa:"\f688"}.fa-users-cog,.fa-users-gear{--fa:"\f509"}.fa-person-military-pointing{--fa:"\e54a"}.fa-bank,.fa-building-columns,.fa-institution,.fa-museum,.fa-university{--fa:"\f19c"}.fa-umbrella{--fa:"\f0e9"}.fa-trowel{--fa:"\e589"}.fa-d{--fa:"\44"}.fa-stapler{--fa:"\e5af"}.fa-masks-theater,.fa-theater-masks{--fa:"\f630"}.fa-kip-sign{--fa:"\e1c4"}.fa-hand-point-left{--fa:"\f0a5"}.fa-handshake-alt,.fa-handshake-simple{--fa:"\f4c6"}.fa-fighter-jet,.fa-jet-fighter{--fa:"\f0fb"}.fa-share-alt-square,.fa-square-share-nodes{--fa:"\f1e1"}.fa-barcode{--fa:"\f02a"}.fa-plus-minus{--fa:"\e43c"}.fa-video,.fa-video-camera{--fa:"\f03d"}.fa-graduation-cap,.fa-mortar-board{--fa:"\f19d"}.fa-hand-holding-medical{--fa:"\e05c"}.fa-person-circle-check{--fa:"\e53e"}.fa-level-up-alt,.fa-turn-up{--fa:"\f3bf"} +.fa-sr-only,.fa-sr-only-focusable:not(:focus),.sr-only,.sr-only-focusable:not(:focus){position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0} \ No newline at end of file diff --git a/css/local.css b/css/local.css new file mode 100644 index 0000000000..f1a326226a --- /dev/null +++ b/css/local.css @@ -0,0 +1,298 @@ +body { + padding-top: 70px; +} +table.nostretch { + width=100% +} +.nostretch td { + class='block' +} +.nostretch tr td{ + width:1%; + white-space:nowrap; +} + +html { + scroll-padding-top: 70px; +} + +ol.hierarchy { + min-height: 40px; + background-color: #f5f5f5; + border: 1px solid #e3e3e3; + border-radius: 3px; + -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.05); +} + +.smallcaps { + font-variant: small-caps; +} +.well .sidebar { + padding: 8px 0 +} +.sidebar a { + padding: 0px,0px,0px,0px +} +.varlist>tbody>tr>td { + padding-left: 3px; + padding-right: 3px; +} +.varlist>tbody>tr>td:first-child, .varlist>thead>tr>td:first-child { + padding-left: 8px; +} +.varlist>tbody>td>td:last-child, .varlist>thead>tr>td:last-child { + padding-right: 8px; +} + +.highlight pre { + overflow-x: auto; + overflow-wrap: normal; + white-space: pre +} + +/* .hl is for when line numbers are included, .highlight is for all + other cases. */ +.hl pre { + counter-reset: line-numbering; + overflow-x: auto; + overflow-wrap: normal; + white-space: pre; + padding: 0; + padding-right: 9.5px; + overflow-y: hidden; + padding-bottom: 9.5px; +} + +.hl pre a::before { + content: counter(line-numbering); + counter-increment: line-numbering; + padding-right: 0.7em; /* space after numbers */ + margin-top: 4.5em; + width: 60px; + text-align: right; + opacity: 0.7; + display: inline-block; + color: #aaa; + background: #eee; + margin-right: 10px; + border-right: 1px solid #ccc; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.hl pre a:first-of-type::before { + padding-top: 9.5px; +} + +.hl pre a:last-of-type::before { + padding-bottom: 9.5px; +} + +.hl pre a:only-of-type::before { + padding: 9.5px; +} + +.hl pre a { + display: inline-block; + height: 4.5em; + margin: -4.5em 0 0; +} +.codesum h3 { + margin-top: 2px; + margin-bottom: 2px; +} + +h1.inline, h2.inline, h3.inline { + display: inline; +} + +.depwarn { + float: right; +} + +.anchor { + position: absolute; + margin: -4.5em; + visibility:hidden; +} + +.alert { + margin-left: 5px; + margin-right: 5px; + margin-top: 5px; +} + +.alert-title { + margin-top: 0; + color: inherit; +} + +div.toc { + font-size: 14.73px; + padding-left: 0px; + padding-right: 0px; +} + +div.toc a { + padding-left: 20px; + padding-right: 20px; + margin-right: 15px; + padding-top: 5px; + padding-bottom: 5px; +} + +div.toc li { + font-size: 0.95em; + padding-left: 15px; +} + +div.toc li.title { + font-size: 1em; +} + +div.toc hr { + margin-top: 12px; + margin-bottom: 10px; +} + +.in-well { + padding: 0px 0px; + margin-bottom: 0px; + float:right; +} + +table tr.submod>td { + border-top: none; + font-size: 13.5px; +} + +.graph-help { + font-size: 10px; +} + +.depgraph { + width: 100%; + max-width: 1140px; +} + +#sidebar a { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.highlighttable { + width: auto; + table-layout: fixed; +} + +ul.checklist { + list-style-type: none; +} + +ul.checklist input[type="checkbox"] { + margin-left: -20.8px; + margin-right: 4.55px; +} + +.gitter-chat-embed { + z-index: 100000; +} + +table.graph { + text-align: center; +} + + +.graph td.root { + border:2px solid black; + padding:10px; +} + +.graph td.triangle-right:after { + content: ""; + display: block; + border-top: 7px solid transparent; + border-bottom: 7px solid transparent; + border-left: 7px solid black; +} + +.graph td.triangle-left:after { + content: ""; + display: block; + border-top: 7px solid transparent; + border-bottom: 7px solid transparent; + border-right: 7px solid black; +} + +.graph td.node { + color: white; + padding:10px; + border-style: solid; + border-width: 3px 0px 3px 0px; + border-color: white; +} + +.graph td.node a{ + color: white; +} + +.graph td.dashedText, +.graph td.solidText { + padding: 0px 10px 0px 10px; + min-width: 40px; + color: black; + border-color: black; +} + +.graph td.dashedText { + border-bottom-style: dashed; +} + +.graph td.solidText { + border-bottom-style: solid; +} + +.graph td.dashedBottom, +.graph td.dashedTop, +.graph td.solidTop, +.graph td.solidBottom { + min-width: 40px; + color: transparent; + border-color: black; +} + +.graph td.dashedBottom { + border-bottom-style: dashed; +} + +.graph td.dashedTop { + border-top-style: dashed; +} + +.graph td.solidBottom { + border-bottom-style: solid; +} + +.graph td.solidTop { + border-top-style: solid; +} + +/* Ensure tables in Pages don't collapse horizontally */ +td, th { + padding-right: 10px; +} + +.nav>li>a { + padding-left: 10px; + padding-right: 10px; +} + +.nav > .nav { + margin-left: 16px; +} diff --git a/css/pygments.css b/css/pygments.css new file mode 100644 index 0000000000..c4b2fd9c96 --- /dev/null +++ b/css/pygments.css @@ -0,0 +1,75 @@ +pre { line-height: 125%; } +td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; } +td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; } +.codehilite .hll { background-color: #ffffcc } +.codehilite { background: #f8f8f8; } +.codehilite .c { color: #3D7B7B; font-style: italic } /* Comment */ +.codehilite .err { border: 1px solid #FF0000 } /* Error */ +.codehilite .k { color: #008000; font-weight: bold } /* Keyword */ +.codehilite .o { color: #666666 } /* Operator */ +.codehilite .ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */ +.codehilite .cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */ +.codehilite .cp { color: #9C6500 } /* Comment.Preproc */ +.codehilite .cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */ +.codehilite .c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */ +.codehilite .cs { color: #3D7B7B; font-style: italic } /* Comment.Special */ +.codehilite .gd { color: #A00000 } /* Generic.Deleted */ +.codehilite .ge { font-style: italic } /* Generic.Emph */ +.codehilite .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */ +.codehilite .gr { color: #E40000 } /* Generic.Error */ +.codehilite .gh { color: #000080; font-weight: bold } /* Generic.Heading */ +.codehilite .gi { color: #008400 } /* Generic.Inserted */ +.codehilite .go { color: #717171 } /* Generic.Output */ +.codehilite .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ +.codehilite .gs { font-weight: bold } /* Generic.Strong */ +.codehilite .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ +.codehilite .gt { color: #0044DD } /* Generic.Traceback */ +.codehilite .kc { color: #008000; font-weight: bold } /* Keyword.Constant */ +.codehilite .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ +.codehilite .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ +.codehilite .kp { color: #008000 } /* Keyword.Pseudo */ +.codehilite .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ +.codehilite .kt { color: #B00040 } /* Keyword.Type */ +.codehilite .m { color: #666666 } /* Literal.Number */ +.codehilite .s { color: #BA2121 } /* Literal.String */ +.codehilite .na { color: #687822 } /* Name.Attribute */ +.codehilite .nb { color: #008000 } /* Name.Builtin */ +.codehilite .nc { color: #0000FF; font-weight: bold } /* Name.Class */ +.codehilite .no { color: #880000 } /* Name.Constant */ +.codehilite .nd { color: #AA22FF } /* Name.Decorator */ +.codehilite .ni { color: #717171; font-weight: bold } /* Name.Entity */ +.codehilite .ne { color: #CB3F38; font-weight: bold } /* Name.Exception */ +.codehilite .nf { color: #0000FF } /* Name.Function */ +.codehilite .nl { color: #767600 } /* Name.Label */ +.codehilite .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ +.codehilite .nt { color: #008000; font-weight: bold } /* Name.Tag */ +.codehilite .nv { color: #19177C } /* Name.Variable */ +.codehilite .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ +.codehilite .w { color: #bbbbbb } /* Text.Whitespace */ +.codehilite .mb { color: #666666 } /* Literal.Number.Bin */ +.codehilite .mf { color: #666666 } /* Literal.Number.Float */ +.codehilite .mh { color: #666666 } /* Literal.Number.Hex */ +.codehilite .mi { color: #666666 } /* Literal.Number.Integer */ +.codehilite .mo { color: #666666 } /* Literal.Number.Oct */ +.codehilite .sa { color: #BA2121 } /* Literal.String.Affix */ +.codehilite .sb { color: #BA2121 } /* Literal.String.Backtick */ +.codehilite .sc { color: #BA2121 } /* Literal.String.Char */ +.codehilite .dl { color: #BA2121 } /* Literal.String.Delimiter */ +.codehilite .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ +.codehilite .s2 { color: #BA2121 } /* Literal.String.Double */ +.codehilite .se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */ +.codehilite .sh { color: #BA2121 } /* Literal.String.Heredoc */ +.codehilite .si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */ +.codehilite .sx { color: #008000 } /* Literal.String.Other */ +.codehilite .sr { color: #A45A77 } /* Literal.String.Regex */ +.codehilite .s1 { color: #BA2121 } /* Literal.String.Single */ +.codehilite .ss { color: #19177C } /* Literal.String.Symbol */ +.codehilite .bp { color: #008000 } /* Name.Builtin.Pseudo */ +.codehilite .fm { color: #0000FF } /* Name.Function.Magic */ +.codehilite .vc { color: #19177C } /* Name.Variable.Class */ +.codehilite .vg { color: #19177C } /* Name.Variable.Global */ +.codehilite .vi { color: #19177C } /* Name.Variable.Instance */ +.codehilite .vm { color: #19177C } /* Name.Variable.Magic */ +.codehilite .il { color: #666666 } /* Literal.Number.Integer.Long */ diff --git a/css/regular.css b/css/regular.css new file mode 100644 index 0000000000..be1e468fcd --- /dev/null +++ b/css/regular.css @@ -0,0 +1,19 @@ +/*! + * Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + * Copyright 2024 Fonticons, Inc. + */ +:root, :host { + --fa-style-family-classic: 'Font Awesome 6 Free'; + --fa-font-regular: normal 400 1em/1 'Font Awesome 6 Free'; } + +@font-face { + font-family: 'Font Awesome 6 Free'; + font-style: normal; + font-weight: 400; + font-display: block; + src: url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.ttf") format("truetype"); } + +.far, +.fa-regular { + font-weight: 400; } diff --git a/css/regular.min.css b/css/regular.min.css new file mode 100644 index 0000000000..31256ee536 --- /dev/null +++ b/css/regular.min.css @@ -0,0 +1,6 @@ +/*! + * Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + * Copyright 2024 Fonticons, Inc. + */ +:host,:root{--fa-style-family-classic:"Font Awesome 6 Free";--fa-font-regular:normal 400 1em/1 "Font Awesome 6 Free"}@font-face{font-family:"Font Awesome 6 Free";font-style:normal;font-weight:400;font-display:block;src:url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.ttf) format("truetype")}.fa-regular,.far{font-weight:400} \ No newline at end of file diff --git a/css/solid.css b/css/solid.css new file mode 100644 index 0000000000..6742be3363 --- /dev/null +++ b/css/solid.css @@ -0,0 +1,19 @@ +/*! + * Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + * Copyright 2024 Fonticons, Inc. + */ +:root, :host { + --fa-style-family-classic: 'Font Awesome 6 Free'; + --fa-font-solid: normal 900 1em/1 'Font Awesome 6 Free'; } + +@font-face { + font-family: 'Font Awesome 6 Free'; + font-style: normal; + font-weight: 900; + font-display: block; + src: url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.ttf") format("truetype"); } + +.fas, +.fa-solid { + font-weight: 900; } diff --git a/css/solid.min.css b/css/solid.min.css new file mode 100644 index 0000000000..8dc01128f1 --- /dev/null +++ b/css/solid.min.css @@ -0,0 +1,6 @@ +/*! + * Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + * Copyright 2024 Fonticons, Inc. + */ +:host,:root{--fa-style-family-classic:"Font Awesome 6 Free";--fa-font-solid:normal 900 1em/1 "Font Awesome 6 Free"}@font-face{font-family:"Font Awesome 6 Free";font-style:normal;font-weight:900;font-display:block;src:url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.ttf) format("truetype")}.fa-solid,.fas{font-weight:900} \ No newline at end of file diff --git a/css/v4-font-face.css b/css/v4-font-face.css new file mode 100644 index 0000000000..c453a99dcc --- /dev/null +++ b/css/v4-font-face.css @@ -0,0 +1,26 @@ +/*! + * Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + * Copyright 2024 Fonticons, Inc. + */ +@font-face { + font-family: 'FontAwesome'; + font-display: block; + src: url("../webfonts/fa-solid-900.woff2") format("woff2"), url("../webfonts/fa-solid-900.ttf") format("truetype"); } + +@font-face { + font-family: 'FontAwesome'; + font-display: block; + src: url("../webfonts/fa-brands-400.woff2") format("woff2"), url("../webfonts/fa-brands-400.ttf") format("truetype"); } + +@font-face { + font-family: 'FontAwesome'; + font-display: block; + src: url("../webfonts/fa-regular-400.woff2") format("woff2"), url("../webfonts/fa-regular-400.ttf") format("truetype"); + unicode-range: U+F003,U+F006,U+F014,U+F016-F017,U+F01A-F01B,U+F01D,U+F022,U+F03E,U+F044,U+F046,U+F05C-F05D,U+F06E,U+F070,U+F087-F088,U+F08A,U+F094,U+F096-F097,U+F09D,U+F0A0,U+F0A2,U+F0A4-F0A7,U+F0C5,U+F0C7,U+F0E5-F0E6,U+F0EB,U+F0F6-F0F8,U+F10C,U+F114-F115,U+F118-F11A,U+F11C-F11D,U+F133,U+F147,U+F14E,U+F150-F152,U+F185-F186,U+F18E,U+F190-F192,U+F196,U+F1C1-F1C9,U+F1D9,U+F1DB,U+F1E3,U+F1EA,U+F1F7,U+F1F9,U+F20A,U+F247-F248,U+F24A,U+F24D,U+F255-F25B,U+F25D,U+F271-F274,U+F278,U+F27B,U+F28C,U+F28E,U+F29C,U+F2B5,U+F2B7,U+F2BA,U+F2BC,U+F2BE,U+F2C0-F2C1,U+F2C3,U+F2D0,U+F2D2,U+F2D4,U+F2DC; } + +@font-face { + font-family: 'FontAwesome'; + font-display: block; + src: url("../webfonts/fa-v4compatibility.woff2") format("woff2"), url("../webfonts/fa-v4compatibility.ttf") format("truetype"); + unicode-range: U+F041,U+F047,U+F065-F066,U+F07D-F07E,U+F080,U+F08B,U+F08E,U+F090,U+F09A,U+F0AC,U+F0AE,U+F0B2,U+F0D0,U+F0D6,U+F0E4,U+F0EC,U+F10A-F10B,U+F123,U+F13E,U+F148-F149,U+F14C,U+F156,U+F15E,U+F160-F161,U+F163,U+F175-F178,U+F195,U+F1F8,U+F219,U+F27A; } diff --git a/css/v4-font-face.min.css b/css/v4-font-face.min.css new file mode 100644 index 0000000000..fa5810700d --- /dev/null +++ b/css/v4-font-face.min.css @@ -0,0 +1,6 @@ +/*! + * Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + * Copyright 2024 Fonticons, Inc. + */ +@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.ttf) format("truetype")}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.ttf) format("truetype")}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.ttf) format("truetype");unicode-range:u+f003,u+f006,u+f014,u+f016-f017,u+f01a-f01b,u+f01d,u+f022,u+f03e,u+f044,u+f046,u+f05c-f05d,u+f06e,u+f070,u+f087-f088,u+f08a,u+f094,u+f096-f097,u+f09d,u+f0a0,u+f0a2,u+f0a4-f0a7,u+f0c5,u+f0c7,u+f0e5-f0e6,u+f0eb,u+f0f6-f0f8,u+f10c,u+f114-f115,u+f118-f11a,u+f11c-f11d,u+f133,u+f147,u+f14e,u+f150-f152,u+f185-f186,u+f18e,u+f190-f192,u+f196,u+f1c1-f1c9,u+f1d9,u+f1db,u+f1e3,u+f1ea,u+f1f7,u+f1f9,u+f20a,u+f247-f248,u+f24a,u+f24d,u+f255-f25b,u+f25d,u+f271-f274,u+f278,u+f27b,u+f28c,u+f28e,u+f29c,u+f2b5,u+f2b7,u+f2ba,u+f2bc,u+f2be,u+f2c0-f2c1,u+f2c3,u+f2d0,u+f2d2,u+f2d4,u+f2dc}@font-face{font-family:"FontAwesome";font-display:block;src:url(../webfonts/fa-v4compatibility.woff2) format("woff2"),url(../webfonts/fa-v4compatibility.ttf) format("truetype");unicode-range:u+f041,u+f047,u+f065-f066,u+f07d-f07e,u+f080,u+f08b,u+f08e,u+f090,u+f09a,u+f0ac,u+f0ae,u+f0b2,u+f0d0,u+f0d6,u+f0e4,u+f0ec,u+f10a-f10b,u+f123,u+f13e,u+f148-f149,u+f14c,u+f156,u+f15e,u+f160-f161,u+f163,u+f175-f178,u+f195,u+f1f8,u+f219,u+f27a} \ No newline at end of file diff --git a/css/v4-shims.css b/css/v4-shims.css new file mode 100644 index 0000000000..7ed4af7d2a --- /dev/null +++ b/css/v4-shims.css @@ -0,0 +1,2194 @@ +/*! + * Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + * Copyright 2024 Fonticons, Inc. + */ +.fa.fa-glass { + --fa: "\f000"; } + +.fa.fa-envelope-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-envelope-o { + --fa: "\f0e0"; } + +.fa.fa-star-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-star-o { + --fa: "\f005"; } + +.fa.fa-remove { + --fa: "\f00d"; } + +.fa.fa-close { + --fa: "\f00d"; } + +.fa.fa-gear { + --fa: "\f013"; } + +.fa.fa-trash-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-trash-o { + --fa: "\f2ed"; } + +.fa.fa-home { + --fa: "\f015"; } + +.fa.fa-file-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-o { + --fa: "\f15b"; } + +.fa.fa-clock-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-clock-o { + --fa: "\f017"; } + +.fa.fa-arrow-circle-o-down { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-arrow-circle-o-down { + --fa: "\f358"; } + +.fa.fa-arrow-circle-o-up { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-arrow-circle-o-up { + --fa: "\f35b"; } + +.fa.fa-play-circle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-play-circle-o { + --fa: "\f144"; } + +.fa.fa-repeat { + --fa: "\f01e"; } + +.fa.fa-rotate-right { + --fa: "\f01e"; } + +.fa.fa-refresh { + --fa: "\f021"; } + +.fa.fa-list-alt { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-list-alt { + --fa: "\f022"; } + +.fa.fa-dedent { + --fa: "\f03b"; } + +.fa.fa-video-camera { + --fa: "\f03d"; } + +.fa.fa-picture-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-picture-o { + --fa: "\f03e"; } + +.fa.fa-photo { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-photo { + --fa: "\f03e"; } + +.fa.fa-image { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-image { + --fa: "\f03e"; } + +.fa.fa-map-marker { + --fa: "\f3c5"; } + +.fa.fa-pencil-square-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-pencil-square-o { + --fa: "\f044"; } + +.fa.fa-edit { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-edit { + --fa: "\f044"; } + +.fa.fa-share-square-o { + --fa: "\f14d"; } + +.fa.fa-check-square-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-check-square-o { + --fa: "\f14a"; } + +.fa.fa-arrows { + --fa: "\f0b2"; } + +.fa.fa-times-circle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-times-circle-o { + --fa: "\f057"; } + +.fa.fa-check-circle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-check-circle-o { + --fa: "\f058"; } + +.fa.fa-mail-forward { + --fa: "\f064"; } + +.fa.fa-expand { + --fa: "\f424"; } + +.fa.fa-compress { + --fa: "\f422"; } + +.fa.fa-eye { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-eye-slash { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-warning { + --fa: "\f071"; } + +.fa.fa-calendar { + --fa: "\f073"; } + +.fa.fa-arrows-v { + --fa: "\f338"; } + +.fa.fa-arrows-h { + --fa: "\f337"; } + +.fa.fa-bar-chart { + --fa: "\e0e3"; } + +.fa.fa-bar-chart-o { + --fa: "\e0e3"; } + +.fa.fa-twitter-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-twitter-square { + --fa: "\f081"; } + +.fa.fa-facebook-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-facebook-square { + --fa: "\f082"; } + +.fa.fa-gears { + --fa: "\f085"; } + +.fa.fa-thumbs-o-up { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-thumbs-o-up { + --fa: "\f164"; } + +.fa.fa-thumbs-o-down { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-thumbs-o-down { + --fa: "\f165"; } + +.fa.fa-heart-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-heart-o { + --fa: "\f004"; } + +.fa.fa-sign-out { + --fa: "\f2f5"; } + +.fa.fa-linkedin-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-linkedin-square { + --fa: "\f08c"; } + +.fa.fa-thumb-tack { + --fa: "\f08d"; } + +.fa.fa-external-link { + --fa: "\f35d"; } + +.fa.fa-sign-in { + --fa: "\f2f6"; } + +.fa.fa-github-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-github-square { + --fa: "\f092"; } + +.fa.fa-lemon-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-lemon-o { + --fa: "\f094"; } + +.fa.fa-square-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-square-o { + --fa: "\f0c8"; } + +.fa.fa-bookmark-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-bookmark-o { + --fa: "\f02e"; } + +.fa.fa-twitter { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-facebook { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-facebook { + --fa: "\f39e"; } + +.fa.fa-facebook-f { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-facebook-f { + --fa: "\f39e"; } + +.fa.fa-github { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-credit-card { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-feed { + --fa: "\f09e"; } + +.fa.fa-hdd-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hdd-o { + --fa: "\f0a0"; } + +.fa.fa-hand-o-right { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-o-right { + --fa: "\f0a4"; } + +.fa.fa-hand-o-left { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-o-left { + --fa: "\f0a5"; } + +.fa.fa-hand-o-up { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-o-up { + --fa: "\f0a6"; } + +.fa.fa-hand-o-down { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-o-down { + --fa: "\f0a7"; } + +.fa.fa-globe { + --fa: "\f57d"; } + +.fa.fa-tasks { + --fa: "\f828"; } + +.fa.fa-arrows-alt { + --fa: "\f31e"; } + +.fa.fa-group { + --fa: "\f0c0"; } + +.fa.fa-chain { + --fa: "\f0c1"; } + +.fa.fa-cut { + --fa: "\f0c4"; } + +.fa.fa-files-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-files-o { + --fa: "\f0c5"; } + +.fa.fa-floppy-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-floppy-o { + --fa: "\f0c7"; } + +.fa.fa-save { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-save { + --fa: "\f0c7"; } + +.fa.fa-navicon { + --fa: "\f0c9"; } + +.fa.fa-reorder { + --fa: "\f0c9"; } + +.fa.fa-magic { + --fa: "\e2ca"; } + +.fa.fa-pinterest { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-pinterest-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-pinterest-square { + --fa: "\f0d3"; } + +.fa.fa-google-plus-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-google-plus-square { + --fa: "\f0d4"; } + +.fa.fa-google-plus { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-google-plus { + --fa: "\f0d5"; } + +.fa.fa-money { + --fa: "\f3d1"; } + +.fa.fa-unsorted { + --fa: "\f0dc"; } + +.fa.fa-sort-desc { + --fa: "\f0dd"; } + +.fa.fa-sort-asc { + --fa: "\f0de"; } + +.fa.fa-linkedin { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-linkedin { + --fa: "\f0e1"; } + +.fa.fa-rotate-left { + --fa: "\f0e2"; } + +.fa.fa-legal { + --fa: "\f0e3"; } + +.fa.fa-tachometer { + --fa: "\f625"; } + +.fa.fa-dashboard { + --fa: "\f625"; } + +.fa.fa-comment-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-comment-o { + --fa: "\f075"; } + +.fa.fa-comments-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-comments-o { + --fa: "\f086"; } + +.fa.fa-flash { + --fa: "\f0e7"; } + +.fa.fa-clipboard { + --fa: "\f0ea"; } + +.fa.fa-lightbulb-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-lightbulb-o { + --fa: "\f0eb"; } + +.fa.fa-exchange { + --fa: "\f362"; } + +.fa.fa-cloud-download { + --fa: "\f0ed"; } + +.fa.fa-cloud-upload { + --fa: "\f0ee"; } + +.fa.fa-bell-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-bell-o { + --fa: "\f0f3"; } + +.fa.fa-cutlery { + --fa: "\f2e7"; } + +.fa.fa-file-text-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-text-o { + --fa: "\f15c"; } + +.fa.fa-building-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-building-o { + --fa: "\f1ad"; } + +.fa.fa-hospital-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hospital-o { + --fa: "\f0f8"; } + +.fa.fa-tablet { + --fa: "\f3fa"; } + +.fa.fa-mobile { + --fa: "\f3cd"; } + +.fa.fa-mobile-phone { + --fa: "\f3cd"; } + +.fa.fa-circle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-circle-o { + --fa: "\f111"; } + +.fa.fa-mail-reply { + --fa: "\f3e5"; } + +.fa.fa-github-alt { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-folder-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-folder-o { + --fa: "\f07b"; } + +.fa.fa-folder-open-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-folder-open-o { + --fa: "\f07c"; } + +.fa.fa-smile-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-smile-o { + --fa: "\f118"; } + +.fa.fa-frown-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-frown-o { + --fa: "\f119"; } + +.fa.fa-meh-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-meh-o { + --fa: "\f11a"; } + +.fa.fa-keyboard-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-keyboard-o { + --fa: "\f11c"; } + +.fa.fa-flag-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-flag-o { + --fa: "\f024"; } + +.fa.fa-mail-reply-all { + --fa: "\f122"; } + +.fa.fa-star-half-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-star-half-o { + --fa: "\f5c0"; } + +.fa.fa-star-half-empty { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-star-half-empty { + --fa: "\f5c0"; } + +.fa.fa-star-half-full { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-star-half-full { + --fa: "\f5c0"; } + +.fa.fa-code-fork { + --fa: "\f126"; } + +.fa.fa-chain-broken { + --fa: "\f127"; } + +.fa.fa-unlink { + --fa: "\f127"; } + +.fa.fa-calendar-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-calendar-o { + --fa: "\f133"; } + +.fa.fa-maxcdn { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-html5 { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-css3 { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-unlock-alt { + --fa: "\f09c"; } + +.fa.fa-minus-square-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-minus-square-o { + --fa: "\f146"; } + +.fa.fa-level-up { + --fa: "\f3bf"; } + +.fa.fa-level-down { + --fa: "\f3be"; } + +.fa.fa-pencil-square { + --fa: "\f14b"; } + +.fa.fa-external-link-square { + --fa: "\f360"; } + +.fa.fa-compass { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-caret-square-o-down { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-caret-square-o-down { + --fa: "\f150"; } + +.fa.fa-toggle-down { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-toggle-down { + --fa: "\f150"; } + +.fa.fa-caret-square-o-up { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-caret-square-o-up { + --fa: "\f151"; } + +.fa.fa-toggle-up { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-toggle-up { + --fa: "\f151"; } + +.fa.fa-caret-square-o-right { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-caret-square-o-right { + --fa: "\f152"; } + +.fa.fa-toggle-right { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-toggle-right { + --fa: "\f152"; } + +.fa.fa-eur { + --fa: "\f153"; } + +.fa.fa-euro { + --fa: "\f153"; } + +.fa.fa-gbp { + --fa: "\f154"; } + +.fa.fa-usd { + --fa: "\24"; } + +.fa.fa-dollar { + --fa: "\24"; } + +.fa.fa-inr { + --fa: "\e1bc"; } + +.fa.fa-rupee { + --fa: "\e1bc"; } + +.fa.fa-jpy { + --fa: "\f157"; } + +.fa.fa-cny { + --fa: "\f157"; } + +.fa.fa-rmb { + --fa: "\f157"; } + +.fa.fa-yen { + --fa: "\f157"; } + +.fa.fa-rub { + --fa: "\f158"; } + +.fa.fa-ruble { + --fa: "\f158"; } + +.fa.fa-rouble { + --fa: "\f158"; } + +.fa.fa-krw { + --fa: "\f159"; } + +.fa.fa-won { + --fa: "\f159"; } + +.fa.fa-btc { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-bitcoin { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-bitcoin { + --fa: "\f15a"; } + +.fa.fa-file-text { + --fa: "\f15c"; } + +.fa.fa-sort-alpha-asc { + --fa: "\f15d"; } + +.fa.fa-sort-alpha-desc { + --fa: "\f881"; } + +.fa.fa-sort-amount-asc { + --fa: "\f884"; } + +.fa.fa-sort-amount-desc { + --fa: "\f160"; } + +.fa.fa-sort-numeric-asc { + --fa: "\f162"; } + +.fa.fa-sort-numeric-desc { + --fa: "\f886"; } + +.fa.fa-youtube-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-youtube-square { + --fa: "\f431"; } + +.fa.fa-youtube { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-xing { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-xing-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-xing-square { + --fa: "\f169"; } + +.fa.fa-youtube-play { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-youtube-play { + --fa: "\f167"; } + +.fa.fa-dropbox { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-stack-overflow { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-instagram { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-flickr { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-adn { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-bitbucket { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-bitbucket-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-bitbucket-square { + --fa: "\f171"; } + +.fa.fa-tumblr { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-tumblr-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-tumblr-square { + --fa: "\f174"; } + +.fa.fa-long-arrow-down { + --fa: "\f309"; } + +.fa.fa-long-arrow-up { + --fa: "\f30c"; } + +.fa.fa-long-arrow-left { + --fa: "\f30a"; } + +.fa.fa-long-arrow-right { + --fa: "\f30b"; } + +.fa.fa-apple { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-windows { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-android { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-linux { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-dribbble { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-skype { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-foursquare { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-trello { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-gratipay { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-gittip { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-gittip { + --fa: "\f184"; } + +.fa.fa-sun-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-sun-o { + --fa: "\f185"; } + +.fa.fa-moon-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-moon-o { + --fa: "\f186"; } + +.fa.fa-vk { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-weibo { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-renren { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-pagelines { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-stack-exchange { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-arrow-circle-o-right { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-arrow-circle-o-right { + --fa: "\f35a"; } + +.fa.fa-arrow-circle-o-left { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-arrow-circle-o-left { + --fa: "\f359"; } + +.fa.fa-caret-square-o-left { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-caret-square-o-left { + --fa: "\f191"; } + +.fa.fa-toggle-left { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-toggle-left { + --fa: "\f191"; } + +.fa.fa-dot-circle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-dot-circle-o { + --fa: "\f192"; } + +.fa.fa-vimeo-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-vimeo-square { + --fa: "\f194"; } + +.fa.fa-try { + --fa: "\e2bb"; } + +.fa.fa-turkish-lira { + --fa: "\e2bb"; } + +.fa.fa-plus-square-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-plus-square-o { + --fa: "\f0fe"; } + +.fa.fa-slack { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-wordpress { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-openid { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-institution { + --fa: "\f19c"; } + +.fa.fa-bank { + --fa: "\f19c"; } + +.fa.fa-mortar-board { + --fa: "\f19d"; } + +.fa.fa-yahoo { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-google { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-reddit { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-reddit-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-reddit-square { + --fa: "\f1a2"; } + +.fa.fa-stumbleupon-circle { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-stumbleupon { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-delicious { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-digg { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-pied-piper-pp { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-pied-piper-alt { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-drupal { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-joomla { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-behance { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-behance-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-behance-square { + --fa: "\f1b5"; } + +.fa.fa-steam { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-steam-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-steam-square { + --fa: "\f1b7"; } + +.fa.fa-automobile { + --fa: "\f1b9"; } + +.fa.fa-cab { + --fa: "\f1ba"; } + +.fa.fa-spotify { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-deviantart { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-soundcloud { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-file-pdf-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-pdf-o { + --fa: "\f1c1"; } + +.fa.fa-file-word-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-word-o { + --fa: "\f1c2"; } + +.fa.fa-file-excel-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-excel-o { + --fa: "\f1c3"; } + +.fa.fa-file-powerpoint-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-powerpoint-o { + --fa: "\f1c4"; } + +.fa.fa-file-image-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-image-o { + --fa: "\f1c5"; } + +.fa.fa-file-photo-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-photo-o { + --fa: "\f1c5"; } + +.fa.fa-file-picture-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-picture-o { + --fa: "\f1c5"; } + +.fa.fa-file-archive-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-archive-o { + --fa: "\f1c6"; } + +.fa.fa-file-zip-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-zip-o { + --fa: "\f1c6"; } + +.fa.fa-file-audio-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-audio-o { + --fa: "\f1c7"; } + +.fa.fa-file-sound-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-sound-o { + --fa: "\f1c7"; } + +.fa.fa-file-video-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-video-o { + --fa: "\f1c8"; } + +.fa.fa-file-movie-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-movie-o { + --fa: "\f1c8"; } + +.fa.fa-file-code-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-file-code-o { + --fa: "\f1c9"; } + +.fa.fa-vine { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-codepen { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-jsfiddle { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-life-bouy { + --fa: "\f1cd"; } + +.fa.fa-life-buoy { + --fa: "\f1cd"; } + +.fa.fa-life-saver { + --fa: "\f1cd"; } + +.fa.fa-support { + --fa: "\f1cd"; } + +.fa.fa-circle-o-notch { + --fa: "\f1ce"; } + +.fa.fa-rebel { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-ra { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-ra { + --fa: "\f1d0"; } + +.fa.fa-resistance { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-resistance { + --fa: "\f1d0"; } + +.fa.fa-empire { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-ge { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-ge { + --fa: "\f1d1"; } + +.fa.fa-git-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-git-square { + --fa: "\f1d2"; } + +.fa.fa-git { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-hacker-news { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-y-combinator-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-y-combinator-square { + --fa: "\f1d4"; } + +.fa.fa-yc-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-yc-square { + --fa: "\f1d4"; } + +.fa.fa-tencent-weibo { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-qq { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-weixin { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-wechat { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-wechat { + --fa: "\f1d7"; } + +.fa.fa-send { + --fa: "\f1d8"; } + +.fa.fa-paper-plane-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-paper-plane-o { + --fa: "\f1d8"; } + +.fa.fa-send-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-send-o { + --fa: "\f1d8"; } + +.fa.fa-circle-thin { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-circle-thin { + --fa: "\f111"; } + +.fa.fa-header { + --fa: "\f1dc"; } + +.fa.fa-futbol-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-futbol-o { + --fa: "\f1e3"; } + +.fa.fa-soccer-ball-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-soccer-ball-o { + --fa: "\f1e3"; } + +.fa.fa-slideshare { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-twitch { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-yelp { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-newspaper-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-newspaper-o { + --fa: "\f1ea"; } + +.fa.fa-paypal { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-google-wallet { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-cc-visa { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-cc-mastercard { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-cc-discover { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-cc-amex { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-cc-paypal { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-cc-stripe { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-bell-slash-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-bell-slash-o { + --fa: "\f1f6"; } + +.fa.fa-trash { + --fa: "\f2ed"; } + +.fa.fa-copyright { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-eyedropper { + --fa: "\f1fb"; } + +.fa.fa-area-chart { + --fa: "\f1fe"; } + +.fa.fa-pie-chart { + --fa: "\f200"; } + +.fa.fa-line-chart { + --fa: "\f201"; } + +.fa.fa-lastfm { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-lastfm-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-lastfm-square { + --fa: "\f203"; } + +.fa.fa-ioxhost { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-angellist { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-cc { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-cc { + --fa: "\f20a"; } + +.fa.fa-ils { + --fa: "\f20b"; } + +.fa.fa-shekel { + --fa: "\f20b"; } + +.fa.fa-sheqel { + --fa: "\f20b"; } + +.fa.fa-buysellads { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-connectdevelop { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-dashcube { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-forumbee { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-leanpub { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-sellsy { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-shirtsinbulk { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-simplybuilt { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-skyatlas { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-diamond { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-diamond { + --fa: "\f3a5"; } + +.fa.fa-transgender { + --fa: "\f224"; } + +.fa.fa-intersex { + --fa: "\f224"; } + +.fa.fa-transgender-alt { + --fa: "\f225"; } + +.fa.fa-facebook-official { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-facebook-official { + --fa: "\f09a"; } + +.fa.fa-pinterest-p { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-whatsapp { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-hotel { + --fa: "\f236"; } + +.fa.fa-viacoin { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-medium { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-y-combinator { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-yc { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-yc { + --fa: "\f23b"; } + +.fa.fa-optin-monster { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-opencart { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-expeditedssl { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-battery-4 { + --fa: "\f240"; } + +.fa.fa-battery { + --fa: "\f240"; } + +.fa.fa-battery-3 { + --fa: "\f241"; } + +.fa.fa-battery-2 { + --fa: "\f242"; } + +.fa.fa-battery-1 { + --fa: "\f243"; } + +.fa.fa-battery-0 { + --fa: "\f244"; } + +.fa.fa-object-group { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-object-ungroup { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-sticky-note-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-sticky-note-o { + --fa: "\f249"; } + +.fa.fa-cc-jcb { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-cc-diners-club { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-clone { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hourglass-o { + --fa: "\f254"; } + +.fa.fa-hourglass-1 { + --fa: "\f251"; } + +.fa.fa-hourglass-2 { + --fa: "\f252"; } + +.fa.fa-hourglass-3 { + --fa: "\f253"; } + +.fa.fa-hand-rock-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-rock-o { + --fa: "\f255"; } + +.fa.fa-hand-grab-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-grab-o { + --fa: "\f255"; } + +.fa.fa-hand-paper-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-paper-o { + --fa: "\f256"; } + +.fa.fa-hand-stop-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-stop-o { + --fa: "\f256"; } + +.fa.fa-hand-scissors-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-scissors-o { + --fa: "\f257"; } + +.fa.fa-hand-lizard-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-lizard-o { + --fa: "\f258"; } + +.fa.fa-hand-spock-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-spock-o { + --fa: "\f259"; } + +.fa.fa-hand-pointer-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-pointer-o { + --fa: "\f25a"; } + +.fa.fa-hand-peace-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-hand-peace-o { + --fa: "\f25b"; } + +.fa.fa-registered { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-creative-commons { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-gg { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-gg-circle { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-odnoklassniki { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-odnoklassniki-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-odnoklassniki-square { + --fa: "\f264"; } + +.fa.fa-get-pocket { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-wikipedia-w { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-safari { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-chrome { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-firefox { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-opera { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-internet-explorer { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-television { + --fa: "\f26c"; } + +.fa.fa-contao { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-500px { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-amazon { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-calendar-plus-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-calendar-plus-o { + --fa: "\f271"; } + +.fa.fa-calendar-minus-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-calendar-minus-o { + --fa: "\f272"; } + +.fa.fa-calendar-times-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-calendar-times-o { + --fa: "\f273"; } + +.fa.fa-calendar-check-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-calendar-check-o { + --fa: "\f274"; } + +.fa.fa-map-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-map-o { + --fa: "\f279"; } + +.fa.fa-commenting { + --fa: "\f4ad"; } + +.fa.fa-commenting-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-commenting-o { + --fa: "\f4ad"; } + +.fa.fa-houzz { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-vimeo { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-vimeo { + --fa: "\f27d"; } + +.fa.fa-black-tie { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-fonticons { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-reddit-alien { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-edge { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-credit-card-alt { + --fa: "\f09d"; } + +.fa.fa-codiepie { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-modx { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-fort-awesome { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-usb { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-product-hunt { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-mixcloud { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-scribd { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-pause-circle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-pause-circle-o { + --fa: "\f28b"; } + +.fa.fa-stop-circle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-stop-circle-o { + --fa: "\f28d"; } + +.fa.fa-bluetooth { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-bluetooth-b { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-gitlab { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-wpbeginner { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-wpforms { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-envira { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-wheelchair-alt { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-wheelchair-alt { + --fa: "\f368"; } + +.fa.fa-question-circle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-question-circle-o { + --fa: "\f059"; } + +.fa.fa-volume-control-phone { + --fa: "\f2a0"; } + +.fa.fa-asl-interpreting { + --fa: "\f2a3"; } + +.fa.fa-deafness { + --fa: "\f2a4"; } + +.fa.fa-hard-of-hearing { + --fa: "\f2a4"; } + +.fa.fa-glide { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-glide-g { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-signing { + --fa: "\f2a7"; } + +.fa.fa-viadeo { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-viadeo-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-viadeo-square { + --fa: "\f2aa"; } + +.fa.fa-snapchat { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-snapchat-ghost { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-snapchat-ghost { + --fa: "\f2ab"; } + +.fa.fa-snapchat-square { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-snapchat-square { + --fa: "\f2ad"; } + +.fa.fa-pied-piper { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-first-order { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-yoast { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-themeisle { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-google-plus-official { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-google-plus-official { + --fa: "\f2b3"; } + +.fa.fa-google-plus-circle { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-google-plus-circle { + --fa: "\f2b3"; } + +.fa.fa-font-awesome { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-fa { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-fa { + --fa: "\f2b4"; } + +.fa.fa-handshake-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-handshake-o { + --fa: "\f2b5"; } + +.fa.fa-envelope-open-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-envelope-open-o { + --fa: "\f2b6"; } + +.fa.fa-linode { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-address-book-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-address-book-o { + --fa: "\f2b9"; } + +.fa.fa-vcard { + --fa: "\f2bb"; } + +.fa.fa-address-card-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-address-card-o { + --fa: "\f2bb"; } + +.fa.fa-vcard-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-vcard-o { + --fa: "\f2bb"; } + +.fa.fa-user-circle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-user-circle-o { + --fa: "\f2bd"; } + +.fa.fa-user-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-user-o { + --fa: "\f007"; } + +.fa.fa-id-badge { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-drivers-license { + --fa: "\f2c2"; } + +.fa.fa-id-card-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-id-card-o { + --fa: "\f2c2"; } + +.fa.fa-drivers-license-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-drivers-license-o { + --fa: "\f2c2"; } + +.fa.fa-quora { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-free-code-camp { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-telegram { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-thermometer-4 { + --fa: "\f2c7"; } + +.fa.fa-thermometer { + --fa: "\f2c7"; } + +.fa.fa-thermometer-3 { + --fa: "\f2c8"; } + +.fa.fa-thermometer-2 { + --fa: "\f2c9"; } + +.fa.fa-thermometer-1 { + --fa: "\f2ca"; } + +.fa.fa-thermometer-0 { + --fa: "\f2cb"; } + +.fa.fa-bathtub { + --fa: "\f2cd"; } + +.fa.fa-s15 { + --fa: "\f2cd"; } + +.fa.fa-window-maximize { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-window-restore { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-times-rectangle { + --fa: "\f410"; } + +.fa.fa-window-close-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-window-close-o { + --fa: "\f410"; } + +.fa.fa-times-rectangle-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-times-rectangle-o { + --fa: "\f410"; } + +.fa.fa-bandcamp { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-grav { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-etsy { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-imdb { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-ravelry { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-eercast { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-eercast { + --fa: "\f2da"; } + +.fa.fa-snowflake-o { + font-family: 'Font Awesome 6 Free'; + font-weight: 400; } + +.fa.fa-snowflake-o { + --fa: "\f2dc"; } + +.fa.fa-superpowers { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-wpexplorer { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } + +.fa.fa-meetup { + font-family: 'Font Awesome 6 Brands'; + font-weight: 400; } diff --git a/css/v4-shims.min.css b/css/v4-shims.min.css new file mode 100644 index 0000000000..93685c8bfa --- /dev/null +++ b/css/v4-shims.min.css @@ -0,0 +1,6 @@ +/*! + * Font Awesome Free 6.7.2 by @fontawesome - https://fontawesome.com + * License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) + * Copyright 2024 Fonticons, Inc. + */ +.fa.fa-glass{--fa:"\f000"}.fa.fa-envelope-o{--fa:"\f0e0"}.fa.fa-envelope-o,.fa.fa-star-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-star-o{--fa:"\f005"}.fa.fa-close,.fa.fa-remove{--fa:"\f00d"}.fa.fa-gear{--fa:"\f013"}.fa.fa-trash-o{font-family:"Font Awesome 6 Free";font-weight:400;--fa:"\f2ed"}.fa.fa-home{--fa:"\f015"}.fa.fa-file-o{--fa:"\f15b"}.fa.fa-clock-o,.fa.fa-file-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-clock-o{--fa:"\f017"}.fa.fa-arrow-circle-o-down{--fa:"\f358"}.fa.fa-arrow-circle-o-down,.fa.fa-arrow-circle-o-up{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-arrow-circle-o-up{--fa:"\f35b"}.fa.fa-play-circle-o{font-family:"Font Awesome 6 Free";font-weight:400;--fa:"\f144"}.fa.fa-repeat,.fa.fa-rotate-right{--fa:"\f01e"}.fa.fa-refresh{--fa:"\f021"}.fa.fa-list-alt{font-family:"Font Awesome 6 Free";font-weight:400;--fa:"\f022"}.fa.fa-dedent{--fa:"\f03b"}.fa.fa-video-camera{--fa:"\f03d"}.fa.fa-picture-o{--fa:"\f03e"}.fa.fa-photo,.fa.fa-picture-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-photo{--fa:"\f03e"}.fa.fa-image{font-family:"Font Awesome 6 Free";font-weight:400;--fa:"\f03e"}.fa.fa-map-marker{--fa:"\f3c5"}.fa.fa-pencil-square-o{--fa:"\f044"}.fa.fa-edit,.fa.fa-pencil-square-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-edit{--fa:"\f044"}.fa.fa-share-square-o{--fa:"\f14d"}.fa.fa-check-square-o{font-family:"Font Awesome 6 Free";font-weight:400;--fa:"\f14a"}.fa.fa-arrows{--fa:"\f0b2"}.fa.fa-times-circle-o{--fa:"\f057"}.fa.fa-check-circle-o,.fa.fa-times-circle-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-check-circle-o{--fa:"\f058"}.fa.fa-mail-forward{--fa:"\f064"}.fa.fa-expand{--fa:"\f424"}.fa.fa-compress{--fa:"\f422"}.fa.fa-eye,.fa.fa-eye-slash{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-warning{--fa:"\f071"}.fa.fa-calendar{--fa:"\f073"}.fa.fa-arrows-v{--fa:"\f338"}.fa.fa-arrows-h{--fa:"\f337"}.fa.fa-bar-chart,.fa.fa-bar-chart-o{--fa:"\e0e3"}.fa.fa-twitter-square{--fa:"\f081"}.fa.fa-facebook-square,.fa.fa-twitter-square{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-facebook-square{--fa:"\f082"}.fa.fa-gears{--fa:"\f085"}.fa.fa-thumbs-o-up{--fa:"\f164"}.fa.fa-thumbs-o-down,.fa.fa-thumbs-o-up{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-thumbs-o-down{--fa:"\f165"}.fa.fa-heart-o{font-family:"Font Awesome 6 Free";font-weight:400;--fa:"\f004"}.fa.fa-sign-out{--fa:"\f2f5"}.fa.fa-linkedin-square{font-family:"Font Awesome 6 Brands";font-weight:400;--fa:"\f08c"}.fa.fa-thumb-tack{--fa:"\f08d"}.fa.fa-external-link{--fa:"\f35d"}.fa.fa-sign-in{--fa:"\f2f6"}.fa.fa-github-square{font-family:"Font Awesome 6 Brands";font-weight:400;--fa:"\f092"}.fa.fa-lemon-o{--fa:"\f094"}.fa.fa-lemon-o,.fa.fa-square-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-square-o{--fa:"\f0c8"}.fa.fa-bookmark-o{font-family:"Font Awesome 6 Free";font-weight:400;--fa:"\f02e"}.fa.fa-facebook,.fa.fa-twitter{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-facebook{--fa:"\f39e"}.fa.fa-facebook-f{--fa:"\f39e"}.fa.fa-facebook-f,.fa.fa-github{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-credit-card{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-feed{--fa:"\f09e"}.fa.fa-hdd-o{font-family:"Font Awesome 6 Free";font-weight:400;--fa:"\f0a0"}.fa.fa-hand-o-right{--fa:"\f0a4"}.fa.fa-hand-o-left,.fa.fa-hand-o-right{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-hand-o-left{--fa:"\f0a5"}.fa.fa-hand-o-up{--fa:"\f0a6"}.fa.fa-hand-o-down,.fa.fa-hand-o-up{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-hand-o-down{--fa:"\f0a7"}.fa.fa-globe{--fa:"\f57d"}.fa.fa-tasks{--fa:"\f828"}.fa.fa-arrows-alt{--fa:"\f31e"}.fa.fa-group{--fa:"\f0c0"}.fa.fa-chain{--fa:"\f0c1"}.fa.fa-cut{--fa:"\f0c4"}.fa.fa-files-o{--fa:"\f0c5"}.fa.fa-files-o,.fa.fa-floppy-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-floppy-o{--fa:"\f0c7"}.fa.fa-save{font-family:"Font Awesome 6 Free";font-weight:400;--fa:"\f0c7"}.fa.fa-navicon,.fa.fa-reorder{--fa:"\f0c9"}.fa.fa-magic{--fa:"\e2ca"}.fa.fa-pinterest,.fa.fa-pinterest-square{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-pinterest-square{--fa:"\f0d3"}.fa.fa-google-plus-square{--fa:"\f0d4"}.fa.fa-google-plus,.fa.fa-google-plus-square{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-google-plus{--fa:"\f0d5"}.fa.fa-money{--fa:"\f3d1"}.fa.fa-unsorted{--fa:"\f0dc"}.fa.fa-sort-desc{--fa:"\f0dd"}.fa.fa-sort-asc{--fa:"\f0de"}.fa.fa-linkedin{font-family:"Font Awesome 6 Brands";font-weight:400;--fa:"\f0e1"}.fa.fa-rotate-left{--fa:"\f0e2"}.fa.fa-legal{--fa:"\f0e3"}.fa.fa-dashboard,.fa.fa-tachometer{--fa:"\f625"}.fa.fa-comment-o{--fa:"\f075"}.fa.fa-comment-o,.fa.fa-comments-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-comments-o{--fa:"\f086"}.fa.fa-flash{--fa:"\f0e7"}.fa.fa-clipboard{--fa:"\f0ea"}.fa.fa-lightbulb-o{font-family:"Font Awesome 6 Free";font-weight:400;--fa:"\f0eb"}.fa.fa-exchange{--fa:"\f362"}.fa.fa-cloud-download{--fa:"\f0ed"}.fa.fa-cloud-upload{--fa:"\f0ee"}.fa.fa-bell-o{font-family:"Font Awesome 6 Free";font-weight:400;--fa:"\f0f3"}.fa.fa-cutlery{--fa:"\f2e7"}.fa.fa-file-text-o{--fa:"\f15c"}.fa.fa-building-o,.fa.fa-file-text-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-building-o{--fa:"\f1ad"}.fa.fa-hospital-o{font-family:"Font Awesome 6 Free";font-weight:400;--fa:"\f0f8"}.fa.fa-tablet{--fa:"\f3fa"}.fa.fa-mobile,.fa.fa-mobile-phone{--fa:"\f3cd"}.fa.fa-circle-o{font-family:"Font Awesome 6 Free";font-weight:400;--fa:"\f111"}.fa.fa-mail-reply{--fa:"\f3e5"}.fa.fa-github-alt{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-folder-o{--fa:"\f07b"}.fa.fa-folder-o,.fa.fa-folder-open-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-folder-open-o{--fa:"\f07c"}.fa.fa-smile-o{--fa:"\f118"}.fa.fa-frown-o,.fa.fa-smile-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-frown-o{--fa:"\f119"}.fa.fa-meh-o{--fa:"\f11a"}.fa.fa-keyboard-o,.fa.fa-meh-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-keyboard-o{--fa:"\f11c"}.fa.fa-flag-o{font-family:"Font Awesome 6 Free";font-weight:400;--fa:"\f024"}.fa.fa-mail-reply-all{--fa:"\f122"}.fa.fa-star-half-o{--fa:"\f5c0"}.fa.fa-star-half-empty,.fa.fa-star-half-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-star-half-empty{--fa:"\f5c0"}.fa.fa-star-half-full{font-family:"Font Awesome 6 Free";font-weight:400;--fa:"\f5c0"}.fa.fa-code-fork{--fa:"\f126"}.fa.fa-chain-broken,.fa.fa-unlink{--fa:"\f127"}.fa.fa-calendar-o{font-family:"Font Awesome 6 Free";font-weight:400;--fa:"\f133"}.fa.fa-css3,.fa.fa-html5,.fa.fa-maxcdn{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-unlock-alt{--fa:"\f09c"}.fa.fa-minus-square-o{font-family:"Font Awesome 6 Free";font-weight:400;--fa:"\f146"}.fa.fa-level-up{--fa:"\f3bf"}.fa.fa-level-down{--fa:"\f3be"}.fa.fa-pencil-square{--fa:"\f14b"}.fa.fa-external-link-square{--fa:"\f360"}.fa.fa-compass{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-caret-square-o-down{font-family:"Font Awesome 6 Free";font-weight:400;--fa:"\f150"}.fa.fa-toggle-down{font-family:"Font Awesome 6 Free";font-weight:400;--fa:"\f150"}.fa.fa-caret-square-o-up{font-family:"Font Awesome 6 Free";font-weight:400;--fa:"\f151"}.fa.fa-toggle-up{font-family:"Font Awesome 6 Free";font-weight:400;--fa:"\f151"}.fa.fa-caret-square-o-right{font-family:"Font Awesome 6 Free";font-weight:400;--fa:"\f152"}.fa.fa-toggle-right{font-family:"Font Awesome 6 Free";font-weight:400;--fa:"\f152"}.fa.fa-eur,.fa.fa-euro{--fa:"\f153"}.fa.fa-gbp{--fa:"\f154"}.fa.fa-dollar,.fa.fa-usd{--fa:"\24"}.fa.fa-inr,.fa.fa-rupee{--fa:"\e1bc"}.fa.fa-cny,.fa.fa-jpy,.fa.fa-rmb,.fa.fa-yen{--fa:"\f157"}.fa.fa-rouble,.fa.fa-rub,.fa.fa-ruble{--fa:"\f158"}.fa.fa-krw,.fa.fa-won{--fa:"\f159"}.fa.fa-bitcoin,.fa.fa-btc{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-bitcoin{--fa:"\f15a"}.fa.fa-file-text{--fa:"\f15c"}.fa.fa-sort-alpha-asc{--fa:"\f15d"}.fa.fa-sort-alpha-desc{--fa:"\f881"}.fa.fa-sort-amount-asc{--fa:"\f884"}.fa.fa-sort-amount-desc{--fa:"\f160"}.fa.fa-sort-numeric-asc{--fa:"\f162"}.fa.fa-sort-numeric-desc{--fa:"\f886"}.fa.fa-youtube-square{--fa:"\f431"}.fa.fa-xing,.fa.fa-xing-square,.fa.fa-youtube,.fa.fa-youtube-square{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-xing-square{--fa:"\f169"}.fa.fa-youtube-play{--fa:"\f167"}.fa.fa-adn,.fa.fa-bitbucket,.fa.fa-bitbucket-square,.fa.fa-dropbox,.fa.fa-flickr,.fa.fa-instagram,.fa.fa-stack-overflow,.fa.fa-youtube-play{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-bitbucket-square{--fa:"\f171"}.fa.fa-tumblr,.fa.fa-tumblr-square{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-tumblr-square{--fa:"\f174"}.fa.fa-long-arrow-down{--fa:"\f309"}.fa.fa-long-arrow-up{--fa:"\f30c"}.fa.fa-long-arrow-left{--fa:"\f30a"}.fa.fa-long-arrow-right{--fa:"\f30b"}.fa.fa-android,.fa.fa-apple,.fa.fa-dribbble,.fa.fa-foursquare,.fa.fa-gittip,.fa.fa-gratipay,.fa.fa-linux,.fa.fa-skype,.fa.fa-trello,.fa.fa-windows{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-gittip{--fa:"\f184"}.fa.fa-sun-o{--fa:"\f185"}.fa.fa-moon-o,.fa.fa-sun-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-moon-o{--fa:"\f186"}.fa.fa-pagelines,.fa.fa-renren,.fa.fa-stack-exchange,.fa.fa-vk,.fa.fa-weibo{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-arrow-circle-o-right{--fa:"\f35a"}.fa.fa-arrow-circle-o-left,.fa.fa-arrow-circle-o-right{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-arrow-circle-o-left{--fa:"\f359"}.fa.fa-caret-square-o-left{font-family:"Font Awesome 6 Free";font-weight:400;--fa:"\f191"}.fa.fa-toggle-left{--fa:"\f191"}.fa.fa-dot-circle-o,.fa.fa-toggle-left{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-dot-circle-o{--fa:"\f192"}.fa.fa-vimeo-square{font-family:"Font Awesome 6 Brands";font-weight:400;--fa:"\f194"}.fa.fa-try,.fa.fa-turkish-lira{--fa:"\e2bb"}.fa.fa-plus-square-o{font-family:"Font Awesome 6 Free";font-weight:400;--fa:"\f0fe"}.fa.fa-openid,.fa.fa-slack,.fa.fa-wordpress{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-bank,.fa.fa-institution{--fa:"\f19c"}.fa.fa-mortar-board{--fa:"\f19d"}.fa.fa-google,.fa.fa-reddit,.fa.fa-reddit-square,.fa.fa-yahoo{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-reddit-square{--fa:"\f1a2"}.fa.fa-behance,.fa.fa-behance-square,.fa.fa-delicious,.fa.fa-digg,.fa.fa-drupal,.fa.fa-joomla,.fa.fa-pied-piper-alt,.fa.fa-pied-piper-pp,.fa.fa-stumbleupon,.fa.fa-stumbleupon-circle{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-behance-square{--fa:"\f1b5"}.fa.fa-steam,.fa.fa-steam-square{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-steam-square{--fa:"\f1b7"}.fa.fa-automobile{--fa:"\f1b9"}.fa.fa-cab{--fa:"\f1ba"}.fa.fa-deviantart,.fa.fa-soundcloud,.fa.fa-spotify{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-file-pdf-o{--fa:"\f1c1"}.fa.fa-file-pdf-o,.fa.fa-file-word-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-file-word-o{--fa:"\f1c2"}.fa.fa-file-excel-o{--fa:"\f1c3"}.fa.fa-file-excel-o,.fa.fa-file-powerpoint-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-file-powerpoint-o{--fa:"\f1c4"}.fa.fa-file-image-o{--fa:"\f1c5"}.fa.fa-file-image-o,.fa.fa-file-photo-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-file-photo-o{--fa:"\f1c5"}.fa.fa-file-picture-o{--fa:"\f1c5"}.fa.fa-file-archive-o,.fa.fa-file-picture-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-file-archive-o{--fa:"\f1c6"}.fa.fa-file-zip-o{--fa:"\f1c6"}.fa.fa-file-audio-o,.fa.fa-file-zip-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-file-audio-o{--fa:"\f1c7"}.fa.fa-file-sound-o{--fa:"\f1c7"}.fa.fa-file-sound-o,.fa.fa-file-video-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-file-video-o{--fa:"\f1c8"}.fa.fa-file-movie-o{--fa:"\f1c8"}.fa.fa-file-code-o,.fa.fa-file-movie-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-file-code-o{--fa:"\f1c9"}.fa.fa-codepen,.fa.fa-jsfiddle,.fa.fa-vine{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-life-bouy,.fa.fa-life-buoy,.fa.fa-life-saver,.fa.fa-support{--fa:"\f1cd"}.fa.fa-circle-o-notch{--fa:"\f1ce"}.fa.fa-ra,.fa.fa-rebel{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-ra{--fa:"\f1d0"}.fa.fa-resistance{--fa:"\f1d0"}.fa.fa-empire,.fa.fa-ge,.fa.fa-resistance{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-ge{--fa:"\f1d1"}.fa.fa-git-square{--fa:"\f1d2"}.fa.fa-git,.fa.fa-git-square,.fa.fa-hacker-news,.fa.fa-y-combinator-square{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-y-combinator-square{--fa:"\f1d4"}.fa.fa-yc-square{--fa:"\f1d4"}.fa.fa-qq,.fa.fa-tencent-weibo,.fa.fa-wechat,.fa.fa-weixin,.fa.fa-yc-square{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-wechat{--fa:"\f1d7"}.fa.fa-send{--fa:"\f1d8"}.fa.fa-paper-plane-o{--fa:"\f1d8"}.fa.fa-paper-plane-o,.fa.fa-send-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-send-o{--fa:"\f1d8"}.fa.fa-circle-thin{font-family:"Font Awesome 6 Free";font-weight:400;--fa:"\f111"}.fa.fa-header{--fa:"\f1dc"}.fa.fa-futbol-o{--fa:"\f1e3"}.fa.fa-futbol-o,.fa.fa-soccer-ball-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-soccer-ball-o{--fa:"\f1e3"}.fa.fa-slideshare,.fa.fa-twitch,.fa.fa-yelp{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-newspaper-o{font-family:"Font Awesome 6 Free";font-weight:400;--fa:"\f1ea"}.fa.fa-cc-amex,.fa.fa-cc-discover,.fa.fa-cc-mastercard,.fa.fa-cc-paypal,.fa.fa-cc-stripe,.fa.fa-cc-visa,.fa.fa-google-wallet,.fa.fa-paypal{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-bell-slash-o{font-family:"Font Awesome 6 Free";font-weight:400;--fa:"\f1f6"}.fa.fa-trash{--fa:"\f2ed"}.fa.fa-copyright{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-eyedropper{--fa:"\f1fb"}.fa.fa-area-chart{--fa:"\f1fe"}.fa.fa-pie-chart{--fa:"\f200"}.fa.fa-line-chart{--fa:"\f201"}.fa.fa-lastfm,.fa.fa-lastfm-square{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-lastfm-square{--fa:"\f203"}.fa.fa-angellist,.fa.fa-ioxhost{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-cc{font-family:"Font Awesome 6 Free";font-weight:400;--fa:"\f20a"}.fa.fa-ils,.fa.fa-shekel,.fa.fa-sheqel{--fa:"\f20b"}.fa.fa-buysellads,.fa.fa-connectdevelop,.fa.fa-dashcube,.fa.fa-forumbee,.fa.fa-leanpub,.fa.fa-sellsy,.fa.fa-shirtsinbulk,.fa.fa-simplybuilt,.fa.fa-skyatlas{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-diamond{font-family:"Font Awesome 6 Free";font-weight:400;--fa:"\f3a5"}.fa.fa-intersex,.fa.fa-transgender{--fa:"\f224"}.fa.fa-transgender-alt{--fa:"\f225"}.fa.fa-facebook-official{--fa:"\f09a"}.fa.fa-facebook-official,.fa.fa-pinterest-p,.fa.fa-whatsapp{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-hotel{--fa:"\f236"}.fa.fa-medium,.fa.fa-viacoin,.fa.fa-y-combinator,.fa.fa-yc{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-yc{--fa:"\f23b"}.fa.fa-expeditedssl,.fa.fa-opencart,.fa.fa-optin-monster{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-battery,.fa.fa-battery-4{--fa:"\f240"}.fa.fa-battery-3{--fa:"\f241"}.fa.fa-battery-2{--fa:"\f242"}.fa.fa-battery-1{--fa:"\f243"}.fa.fa-battery-0{--fa:"\f244"}.fa.fa-object-group,.fa.fa-object-ungroup,.fa.fa-sticky-note-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-sticky-note-o{--fa:"\f249"}.fa.fa-cc-diners-club,.fa.fa-cc-jcb{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-clone{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-hourglass-o{--fa:"\f254"}.fa.fa-hourglass-1{--fa:"\f251"}.fa.fa-hourglass-2{--fa:"\f252"}.fa.fa-hourglass-3{--fa:"\f253"}.fa.fa-hand-rock-o{--fa:"\f255"}.fa.fa-hand-grab-o,.fa.fa-hand-rock-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-hand-grab-o{--fa:"\f255"}.fa.fa-hand-paper-o{--fa:"\f256"}.fa.fa-hand-paper-o,.fa.fa-hand-stop-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-hand-stop-o{--fa:"\f256"}.fa.fa-hand-scissors-o{--fa:"\f257"}.fa.fa-hand-lizard-o,.fa.fa-hand-scissors-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-hand-lizard-o{--fa:"\f258"}.fa.fa-hand-spock-o{--fa:"\f259"}.fa.fa-hand-pointer-o,.fa.fa-hand-spock-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-hand-pointer-o{--fa:"\f25a"}.fa.fa-hand-peace-o{--fa:"\f25b"}.fa.fa-hand-peace-o,.fa.fa-registered{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-creative-commons,.fa.fa-gg,.fa.fa-gg-circle,.fa.fa-odnoklassniki,.fa.fa-odnoklassniki-square{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-odnoklassniki-square{--fa:"\f264"}.fa.fa-chrome,.fa.fa-firefox,.fa.fa-get-pocket,.fa.fa-internet-explorer,.fa.fa-opera,.fa.fa-safari,.fa.fa-wikipedia-w{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-television{--fa:"\f26c"}.fa.fa-500px,.fa.fa-amazon,.fa.fa-contao{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-calendar-plus-o{--fa:"\f271"}.fa.fa-calendar-minus-o,.fa.fa-calendar-plus-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-calendar-minus-o{--fa:"\f272"}.fa.fa-calendar-times-o{--fa:"\f273"}.fa.fa-calendar-check-o,.fa.fa-calendar-times-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-calendar-check-o{--fa:"\f274"}.fa.fa-map-o{font-family:"Font Awesome 6 Free";font-weight:400;--fa:"\f279"}.fa.fa-commenting{--fa:"\f4ad"}.fa.fa-commenting-o{font-family:"Font Awesome 6 Free";font-weight:400;--fa:"\f4ad"}.fa.fa-houzz,.fa.fa-vimeo{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-vimeo{--fa:"\f27d"}.fa.fa-black-tie,.fa.fa-edge,.fa.fa-fonticons,.fa.fa-reddit-alien{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-credit-card-alt{--fa:"\f09d"}.fa.fa-codiepie,.fa.fa-fort-awesome,.fa.fa-mixcloud,.fa.fa-modx,.fa.fa-product-hunt,.fa.fa-scribd,.fa.fa-usb{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-pause-circle-o{--fa:"\f28b"}.fa.fa-pause-circle-o,.fa.fa-stop-circle-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-stop-circle-o{--fa:"\f28d"}.fa.fa-bluetooth,.fa.fa-bluetooth-b,.fa.fa-envira,.fa.fa-gitlab,.fa.fa-wheelchair-alt,.fa.fa-wpbeginner,.fa.fa-wpforms{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-wheelchair-alt{--fa:"\f368"}.fa.fa-question-circle-o{font-family:"Font Awesome 6 Free";font-weight:400;--fa:"\f059"}.fa.fa-volume-control-phone{--fa:"\f2a0"}.fa.fa-asl-interpreting{--fa:"\f2a3"}.fa.fa-deafness,.fa.fa-hard-of-hearing{--fa:"\f2a4"}.fa.fa-glide,.fa.fa-glide-g{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-signing{--fa:"\f2a7"}.fa.fa-viadeo,.fa.fa-viadeo-square{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-viadeo-square{--fa:"\f2aa"}.fa.fa-snapchat,.fa.fa-snapchat-ghost{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-snapchat-ghost{--fa:"\f2ab"}.fa.fa-snapchat-square{--fa:"\f2ad"}.fa.fa-first-order,.fa.fa-google-plus-official,.fa.fa-pied-piper,.fa.fa-snapchat-square,.fa.fa-themeisle,.fa.fa-yoast{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-google-plus-official{--fa:"\f2b3"}.fa.fa-google-plus-circle{--fa:"\f2b3"}.fa.fa-fa,.fa.fa-font-awesome,.fa.fa-google-plus-circle{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-fa{--fa:"\f2b4"}.fa.fa-handshake-o{--fa:"\f2b5"}.fa.fa-envelope-open-o,.fa.fa-handshake-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-envelope-open-o{--fa:"\f2b6"}.fa.fa-linode{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-address-book-o{font-family:"Font Awesome 6 Free";font-weight:400;--fa:"\f2b9"}.fa.fa-vcard{--fa:"\f2bb"}.fa.fa-address-card-o{--fa:"\f2bb"}.fa.fa-address-card-o,.fa.fa-vcard-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-vcard-o{--fa:"\f2bb"}.fa.fa-user-circle-o{--fa:"\f2bd"}.fa.fa-user-circle-o,.fa.fa-user-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-user-o{--fa:"\f007"}.fa.fa-id-badge{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-drivers-license{--fa:"\f2c2"}.fa.fa-id-card-o{--fa:"\f2c2"}.fa.fa-drivers-license-o,.fa.fa-id-card-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-drivers-license-o{--fa:"\f2c2"}.fa.fa-free-code-camp,.fa.fa-quora,.fa.fa-telegram{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-thermometer,.fa.fa-thermometer-4{--fa:"\f2c7"}.fa.fa-thermometer-3{--fa:"\f2c8"}.fa.fa-thermometer-2{--fa:"\f2c9"}.fa.fa-thermometer-1{--fa:"\f2ca"}.fa.fa-thermometer-0{--fa:"\f2cb"}.fa.fa-bathtub,.fa.fa-s15{--fa:"\f2cd"}.fa.fa-window-maximize,.fa.fa-window-restore{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-times-rectangle{--fa:"\f410"}.fa.fa-window-close-o{--fa:"\f410"}.fa.fa-times-rectangle-o,.fa.fa-window-close-o{font-family:"Font Awesome 6 Free";font-weight:400}.fa.fa-times-rectangle-o{--fa:"\f410"}.fa.fa-bandcamp,.fa.fa-eercast,.fa.fa-etsy,.fa.fa-grav,.fa.fa-imdb,.fa.fa-ravelry{font-family:"Font Awesome 6 Brands";font-weight:400}.fa.fa-eercast{--fa:"\f2da"}.fa.fa-snowflake-o{font-family:"Font Awesome 6 Free";font-weight:400;--fa:"\f2dc"}.fa.fa-meetup,.fa.fa-superpowers,.fa.fa-wpexplorer{font-family:"Font Awesome 6 Brands";font-weight:400} \ No newline at end of file diff --git a/doc/Contributing.md b/doc/Contributing.md deleted file mode 100644 index 5a7fccc81a..0000000000 --- a/doc/Contributing.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Contributing Guidelines ---- - -{!CONTRIBUTING.md!} diff --git a/doc/License.md b/doc/License.md deleted file mode 100644 index 6a51b7d35c..0000000000 --- a/doc/License.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: License ---- - -{!LICENSE!} diff --git a/doc/Manifest.md b/doc/Manifest.md deleted file mode 100644 index 1ad48cec43..0000000000 --- a/doc/Manifest.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -title: Manifest reference ---- - -{!manifest-reference.md!} - diff --git a/doc/Packaging.md b/doc/Packaging.md deleted file mode 100644 index 46a4c1bd96..0000000000 --- a/doc/Packaging.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Packaging with fpm ---- - -{!PACKAGING.md!} diff --git a/doc/index.md b/doc/index.md deleted file mode 100644 index 2db3638862..0000000000 --- a/doc/index.md +++ /dev/null @@ -1,3 +0,0 @@ ---- -title: Packaging and contributing ---- diff --git a/docs.md b/docs.md deleted file mode 100644 index e94a5633f8..0000000000 --- a/docs.md +++ /dev/null @@ -1,95 +0,0 @@ ---- -project: Fortran-lang/fpm -summary: Fortran Package Manager -project_github: https://github.com/fortran-lang/fpm -project_download: https://github.com/fortran-lang/fpm/archive/main.zip -author: fortran-lang/fpm contributors -author_pic: https://fortran-lang.org/assets/img/fortran_logo_512x512.png -author_email: fortran-lang@groups.io -github: https://github.com/fortran-lang -twitter: https://twitter.com/fortranlang -website: https://fortran-lang.org -src_dir: ./src - ./app -output_dir: ./fpm-doc -page_dir: ./doc -media_dir: ./doc/media -exclude_dir: ./example_packages - ./test -display: public - protected -source: true -proc_internals: true -sort: permission-alpha -favicon: doc/media/favicon.ico -print_creation_date: true -extra_mods: iso_fortran_env:https://gcc.gnu.org/onlinedocs/gfortran/ISO_005fFORTRAN_005fENV.html - tomlf:https://toml-f.github.io/toml-f - M_CLI2:https://github.com/urbanjost/M_CLI2 -creation_date: %Y-%m-%d %H:%M %z -md_extensions: markdown.extensions.toc - markdown.extensions.smarty ---- - -[TOC] - -# Fortran package manager developer documentation - -This is the main documentation of the Fortran package manager (*fpm*). -This document serves as developer documentation of *fpm* itself and contains general advice for developing in the *fpm* code base. - - -## The package manifest - -The central object describing an *fpm* project is the package manifest ``fpm.toml``. -The manifest is written in TOML, you can find the TOML specification at the official [TOML homepage](https://toml.io). - -The ``fpm.toml`` file targets project developers and maintainers to relieve them from writing build files for their packages. -With the package manifest a central place to collect information about the project is provided. -It contains the versioning and licensing meta data, as well as the information on external dependencies and the required build-tools or compiler settings. - -The manifest format specific to *fpm* projects is documented in the [manifest reference](page/Manifest.html). - -@Note For a more practical but less complete guide on creating *fpm* projects see the [packaging guide](page/Packaging.html). - -The details of the TOML parsing are implemented with using the [tomlf](https://toml-f.github.io/toml-f) module. -Generally, the interface to all TOML related functions for *fpm* is found in the proxy module [[fpm_toml]]. - -All the manifest types are bundled in [[fpm_manifest]]. -While the specific subtables for the package configuration are found in the ``src/fpm/manifest`` directory, they should be reexported in the [[fpm_manifest]] module if they should be elsewhere in *fpm*. - - -## Command line interface - -*fpm* is mainly used as a command line tool. -To work with an *fpm* project as a user you can completely rely on the command line. - -The command line interface is build with the [M_CLI2](https://github.com/urbanjost/M_CLI2) module and can be found in [[fpm_command_line]]. - - -## The package model - -Once front-end inputs have been received from the package manifest and command line interface, *fpm* will construct an -internal representation of the package and its dependencies. This internal representation is known as the package *model*. -The model and its associated data types should encapsulate all the information required to correctly build a package and -should be independent of the intended backend build system. Information stored in the model includes: build targets and -their inter-dependencies; compiler and compiler flags; library linking information. - -For more information on the contents of the package model and the process for constructing it, please see [[fpm_model]]. - -## The build backend - -Once a complete package model has been constructed, it can be passed to a *backend* for either performing the compilation -and linking of targets, or for generating configuration files for a third-party build system. -Currently, only a native backend is implemented in *fpm*. See [[fpm_backend]] for more information. - -## Generating this documentation - -This documentation is generated by [FORD](https://github.com/Fortran-FOSS-Programmers/FORD). -For more details on the [project file](https://github.com/fortran-lang/fpm/docs.md) and the comment markup in the source code visit the [FORD documentation](https://github.com/Fortran-FOSS-Programmers/ford/wiki). - -To regenerate this documentation run: - -```shell -ford docs.md -``` diff --git a/example_packages/README.md b/example_packages/README.md deleted file mode 100644 index 2a93b87106..0000000000 --- a/example_packages/README.md +++ /dev/null @@ -1,40 +0,0 @@ -# Example packages - -See the table below for a list of the example packages provided in this directory including -the features demonstrated in each package and which versions of fpm are supported. - -| Name | Features | Bootstrap (Haskell) fpm | fpm | -| --------------------------- | ------------------------------------------------------------- | :---------------------: | :-: | -| app_with_c | C files located in app directory (not src) | N | Y | -| app_with_submodule | Submodules located in app directory (not src) | N | Y | -| auto_discovery_off | Default layout with auto-discovery disabled | N | Y | -| c_header_only | C header-only library | N | Y | -| c_includes | C library with c include directory and dependency includes | N | Y | -| circular_example | Local path dependency; circular dependency | Y | Y | -| circular_test | Local path dependency; circular dependency | Y | Y | -| c_main | C App | N | Y | -| c_main_preprocess | C App; propagate command line preprocessor macros to the app | N | Y | -| cpp_files | C++ files get compiled using fpm | N | Y | -| fortran_includes | Fortran library with explicit include directory | Y | N | -| fpm_test_exe_issues | Test parse order of module files and apps | N | Y | -| hello_complex | Non-standard directory layout; multiple tests and executables | Y | Y | -| hello_complex_2 | Auto-discovery of tests and executables with modules | N | Y | -| hello_fpm | App-only; local path dependency | Y | Y | -| hello_fpm_path | Define local path dependencies | N | Y | -| hello_world | App-only | Y | Y | -| link_executable | Link external library to a single executable | N | Y | -| link_external | Link external library | N | Y | -| makefile_complex | External build command (makefile); local path dependency | Y | N | -| preprocess_cpp | Lib only; C preprocessing; Macro parsing | N | Y | -| preprocess_cpp_c | C App; progate macros from fpm.toml to app | N | Y | -| preprocess_cpp_deps | App; cpp preprocessor settings in local path dependency only | N | Y | -| preprocess_hello | App only; Macros remain local to the package | N | Y | -| preprocess_hello_dependency | Lib only; Macros not getting passed here from root | N | Y | -| program_with_module | App-only; module+program in single source file | Y | Y | -| submodules | Lib-only; submodules (3 levels) | N | Y | -| submodule_tree_shake | Test tree-shaking/pruning with submodules dependencies | N | Y | -| tree_shake | Test tree-shaking/pruning of unused module dependencies | N | Y | -| version_file | Read version number from a file in the project root | N | Y | -| with_c | Compile with `c` source files | N | Y | -| with_examples | Example-only | Y | Y | -| with_makefile | External build command (makefile) | Y | N | diff --git a/example_packages/app_with_c/.gitignore b/example_packages/app_with_c/.gitignore deleted file mode 100644 index a007feab07..0000000000 --- a/example_packages/app_with_c/.gitignore +++ /dev/null @@ -1 +0,0 @@ -build/* diff --git a/example_packages/app_with_c/app/c_code.c b/example_packages/app_with_c/app/c_code.c deleted file mode 100644 index 5a27c538b3..0000000000 --- a/example_packages/app_with_c/app/c_code.c +++ /dev/null @@ -1,11 +0,0 @@ -#include -/* - * Decides whether a given file name is a directory. - * return 1 if file exists and is a directory - * Source (Public domain): https://github.com/urbanjost/M_system - */ -int my_isdir(const char *path) -{ - struct stat sb; - return stat(path, &sb) == 0 && S_ISDIR(sb.st_mode); -} \ No newline at end of file diff --git a/example_packages/app_with_c/app/main.f90 b/example_packages/app_with_c/app/main.f90 deleted file mode 100644 index 297352df15..0000000000 --- a/example_packages/app_with_c/app/main.f90 +++ /dev/null @@ -1,37 +0,0 @@ -module with_c - use iso_c_binding, only: c_char, c_int, c_null_char - implicit none - -contains - - function system_isdir(dirname) - ! Source (Public domain): https://github.com/urbanjost/M_system - ! - implicit none - character(len=*), intent(in) :: dirname - logical :: system_isdir - - interface - function c_isdir(dirname) bind(C, name="my_isdir") result(c_ierr) - import c_char, c_int - character(kind=c_char, len=1), intent(in) :: dirname(*) - integer(kind=c_int) :: c_ierr - end function c_isdir - end interface - - system_isdir = c_isdir(trim(dirname)//c_null_char) == 1 - - end function system_isdir - -end module with_c - -program with_c_app - use with_c - implicit none - - write (*, *) "isdir('app') = ", system_isdir('app') - write (*, *) "isdir('src') = ", system_isdir('src') - write (*, *) "isdir('test') = ", system_isdir('test') - write (*, *) "isdir('bench') = ", system_isdir('bench') - -end program with_c_app diff --git a/example_packages/app_with_c/fpm.toml b/example_packages/app_with_c/fpm.toml deleted file mode 100644 index 97e31109c5..0000000000 --- a/example_packages/app_with_c/fpm.toml +++ /dev/null @@ -1 +0,0 @@ -name = "with_c" diff --git a/example_packages/app_with_submodule/.gitignore b/example_packages/app_with_submodule/.gitignore deleted file mode 100644 index a007feab07..0000000000 --- a/example_packages/app_with_submodule/.gitignore +++ /dev/null @@ -1 +0,0 @@ -build/* diff --git a/example_packages/app_with_submodule/app/app1/child1.f90 b/example_packages/app_with_submodule/app/app1/child1.f90 deleted file mode 100644 index 8f0c97247f..0000000000 --- a/example_packages/app_with_submodule/app/app1/child1.f90 +++ /dev/null @@ -1,16 +0,0 @@ -submodule(parent) child1 -implicit none - -interface - module function my_fun() result (b) - integer :: b - end function my_fun -end interface - -contains - -module procedure my_sub1 - a = my_fun() -end procedure my_sub1 - -end submodule child1 \ No newline at end of file diff --git a/example_packages/app_with_submodule/app/app1/grandchild.f90 b/example_packages/app_with_submodule/app/app1/grandchild.f90 deleted file mode 100644 index ad8913e641..0000000000 --- a/example_packages/app_with_submodule/app/app1/grandchild.f90 +++ /dev/null @@ -1,10 +0,0 @@ -submodule(parent:child1) grandchild -implicit none - -contains - -module procedure my_fun - b = 1 -end procedure my_fun - -end submodule grandchild \ No newline at end of file diff --git a/example_packages/app_with_submodule/app/app1/main1.f90 b/example_packages/app_with_submodule/app/app1/main1.f90 deleted file mode 100644 index bbcc3450db..0000000000 --- a/example_packages/app_with_submodule/app/app1/main1.f90 +++ /dev/null @@ -1,14 +0,0 @@ -program test -use parent -implicit none - -integer :: a - -call my_sub1(a) - -if (a /= 1) then - write(*,*) 'FAILED: Unexpected value of a' - stop 1 -end if - -end program test \ No newline at end of file diff --git a/example_packages/app_with_submodule/app/app2/child2.f90 b/example_packages/app_with_submodule/app/app2/child2.f90 deleted file mode 100644 index 9eb4fb9225..0000000000 --- a/example_packages/app_with_submodule/app/app2/child2.f90 +++ /dev/null @@ -1,10 +0,0 @@ -submodule(parent) child2 -implicit none - -contains - -module procedure my_sub1 - a = 2 -end procedure my_sub1 - -end submodule child2 \ No newline at end of file diff --git a/example_packages/app_with_submodule/app/app2/main2.f90 b/example_packages/app_with_submodule/app/app2/main2.f90 deleted file mode 100644 index f528638900..0000000000 --- a/example_packages/app_with_submodule/app/app2/main2.f90 +++ /dev/null @@ -1,14 +0,0 @@ -program test -use parent -implicit none - -integer :: a - -call my_sub1(a) - -if (a /= 2) then - write(*,*) 'FAILED: Unexpected value of a' - stop 1 -end if - -end program test \ No newline at end of file diff --git a/example_packages/app_with_submodule/fpm.toml b/example_packages/app_with_submodule/fpm.toml deleted file mode 100644 index 8b2847ee18..0000000000 --- a/example_packages/app_with_submodule/fpm.toml +++ /dev/null @@ -1 +0,0 @@ -name = "app_with_submodule" \ No newline at end of file diff --git a/example_packages/app_with_submodule/src/parent.f90 b/example_packages/app_with_submodule/src/parent.f90 deleted file mode 100644 index c3386eee65..0000000000 --- a/example_packages/app_with_submodule/src/parent.f90 +++ /dev/null @@ -1,11 +0,0 @@ -module parent -implicit none - -interface - - module subroutine my_sub1(a) - integer, intent(out) :: a - end subroutine my_sub1 -end interface - -end module parent \ No newline at end of file diff --git a/example_packages/auto_discovery_off/.gitignore b/example_packages/auto_discovery_off/.gitignore deleted file mode 100644 index a007feab07..0000000000 --- a/example_packages/auto_discovery_off/.gitignore +++ /dev/null @@ -1 +0,0 @@ -build/* diff --git a/example_packages/auto_discovery_off/app/main.f90 b/example_packages/auto_discovery_off/app/main.f90 deleted file mode 100644 index 8902dc6de8..0000000000 --- a/example_packages/auto_discovery_off/app/main.f90 +++ /dev/null @@ -1,6 +0,0 @@ -program main -implicit none - -print *, "This program should run." - -end program main diff --git a/example_packages/auto_discovery_off/app/unused.f90 b/example_packages/auto_discovery_off/app/unused.f90 deleted file mode 100644 index 57d8153878..0000000000 --- a/example_packages/auto_discovery_off/app/unused.f90 +++ /dev/null @@ -1,6 +0,0 @@ -program unused -implicit none - -print *, "This program should NOT run." - -end program unused diff --git a/example_packages/auto_discovery_off/fpm.toml b/example_packages/auto_discovery_off/fpm.toml deleted file mode 100644 index 9a852dfc6f..0000000000 --- a/example_packages/auto_discovery_off/fpm.toml +++ /dev/null @@ -1,12 +0,0 @@ -name = "auto_discovery_off" - -[build] -auto-executables = false -auto-tests = false - - -[[test]] -name = "my_test" -source-dir="test" -main="my_test.f90" - diff --git a/example_packages/auto_discovery_off/test/my_test.f90 b/example_packages/auto_discovery_off/test/my_test.f90 deleted file mode 100644 index fd59f9fef4..0000000000 --- a/example_packages/auto_discovery_off/test/my_test.f90 +++ /dev/null @@ -1,6 +0,0 @@ -program my_test -implicit none - -print *, "Test passed! That was easy!" - -end program my_test diff --git a/example_packages/auto_discovery_off/test/unused_test.f90 b/example_packages/auto_discovery_off/test/unused_test.f90 deleted file mode 100644 index 5c4261120a..0000000000 --- a/example_packages/auto_discovery_off/test/unused_test.f90 +++ /dev/null @@ -1,7 +0,0 @@ -program unused_test -implicit none - -print *, "This program should NOT run." - -end program unused_test - diff --git a/example_packages/auto_with_nondefault_main/.gitignore b/example_packages/auto_with_nondefault_main/.gitignore deleted file mode 100644 index 8edd8d1924..0000000000 --- a/example_packages/auto_with_nondefault_main/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -build/* -installed/* diff --git a/example_packages/auto_with_nondefault_main/README.md b/example_packages/auto_with_nondefault_main/README.md deleted file mode 100644 index 8cae78a035..0000000000 --- a/example_packages/auto_with_nondefault_main/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# auto_with_nondefault_main -Install auto-executable with non-default source name -fpm install --prefix=/path/to/install diff --git a/example_packages/auto_with_nondefault_main/app/non_default_name.f90 b/example_packages/auto_with_nondefault_main/app/non_default_name.f90 deleted file mode 100644 index b31155a8df..0000000000 --- a/example_packages/auto_with_nondefault_main/app/non_default_name.f90 +++ /dev/null @@ -1,3 +0,0 @@ -program main - print *, 'hello, world!' -end program main diff --git a/example_packages/auto_with_nondefault_main/fpm.toml b/example_packages/auto_with_nondefault_main/fpm.toml deleted file mode 100644 index 549d6cd040..0000000000 --- a/example_packages/auto_with_nondefault_main/fpm.toml +++ /dev/null @@ -1,5 +0,0 @@ -name = "auto_with_nondefault_main" -[build] -auto-executables = true -[library] - diff --git a/example_packages/c_header_only/.gitignore b/example_packages/c_header_only/.gitignore deleted file mode 100644 index a007feab07..0000000000 --- a/example_packages/c_header_only/.gitignore +++ /dev/null @@ -1 +0,0 @@ -build/* diff --git a/example_packages/c_header_only/fpm.toml b/example_packages/c_header_only/fpm.toml deleted file mode 100644 index 372fe0e88c..0000000000 --- a/example_packages/c_header_only/fpm.toml +++ /dev/null @@ -1 +0,0 @@ -name = "c_header_only" diff --git a/example_packages/c_header_only/include/c_header.h b/example_packages/c_header_only/include/c_header.h deleted file mode 100644 index ec88a4bffa..0000000000 --- a/example_packages/c_header_only/include/c_header.h +++ /dev/null @@ -1 +0,0 @@ -int printf ( const char * format, ... ); diff --git a/example_packages/c_includes/.gitignore b/example_packages/c_includes/.gitignore deleted file mode 100644 index a007feab07..0000000000 --- a/example_packages/c_includes/.gitignore +++ /dev/null @@ -1 +0,0 @@ -build/* diff --git a/example_packages/c_includes/fpm.toml b/example_packages/c_includes/fpm.toml deleted file mode 100644 index 46918d610c..0000000000 --- a/example_packages/c_includes/fpm.toml +++ /dev/null @@ -1,4 +0,0 @@ -name = "c_includes" - -[dependencies] -c_header_only = { path = "../c_header_only"} diff --git a/example_packages/c_includes/include/lib.h b/example_packages/c_includes/include/lib.h deleted file mode 100644 index 4f29282ceb..0000000000 --- a/example_packages/c_includes/include/lib.h +++ /dev/null @@ -1,4 +0,0 @@ -// Include from "c_header_only" dependency -#include "c_header.h" - -int test(const int a); diff --git a/example_packages/c_includes/src/lib.c b/example_packages/c_includes/src/lib.c deleted file mode 100644 index 233982208c..0000000000 --- a/example_packages/c_includes/src/lib.c +++ /dev/null @@ -1,7 +0,0 @@ -#include "lib.h" - -int test(const int a){ - - return printf("input: %d\n", a); - -} \ No newline at end of file diff --git a/example_packages/c_main/app/main.c b/example_packages/c_main/app/main.c deleted file mode 100644 index 398ec675a0..0000000000 --- a/example_packages/c_main/app/main.c +++ /dev/null @@ -1,5 +0,0 @@ -int -main (void) -{ - return 0; -} diff --git a/example_packages/c_main/fpm.toml b/example_packages/c_main/fpm.toml deleted file mode 100644 index eb18e9be50..0000000000 --- a/example_packages/c_main/fpm.toml +++ /dev/null @@ -1,5 +0,0 @@ -name = "c-main" - -[[executable]] -name = "c-main" -main = "main.c" diff --git a/example_packages/c_main_preprocess/app/main.c b/example_packages/c_main_preprocess/app/main.c deleted file mode 100644 index 61fbaacbeb..0000000000 --- a/example_packages/c_main_preprocess/app/main.c +++ /dev/null @@ -1,7 +0,0 @@ -#include - -#include "val.h" - -int main() { - printf("%d\n", variable); -} diff --git a/example_packages/c_main_preprocess/fpm.toml b/example_packages/c_main_preprocess/fpm.toml deleted file mode 100644 index 7a210658f4..0000000000 --- a/example_packages/c_main_preprocess/fpm.toml +++ /dev/null @@ -1,7 +0,0 @@ -name = "c_main_preprocess" -[library] -include-dir = ["src"] - -[[executable]] -name="main-c" -main="main.c" diff --git a/example_packages/c_main_preprocess/src/stub.c b/example_packages/c_main_preprocess/src/stub.c deleted file mode 100644 index 2c4c16b3bd..0000000000 --- a/example_packages/c_main_preprocess/src/stub.c +++ /dev/null @@ -1 +0,0 @@ -#include "val.h" diff --git a/example_packages/c_main_preprocess/src/val.h b/example_packages/c_main_preprocess/src/val.h deleted file mode 100644 index 884f644d30..0000000000 --- a/example_packages/c_main_preprocess/src/val.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _VAL_H_ -#define _VAL_H_ - -#ifdef VAL -const int variable = 1; -#endif -#endif diff --git a/example_packages/circular_example/.gitignore b/example_packages/circular_example/.gitignore deleted file mode 100644 index a007feab07..0000000000 --- a/example_packages/circular_example/.gitignore +++ /dev/null @@ -1 +0,0 @@ -build/* diff --git a/example_packages/circular_example/fpm.toml b/example_packages/circular_example/fpm.toml deleted file mode 100644 index c524ce5762..0000000000 --- a/example_packages/circular_example/fpm.toml +++ /dev/null @@ -1,4 +0,0 @@ -name = "circular_example" - -[dev-dependencies] -circular_test = { path = "../circular_test" } diff --git a/example_packages/circular_example/src/greet_m.f90 b/example_packages/circular_example/src/greet_m.f90 deleted file mode 100644 index 2372f9a446..0000000000 --- a/example_packages/circular_example/src/greet_m.f90 +++ /dev/null @@ -1,13 +0,0 @@ -module greet_m - implicit none - private - - public :: make_greeting -contains - function make_greeting(name) result(greeting) - character(len=*), intent(in) :: name - character(len=:), allocatable :: greeting - - greeting = "Hello, " // name // "!" - end function make_greeting -end module greet_m diff --git a/example_packages/circular_example/test/main.f90 b/example_packages/circular_example/test/main.f90 deleted file mode 100644 index 5b7d8030e4..0000000000 --- a/example_packages/circular_example/test/main.f90 +++ /dev/null @@ -1,7 +0,0 @@ -program run_tests - use hello_test, only: run_test - - implicit none - - call run_test -end program run_tests diff --git a/example_packages/circular_test/.gitignore b/example_packages/circular_test/.gitignore deleted file mode 100644 index a007feab07..0000000000 --- a/example_packages/circular_test/.gitignore +++ /dev/null @@ -1 +0,0 @@ -build/* diff --git a/example_packages/circular_test/fpm.toml b/example_packages/circular_test/fpm.toml deleted file mode 100644 index 56cfa2e3a5..0000000000 --- a/example_packages/circular_test/fpm.toml +++ /dev/null @@ -1,4 +0,0 @@ -name = "circular_test" - -[dependencies] -circular_example = { path = "../circular_example"} diff --git a/example_packages/circular_test/src/hello_test.f90 b/example_packages/circular_test/src/hello_test.f90 deleted file mode 100644 index 5a591c6123..0000000000 --- a/example_packages/circular_test/src/hello_test.f90 +++ /dev/null @@ -1,12 +0,0 @@ -module hello_test - use greet_m, only: make_greeting - - implicit none - private - - public :: run_test -contains - subroutine run_test - print *, make_greeting("from test") - end subroutine run_test -end module hello_test diff --git a/example_packages/cpp_files/README.md b/example_packages/cpp_files/README.md deleted file mode 100644 index ff795a76bb..0000000000 --- a/example_packages/cpp_files/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# cpp_files -My cool new project! diff --git a/example_packages/cpp_files/fpm.toml b/example_packages/cpp_files/fpm.toml deleted file mode 100644 index 1e29a93c40..0000000000 --- a/example_packages/cpp_files/fpm.toml +++ /dev/null @@ -1 +0,0 @@ -name = "cpp_files" diff --git a/example_packages/cpp_files/src/cpp_files.f90 b/example_packages/cpp_files/src/cpp_files.f90 deleted file mode 100644 index 818beb53a2..0000000000 --- a/example_packages/cpp_files/src/cpp_files.f90 +++ /dev/null @@ -1,15 +0,0 @@ -module cpp_files - use, intrinsic :: ISO_C_Binding - implicit none - private - - public :: intvec_maxval - - interface - integer function intvec_maxval(array, n) bind(C, name = "intvec_maxval") - import :: c_int, c_size_t - integer(c_int), intent(in) :: array(*) - integer(c_size_t), intent(in), value :: n - end function intvec_maxval - end interface -end module cpp_files diff --git a/example_packages/cpp_files/src/hello_world.cpp b/example_packages/cpp_files/src/hello_world.cpp deleted file mode 100644 index 54720593f8..0000000000 --- a/example_packages/cpp_files/src/hello_world.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include -#include - -extern "C" { - -int intvec_maxval(int* array, size_t n){ - - std::vector vec(array, array + n); - - return *(std::max_element(vec.begin(), vec.end())); - -} - -} \ No newline at end of file diff --git a/example_packages/cpp_files/test/check.f90 b/example_packages/cpp_files/test/check.f90 deleted file mode 100644 index 2e5bd1ee84..0000000000 --- a/example_packages/cpp_files/test/check.f90 +++ /dev/null @@ -1,18 +0,0 @@ -program check - use iso_c_binding, only: c_size_t - use cpp_files - implicit none - - integer :: i, max_element - integer, parameter :: array(*) = [(i,i=-50,10)] - - max_element = intvec_maxval(array,size(array,1,c_size_t)) - - if (max_element == maxval(array)) then - write(*,*) ' PASSED: Max element is ',max_element - else - write(*,*) ' (!) FAILED: Incorrect max element returned' - stop 1 - end if - -end program check diff --git a/example_packages/dependency_priority/README.md b/example_packages/dependency_priority/README.md deleted file mode 100644 index 58038a2f98..0000000000 --- a/example_packages/dependency_priority/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# dependency_tree -Check dependency tree cascade. "Standard" fpm dependencies feature that the highest-priority one wins -(i.e., top-level dependencies in the manifest, or the first time it's found down the dependency tree) -Check this behavior is confirmed. diff --git a/example_packages/dependency_priority/app/main.f90 b/example_packages/dependency_priority/app/main.f90 deleted file mode 100644 index 4f68826031..0000000000 --- a/example_packages/dependency_priority/app/main.f90 +++ /dev/null @@ -1,14 +0,0 @@ -program main - use tomlf_version, only: tomlf_version_string - implicit none - - print *, 'using version =',tomlf_version_string - print *, 'should be =0.3.1' - - if (tomlf_version_string=="0.3.1") then - stop 0 - else - stop 1 - endif - -end program main diff --git a/example_packages/dependency_priority/fpm.toml b/example_packages/dependency_priority/fpm.toml deleted file mode 100644 index 61dda2d4bd..0000000000 --- a/example_packages/dependency_priority/fpm.toml +++ /dev/null @@ -1,12 +0,0 @@ -name = "dependency_tree" -version = "0.1.0" -[build] -auto-executables=true -[dependencies] -# Request toml-f v0.3.1. -toml-f.git = "https://github.com/toml-f/toml-f" -toml-f.tag = "v0.3.1" -# jonquil 0.2.0 requires toml-f v0.4.0. -# Because 0.4.0 is a derived dependency, it should not be used -jonquil.git = "https://github.com/toml-f/jonquil" -jonquil.tag = "v0.2.0" diff --git a/example_packages/fixed-form/app/main.f90 b/example_packages/fixed-form/app/main.f90 deleted file mode 100644 index 4524bbd8d0..0000000000 --- a/example_packages/fixed-form/app/main.f90 +++ /dev/null @@ -1,4 +0,0 @@ - program test - use lib - call hello - end diff --git a/example_packages/fixed-form/fpm.toml b/example_packages/fixed-form/fpm.toml deleted file mode 100644 index 26b8e4bb68..0000000000 --- a/example_packages/fixed-form/fpm.toml +++ /dev/null @@ -1,2 +0,0 @@ -name = "fixed-form" -fortran.source-form = "fixed" diff --git a/example_packages/fixed-form/src/lib.f90 b/example_packages/fixed-form/src/lib.f90 deleted file mode 100644 index a2ed363db1..0000000000 --- a/example_packages/fixed-form/src/lib.f90 +++ /dev/null @@ -1,7 +0,0 @@ - module lib - contains - subroutine h e l l o - print '(a)', - +"Hello, fixed world!" - end subroutine - end module diff --git a/example_packages/fortran_includes/.gitignore b/example_packages/fortran_includes/.gitignore deleted file mode 100644 index a007feab07..0000000000 --- a/example_packages/fortran_includes/.gitignore +++ /dev/null @@ -1 +0,0 @@ -build/* diff --git a/example_packages/fortran_includes/fpm.toml b/example_packages/fortran_includes/fpm.toml deleted file mode 100644 index 8557b72dad..0000000000 --- a/example_packages/fortran_includes/fpm.toml +++ /dev/null @@ -1,4 +0,0 @@ -name = "fortran_includes" - -[library] -include-dir = "inc" diff --git a/example_packages/fortran_includes/inc/parameters.f90 b/example_packages/fortran_includes/inc/parameters.f90 deleted file mode 100644 index e9e1af507e..0000000000 --- a/example_packages/fortran_includes/inc/parameters.f90 +++ /dev/null @@ -1 +0,0 @@ -integer, parameter :: dp = kind(0.d0) \ No newline at end of file diff --git a/example_packages/fortran_includes/src/lib.f90 b/example_packages/fortran_includes/src/lib.f90 deleted file mode 100644 index a27a001e2a..0000000000 --- a/example_packages/fortran_includes/src/lib.f90 +++ /dev/null @@ -1,14 +0,0 @@ -module test_mod - implicit none - - include "parameters.f90" - - contains - - subroutine test_sub(a) - real(dp), intent(in) :: a - - write(*,*) 'a: ', a - end subroutine test_sub - -end module test_mod \ No newline at end of file diff --git a/example_packages/fpm_test_exe_issues/fpm.toml b/example_packages/fpm_test_exe_issues/fpm.toml deleted file mode 100644 index 45c078c883..0000000000 --- a/example_packages/fpm_test_exe_issues/fpm.toml +++ /dev/null @@ -1,15 +0,0 @@ -# See https://github.com/fortran-lang/fpm/issues/734 -name = "fpm-test" - -[build] -auto-executables = true -auto-tests = true -auto-examples = true - -[install] -library = false - -[[executable]] -name = "main" -source-dir = "src" -main = "main.f90" \ No newline at end of file diff --git a/example_packages/fpm_test_exe_issues/src/a/a_mod.f90 b/example_packages/fpm_test_exe_issues/src/a/a_mod.f90 deleted file mode 100644 index f5e27fbdad..0000000000 --- a/example_packages/fpm_test_exe_issues/src/a/a_mod.f90 +++ /dev/null @@ -1,10 +0,0 @@ -module a_mod - use b_mod, only: hello_world - -contains - - subroutine a_mod_sub() - call hello_world() - end subroutine - -end module diff --git a/example_packages/fpm_test_exe_issues/src/b_mod.f90 b/example_packages/fpm_test_exe_issues/src/b_mod.f90 deleted file mode 100644 index beaa0807ed..0000000000 --- a/example_packages/fpm_test_exe_issues/src/b_mod.f90 +++ /dev/null @@ -1,10 +0,0 @@ -module b_mod - implicit none - -contains - - subroutine hello_world() - print *, "Hello world!" - end subroutine - -end module diff --git a/example_packages/fpm_test_exe_issues/src/main.f90 b/example_packages/fpm_test_exe_issues/src/main.f90 deleted file mode 100644 index 9489932d0c..0000000000 --- a/example_packages/fpm_test_exe_issues/src/main.f90 +++ /dev/null @@ -1,6 +0,0 @@ -program main - use a_mod - implicit none - - call a_mod_sub() -end program diff --git a/example_packages/fpm_test_exit_code/README.md b/example_packages/fpm_test_exit_code/README.md deleted file mode 100644 index 1f6757a092..0000000000 --- a/example_packages/fpm_test_exit_code/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# fpm_test_exit_code -Test program for application exit codes -see https://github.com/fortran-lang/fpm/issues/848 - -This app expects to receive an integer command line argument, to check whether it is odd or even. -It returns 0 on success (odd input), or among a few error codes otherwise. diff --git a/example_packages/fpm_test_exit_code/app/main.f90 b/example_packages/fpm_test_exit_code/app/main.f90 deleted file mode 100644 index 1e9d1aaaed..0000000000 --- a/example_packages/fpm_test_exit_code/app/main.f90 +++ /dev/null @@ -1,42 +0,0 @@ -! Test program for application exit codes -! see https://github.com/fortran-lang/fpm/issues/848 - -! This app expects to receive an integer command line argument, to check whether it is odd or even. -! It returns 0 on success (odd input), or among a few error codes otherwise. - -program check_odd_number - implicit none - - integer, parameter :: SUCCESS = 0 - integer, parameter :: INVALID_ARGUMENT = 1 - integer, parameter :: NOT_AN_INTEGER = 2 - integer, parameter :: NOT_ODD = 3 - - character(len=1024) :: buffer - integer :: ierr,ln,the_number - - ! If the argument is missing or not an integer, return an error flag - if (command_argument_count()/=1) stop INVALID_ARGUMENT - - ! Get command argument - call get_command_argument(1,value=buffer,length=ln,status=ierr) - - ! On invalid string - if (ln<1 .or. ierr/=0) stop INVALID_ARGUMENT - - ! Read to int - read(buffer(:ln),*,iostat=ierr) the_number - - ! On invalid integer - if (ierr/=0) stop NOT_AN_INTEGER - - ! Check if it is odd or even - if (mod(the_number,2)==0) then - ! Is even - stop NOT_ODD - else - ! Is odd - stop SUCCESS - end if - -end program check_odd_number diff --git a/example_packages/fpm_test_exit_code/fpm.toml b/example_packages/fpm_test_exit_code/fpm.toml deleted file mode 100644 index c8fc1977d0..0000000000 --- a/example_packages/fpm_test_exit_code/fpm.toml +++ /dev/null @@ -1,10 +0,0 @@ -name = "fpm_test_exit_code" -version = "0.1.0" -license = "license" -author = "Federico Perini" -maintainer = "jane.doe@example.com" -copyright = "Copyright 2023, Jane Doe" -[build] -auto-executables = true -[install] -library = false diff --git a/example_packages/free-form/app/main.f b/example_packages/free-form/app/main.f deleted file mode 100644 index e2d305a049..0000000000 --- a/example_packages/free-form/app/main.f +++ /dev/null @@ -1,4 +0,0 @@ -program test -use lib -call hello -end diff --git a/example_packages/free-form/fpm.toml b/example_packages/free-form/fpm.toml deleted file mode 100644 index c10afba2a6..0000000000 --- a/example_packages/free-form/fpm.toml +++ /dev/null @@ -1,3 +0,0 @@ -name = "free-form" -fortran.source-form = "free" -executable = [{main="main.f", name="free-form"}] diff --git a/example_packages/free-form/src/lib.f b/example_packages/free-form/src/lib.f deleted file mode 100644 index 520d6265c9..0000000000 --- a/example_packages/free-form/src/lib.f +++ /dev/null @@ -1,6 +0,0 @@ -module lib -contains -subroutine hello -print '(a)', "Hello, free world!" -end subroutine -end module diff --git a/example_packages/hello_complex/.gitignore b/example_packages/hello_complex/.gitignore deleted file mode 100644 index a007feab07..0000000000 --- a/example_packages/hello_complex/.gitignore +++ /dev/null @@ -1 +0,0 @@ -build/* diff --git a/example_packages/hello_complex/apps/say_goodbye/say_goodbye.f90 b/example_packages/hello_complex/apps/say_goodbye/say_goodbye.f90 deleted file mode 100644 index 6966e790f6..0000000000 --- a/example_packages/hello_complex/apps/say_goodbye/say_goodbye.f90 +++ /dev/null @@ -1,7 +0,0 @@ -program say_goodbye - use farewell_m, only: make_farewell - - implicit none - - print *, make_farewell("World") -end program say_goodbye diff --git a/example_packages/hello_complex/apps/say_hello/say_Hello.f90 b/example_packages/hello_complex/apps/say_hello/say_Hello.f90 deleted file mode 100644 index cf4a7421d3..0000000000 --- a/example_packages/hello_complex/apps/say_hello/say_Hello.f90 +++ /dev/null @@ -1,7 +0,0 @@ -program say_Hello - use greet_m, only: make_greeting - - implicit none - - print *, make_greeting("World") -end program say_Hello diff --git a/example_packages/hello_complex/fpm.toml b/example_packages/hello_complex/fpm.toml deleted file mode 100644 index 30ed293644..0000000000 --- a/example_packages/hello_complex/fpm.toml +++ /dev/null @@ -1,24 +0,0 @@ -name = "hello_complex" - -[library] -source-dir="source" - -[[executable]] -name="say_Hello" -source-dir="apps/say_hello" -main="say_Hello.f90" - -[[executable]] -name="say_goodbye" -source-dir="apps/say_goodbye" -main="say_goodbye.f90" - -[[test]] -name="greet_test" -source-dir="tests/greet" -main="greet_test.f90" - -[[test]] -name="farewell_test" -source-dir="tests/farewell" -main="farewell_test.f90" diff --git a/example_packages/hello_complex/source/farewell_m.f90 b/example_packages/hello_complex/source/farewell_m.f90 deleted file mode 100644 index fbc45edf22..0000000000 --- a/example_packages/hello_complex/source/farewell_m.f90 +++ /dev/null @@ -1,14 +0,0 @@ -module farewell_m - use subdir_constants, only: FAREWELL_STR - implicit none - private - - public :: make_farewell -contains - function make_farewell(name) result(greeting) - character(len=*), intent(in) :: name - character(len=:), allocatable :: greeting - - greeting = FAREWELL_STR // name // "!" - end function make_farewell -end module farewell_m diff --git a/example_packages/hello_complex/source/greet_m.f90 b/example_packages/hello_complex/source/greet_m.f90 deleted file mode 100644 index 38afd08352..0000000000 --- a/example_packages/hello_complex/source/greet_m.f90 +++ /dev/null @@ -1,14 +0,0 @@ -module greet_m - use subdir_constants, only: GREET_STR - implicit none - private - - public :: make_greeting -contains - function make_greeting(name) result(greeting) - character(len=*), intent(in) :: name - character(len=:), allocatable :: greeting - - greeting = GREET_STR // name // "!" - end function make_greeting -end module greet_m diff --git a/example_packages/hello_complex/source/subdir/constants.f90 b/example_packages/hello_complex/source/subdir/constants.f90 deleted file mode 100644 index 59d6e5fee6..0000000000 --- a/example_packages/hello_complex/source/subdir/constants.f90 +++ /dev/null @@ -1,7 +0,0 @@ -module subdir_constants -implicit none - -character(*), parameter :: GREET_STR = 'Hello, ' -character(*), parameter :: FAREWELL_STR = 'Goodbye, ' - -end module subdir_constants diff --git a/example_packages/hello_complex/tests/farewell/farewell_test.f90 b/example_packages/hello_complex/tests/farewell/farewell_test.f90 deleted file mode 100644 index 0f21b18015..0000000000 --- a/example_packages/hello_complex/tests/farewell/farewell_test.f90 +++ /dev/null @@ -1,18 +0,0 @@ -program farewell_test - use farewell_m, only: make_farewell - use iso_fortran_env, only: error_unit, output_unit - - implicit none - - character(len=:), allocatable :: farewell - - allocate(character(len=0) :: farewell) - farewell = make_farewell("World") - - if (farewell == "Goodbye, World!") then - write(output_unit, *) "Passed" - else - write(error_unit, *) "Failed" - call exit(1) - end if -end program farewell_test diff --git a/example_packages/hello_complex/tests/greet/greet_test.f90 b/example_packages/hello_complex/tests/greet/greet_test.f90 deleted file mode 100644 index 41fa50878e..0000000000 --- a/example_packages/hello_complex/tests/greet/greet_test.f90 +++ /dev/null @@ -1,18 +0,0 @@ -program greet_test - use greet_m, only: make_greeting - use iso_fortran_env, only: error_unit, output_unit - - implicit none - - character(len=:), allocatable :: greeting - - allocate(character(len=0) :: greeting) - greeting = make_greeting("World") - - if (greeting == "Hello, World!") then - write(output_unit, *) "Passed" - else - write(error_unit, *) "Failed" - call exit(1) - end if -end program greet_test diff --git a/example_packages/hello_complex_2/.gitignore b/example_packages/hello_complex_2/.gitignore deleted file mode 100644 index a007feab07..0000000000 --- a/example_packages/hello_complex_2/.gitignore +++ /dev/null @@ -1 +0,0 @@ -build/* diff --git a/example_packages/hello_complex_2/app/app_mod.f90 b/example_packages/hello_complex_2/app/app_mod.f90 deleted file mode 100644 index d69a228b6e..0000000000 --- a/example_packages/hello_complex_2/app/app_mod.f90 +++ /dev/null @@ -1,5 +0,0 @@ -module app_mod -implicit none - - -end module app_mod diff --git a/example_packages/hello_complex_2/app/say_goodbye.f90 b/example_packages/hello_complex_2/app/say_goodbye.f90 deleted file mode 100644 index db12cbf40e..0000000000 --- a/example_packages/hello_complex_2/app/say_goodbye.f90 +++ /dev/null @@ -1,8 +0,0 @@ -program say_goodbye - use farewell_m, only: make_farewell - use app_mod - - implicit none - - print *, make_farewell("World") -end program say_goodbye diff --git a/example_packages/hello_complex_2/app/say_hello/app_extra_mod.f90 b/example_packages/hello_complex_2/app/say_hello/app_extra_mod.f90 deleted file mode 100644 index 5059e22f78..0000000000 --- a/example_packages/hello_complex_2/app/say_hello/app_extra_mod.f90 +++ /dev/null @@ -1,6 +0,0 @@ -module app_extra_mod -implicit none - -character(len=5) :: greet_object = "World" - -end module app_extra_mod diff --git a/example_packages/hello_complex_2/app/say_hello/app_hello_mod.f90 b/example_packages/hello_complex_2/app/say_hello/app_hello_mod.f90 deleted file mode 100644 index e44edd7dd7..0000000000 --- a/example_packages/hello_complex_2/app/say_hello/app_hello_mod.f90 +++ /dev/null @@ -1,7 +0,0 @@ -module app_hello_mod -use app_extra_mod, only: greet_object -implicit none - -integer :: hello_int = 42 - -end module app_hello_mod diff --git a/example_packages/hello_complex_2/app/say_hello/say_Hello.f90 b/example_packages/hello_complex_2/app/say_hello/say_Hello.f90 deleted file mode 100644 index 3ebaebb5b4..0000000000 --- a/example_packages/hello_complex_2/app/say_hello/say_Hello.f90 +++ /dev/null @@ -1,8 +0,0 @@ -program say_Hello - use greet_m, only: make_greeting - use app_hello_mod, only: greet_object - - implicit none - - print *, make_greeting(greet_object) -end program say_Hello diff --git a/example_packages/hello_complex_2/fpm.toml b/example_packages/hello_complex_2/fpm.toml deleted file mode 100644 index 28c91d8443..0000000000 --- a/example_packages/hello_complex_2/fpm.toml +++ /dev/null @@ -1,6 +0,0 @@ -name = "hello_complex" - -[[executable]] -name="say_hello_world" -source-dir="app/say_hello" -main="say_Hello.f90" diff --git a/example_packages/hello_complex_2/src/farewell_m.f90 b/example_packages/hello_complex_2/src/farewell_m.f90 deleted file mode 100644 index 9fc75b9c23..0000000000 --- a/example_packages/hello_complex_2/src/farewell_m.f90 +++ /dev/null @@ -1,13 +0,0 @@ -module farewell_m - implicit none - private - - public :: make_farewell -contains - function make_farewell(name) result(greeting) - character(len=*), intent(in) :: name - character(len=:), allocatable :: greeting - - greeting = "Goodbye, " // name // "!" - end function make_farewell -end module farewell_m diff --git a/example_packages/hello_complex_2/src/greet_m.f90 b/example_packages/hello_complex_2/src/greet_m.f90 deleted file mode 100644 index 2372f9a446..0000000000 --- a/example_packages/hello_complex_2/src/greet_m.f90 +++ /dev/null @@ -1,13 +0,0 @@ -module greet_m - implicit none - private - - public :: make_greeting -contains - function make_greeting(name) result(greeting) - character(len=*), intent(in) :: name - character(len=:), allocatable :: greeting - - greeting = "Hello, " // name // "!" - end function make_greeting -end module greet_m diff --git a/example_packages/hello_complex_2/test/farewell_test.f90 b/example_packages/hello_complex_2/test/farewell_test.f90 deleted file mode 100644 index dbe98d6c2c..0000000000 --- a/example_packages/hello_complex_2/test/farewell_test.f90 +++ /dev/null @@ -1,19 +0,0 @@ -program farewell_test - use farewell_m, only: make_farewell - use test_mod - use iso_fortran_env, only: error_unit, output_unit - - implicit none - - character(len=:), allocatable :: farewell - - allocate(character(len=0) :: farewell) - farewell = make_farewell("World") - - if (farewell == "Goodbye, World!") then - write(output_unit, *) "Passed" - else - write(error_unit, *) "Failed" - call exit(1) - end if -end program farewell_test diff --git a/example_packages/hello_complex_2/test/greet_test.f90 b/example_packages/hello_complex_2/test/greet_test.f90 deleted file mode 100644 index 38e9be0710..0000000000 --- a/example_packages/hello_complex_2/test/greet_test.f90 +++ /dev/null @@ -1,19 +0,0 @@ -program greet_test - use greet_m, only: make_greeting - use test_mod - use iso_fortran_env, only: error_unit, output_unit - - implicit none - - character(len=:), allocatable :: greeting - - allocate(character(len=0) :: greeting) - greeting = make_greeting("World") - - if (greeting == "Hello, World!") then - write(output_unit, *) "Passed" - else - write(error_unit, *) "Failed" - call exit(1) - end if -end program greet_test diff --git a/example_packages/hello_complex_2/test/test_mod.f90 b/example_packages/hello_complex_2/test/test_mod.f90 deleted file mode 100644 index edb26263d0..0000000000 --- a/example_packages/hello_complex_2/test/test_mod.f90 +++ /dev/null @@ -1,5 +0,0 @@ -module test_mod -implicit none - - -end module test_mod diff --git a/example_packages/hello_fpm/.gitignore b/example_packages/hello_fpm/.gitignore deleted file mode 100644 index a007feab07..0000000000 --- a/example_packages/hello_fpm/.gitignore +++ /dev/null @@ -1 +0,0 @@ -build/* diff --git a/example_packages/hello_fpm/app/main.f90 b/example_packages/hello_fpm/app/main.f90 deleted file mode 100644 index 5df6d64636..0000000000 --- a/example_packages/hello_fpm/app/main.f90 +++ /dev/null @@ -1,9 +0,0 @@ -program hello_fpm - use farewell_m, only: make_farewell - use greet_m, only: make_greeting - - implicit none - - print *, make_greeting("fpm") - print *, make_farewell("fpm") -end program hello_fpm diff --git a/example_packages/hello_fpm/fpm.toml b/example_packages/hello_fpm/fpm.toml deleted file mode 100644 index d94d904ac1..0000000000 --- a/example_packages/hello_fpm/fpm.toml +++ /dev/null @@ -1,4 +0,0 @@ -name = "hello_fpm" - -[dependencies] -hello_complex = { path = "../hello_complex" } diff --git a/example_packages/hello_fpm_path/app/main.f90 b/example_packages/hello_fpm_path/app/main.f90 deleted file mode 100644 index 61303b1a69..0000000000 --- a/example_packages/hello_fpm_path/app/main.f90 +++ /dev/null @@ -1,10 +0,0 @@ -program hello_fpm - use utils1_m, only: say_hello1 - use utils1_1_m, only: say_hello1_1 - use utils2_m, only: say_hello2 - - call say_hello1() - call say_hello1_1() - call say_hello2() - -end program hello_fpm diff --git a/example_packages/hello_fpm_path/crate/utils1/fpm.toml b/example_packages/hello_fpm_path/crate/utils1/fpm.toml deleted file mode 100644 index 61c494eb12..0000000000 --- a/example_packages/hello_fpm_path/crate/utils1/fpm.toml +++ /dev/null @@ -1,4 +0,0 @@ -name = "utils1" - -[dependencies] -utils1_1 = { path = "../utils1_1" } diff --git a/example_packages/hello_fpm_path/crate/utils1/src/say_hello.f90 b/example_packages/hello_fpm_path/crate/utils1/src/say_hello.f90 deleted file mode 100644 index dd7cdb881d..0000000000 --- a/example_packages/hello_fpm_path/crate/utils1/src/say_hello.f90 +++ /dev/null @@ -1,11 +0,0 @@ -module utils1_m - - implicit none - -contains - - subroutine say_hello1() - print '(a)', "Hello, utils1." - end subroutine say_hello1 - -end module utils1_m diff --git a/example_packages/hello_fpm_path/crate/utils1_1/fpm.toml b/example_packages/hello_fpm_path/crate/utils1_1/fpm.toml deleted file mode 100644 index 0aff12820d..0000000000 --- a/example_packages/hello_fpm_path/crate/utils1_1/fpm.toml +++ /dev/null @@ -1 +0,0 @@ -name = "utils1_1" diff --git a/example_packages/hello_fpm_path/crate/utils1_1/src/say_hello.f90 b/example_packages/hello_fpm_path/crate/utils1_1/src/say_hello.f90 deleted file mode 100644 index 59ce519457..0000000000 --- a/example_packages/hello_fpm_path/crate/utils1_1/src/say_hello.f90 +++ /dev/null @@ -1,11 +0,0 @@ -module utils1_1_m - - implicit none - -contains - - subroutine say_hello1_1() - print '(a)', "Hello, utils1_1." - end subroutine say_hello1_1 - -end module utils1_1_m diff --git a/example_packages/hello_fpm_path/crate/utils2/fpm.toml b/example_packages/hello_fpm_path/crate/utils2/fpm.toml deleted file mode 100644 index 6291485067..0000000000 --- a/example_packages/hello_fpm_path/crate/utils2/fpm.toml +++ /dev/null @@ -1 +0,0 @@ -name = "utils2" diff --git a/example_packages/hello_fpm_path/crate/utils2/src/say_hello.f90 b/example_packages/hello_fpm_path/crate/utils2/src/say_hello.f90 deleted file mode 100644 index 19772fc2b3..0000000000 --- a/example_packages/hello_fpm_path/crate/utils2/src/say_hello.f90 +++ /dev/null @@ -1,11 +0,0 @@ -module utils2_m - - implicit none - -contains - - subroutine say_hello2() - print '(a)', "Hello, utils2." - end subroutine say_hello2 - -end module utils2_m diff --git a/example_packages/hello_fpm_path/fpm.toml b/example_packages/hello_fpm_path/fpm.toml deleted file mode 100644 index 789b20c60f..0000000000 --- a/example_packages/hello_fpm_path/fpm.toml +++ /dev/null @@ -1,5 +0,0 @@ -name = "hello_fpm_path" - -[dependencies] -utils1 = { path = "crate/utils1" } -utils2 = { path = "crate/utils2" } diff --git a/example_packages/hello_world/.gitignore b/example_packages/hello_world/.gitignore deleted file mode 100644 index a007feab07..0000000000 --- a/example_packages/hello_world/.gitignore +++ /dev/null @@ -1 +0,0 @@ -build/* diff --git a/example_packages/hello_world/app/main.f90 b/example_packages/hello_world/app/main.f90 deleted file mode 100644 index d16022bcc8..0000000000 --- a/example_packages/hello_world/app/main.f90 +++ /dev/null @@ -1,3 +0,0 @@ -program hello_world - print *, "Hello, World!" -end program hello_world diff --git a/example_packages/hello_world/fpm.toml b/example_packages/hello_world/fpm.toml deleted file mode 100644 index b80e8d15c2..0000000000 --- a/example_packages/hello_world/fpm.toml +++ /dev/null @@ -1 +0,0 @@ -name = "hello_world" diff --git a/example_packages/implicit-external/app/main.f90 b/example_packages/implicit-external/app/main.f90 deleted file mode 100644 index 5b6e8f6fc5..0000000000 --- a/example_packages/implicit-external/app/main.f90 +++ /dev/null @@ -1,5 +0,0 @@ -program test - integer :: ijk - call impl(ijk) - if (ijk /= 1) error stop -end program test diff --git a/example_packages/implicit-external/fpm.toml b/example_packages/implicit-external/fpm.toml deleted file mode 100644 index c32145c56f..0000000000 --- a/example_packages/implicit-external/fpm.toml +++ /dev/null @@ -1,2 +0,0 @@ -name = "implicit-external" -fortran.implicit-external = true diff --git a/example_packages/implicit-external/src/impl.f90 b/example_packages/implicit-external/src/impl.f90 deleted file mode 100644 index 1b609f561f..0000000000 --- a/example_packages/implicit-external/src/impl.f90 +++ /dev/null @@ -1,4 +0,0 @@ -subroutine impl(ijk) - integer :: ijk - ijk = 1 -end subroutine impl diff --git a/example_packages/implicit-typing/app/main.f90 b/example_packages/implicit-typing/app/main.f90 deleted file mode 100644 index 944d95ede3..0000000000 --- a/example_packages/implicit-typing/app/main.f90 +++ /dev/null @@ -1,4 +0,0 @@ -program test - use impl - if (ijk /= 1) error stop -end program diff --git a/example_packages/implicit-typing/fpm.toml b/example_packages/implicit-typing/fpm.toml deleted file mode 100644 index fe5c635069..0000000000 --- a/example_packages/implicit-typing/fpm.toml +++ /dev/null @@ -1,2 +0,0 @@ -name = "implicit-typing" -fortran.implicit-typing = true diff --git a/example_packages/implicit-typing/src/impl.f90 b/example_packages/implicit-typing/src/impl.f90 deleted file mode 100644 index 1803cb3cc9..0000000000 --- a/example_packages/implicit-typing/src/impl.f90 +++ /dev/null @@ -1,3 +0,0 @@ -module impl - parameter(ijk = 1) -end module diff --git a/example_packages/link_executable/.gitignore b/example_packages/link_executable/.gitignore deleted file mode 100644 index a007feab07..0000000000 --- a/example_packages/link_executable/.gitignore +++ /dev/null @@ -1 +0,0 @@ -build/* diff --git a/example_packages/link_executable/app/main.f90 b/example_packages/link_executable/app/main.f90 deleted file mode 100644 index b1df4025f3..0000000000 --- a/example_packages/link_executable/app/main.f90 +++ /dev/null @@ -1,11 +0,0 @@ -program gomp_example - implicit none - - interface - integer function omp_get_num_procs() - end function - end interface - - print *, omp_get_num_procs() - -end program gomp_example diff --git a/example_packages/link_executable/fpm.toml b/example_packages/link_executable/fpm.toml deleted file mode 100644 index d9e94bb8bb..0000000000 --- a/example_packages/link_executable/fpm.toml +++ /dev/null @@ -1,7 +0,0 @@ -name = "link_executable" - -[[executable]] -name = "gomp_test" -source-dir = "app" -main = "main.f90" -link = ["gomp"] diff --git a/example_packages/link_executable/include/test.f90 b/example_packages/link_executable/include/test.f90 deleted file mode 100644 index 5413cbc2a9..0000000000 --- a/example_packages/link_executable/include/test.f90 +++ /dev/null @@ -1 +0,0 @@ -real, parameter :: a = 2.0 diff --git a/example_packages/link_external/.gitignore b/example_packages/link_external/.gitignore deleted file mode 100644 index a007feab07..0000000000 --- a/example_packages/link_external/.gitignore +++ /dev/null @@ -1 +0,0 @@ -build/* diff --git a/example_packages/link_external/app/main.f90 b/example_packages/link_external/app/main.f90 deleted file mode 100644 index 8df408d010..0000000000 --- a/example_packages/link_external/app/main.f90 +++ /dev/null @@ -1,21 +0,0 @@ -program test_blas - use wrapped_gemv, only : sp, gemv - implicit none - - integer :: i, j - real(sp) :: mat(4, 4), vec(4), res(4) - - do i = 1, size(vec) - vec(i) = sqrt(real(i, sp)) - end do - - do i = 1, size(mat, 2) - do j = 1, size(mat, 1) - mat(j, i) = sqrt(real(j * i, sp)) - end do - end do - - call gemv(mat, vec, res, alpha=-1.0_sp, trans='t') - -end program test_blas - diff --git a/example_packages/link_external/fpm.toml b/example_packages/link_external/fpm.toml deleted file mode 100644 index f2eafa263e..0000000000 --- a/example_packages/link_external/fpm.toml +++ /dev/null @@ -1,4 +0,0 @@ -name = "link_external" - -[build] -link = "blas" diff --git a/example_packages/link_external/src/wrapped_gemv.f90 b/example_packages/link_external/src/wrapped_gemv.f90 deleted file mode 100644 index 5ff1d7c152..0000000000 --- a/example_packages/link_external/src/wrapped_gemv.f90 +++ /dev/null @@ -1,126 +0,0 @@ -!> Performs one of the matrix-vector operations -!> -!> y := alpha*A*x + beta*y, or y := alpha*A**T*x + beta*y, -!> -!> where alpha and beta are scalars, x and y are vectors and A is an -!> m by n matrix. -module wrapped_gemv - implicit none - private - - public :: sp, dp, gemv - - integer, parameter :: sp = selected_real_kind(6) - integer, parameter :: dp = selected_real_kind(15) - - - interface gemv - module procedure :: wrap_sgemv - module procedure :: wrap_dgemv - end interface gemv - - - interface blas_gemv - subroutine sgemv(trans, m, n, alpha, a, lda, x, incx, beta, y, incy) - import :: sp - real(sp), intent(in) :: a(lda, *) - real(sp), intent(in) :: x(*) - real(sp), intent(inout) :: y(*) - real(sp), intent(in) :: alpha - real(sp), intent(in) :: beta - character(len=1), intent(in) :: trans - integer, intent(in) :: incx - integer, intent(in) :: incy - integer, intent(in) :: m - integer, intent(in) :: n - integer, intent(in) :: lda - end subroutine sgemv - subroutine dgemv(trans, m, n, alpha, a, lda, x, incx, beta, y, incy) - import :: dp - real(dp), intent(in) :: a(lda, *) - real(dp), intent(in) :: x(*) - real(dp), intent(inout) :: y(*) - real(dp), intent(in) :: alpha - real(dp), intent(in) :: beta - character(len=1), intent(in) :: trans - integer, intent(in) :: incx - integer, intent(in) :: incy - integer, intent(in) :: m - integer, intent(in) :: n - integer, intent(in) :: lda - end subroutine dgemv - end interface blas_gemv - - -contains - - - subroutine wrap_sgemv(amat, xvec, yvec, alpha, beta, trans) - real(sp), intent(in) :: amat(:, :) - real(sp), intent(in) :: xvec(:) - real(sp), intent(inout) :: yvec(:) - real(sp), intent(in), optional :: alpha - real(sp), intent(in), optional :: beta - character(len=1), intent(in), optional :: trans - real(sp) :: a, b - character(len=1) :: tra - integer :: incx, incy, m, n, lda - if (present(alpha)) then - a = alpha - else - a = 1.0_sp - end if - if (present(beta)) then - b = beta - else - b = 0 - end if - if (present(trans)) then - tra = trans - else - tra = 'n' - end if - incx = 1 - incy = 1 - lda = max(1, size(amat, 1)) - m = size(amat, 1) - n = size(amat, 2) - call blas_gemv(tra, m, n, a, amat, lda, xvec, incx, b, yvec, incy) - end subroutine wrap_sgemv - - - subroutine wrap_dgemv(amat, xvec, yvec, alpha, beta, trans) - real(dp), intent(in) :: amat(:, :) - real(dp), intent(in) :: xvec(:) - real(dp), intent(inout) :: yvec(:) - real(dp), intent(in), optional :: alpha - real(dp), intent(in), optional :: beta - character(len=1), intent(in), optional :: trans - real(dp) :: a, b - character(len=1) :: tra - integer :: incx, incy, m, n, lda - if (present(alpha)) then - a = alpha - else - a = 1.0_dp - end if - if (present(beta)) then - b = beta - else - b = 0 - end if - if (present(trans)) then - tra = trans - else - tra = 'n' - end if - incx = 1 - incy = 1 - lda = max(1, size(amat, 1)) - m = size(amat, 1) - n = size(amat, 2) - call blas_gemv(tra, m, n, a, amat, lda, xvec, incx, b, yvec, incy) - end subroutine wrap_dgemv - - -end module wrapped_gemv diff --git a/example_packages/makefile_complex/.gitignore b/example_packages/makefile_complex/.gitignore deleted file mode 100644 index a007feab07..0000000000 --- a/example_packages/makefile_complex/.gitignore +++ /dev/null @@ -1 +0,0 @@ -build/* diff --git a/example_packages/makefile_complex/Makefile b/example_packages/makefile_complex/Makefile deleted file mode 100644 index 497c6b2238..0000000000 --- a/example_packages/makefile_complex/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -INCLUDE_FLAGS = $(addprefix -I,$(INCLUDE_DIRS)) - -$(BUILD_DIR)/libmakefile_complex.a: $(BUILD_DIR)/wrapper_mod.o - ar rs $(@) $(^) - -$(BUILD_DIR)/wrapper_mod.mod: src/wrapper_mod.f90 - -$(BUILD_DIR)/wrapper_mod.o: src/wrapper_mod.f90 - $(FC) -c -J$(BUILD_DIR) $(INCLUDE_FLAGS) $(FFLAGS) -o $(@) $(<) diff --git a/example_packages/makefile_complex/app/main.f90 b/example_packages/makefile_complex/app/main.f90 deleted file mode 100644 index ac9ed51d03..0000000000 --- a/example_packages/makefile_complex/app/main.f90 +++ /dev/null @@ -1,7 +0,0 @@ -program makefile_complex - use wrapper_mod, only: do_stuff - - implicit none - - call do_stuff -end program makefile_complex diff --git a/example_packages/makefile_complex/fpm.toml b/example_packages/makefile_complex/fpm.toml deleted file mode 100644 index 3282cbe378..0000000000 --- a/example_packages/makefile_complex/fpm.toml +++ /dev/null @@ -1,8 +0,0 @@ -name = "makefile_complex" - -[dependencies] -with_makefile = { path = "../with_makefile" } - -[library] -source-dir = "src" -build-script = "Makefile" diff --git a/example_packages/makefile_complex/src/wrapper_mod.f90 b/example_packages/makefile_complex/src/wrapper_mod.f90 deleted file mode 100644 index e8028b5d2f..0000000000 --- a/example_packages/makefile_complex/src/wrapper_mod.f90 +++ /dev/null @@ -1,12 +0,0 @@ -module wrapper_mod - use hello_makefile, only: say_hello_from_makefile - - implicit none - private - - public :: do_stuff -contains - subroutine do_stuff - call say_hello_from_makefile - end subroutine do_stuff -end module wrapper_mod diff --git a/example_packages/many_examples/.gitignore b/example_packages/many_examples/.gitignore deleted file mode 100644 index d9b4f015d3..0000000000 --- a/example_packages/many_examples/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build/* diff --git a/example_packages/many_examples/app/demo-prog.f90 b/example_packages/many_examples/app/demo-prog.f90 deleted file mode 100644 index f26e898fc8..0000000000 --- a/example_packages/many_examples/app/demo-prog.f90 +++ /dev/null @@ -1,3 +0,0 @@ -program demo - write(*, '(a)') "This is a simple program" -end program demo diff --git a/example_packages/many_examples/demo1/prog.f90 b/example_packages/many_examples/demo1/prog.f90 deleted file mode 100644 index 817bff0add..0000000000 --- a/example_packages/many_examples/demo1/prog.f90 +++ /dev/null @@ -1,7 +0,0 @@ -program demo - integer :: i - open(newunit=i,file="demo1.txt",form="formatted",action="write") - write(i, '(a)') "DEMO1" - close(i) - stop 0 -end program demo diff --git a/example_packages/many_examples/demo2/prog.f90 b/example_packages/many_examples/demo2/prog.f90 deleted file mode 100644 index 951ce9b51c..0000000000 --- a/example_packages/many_examples/demo2/prog.f90 +++ /dev/null @@ -1,7 +0,0 @@ -program demo - integer :: i - open(newunit=i,file="demo2.txt",form="formatted",action="write") - write(i, '(a)') "DEMO2" - close(i) - stop 0 -end program demo diff --git a/example_packages/many_examples/fpm.toml b/example_packages/many_examples/fpm.toml deleted file mode 100644 index 6004375307..0000000000 --- a/example_packages/many_examples/fpm.toml +++ /dev/null @@ -1,12 +0,0 @@ -name = "many_examples" -build.auto-examples = false - -[[example]] -name = "demo-1" -source-dir = "demo1" -main = "prog.f90" - -[[example]] -name = "demo-2" -source-dir = "demo2" -main = "prog.f90" diff --git a/example_packages/many_targets/.gitignore b/example_packages/many_targets/.gitignore deleted file mode 100644 index a007feab07..0000000000 --- a/example_packages/many_targets/.gitignore +++ /dev/null @@ -1 +0,0 @@ -build/* diff --git a/example_packages/many_targets/app/run1.f90 b/example_packages/many_targets/app/run1.f90 deleted file mode 100644 index 7033d98755..0000000000 --- a/example_packages/many_targets/app/run1.f90 +++ /dev/null @@ -1,6 +0,0 @@ -program run1 - use file_mod - implicit none - call print_file("run",1) - stop 0 -end program run1 diff --git a/example_packages/many_targets/app/run2.f90 b/example_packages/many_targets/app/run2.f90 deleted file mode 100644 index d8eaaef29a..0000000000 --- a/example_packages/many_targets/app/run2.f90 +++ /dev/null @@ -1,6 +0,0 @@ -program run2 - use file_mod - implicit none - call print_file("run",2) - stop 0 -end program run2 diff --git a/example_packages/many_targets/app/run3.f90 b/example_packages/many_targets/app/run3.f90 deleted file mode 100644 index a3da040f99..0000000000 --- a/example_packages/many_targets/app/run3.f90 +++ /dev/null @@ -1,6 +0,0 @@ -program run3 - use file_mod - implicit none - call print_file("run",3) - stop 0 -end program run3 diff --git a/example_packages/many_targets/example/example1.f90 b/example_packages/many_targets/example/example1.f90 deleted file mode 100644 index f8416702ce..0000000000 --- a/example_packages/many_targets/example/example1.f90 +++ /dev/null @@ -1,6 +0,0 @@ -program example1 - use file_mod - implicit none - call print_file("example",1) - stop 0 -end program example1 diff --git a/example_packages/many_targets/example/example2.f90 b/example_packages/many_targets/example/example2.f90 deleted file mode 100644 index ce97407da4..0000000000 --- a/example_packages/many_targets/example/example2.f90 +++ /dev/null @@ -1,6 +0,0 @@ -program example2 - use file_mod - implicit none - call print_file("example",2) - stop 0 -end program example2 diff --git a/example_packages/many_targets/example/example3.f90 b/example_packages/many_targets/example/example3.f90 deleted file mode 100644 index b36a4465c3..0000000000 --- a/example_packages/many_targets/example/example3.f90 +++ /dev/null @@ -1,6 +0,0 @@ -program example3 - use file_mod - implicit none - call print_file("example",3) - stop 0 -end program example3 diff --git a/example_packages/many_targets/fpm.toml b/example_packages/many_targets/fpm.toml deleted file mode 100644 index 88aa8cc1e0..0000000000 --- a/example_packages/many_targets/fpm.toml +++ /dev/null @@ -1 +0,0 @@ -name = "many_targets" diff --git a/example_packages/many_targets/src/file_mod.f90 b/example_packages/many_targets/src/file_mod.f90 deleted file mode 100644 index fd4368e5d9..0000000000 --- a/example_packages/many_targets/src/file_mod.f90 +++ /dev/null @@ -1,17 +0,0 @@ -module file_mod - implicit none - public - contains - subroutine print_file(name,id) - character(*), intent(in) :: name - integer, intent(in) :: id - integer :: i - character(len(name)+1) :: nm - write(nm,1)name,id - open(newunit=i,file=nm//'.txt',form="formatted",action="write") - write(i, '(a)') nm - close(i) - 1 format(a,i1) - end subroutine print_file -end module file_mod - diff --git a/example_packages/many_targets/test/test1.f90 b/example_packages/many_targets/test/test1.f90 deleted file mode 100644 index cc7226b033..0000000000 --- a/example_packages/many_targets/test/test1.f90 +++ /dev/null @@ -1,6 +0,0 @@ -program test1 - use file_mod - implicit none - call print_file("test",1) - stop 0 -end program test1 diff --git a/example_packages/many_targets/test/test2.f90 b/example_packages/many_targets/test/test2.f90 deleted file mode 100644 index d43252907d..0000000000 --- a/example_packages/many_targets/test/test2.f90 +++ /dev/null @@ -1,6 +0,0 @@ -program test2 - use file_mod - implicit none - call print_file("test",2) - stop 0 -end program test2 diff --git a/example_packages/many_targets/test/test3.f90 b/example_packages/many_targets/test/test3.f90 deleted file mode 100644 index af4a44cbfd..0000000000 --- a/example_packages/many_targets/test/test3.f90 +++ /dev/null @@ -1,6 +0,0 @@ -program test3 - use file_mod - implicit none - call print_file("test",3) - stop 0 -end program test3 diff --git a/example_packages/metapackage_blas/app/main.f90 b/example_packages/metapackage_blas/app/main.f90 deleted file mode 100644 index 2b76d47e57..0000000000 --- a/example_packages/metapackage_blas/app/main.f90 +++ /dev/null @@ -1,58 +0,0 @@ -program metapackage_blas - implicit none - - interface - subroutine dgesv(n, nrhs, a, lda, ipiv, b, ldb, info) - integer, intent(in) :: n, nrhs, lda, ldb - double precision, intent(in out) :: a(lda,*), b(ldb,*) - integer, intent(out) :: ipiv(*), info - end subroutine dgesv - end interface - - integer, parameter :: dp = kind(1.0d0) - real(dp), dimension(:,:), allocatable :: a - real(dp), dimension(:), allocatable :: b - integer :: info - - allocate(a(3,3), b(3)) - a = reshape([1.0_dp, 2.0_dp, 3.0_dp, & - 4.0_dp, 5.0_dp, 6.0_dp, & - 7.0_dp, 8.0_dp, 9.0_dp], [3,3]) - b = [1.0_dp, 2.0_dp, 3.0_dp] - - call solve_eqsys(a, b, info) - if (info /= 0) error stop - - stop 0 - - contains - - !> simple wrapper for solvers for real system of linear - !> equations A * X = B - subroutine solve_eqsys(a, b, info) - - real(dp), dimension(:,:), intent(inout) :: a - real(dp), dimension(:), intent(inout) :: b - integer, intent(out) :: info - integer :: i_alloc - integer :: n, nrhs, lda, ldb - integer, dimension(:), allocatable :: ipiv - ! ------------------------------------------------------------------ - - lda = size(a,1) - n = size(a,2) - ldb = size(b,1) - nrhs = 1 - - allocate(ipiv(n), stat = i_alloc) - if (i_alloc /= 0) stop 'solve_eqsys: Allocation for array failed!' - - call dgesv(n, nrhs, a, lda, ipiv, b, ldb, info) - - info = 0 - - deallocate(ipiv, stat = i_alloc) - if (i_alloc /= 0) stop 'solve_eqsys: Deallocation for array failed!' - - end subroutine solve_eqsys -end program metapackage_blas diff --git a/example_packages/metapackage_blas/fpm.toml b/example_packages/metapackage_blas/fpm.toml deleted file mode 100644 index 440192c69a..0000000000 --- a/example_packages/metapackage_blas/fpm.toml +++ /dev/null @@ -1,2 +0,0 @@ -name = "metapackage_blas" -dependencies.blas="*" diff --git a/example_packages/metapackage_hdf5/app/main.f90 b/example_packages/metapackage_hdf5/app/main.f90 deleted file mode 100644 index 3735a3e525..0000000000 --- a/example_packages/metapackage_hdf5/app/main.f90 +++ /dev/null @@ -1,15 +0,0 @@ -program metapackage_hdf5 - use hdf5 - implicit none - - integer :: error - - call h5open_f(error) - if (error/=0) stop -1 - - call h5close_f(error) - if (error/=0) stop -2 - - stop 0 - -end program metapackage_hdf5 diff --git a/example_packages/metapackage_hdf5/fpm.toml b/example_packages/metapackage_hdf5/fpm.toml deleted file mode 100644 index 5a7d2f12b4..0000000000 --- a/example_packages/metapackage_hdf5/fpm.toml +++ /dev/null @@ -1,2 +0,0 @@ -name = "metapackage_hdf5" -dependencies.hdf5="*" diff --git a/example_packages/metapackage_minpack/app/main.f90 b/example_packages/metapackage_minpack/app/main.f90 deleted file mode 100644 index 64008e4102..0000000000 --- a/example_packages/metapackage_minpack/app/main.f90 +++ /dev/null @@ -1,7 +0,0 @@ -program main - use metapackage_minpack, only: simple_test - implicit none - logical :: success - call simple_test(success) - stop merge(0,1,success) -end program main diff --git a/example_packages/metapackage_minpack/fpm.toml b/example_packages/metapackage_minpack/fpm.toml deleted file mode 100644 index f178da2a48..0000000000 --- a/example_packages/metapackage_minpack/fpm.toml +++ /dev/null @@ -1,2 +0,0 @@ -name = "metapackage_minpack" -dependencies.minpack="*" diff --git a/example_packages/metapackage_minpack/src/metapackage_minpack.f90 b/example_packages/metapackage_minpack/src/metapackage_minpack.f90 deleted file mode 100644 index d09d778409..0000000000 --- a/example_packages/metapackage_minpack/src/metapackage_minpack.f90 +++ /dev/null @@ -1,14 +0,0 @@ -module metapackage_minpack - use minpack_module, only: wp - use iso_fortran_env, only: real64 - implicit none - private - - public :: simple_test -contains - subroutine simple_test(success) - logical, intent(out) :: success - ! Success! can read minpack module - success = wp == real64 - end subroutine simple_test -end module metapackage_minpack diff --git a/example_packages/metapackage_mpi/README.md b/example_packages/metapackage_mpi/README.md deleted file mode 100644 index e1ea0c2194..0000000000 --- a/example_packages/metapackage_mpi/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# test_mpi -This test program prints the running thread ID using MPI. -PLEASE NOTE: -- Test app uses 'mpif.h' and not 'use mpi' or 'use mpi_f08' because the latter are compiler-dependent, - and the MPI implementation on the local machine may not offer an implementation for them with the same - compiler that fpm is using. -- Using mpif.h will be the most backward compatible and platform agnostic diff --git a/example_packages/metapackage_mpi/app/main.f90 b/example_packages/metapackage_mpi/app/main.f90 deleted file mode 100644 index 8119ac21da..0000000000 --- a/example_packages/metapackage_mpi/app/main.f90 +++ /dev/null @@ -1,32 +0,0 @@ -program with_mpi - implicit none - - include 'mpif.h' - - integer, parameter :: INIT_ERROR = 1 - integer, parameter :: RANK_ERROR = 2 - - integer :: ierror,ncpus,cpuid - - - ! Initialize MPI argument - call MPI_INIT(ierror); - if (ierror/=0) stop INIT_ERROR - - ! Get number of processes and current rank - call MPI_Comm_size(MPI_COMM_WORLD, ncpus, ierror) - if (ierror/=0) stop RANK_ERROR - - call MPI_Comm_rank(MPI_COMM_WORLD, cpuid, ierror) - if (ierror/=0) stop RANK_ERROR - - print "('Hello, mpi world from rank ',i0,' of ',i0,'!')", cpuid+1,ncpus - - ! Finalize MPI environment. - call MPI_FINALIZE(ierror) - if (ierror/=0) stop INIT_ERROR - - stop 0 - -end program with_mpi - diff --git a/example_packages/metapackage_mpi/fpm.toml b/example_packages/metapackage_mpi/fpm.toml deleted file mode 100644 index 8588e99979..0000000000 --- a/example_packages/metapackage_mpi/fpm.toml +++ /dev/null @@ -1,4 +0,0 @@ -name = "test_mpi" -dependencies.mpi = "*" -fortran.implicit-external=true -fortran.implicit-typing=true diff --git a/example_packages/metapackage_mpi_c/README.md b/example_packages/metapackage_mpi_c/README.md deleted file mode 100644 index 6ec9d07215..0000000000 --- a/example_packages/metapackage_mpi_c/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# test_mpi -This test program prints the running thread ID using MPI. diff --git a/example_packages/metapackage_mpi_c/app/main.c b/example_packages/metapackage_mpi_c/app/main.c deleted file mode 100644 index ab20ac1d16..0000000000 --- a/example_packages/metapackage_mpi_c/app/main.c +++ /dev/null @@ -1,34 +0,0 @@ -// Test MPI linking from a C main program -#include -#include - -int main(int argc, char** argv) -{ - - int ierror,ncpus,cpuid; - - // Initialize MPI argument - ierror = MPI_Init(&argc, &argv); - if (ierror) { - printf("MPI_Init failed with error %d \n",ierror); - return 1; - } - - // Get number of processes and current rank - MPI_Comm_size(MPI_COMM_WORLD, &ncpus); - - // Get Rank of the current process - MPI_Comm_rank(MPI_COMM_WORLD, &cpuid); - - printf("Hello, MPI C World from rank %d of %d! \n",cpuid+1,ncpus); - - // Finalize MPI environment. - ierror = MPI_Finalize(); - if (ierror) { - printf("MPI_Finalize failed with error %d \n",ierror); - return 1; - } else { - return 0; - } -} - diff --git a/example_packages/metapackage_mpi_c/fpm.toml b/example_packages/metapackage_mpi_c/fpm.toml deleted file mode 100644 index 67f4e99918..0000000000 --- a/example_packages/metapackage_mpi_c/fpm.toml +++ /dev/null @@ -1,9 +0,0 @@ -name = "test_mpi_c" -dependencies.mpi = "*" -fortran.implicit-typing=true -fortran.implicit-external=true - -[[executable]] -name = "test-mpi-c-main" -main = "main.c" - diff --git a/example_packages/metapackage_mpi_cpp/README.md b/example_packages/metapackage_mpi_cpp/README.md deleted file mode 100644 index 6ec9d07215..0000000000 --- a/example_packages/metapackage_mpi_cpp/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# test_mpi -This test program prints the running thread ID using MPI. diff --git a/example_packages/metapackage_mpi_cpp/app/main.cpp b/example_packages/metapackage_mpi_cpp/app/main.cpp deleted file mode 100644 index 45abe795a2..0000000000 --- a/example_packages/metapackage_mpi_cpp/app/main.cpp +++ /dev/null @@ -1,36 +0,0 @@ -// Test MPI linking from a C main program -#include -#include - -using namespace std; - -int main(int argc, char** argv) -{ - - int ierror,ncpus,cpuid; - - // Initialize MPI argument - ierror = MPI_Init(&argc, &argv); - if (ierror) { - cout << "MPI_Init failed with error " << ierror << endl; - return 1; - } - - // Get number of processes and current rank - MPI_Comm_size(MPI_COMM_WORLD, &ncpus); - - // Get Rank of the current process - MPI_Comm_rank(MPI_COMM_WORLD, &cpuid); - - cout << "Hello, MPI C++ World from rank " << cpuid << " of " << ncpus << "!" << endl; - - // Finalize MPI environment. - ierror = MPI_Finalize(); - if (ierror) { - cout << "MPI_Finalize failed with error " << ierror << endl; - return 1; - } else { - return 0; - } -} - diff --git a/example_packages/metapackage_mpi_cpp/fpm.toml b/example_packages/metapackage_mpi_cpp/fpm.toml deleted file mode 100644 index 4fef8f710c..0000000000 --- a/example_packages/metapackage_mpi_cpp/fpm.toml +++ /dev/null @@ -1,8 +0,0 @@ -name = "test_mpi_cpp" -dependencies.mpi="*" -fortran.implicit-typing=true -fortran.implicit-external=true - -[[executable]] -name="test-mpi-cpp" -main="main.cpp" diff --git a/example_packages/metapackage_netcdf/app/main.f90 b/example_packages/metapackage_netcdf/app/main.f90 deleted file mode 100644 index 6e3a2d11e8..0000000000 --- a/example_packages/metapackage_netcdf/app/main.f90 +++ /dev/null @@ -1,10 +0,0 @@ -program metapackage_netcdf - use netcdf4_f03 - implicit none - - integer(c_int) :: ncid, retval - - retval = nf_create("dummy.nc", NF_INMEMORY, ncid) - if (retval /= nf_noerr) error stop nf_strerror(retval) - stop 0 -end program metapackage_netcdf diff --git a/example_packages/metapackage_netcdf/fpm.toml b/example_packages/metapackage_netcdf/fpm.toml deleted file mode 100644 index f5fd4869d7..0000000000 --- a/example_packages/metapackage_netcdf/fpm.toml +++ /dev/null @@ -1,2 +0,0 @@ -name = "metapackage_netcdf" -dependencies.netcdf="*" diff --git a/example_packages/metapackage_openmp/README.md b/example_packages/metapackage_openmp/README.md deleted file mode 100644 index e191664959..0000000000 --- a/example_packages/metapackage_openmp/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# test_openmp -This test program prints the running thread ID using OpenMP. -Module omp_lib is invoked, so, this code cannot build if the OpenMP library -is not properly enabled by the compiler flags. diff --git a/example_packages/metapackage_openmp/app/main.f90 b/example_packages/metapackage_openmp/app/main.f90 deleted file mode 100644 index 21b0aef90f..0000000000 --- a/example_packages/metapackage_openmp/app/main.f90 +++ /dev/null @@ -1,16 +0,0 @@ -! OpenMP test case -! This test program will only run if openmp is properly enabled in the compiler flags. -! Otherwise, the omp_lib module won't be found and the code cannot be built. -program openmp_test - use test_openmp, only: say_hello - use omp_lib - implicit none - -!$omp parallel - call say_hello(thread_ID=OMP_GET_THREAD_NUM()) -!$omp end parallel - -! Successful return -stop 0 - -end program openmp_test diff --git a/example_packages/metapackage_openmp/fpm.toml b/example_packages/metapackage_openmp/fpm.toml deleted file mode 100644 index f22f381100..0000000000 --- a/example_packages/metapackage_openmp/fpm.toml +++ /dev/null @@ -1,3 +0,0 @@ -name = "test_openmp" -dependencies.openmp = "*" - diff --git a/example_packages/metapackage_openmp/src/test_openmp.f90 b/example_packages/metapackage_openmp/src/test_openmp.f90 deleted file mode 100644 index d83b4b1605..0000000000 --- a/example_packages/metapackage_openmp/src/test_openmp.f90 +++ /dev/null @@ -1,11 +0,0 @@ -module test_openmp - implicit none - private - - public :: say_hello -contains - subroutine say_hello(thread_ID) - integer, intent(in) :: thread_ID - print "(a,i0,a)", "Hello, test_openmp is called from thread ",thread_ID,"!" - end subroutine say_hello -end module test_openmp diff --git a/example_packages/metapackage_openmp/test/check.f90 b/example_packages/metapackage_openmp/test/check.f90 deleted file mode 100644 index d7e3cba687..0000000000 --- a/example_packages/metapackage_openmp/test/check.f90 +++ /dev/null @@ -1,5 +0,0 @@ -program check -implicit none - -print *, "Put some tests in here!" -end program check diff --git a/example_packages/metapackage_stdlib/README.md b/example_packages/metapackage_stdlib/README.md deleted file mode 100644 index 11eddc7462..0000000000 --- a/example_packages/metapackage_stdlib/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# test_stdlib -This test program generates a real [1,2,3,4,5] array using stdlib. -stdlib math and kinds modules are invoked; so this program cannot be built if stdlib is not -properly built and linked. stdlib tests are not run in this program. diff --git a/example_packages/metapackage_stdlib/app/main.f90 b/example_packages/metapackage_stdlib/app/main.f90 deleted file mode 100644 index 30630e90a6..0000000000 --- a/example_packages/metapackage_stdlib/app/main.f90 +++ /dev/null @@ -1,24 +0,0 @@ -! fortran-lang stdlib test case -! This test program will only run if stdlib is properly built and linked to this project. -program test_stdlib_metapackage - - ! These USEs would not be possible if stdlib is not found - use stdlib_kinds, only: int32, int64, dp, sp - use stdlib_math - implicit none - - real(dp), allocatable :: indices(:) - - indices = linspace(1.0_dp,5.0_dp,5) - - if (.not.allocated(indices)) then - stop 1 - elseif (size(indices)/=5) then - stop 2 - elseif (any(nint(indices)/=[1,2,3,4,5])) then - stop 3 - else - stop 0 - endif - -end program test_stdlib_metapackage diff --git a/example_packages/metapackage_stdlib/fpm.toml b/example_packages/metapackage_stdlib/fpm.toml deleted file mode 100644 index 3e4e8efe66..0000000000 --- a/example_packages/metapackage_stdlib/fpm.toml +++ /dev/null @@ -1,2 +0,0 @@ -name = "test_stdlib" -dependencies.stdlib = "*" diff --git a/example_packages/metapackage_stdlib/src/metapackage_stdlib.f90 b/example_packages/metapackage_stdlib/src/metapackage_stdlib.f90 deleted file mode 100644 index 4f041d6d7d..0000000000 --- a/example_packages/metapackage_stdlib/src/metapackage_stdlib.f90 +++ /dev/null @@ -1,10 +0,0 @@ -module metapackage_stdlib - implicit none - private - - public :: say_hello -contains - subroutine say_hello - print *, "Hello, metapackage_stdlib!" - end subroutine say_hello -end module metapackage_stdlib diff --git a/example_packages/metapackage_stdlib_extblas/app/main.f90 b/example_packages/metapackage_stdlib_extblas/app/main.f90 deleted file mode 100644 index 557f2fe737..0000000000 --- a/example_packages/metapackage_stdlib_extblas/app/main.f90 +++ /dev/null @@ -1,16 +0,0 @@ -! fortran-lang stdlib + external BLAS test case -! Program will fail if an external BLAS has not been linked against. -program test_stdlib_metapackage - use stdlib_linalg_constants, only: external_blas_ilp32,external_lapack_ilp32, & - external_blas_ilp64,external_lapack_ilp64 - implicit none - - if (.not.(external_blas_ilp32 .or. external_blas_ilp64)) then - stop 1 - elseif (.not.(external_lapack_ilp32 .or. external_lapack_ilp64)) then - stop 2 - else - stop 0 - end if - -end program test_stdlib_metapackage diff --git a/example_packages/metapackage_stdlib_extblas/fpm.toml b/example_packages/metapackage_stdlib_extblas/fpm.toml deleted file mode 100644 index 517dc0dcf3..0000000000 --- a/example_packages/metapackage_stdlib_extblas/fpm.toml +++ /dev/null @@ -1,3 +0,0 @@ -name = "test_stdlib_ext_blas" -dependencies.blas = "*" -dependencies.stdlib = "*" diff --git a/example_packages/nonintrinsic/.gitignore b/example_packages/nonintrinsic/.gitignore deleted file mode 100644 index a007feab07..0000000000 --- a/example_packages/nonintrinsic/.gitignore +++ /dev/null @@ -1 +0,0 @@ -build/* diff --git a/example_packages/nonintrinsic/app/main.f90 b/example_packages/nonintrinsic/app/main.f90 deleted file mode 100644 index a45f06d8f7..0000000000 --- a/example_packages/nonintrinsic/app/main.f90 +++ /dev/null @@ -1,6 +0,0 @@ -program test_nonintr - use, non_intrinsic :: iso_fortran_env - - ! ijk=0 can be read - stop ijk -end program test_nonintr diff --git a/example_packages/nonintrinsic/fpm.toml b/example_packages/nonintrinsic/fpm.toml deleted file mode 100644 index 77e149814d..0000000000 --- a/example_packages/nonintrinsic/fpm.toml +++ /dev/null @@ -1 +0,0 @@ -name = "non-intrinsic" diff --git a/example_packages/nonintrinsic/src/iso_fortran_env.f90 b/example_packages/nonintrinsic/src/iso_fortran_env.f90 deleted file mode 100644 index 20eea596f4..0000000000 --- a/example_packages/nonintrinsic/src/iso_fortran_env.f90 +++ /dev/null @@ -1,4 +0,0 @@ -module iso_fortran_env - implicit none - integer, parameter :: ijk = 0 -end module iso_fortran_env diff --git a/example_packages/preprocess_cpp/.gitignore b/example_packages/preprocess_cpp/.gitignore deleted file mode 100644 index a007feab07..0000000000 --- a/example_packages/preprocess_cpp/.gitignore +++ /dev/null @@ -1 +0,0 @@ -build/* diff --git a/example_packages/preprocess_cpp/app/main.f90 b/example_packages/preprocess_cpp/app/main.f90 deleted file mode 100644 index 1ddf72a7cd..0000000000 --- a/example_packages/preprocess_cpp/app/main.f90 +++ /dev/null @@ -1,4 +0,0 @@ -program cpp - use preprocess_cpp - call say_hello() -end program diff --git a/example_packages/preprocess_cpp/fpm.toml b/example_packages/preprocess_cpp/fpm.toml deleted file mode 100644 index 98ce770551..0000000000 --- a/example_packages/preprocess_cpp/fpm.toml +++ /dev/null @@ -1,7 +0,0 @@ -name = "preprocess_cpp" - -version = "1" - -[preprocess] -[preprocess.cpp] -macros = ["TESTMACRO", "TESTMACRO2=3", "TESTMACRO3={version}"] diff --git a/example_packages/preprocess_cpp/src/preprocess_cpp.f90 b/example_packages/preprocess_cpp/src/preprocess_cpp.f90 deleted file mode 100644 index d7ab5d1485..0000000000 --- a/example_packages/preprocess_cpp/src/preprocess_cpp.f90 +++ /dev/null @@ -1,22 +0,0 @@ -module preprocess_cpp - implicit none - private - - public :: say_hello -contains - subroutine say_hello - print *, "Hello, preprocess_cpp!" -#ifndef TESTMACRO - This breaks the build. -#endif - -#if TESTMACRO2 != 3 - This breaks the build. -#endif - -#if TESTMACRO3 != 1 - This breaks the build. -#endif - - end subroutine say_hello -end module preprocess_cpp diff --git a/example_packages/preprocess_cpp_c/app/main.c b/example_packages/preprocess_cpp_c/app/main.c deleted file mode 100644 index 6de67a47c1..0000000000 --- a/example_packages/preprocess_cpp_c/app/main.c +++ /dev/null @@ -1,5 +0,0 @@ -#include - -#include "val.h" - -int main() { printf("%d\n", variable); } diff --git a/example_packages/preprocess_cpp_c/fpm.toml b/example_packages/preprocess_cpp_c/fpm.toml deleted file mode 100644 index 785317b7c5..0000000000 --- a/example_packages/preprocess_cpp_c/fpm.toml +++ /dev/null @@ -1,9 +0,0 @@ -name = "preprocess_cpp_c" - -[[executable]] -name = "main" -main = "main.c" - -[preprocess] -[preprocess.cpp] -macros = ["VAL"] diff --git a/example_packages/preprocess_cpp_c/include/val.h b/example_packages/preprocess_cpp_c/include/val.h deleted file mode 100644 index 884f644d30..0000000000 --- a/example_packages/preprocess_cpp_c/include/val.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _VAL_H_ -#define _VAL_H_ - -#ifdef VAL -const int variable = 1; -#endif -#endif diff --git a/example_packages/preprocess_cpp_deps/app/main.f90 b/example_packages/preprocess_cpp_deps/app/main.f90 deleted file mode 100644 index adf5eee6bf..0000000000 --- a/example_packages/preprocess_cpp_deps/app/main.f90 +++ /dev/null @@ -1,6 +0,0 @@ -program hello_fpm - use utils, only: say_hello - - call say_hello() - -end program hello_fpm diff --git a/example_packages/preprocess_cpp_deps/crate/utils/fpm.toml b/example_packages/preprocess_cpp_deps/crate/utils/fpm.toml deleted file mode 100644 index f3c03f9934..0000000000 --- a/example_packages/preprocess_cpp_deps/crate/utils/fpm.toml +++ /dev/null @@ -1,5 +0,0 @@ -name = "utils" - -[preprocess] -[preprocess.cpp] -macros = ["X=1"] diff --git a/example_packages/preprocess_cpp_deps/crate/utils/src/say_hello.f90 b/example_packages/preprocess_cpp_deps/crate/utils/src/say_hello.f90 deleted file mode 100644 index c5fc9f04f5..0000000000 --- a/example_packages/preprocess_cpp_deps/crate/utils/src/say_hello.f90 +++ /dev/null @@ -1,11 +0,0 @@ -module utils - - implicit none - -contains - - subroutine say_hello() - print '(a,1x,i0)', "Hello, X =", X - end subroutine say_hello - -end module utils diff --git a/example_packages/preprocess_cpp_deps/fpm.toml b/example_packages/preprocess_cpp_deps/fpm.toml deleted file mode 100644 index adf2239854..0000000000 --- a/example_packages/preprocess_cpp_deps/fpm.toml +++ /dev/null @@ -1,4 +0,0 @@ -name = "preprocess_cpp_deps" - -[dependencies] -utils = { path = "crate/utils" } diff --git a/example_packages/preprocess_cpp_suffix/.gitignore b/example_packages/preprocess_cpp_suffix/.gitignore deleted file mode 100644 index a007feab07..0000000000 --- a/example_packages/preprocess_cpp_suffix/.gitignore +++ /dev/null @@ -1 +0,0 @@ -build/* diff --git a/example_packages/preprocess_cpp_suffix/app/main.f90 b/example_packages/preprocess_cpp_suffix/app/main.f90 deleted file mode 100644 index 7d77b56a06..0000000000 --- a/example_packages/preprocess_cpp_suffix/app/main.f90 +++ /dev/null @@ -1,8 +0,0 @@ -program test_preprocess_suffix - use preprocess_cpp -#ifndef TESTMACRO - stop -1 -#else - stop 0 -#endif -end program test_preprocess_suffix diff --git a/example_packages/preprocess_cpp_suffix/fpm.toml b/example_packages/preprocess_cpp_suffix/fpm.toml deleted file mode 100644 index 6399f1a67d..0000000000 --- a/example_packages/preprocess_cpp_suffix/fpm.toml +++ /dev/null @@ -1,7 +0,0 @@ -name = "preprocess_cpp_suffix" -version = "1" - -[preprocess] -[preprocess.cpp] -macros = ["TESTMACRO", "TESTMACRO2=3", "TESTMACRO3={version}"] -suffixes = ["fpp"] diff --git a/example_packages/preprocess_cpp_suffix/src/preprocess_cpp.fpp b/example_packages/preprocess_cpp_suffix/src/preprocess_cpp.fpp deleted file mode 100644 index d7ab5d1485..0000000000 --- a/example_packages/preprocess_cpp_suffix/src/preprocess_cpp.fpp +++ /dev/null @@ -1,22 +0,0 @@ -module preprocess_cpp - implicit none - private - - public :: say_hello -contains - subroutine say_hello - print *, "Hello, preprocess_cpp!" -#ifndef TESTMACRO - This breaks the build. -#endif - -#if TESTMACRO2 != 3 - This breaks the build. -#endif - -#if TESTMACRO3 != 1 - This breaks the build. -#endif - - end subroutine say_hello -end module preprocess_cpp diff --git a/example_packages/preprocess_hello/README.md b/example_packages/preprocess_hello/README.md deleted file mode 100644 index 6bcc72c759..0000000000 --- a/example_packages/preprocess_hello/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# preprocess_hello -My cool new project! diff --git a/example_packages/preprocess_hello/app/main.f90 b/example_packages/preprocess_hello/app/main.f90 deleted file mode 100644 index f08a5d979c..0000000000 --- a/example_packages/preprocess_hello/app/main.f90 +++ /dev/null @@ -1,6 +0,0 @@ -program preprocess_hello - use preprocess_hello_dependency, only: say_hello - - implicit none - call say_hello() -end program preprocess_hello diff --git a/example_packages/preprocess_hello/fpm.toml b/example_packages/preprocess_hello/fpm.toml deleted file mode 100644 index 0ff85a68b5..0000000000 --- a/example_packages/preprocess_hello/fpm.toml +++ /dev/null @@ -1,8 +0,0 @@ -name = "preprocess_hello" - -[preprocess] -[preprocess.cpp] -macros = ["FOO"] - -[dependencies] -preprocess_hello_dependency = { path = "../preprocess_hello_dependency" } \ No newline at end of file diff --git a/example_packages/preprocess_hello_dependency/README.md b/example_packages/preprocess_hello_dependency/README.md deleted file mode 100644 index d10458555b..0000000000 --- a/example_packages/preprocess_hello_dependency/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# preprocess_hello_dependency -My cool new project! diff --git a/example_packages/preprocess_hello_dependency/fpm.toml b/example_packages/preprocess_hello_dependency/fpm.toml deleted file mode 100644 index 46e4cf34fe..0000000000 --- a/example_packages/preprocess_hello_dependency/fpm.toml +++ /dev/null @@ -1 +0,0 @@ -name = "preprocess_hello_dependency" diff --git a/example_packages/preprocess_hello_dependency/src/preprocess_hello_dependency.f90 b/example_packages/preprocess_hello_dependency/src/preprocess_hello_dependency.f90 deleted file mode 100644 index 14b1e8708d..0000000000 --- a/example_packages/preprocess_hello_dependency/src/preprocess_hello_dependency.f90 +++ /dev/null @@ -1,15 +0,0 @@ -module preprocess_hello_dependency - implicit none - private - - public :: say_hello -contains - subroutine say_hello - -!> If this build fails, then it implies that macros are getting passed to the dependency. -#ifdef FOO - This breaks the build inside dependency. This implies that macros are getting passed to the dependeny. -#endif - print *, "Hello, preprocess_hello_dependency!" - end subroutine say_hello -end module preprocess_hello_dependency diff --git a/example_packages/preprocess_per_dependency/app/main.f90 b/example_packages/preprocess_per_dependency/app/main.f90 deleted file mode 100644 index aed30cd33d..0000000000 --- a/example_packages/preprocess_per_dependency/app/main.f90 +++ /dev/null @@ -1,8 +0,0 @@ -program hello_fpm - use utils, only: say_hello - integer :: ierr - - call say_hello(ierr) - stop ierr ! ierr==0 if DEPENDENCY_MACRO is defined - -end program hello_fpm diff --git a/example_packages/preprocess_per_dependency/crate/utils/fpm.toml b/example_packages/preprocess_per_dependency/crate/utils/fpm.toml deleted file mode 100644 index f3c03f9934..0000000000 --- a/example_packages/preprocess_per_dependency/crate/utils/fpm.toml +++ /dev/null @@ -1,5 +0,0 @@ -name = "utils" - -[preprocess] -[preprocess.cpp] -macros = ["X=1"] diff --git a/example_packages/preprocess_per_dependency/crate/utils/src/say_hello.f90 b/example_packages/preprocess_per_dependency/crate/utils/src/say_hello.f90 deleted file mode 100644 index 5f333bab7e..0000000000 --- a/example_packages/preprocess_per_dependency/crate/utils/src/say_hello.f90 +++ /dev/null @@ -1,19 +0,0 @@ -module utils - - implicit none - -contains - - subroutine say_hello(ierr) - integer, intent(out) :: ierr - - ierr = -1 -#ifdef DEPENDENCY_MACRO - ierr = 0 -#endif - - print *, "Dependency macro ", merge(" IS","NOT",ierr==0)," defined" - - end subroutine say_hello - -end module utils diff --git a/example_packages/preprocess_per_dependency/fpm.toml b/example_packages/preprocess_per_dependency/fpm.toml deleted file mode 100644 index 4730973ab1..0000000000 --- a/example_packages/preprocess_per_dependency/fpm.toml +++ /dev/null @@ -1,4 +0,0 @@ -name = "preprocess_cpp_deps" - -[dependencies] -utils = { path = "crate/utils" , preprocess.cpp.macros=["DEPENDENCY_MACRO"] } diff --git a/example_packages/program_with_module/.gitignore b/example_packages/program_with_module/.gitignore deleted file mode 100644 index a007feab07..0000000000 --- a/example_packages/program_with_module/.gitignore +++ /dev/null @@ -1 +0,0 @@ -build/* diff --git a/example_packages/program_with_module/app/main.f90 b/example_packages/program_with_module/app/main.f90 deleted file mode 100644 index 59441f0423..0000000000 --- a/example_packages/program_with_module/app/main.f90 +++ /dev/null @@ -1,10 +0,0 @@ -module greet_m - implicit none - character(*), parameter :: greeting = 'Hello, fpm!' -end module greet_m - -program program_with_module - use greet_m, only: greeting - implicit none - print *, greeting -end program program_with_module diff --git a/example_packages/program_with_module/fpm.toml b/example_packages/program_with_module/fpm.toml deleted file mode 100644 index bce6aa2cfc..0000000000 --- a/example_packages/program_with_module/fpm.toml +++ /dev/null @@ -1 +0,0 @@ -name = "Program_with_module" diff --git a/example_packages/shared_app_only/app/main.f90 b/example_packages/shared_app_only/app/main.f90 deleted file mode 100644 index 38fcad0975..0000000000 --- a/example_packages/shared_app_only/app/main.f90 +++ /dev/null @@ -1,4 +0,0 @@ -program main - use testdrive - print *, 'Hello, world!' -end program main diff --git a/example_packages/shared_app_only/fpm.toml b/example_packages/shared_app_only/fpm.toml deleted file mode 100644 index 1506a4c44e..0000000000 --- a/example_packages/shared_app_only/fpm.toml +++ /dev/null @@ -1,8 +0,0 @@ -# App only, use shared lib from other folder -name = "shared_app_only" -library.type="shared" -install.library=true -[dependencies] -shared_lib_extra = { path = "../shared_lib_extra" } -[dev-dependencies] -test-drive = { git = "https://github.com/fortran-lang/test-drive", tag="v0.5.0" } diff --git a/example_packages/shared_app_only/test/test.f90 b/example_packages/shared_app_only/test/test.f90 deleted file mode 100644 index 652d58d603..0000000000 --- a/example_packages/shared_app_only/test/test.f90 +++ /dev/null @@ -1,50 +0,0 @@ -module test_shared_lib - use testdrive, only : new_unittest, unittest_type, error_type, check - use shared_lib, only: test_something - - implicit none - - public :: collect - - -contains - - !> Collect all exported unit tests - subroutine collect(testsuite) - !> Collection of tests - type(unittest_type), allocatable, intent(out) :: testsuite(:) - - testsuite = [ new_unittest("shared_lib", test_shared) ] - - end subroutine collect - - subroutine test_shared(error) - type(error_type), allocatable, intent(out) :: error - - call check(error, test_something(), 123, "Should be test_something==123") - - end subroutine test_shared - -end module test_shared_lib - -program tester - use, intrinsic :: iso_fortran_env, only : error_unit - use testdrive, only : run_testsuite, new_testsuite, testsuite_type - use test_shared_lib, only : collect - implicit none - integer :: stat - type(testsuite_type), allocatable :: testsuite - character(len=*), parameter :: fmt = '("#", *(1x, a))' - - stat = 0 - - testsuite = new_testsuite("shared_lib", collect) - - write(error_unit, fmt) "Testing:", testsuite%name - call run_testsuite(testsuite%collect, error_unit, stat) - - if (stat > 0) then - write(error_unit, '(i0, 1x, a)') stat, "test(s) failed!" - error stop - end if -end program tester diff --git a/example_packages/shared_lib/fpm.toml b/example_packages/shared_lib/fpm.toml deleted file mode 100644 index 5d812881f2..0000000000 --- a/example_packages/shared_lib/fpm.toml +++ /dev/null @@ -1,3 +0,0 @@ -# Shared library with no executables -name = "shared_lib" -library.type="shared" diff --git a/example_packages/shared_lib/src/shared_lib.f90 b/example_packages/shared_lib/src/shared_lib.f90 deleted file mode 100644 index 1743c9fc05..0000000000 --- a/example_packages/shared_lib/src/shared_lib.f90 +++ /dev/null @@ -1,14 +0,0 @@ -module shared_lib - implicit none - private - - public :: say_hello - public :: test_something -contains - subroutine say_hello - print *, "Hello, shared_lib!" - end subroutine say_hello - integer function test_something() - test_something = 123 - end function test_something -end module shared_lib diff --git a/example_packages/shared_lib_empty/fpm.toml b/example_packages/shared_lib_empty/fpm.toml deleted file mode 100644 index af881f59a0..0000000000 --- a/example_packages/shared_lib_empty/fpm.toml +++ /dev/null @@ -1,5 +0,0 @@ -name = "shared_lib_empty" -library.type="shared" -[dependencies] -shared_lib = { path = "../shared_lib" } -shared_app_only = { path = "../shared_app_only" } diff --git a/example_packages/shared_lib_extra/fpm.toml b/example_packages/shared_lib_extra/fpm.toml deleted file mode 100644 index 5ad49477d9..0000000000 --- a/example_packages/shared_lib_extra/fpm.toml +++ /dev/null @@ -1,4 +0,0 @@ -name = "shared_lib_extra" -library.type="shared" -[dependencies] -shared_lib = { path = "../shared_lib" } diff --git a/example_packages/shared_lib_extra/src/shared_lib_extra.f90 b/example_packages/shared_lib_extra/src/shared_lib_extra.f90 deleted file mode 100644 index f4b12ef121..0000000000 --- a/example_packages/shared_lib_extra/src/shared_lib_extra.f90 +++ /dev/null @@ -1,10 +0,0 @@ -module shared_lib_extra - implicit none - private - - public :: say_extra_hello -contains - subroutine say_extra_hello - print *, "Hello, shared_lib_extra!" - end subroutine say_extra_hello -end module shared_lib_extra diff --git a/example_packages/static_app_only/app/main.f90 b/example_packages/static_app_only/app/main.f90 deleted file mode 100644 index 38fcad0975..0000000000 --- a/example_packages/static_app_only/app/main.f90 +++ /dev/null @@ -1,4 +0,0 @@ -program main - use testdrive - print *, 'Hello, world!' -end program main diff --git a/example_packages/static_app_only/fpm.toml b/example_packages/static_app_only/fpm.toml deleted file mode 100644 index 914339b6b5..0000000000 --- a/example_packages/static_app_only/fpm.toml +++ /dev/null @@ -1,8 +0,0 @@ -# App only, use shared libs from other folder, no provided sources -name = "static_app_only" -library.type="static" -install.library=true -[dependencies] -shared_lib_extra = { path = "../shared_lib_extra" } -[dev-dependencies] -test-drive = { git = "https://github.com/fortran-lang/test-drive", tag="v0.5.0" } diff --git a/example_packages/static_app_only/test/test.f90 b/example_packages/static_app_only/test/test.f90 deleted file mode 100644 index 652d58d603..0000000000 --- a/example_packages/static_app_only/test/test.f90 +++ /dev/null @@ -1,50 +0,0 @@ -module test_shared_lib - use testdrive, only : new_unittest, unittest_type, error_type, check - use shared_lib, only: test_something - - implicit none - - public :: collect - - -contains - - !> Collect all exported unit tests - subroutine collect(testsuite) - !> Collection of tests - type(unittest_type), allocatable, intent(out) :: testsuite(:) - - testsuite = [ new_unittest("shared_lib", test_shared) ] - - end subroutine collect - - subroutine test_shared(error) - type(error_type), allocatable, intent(out) :: error - - call check(error, test_something(), 123, "Should be test_something==123") - - end subroutine test_shared - -end module test_shared_lib - -program tester - use, intrinsic :: iso_fortran_env, only : error_unit - use testdrive, only : run_testsuite, new_testsuite, testsuite_type - use test_shared_lib, only : collect - implicit none - integer :: stat - type(testsuite_type), allocatable :: testsuite - character(len=*), parameter :: fmt = '("#", *(1x, a))' - - stat = 0 - - testsuite = new_testsuite("shared_lib", collect) - - write(error_unit, fmt) "Testing:", testsuite%name - call run_testsuite(testsuite%collect, error_unit, stat) - - if (stat > 0) then - write(error_unit, '(i0, 1x, a)') stat, "test(s) failed!" - error stop - end if -end program tester diff --git a/example_packages/static_lib_empty/fpm.toml b/example_packages/static_lib_empty/fpm.toml deleted file mode 100644 index 513661708f..0000000000 --- a/example_packages/static_lib_empty/fpm.toml +++ /dev/null @@ -1,5 +0,0 @@ -name = "static_lib_empty" -library.type="static" -[dependencies] -shared_lib = { path = "../shared_lib" } -shared_app_only = { path = "../shared_app_only" } diff --git a/example_packages/submodule_tree_shake/.gitignore b/example_packages/submodule_tree_shake/.gitignore deleted file mode 100644 index a007feab07..0000000000 --- a/example_packages/submodule_tree_shake/.gitignore +++ /dev/null @@ -1 +0,0 @@ -build/* diff --git a/example_packages/submodule_tree_shake/app/main.f90 b/example_packages/submodule_tree_shake/app/main.f90 deleted file mode 100644 index 4bbd2f8c48..0000000000 --- a/example_packages/submodule_tree_shake/app/main.f90 +++ /dev/null @@ -1,9 +0,0 @@ -program test -use parent - -integer :: a, b - -call my_sub1(a) -call my_sub2(b) - -end program test \ No newline at end of file diff --git a/example_packages/submodule_tree_shake/fpm.toml b/example_packages/submodule_tree_shake/fpm.toml deleted file mode 100644 index 731b8f9cd2..0000000000 --- a/example_packages/submodule_tree_shake/fpm.toml +++ /dev/null @@ -1 +0,0 @@ -name = "submodule_tree_shake" diff --git a/example_packages/submodule_tree_shake/src/child1.f90 b/example_packages/submodule_tree_shake/src/child1.f90 deleted file mode 100644 index 8f0c97247f..0000000000 --- a/example_packages/submodule_tree_shake/src/child1.f90 +++ /dev/null @@ -1,16 +0,0 @@ -submodule(parent) child1 -implicit none - -interface - module function my_fun() result (b) - integer :: b - end function my_fun -end interface - -contains - -module procedure my_sub1 - a = my_fun() -end procedure my_sub1 - -end submodule child1 \ No newline at end of file diff --git a/example_packages/submodule_tree_shake/src/child2.f90 b/example_packages/submodule_tree_shake/src/child2.f90 deleted file mode 100644 index 179cc3209a..0000000000 --- a/example_packages/submodule_tree_shake/src/child2.f90 +++ /dev/null @@ -1,10 +0,0 @@ -submodule(parent) child2 -implicit none - -contains - -module procedure my_sub2 - a = 2 -end procedure my_sub2 - -end submodule child2 \ No newline at end of file diff --git a/example_packages/submodule_tree_shake/src/child_unused.f90 b/example_packages/submodule_tree_shake/src/child_unused.f90 deleted file mode 100644 index 2f5a45ff65..0000000000 --- a/example_packages/submodule_tree_shake/src/child_unused.f90 +++ /dev/null @@ -1,10 +0,0 @@ -submodule(parent_unused) child_unused -implicit none - -contains - -module procedure unused_sub - a = 1 -end procedure unused_sub - -end submodule child_unused \ No newline at end of file diff --git a/example_packages/submodule_tree_shake/src/grandchild.f90 b/example_packages/submodule_tree_shake/src/grandchild.f90 deleted file mode 100644 index 8c5aa17708..0000000000 --- a/example_packages/submodule_tree_shake/src/grandchild.f90 +++ /dev/null @@ -1,10 +0,0 @@ -submodule(parent:child1) grandchild -implicit none - -contains - -module procedure my_fun - b = 2 -end procedure my_fun - -end submodule grandchild \ No newline at end of file diff --git a/example_packages/submodule_tree_shake/src/parent.f90 b/example_packages/submodule_tree_shake/src/parent.f90 deleted file mode 100644 index 570827cd06..0000000000 --- a/example_packages/submodule_tree_shake/src/parent.f90 +++ /dev/null @@ -1,15 +0,0 @@ -module parent -implicit none - -interface - - module subroutine my_sub1(a) - integer, intent(out) :: a - end subroutine my_sub1 - - module subroutine my_sub2(a) - integer, intent(out) :: a - end subroutine my_sub2 -end interface - -end module parent \ No newline at end of file diff --git a/example_packages/submodule_tree_shake/src/parent_unused.f90 b/example_packages/submodule_tree_shake/src/parent_unused.f90 deleted file mode 100644 index 73ceb24c8f..0000000000 --- a/example_packages/submodule_tree_shake/src/parent_unused.f90 +++ /dev/null @@ -1,12 +0,0 @@ -module parent_unused -implicit none - -interface - - module subroutine unused_sub(a) - integer, intent(out) :: a - end subroutine unused_sub - -end interface - -end module parent_unused \ No newline at end of file diff --git a/example_packages/submodules/.gitignore b/example_packages/submodules/.gitignore deleted file mode 100644 index a007feab07..0000000000 --- a/example_packages/submodules/.gitignore +++ /dev/null @@ -1 +0,0 @@ -build/* diff --git a/example_packages/submodules/fpm.toml b/example_packages/submodules/fpm.toml deleted file mode 100644 index cfc3d617b6..0000000000 --- a/example_packages/submodules/fpm.toml +++ /dev/null @@ -1 +0,0 @@ -name = "submodules" diff --git a/example_packages/submodules/src/child1.f90 b/example_packages/submodules/src/child1.f90 deleted file mode 100644 index dbd0fa5395..0000000000 --- a/example_packages/submodules/src/child1.f90 +++ /dev/null @@ -1,16 +0,0 @@ -submodule(parent) child1 -implicit none - -interface - module function my_fun() result (b) - integer :: b - end function my_fun -end interface - -contains - -module procedure my_sub1 - a = 1 -end procedure my_sub1 - -end submodule child1 \ No newline at end of file diff --git a/example_packages/submodules/src/child2.f90 b/example_packages/submodules/src/child2.f90 deleted file mode 100644 index 179cc3209a..0000000000 --- a/example_packages/submodules/src/child2.f90 +++ /dev/null @@ -1,10 +0,0 @@ -submodule(parent) child2 -implicit none - -contains - -module procedure my_sub2 - a = 2 -end procedure my_sub2 - -end submodule child2 \ No newline at end of file diff --git a/example_packages/submodules/src/grandchild.f90 b/example_packages/submodules/src/grandchild.f90 deleted file mode 100644 index 8c5aa17708..0000000000 --- a/example_packages/submodules/src/grandchild.f90 +++ /dev/null @@ -1,10 +0,0 @@ -submodule(parent:child1) grandchild -implicit none - -contains - -module procedure my_fun - b = 2 -end procedure my_fun - -end submodule grandchild \ No newline at end of file diff --git a/example_packages/submodules/src/parent.f90 b/example_packages/submodules/src/parent.f90 deleted file mode 100644 index 570827cd06..0000000000 --- a/example_packages/submodules/src/parent.f90 +++ /dev/null @@ -1,15 +0,0 @@ -module parent -implicit none - -interface - - module subroutine my_sub1(a) - integer, intent(out) :: a - end subroutine my_sub1 - - module subroutine my_sub2(a) - integer, intent(out) :: a - end subroutine my_sub2 -end interface - -end module parent \ No newline at end of file diff --git a/example_packages/tree_shake/.gitignore b/example_packages/tree_shake/.gitignore deleted file mode 100644 index a007feab07..0000000000 --- a/example_packages/tree_shake/.gitignore +++ /dev/null @@ -1 +0,0 @@ -build/* diff --git a/example_packages/tree_shake/app/say_Hello.f90 b/example_packages/tree_shake/app/say_Hello.f90 deleted file mode 100644 index f620dc2aa5..0000000000 --- a/example_packages/tree_shake/app/say_Hello.f90 +++ /dev/null @@ -1,15 +0,0 @@ -program say_Hello - use greet_m, only: make_greeting - - implicit none - - interface - function external_function() result(i) - integer :: i - end function external_function - end interface - - print *, make_greeting("World") - print *, external_function() - -end program say_Hello diff --git a/example_packages/tree_shake/fpm.toml b/example_packages/tree_shake/fpm.toml deleted file mode 100644 index 78267ce7cc..0000000000 --- a/example_packages/tree_shake/fpm.toml +++ /dev/null @@ -1 +0,0 @@ -name = "tree_shake" \ No newline at end of file diff --git a/example_packages/tree_shake/src/extra_m.f90 b/example_packages/tree_shake/src/extra_m.f90 deleted file mode 100644 index 772fe6b789..0000000000 --- a/example_packages/tree_shake/src/extra_m.f90 +++ /dev/null @@ -1,15 +0,0 @@ -! This module is not used by any other sources, -! however because it also contains an external function -! it cannot be dropped during tree-shaking/pruning -module extra_m - use subdir_constants, only: FAREWELL_STR - implicit none - private - - integer, parameter :: m = 0 -end - -function external_function() result(i) - integer :: i - i = 1 -end function external_function \ No newline at end of file diff --git a/example_packages/tree_shake/src/farewell_m.f90 b/example_packages/tree_shake/src/farewell_m.f90 deleted file mode 100644 index 5a48ffffb9..0000000000 --- a/example_packages/tree_shake/src/farewell_m.f90 +++ /dev/null @@ -1,17 +0,0 @@ -! This module is not used by any other sources -! and only contains a module (no non-module subprograms), -! therefore it should be dropped during tree-shaking/pruning -module farewell_m - use subdir_constants, only: FAREWELL_STR - implicit none - private - - public :: make_farewell -contains - function make_farewell(name) result(greeting) - character(len=*), intent(in) :: name - character(len=:), allocatable :: greeting - - greeting = FAREWELL_STR // name // "!" - end function make_farewell -end module farewell_m diff --git a/example_packages/tree_shake/src/greet_m.f90 b/example_packages/tree_shake/src/greet_m.f90 deleted file mode 100644 index c2992e744e..0000000000 --- a/example_packages/tree_shake/src/greet_m.f90 +++ /dev/null @@ -1,16 +0,0 @@ -! This module is directly by the executables and -! hence should not be dropped during tree-shaking/pruning -module greet_m - use subdir_constants, only: GREET_STR - implicit none - private - - public :: make_greeting -contains - function make_greeting(name) result(greeting) - character(len=*), intent(in) :: name - character(len=:), allocatable :: greeting - - greeting = GREET_STR // name // "!" - end function make_greeting -end module greet_m diff --git a/example_packages/tree_shake/src/subdir/constants.f90 b/example_packages/tree_shake/src/subdir/constants.f90 deleted file mode 100644 index d34307bd00..0000000000 --- a/example_packages/tree_shake/src/subdir/constants.f90 +++ /dev/null @@ -1,9 +0,0 @@ -! This module is used indirectly by the executables -! and hence should not be dropped during tree-shaking/pruning -module subdir_constants -implicit none - -character(*), parameter :: GREET_STR = 'Hello, ' -character(*), parameter :: FAREWELL_STR = 'Goodbye, ' - -end module subdir_constants diff --git a/example_packages/tree_shake/test/greet_test.f90 b/example_packages/tree_shake/test/greet_test.f90 deleted file mode 100644 index 41fa50878e..0000000000 --- a/example_packages/tree_shake/test/greet_test.f90 +++ /dev/null @@ -1,18 +0,0 @@ -program greet_test - use greet_m, only: make_greeting - use iso_fortran_env, only: error_unit, output_unit - - implicit none - - character(len=:), allocatable :: greeting - - allocate(character(len=0) :: greeting) - greeting = make_greeting("World") - - if (greeting == "Hello, World!") then - write(output_unit, *) "Passed" - else - write(error_unit, *) "Failed" - call exit(1) - end if -end program greet_test diff --git a/example_packages/version_file/VERSION b/example_packages/version_file/VERSION deleted file mode 100644 index ae84a9c594..0000000000 --- a/example_packages/version_file/VERSION +++ /dev/null @@ -1 +0,0 @@ -5.42.1 diff --git a/example_packages/version_file/app/main.f90 b/example_packages/version_file/app/main.f90 deleted file mode 100644 index fcf8d64ffd..0000000000 --- a/example_packages/version_file/app/main.f90 +++ /dev/null @@ -1,13 +0,0 @@ -program stub - implicit none - logical :: exists - integer :: unit - character(len=100) :: line - inquire(file="VERSION", exist=exists) - if (.not.exists) error stop "File VERSION does not exist." - open(file="VERSION", newunit=unit) - read(unit, '(a)') line - close(unit) - - print '(*(a))', "File VERSION contains '", trim(line), "'" -end program stub diff --git a/example_packages/version_file/fpm.toml b/example_packages/version_file/fpm.toml deleted file mode 100644 index 4dd64fdf8a..0000000000 --- a/example_packages/version_file/fpm.toml +++ /dev/null @@ -1,2 +0,0 @@ -name = "version_file" -version = "VERSION" diff --git a/example_packages/with_c/.gitignore b/example_packages/with_c/.gitignore deleted file mode 100644 index a007feab07..0000000000 --- a/example_packages/with_c/.gitignore +++ /dev/null @@ -1 +0,0 @@ -build/* diff --git a/example_packages/with_c/app/main.f90 b/example_packages/with_c/app/main.f90 deleted file mode 100644 index 4d3174b61e..0000000000 --- a/example_packages/with_c/app/main.f90 +++ /dev/null @@ -1,10 +0,0 @@ -program with_c_app -use with_c -implicit none - -write(*,*) "isdir('app') = ", system_isdir('app') -write(*,*) "isdir('src') = ", system_isdir('src') -write(*,*) "isdir('test') = ", system_isdir('test') -write(*,*) "isdir('bench') = ", system_isdir('bench') - -end program with_c_app \ No newline at end of file diff --git a/example_packages/with_c/fpm.toml b/example_packages/with_c/fpm.toml deleted file mode 100644 index 97e31109c5..0000000000 --- a/example_packages/with_c/fpm.toml +++ /dev/null @@ -1 +0,0 @@ -name = "with_c" diff --git a/example_packages/with_c/src/c_code.c b/example_packages/with_c/src/c_code.c deleted file mode 100644 index 44604f029c..0000000000 --- a/example_packages/with_c/src/c_code.c +++ /dev/null @@ -1,10 +0,0 @@ -#include -/* - * Decides whether a given file name is a directory. - * return 1 if file exists and is a directory - * Source (Public domain): https://github.com/urbanjost/M_system - */ -int my_isdir (const char *path) { - struct stat sb; - return stat(path, &sb) == 0 && S_ISDIR (sb.st_mode); -} \ No newline at end of file diff --git a/example_packages/with_c/src/with_c.f90 b/example_packages/with_c/src/with_c.f90 deleted file mode 100644 index edd839e3c4..0000000000 --- a/example_packages/with_c/src/with_c.f90 +++ /dev/null @@ -1,26 +0,0 @@ -module with_c - use iso_c_binding, only: c_char, c_int, c_null_char - implicit none - -contains - - function system_isdir(dirname) - ! Source (Public domain): https://github.com/urbanjost/M_system - ! - implicit none - character(len=*),intent(in) :: dirname - logical :: system_isdir - - interface - function c_isdir(dirname) bind (C,name="my_isdir") result (c_ierr) - import c_char,c_int - character(kind=c_char,len=1),intent(in) :: dirname(*) - integer(kind=c_int) :: c_ierr - end function c_isdir - end interface - - system_isdir= c_isdir(trim(dirname)//c_null_char) == 1 - - end function system_isdir - -end module with_c \ No newline at end of file diff --git a/example_packages/with_examples/.gitignore b/example_packages/with_examples/.gitignore deleted file mode 100644 index d9b4f015d3..0000000000 --- a/example_packages/with_examples/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/build/* diff --git a/example_packages/with_examples/app/demo-prog.f90 b/example_packages/with_examples/app/demo-prog.f90 deleted file mode 100644 index f26e898fc8..0000000000 --- a/example_packages/with_examples/app/demo-prog.f90 +++ /dev/null @@ -1,3 +0,0 @@ -program demo - write(*, '(a)') "This is a simple program" -end program demo diff --git a/example_packages/with_examples/demo/prog.f90 b/example_packages/with_examples/demo/prog.f90 deleted file mode 100644 index 8b3d8821b0..0000000000 --- a/example_packages/with_examples/demo/prog.f90 +++ /dev/null @@ -1,3 +0,0 @@ -program demo - write(*, '(a)') "This is a simple demo program, but not a real application" -end program demo diff --git a/example_packages/with_examples/fpm.toml b/example_packages/with_examples/fpm.toml deleted file mode 100644 index d7d29262c8..0000000000 --- a/example_packages/with_examples/fpm.toml +++ /dev/null @@ -1,7 +0,0 @@ -name = "with_examples" -build.auto-examples = false - -[[example]] -name = "demo-prog" -source-dir = "demo" -main = "prog.f90" diff --git a/example_packages/with_makefile/.gitignore b/example_packages/with_makefile/.gitignore deleted file mode 100644 index a007feab07..0000000000 --- a/example_packages/with_makefile/.gitignore +++ /dev/null @@ -1 +0,0 @@ -build/* diff --git a/example_packages/with_makefile/Makefile b/example_packages/with_makefile/Makefile deleted file mode 100644 index 51e72d46cd..0000000000 --- a/example_packages/with_makefile/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -INCLUDE_FLAGS = $(addprefix -I,$(INCLUDE_DIRS)) - -$(BUILD_DIR)/libwith_makefile.a: $(BUILD_DIR)/hello_makefile.o - ar rs $(@) $(^) - -$(BUILD_DIR)/hello_makefile.mod: src/hello_makefile.f90 - -$(BUILD_DIR)/hello_makefile.o: src/hello_makefile.f90 - $(FC) -c -J$(BUILD_DIR) $(INCLUDE_FLAGS) $(FFLAGS) -o $(@) $(<) diff --git a/example_packages/with_makefile/fpm.toml b/example_packages/with_makefile/fpm.toml deleted file mode 100644 index 81dd02ab10..0000000000 --- a/example_packages/with_makefile/fpm.toml +++ /dev/null @@ -1,5 +0,0 @@ -name = "with_makefile" - -[library] -source-dir = "src" -build-script = "Makefile" diff --git a/example_packages/with_makefile/src/hello_makefile.f90 b/example_packages/with_makefile/src/hello_makefile.f90 deleted file mode 100644 index 2d4d1a2fa0..0000000000 --- a/example_packages/with_makefile/src/hello_makefile.f90 +++ /dev/null @@ -1,10 +0,0 @@ -module hello_makefile - implicit none - private - - public :: say_hello_from_makefile -contains - subroutine say_hello_from_makefile() - print *, "Hello from Makefile library!" - end subroutine say_hello_from_makefile -end module hello_makefile diff --git a/ci/installer-icon.ico b/favicon.png similarity index 100% rename from ci/installer-icon.ico rename to favicon.png diff --git a/fpm.toml b/fpm.toml deleted file mode 100644 index 80829a38ef..0000000000 --- a/fpm.toml +++ /dev/null @@ -1,45 +0,0 @@ -name = "fpm" -version = "0.12.0" -license = "MIT" -author = "fpm maintainers" -maintainer = "@fortran-lang/fpm" -copyright = "2020-2025 fpm contributors" -homepage = "https://fpm.fortran-lang.org/" -description = "Fortran Package Manager" - -[preprocess] -[preprocess.cpp] -macros=["FPM_RELEASE_VERSION={version}"] - -[dependencies] -toml-f.git = "https://github.com/toml-f/toml-f" -toml-f.rev = "d7b892b1d074b7cfc5d75c3e0eb36ebc1f7958c1" -M_CLI2.git = "https://github.com/urbanjost/M_CLI2.git" -M_CLI2.rev = "7264878cdb1baff7323cc48596d829ccfe7751b8" -fortran-regex.git = "https://github.com/perazz/fortran-regex" -fortran-regex.tag = "1.1.2" -jonquil.git = "https://github.com/toml-f/jonquil" -jonquil.rev = "4fbd4cf34d577c0fd25e32667ee9e41bf231ece8" -fortran-shlex.git = "https://github.com/perazz/fortran-shlex" -fortran-shlex.tag = "2.0.0" - -[[test]] -name = "cli-test" -source-dir = "test/cli_test" -main = "cli_test.f90" - -[[test]] -name = "new-test" -source-dir = "test/new_test" -main = "new_test.f90" - -[[test]] -name = "fpm-test" -source-dir = "test/fpm_test" -main = "main.f90" - -[[test]] -name = "help-test" -source-dir = "test/help_test" -main = "help_test.f90" - diff --git a/index.html b/index.html new file mode 100644 index 0000000000..e330cdd6e6 --- /dev/null +++ b/index.html @@ -0,0 +1,240 @@ + + + + + + + + + + + + + Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+ +
+

Fortran Package Manager

+

Find us on…

+

+ GitHub + + + + + Download the Source +

+
+ +
+
+

Fortran-lang/fpm

+ +

Fortran package manager developer documentation

+

This is the main documentation of the Fortran package manager (fpm). +This document serves as developer documentation of fpm itself and contains general advice for developing in the fpm code base.

+

The package manifest

+

The central object describing an fpm project is the package manifest fpm.toml. +The manifest is written in TOML, you can find the TOML specification at the official TOML homepage.

+

The fpm.toml file targets project developers and maintainers to relieve them from writing build files for their packages. +With the package manifest a central place to collect information about the project is provided. +It contains the versioning and licensing meta data, as well as the information on external dependencies and the required build-tools or compiler settings.

+

The manifest format specific to fpm projects is documented in the manifest reference.

+
+

Note

+

For a more practical but less complete guide on creating fpm projects see the packaging guide.

+
+

The details of the TOML parsing are implemented with using the tomlf module. +Generally, the interface to all TOML related functions for fpm is found in the proxy module fpm_toml.

+

All the manifest types are bundled in fpm_manifest. +While the specific subtables for the package configuration are found in the src/fpm/manifest directory, they should be reexported in the fpm_manifest module if they should be elsewhere in fpm.

+

Command line interface

+

fpm is mainly used as a command line tool. +To work with an fpm project as a user you can completely rely on the command line.

+

The command line interface is build with the M_CLI2 module and can be found in fpm_command_line.

+

The package model

+

Once front-end inputs have been received from the package manifest and command line interface, fpm will construct an +internal representation of the package and its dependencies. This internal representation is known as the package model. +The model and its associated data types should encapsulate all the information required to correctly build a package and +should be independent of the intended backend build system. Information stored in the model includes: build targets and +their inter-dependencies; compiler and compiler flags; library linking information.

+

For more information on the contents of the package model and the process for constructing it, please see fpm_model.

+

The build backend

+

Once a complete package model has been constructed, it can be passed to a backend for either performing the compilation +and linking of targets, or for generating configuration files for a third-party build system. +Currently, only a native backend is implemented in fpm. See fpm_backend for more information.

+

Generating this documentation

+

This documentation is generated by FORD. +For more details on the project file and the comment markup in the source code visit the FORD documentation.

+

To regenerate this documentation run:

+
ford docs.md
+
+
+
+
+ Developer picture +

Developer Info

+

fortran-lang/fpm contributors

+

+
+ + + + + + + + +
+
+
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/install.sh b/install.sh deleted file mode 100755 index ca03cf4679..0000000000 --- a/install.sh +++ /dev/null @@ -1,97 +0,0 @@ -#!/bin/sh - -set -e # exit on error - -usage() -{ - echo "Fortran Package Manager Bootstrap Script" - echo "" - echo "USAGE:" - echo "./install.sh [--help | [--prefix=PREFIX]" - echo "" - echo " --help Display this help text" - echo " --prefix=PREFIX Install binary in 'PREFIX/bin'" - echo " Default prefix='\$HOME/.local/bin'" - echo "" - echo "FC and FFLAGS environment variables can be used to select the" - echo "Fortran compiler and the build flags." - echo "" -} - -# Return a download command -get_fetch_command() -{ - if command -v curl > /dev/null 2>&1; then - echo "curl -L" - elif command -v wget > /dev/null 2>&1; then - echo "wget -O -" - else - echo "No download mechanism found. Install curl or wget first." - return 1 - fi -} - -# Return value of the latest published release on GitHub, with no heading "v" (e.g., "0.7.0") -get_latest_release() -{ - $2 "https://api.github.com/repos/$1/releases/latest" | # Get latest release from GitHub api - grep '"tag_name":' | # Get tag line - sed -E 's/.*"([^"]+)".*/\1/' | # Pluck JSON value - sed -E 's/^v//' # Remove heading "v" if present -} - -PREFIX="$HOME/.local" - -while [ "$1" != "" ]; do - PARAM=$(echo "$1" | awk -F= '{print $1}') - VALUE=$(echo "$1" | awk -F= '{print $2}') - case $PARAM in - -h | --help) - usage - exit - ;; - --prefix) - PREFIX=$VALUE - ;; - *) - echo "ERROR: unknown parameter \"$PARAM\"" - usage - exit 1 - ;; - esac - shift -done - -set -u # error on use of undefined variable - -# Get download command -FETCH=$(get_fetch_command) -if [ $? -ne 0 ]; then - echo "No download mechanism found. Install curl or wget first." - exit 2 -fi - -# Use 0.8.0 too bootstrap -BOOTSTRAP_RELEASE="0.8.0" -SOURCE_URL="https://github.com/fortran-lang/fpm/releases/download/v${BOOTSTRAP_RELEASE}/fpm-${BOOTSTRAP_RELEASE}.F90" -BOOTSTRAP_DIR="build/bootstrap" - -if [ -z ${FC+x} ]; then - FC="gfortran" -fi -if [ -z ${FFLAGS+x} ]; then - FFLAGS="-g -fbacktrace -O3" -fi - -mkdir -p $BOOTSTRAP_DIR - -$FETCH $SOURCE_URL > $BOOTSTRAP_DIR/fpm.F90 - -SAVEDIR="$(pwd)" -cd $BOOTSTRAP_DIR -$FC $FFLAGS fpm.F90 -o fpm -cd "$SAVEDIR" - -$BOOTSTRAP_DIR/fpm update -$BOOTSTRAP_DIR/fpm install --compiler "$FC" --flag "$FFLAGS" --prefix "$PREFIX" -rm -r $BOOTSTRAP_DIR diff --git a/interface/add_table.html b/interface/add_table.html new file mode 100644 index 0000000000..ec46762727 --- /dev/null +++ b/interface/add_table.html @@ -0,0 +1,297 @@ + + + + + + + + + + + + + add_table – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

add_table + Interface + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public interface add_table

+

add_table: fpm interface

+
+ + +

Module Procedures

+
+

private subroutine add_table_fpm(table, key, ptr, error, whereAt) +

+
+

Function wrapper to add a toml table and return an fpm error

+

Nullify pointer

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(toml_table), + intent(inout) + + ::table +

Instance of the TOML data structure

+
+ + character(len=*), + intent(in) + + ::key +

Table key

+
+ + type(toml_table), + intent(out), + pointer + ::ptr +

The character variable

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + character(len=*), + intent(in),optional + + ::whereAt +

Optional description

+
+ + +
+
+ +
+
+
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/interface/add_target.html b/interface/add_target.html new file mode 100644 index 0000000000..5cce7a5367 --- /dev/null +++ b/interface/add_target.html @@ -0,0 +1,481 @@ + + + + + + + + + + + + + add_target – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

add_target + Interface + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public interface add_target

+ + + + +

Module Procedures

+
+

private subroutine add_new_target(targets, package, type, output_name, source, link_libraries, features, preprocess, version, output_dir) +

+
+

Allocate a new target and append to target list

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(build_target_ptr), + intent(inout), + allocatable + ::targets(:) + +
+ + character(len=*), + intent(in) + + ::package + +
+ + integer, + intent(in) + + ::type + +
+ + character(len=*), + intent(in) + + ::output_name + +
+ + type(srcfile_t), + intent(in),optional + + ::source + +
+ + type(string_t), + intent(in),optional + + ::link_libraries(:) + +
+ + type(fortran_features_t), + intent(in),optional + + ::features + +
+ + type(preprocess_config_t), + intent(in),optional + + ::preprocess + +
+ + character(len=*), + intent(in),optional + + ::version + +
+ + character(len=*), + intent(in),optional + + ::output_dir + +
+ + +
+
+ +
+

private subroutine add_old_target(targets, add_target) +

+
+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(build_target_ptr), + intent(inout), + allocatable + ::targets(:) + +
+ + type(build_target_ptr), + intent(in) + + ::add_target + +
+ + +
+
+ +
+

private subroutine add_old_targets(targets, add_targets) +

+
+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(build_target_ptr), + intent(inout), + allocatable + ::targets(:) + +
+ + type(build_target_ptr), + intent(in) + + ::add_targets(:) + +
+ + +
+
+ +
+
+
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/interface/build_progress_t.html b/interface/build_progress_t.html new file mode 100644 index 0000000000..61f4add770 --- /dev/null +++ b/interface/build_progress_t.html @@ -0,0 +1,256 @@ + + + + + + + + + + + + + build_progress_t – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

build_progress_t + Interface + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public interface build_progress_t

+

Constructor for build_progress_t

+
+ + +

Module Procedures

+
+

private function new_build_progress(target_queue, plain_mode) result(progress) +

+
+

Initialise a new build progress object

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(build_target_ptr), + intent(in), + target + ::target_queue(:) +

The queue of scheduled targets

+
+ + logical, + intent(in),optional + + ::plain_mode +

Enable ‘plain’ output for progress object

+
+ +

+ Return Value + type(build_progress_t) +

+

Progress object to initialise

+ +
+
+ +
+
+
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/interface/compile_command_t.html b/interface/compile_command_t.html new file mode 100644 index 0000000000..876f71babe --- /dev/null +++ b/interface/compile_command_t.html @@ -0,0 +1,272 @@ + + + + + + + + + + + + + compile_command_t – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

compile_command_t + Interface + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public interface compile_command_t

+ + + + +

Module Procedures

+
+

public function cct_new(directory, arguments, file) result(cct) +

+
+ +

Override default initializer (GCC 15 bug)

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::directory + +
+ + character(len=*), + intent(in),optional + + ::arguments(:) + +
+ + character(len=*), + intent(in) + + ::file + +
+ +

+ Return Value + type(compile_command_t) +

+ + +
+
+ +
+
+
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/interface/debug.html b/interface/debug.html new file mode 100644 index 0000000000..54fbdbc5bb --- /dev/null +++ b/interface/debug.html @@ -0,0 +1,288 @@ + + + + + + + + + + + + + debug – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

debug + Interface + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public interface debug

+

Create debug printout

+
+ + +

Module Procedures

+
+

public pure function debug_compiler(self) result(repr) +

+
+ +

String representation of a compiler object

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(compiler_t), + intent(in) + + ::self +

Instance of the compiler object

+
+ +

+ Return Value + character(len=:), allocatable +

+

Representation as string

+ +
+
+ +
+

public pure function debug_archiver(self) result(repr) +

+
+ +

String representation of an archiver object

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(archiver_t), + intent(in) + + ::self +

Instance of the archiver object

+
+ +

+ Return Value + character(len=:), allocatable +

+

Representation as string

+ +
+
+ +
+
+
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/interface/fnv_1a.html b/interface/fnv_1a.html new file mode 100644 index 0000000000..04abeec61d --- /dev/null +++ b/interface/fnv_1a.html @@ -0,0 +1,316 @@ + + + + + + + + + + + + + fnv_1a – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fnv_1a + Interface + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public interface fnv_1a

+ + + + +

Module Procedures

+
+

private pure function fnv_1a_char(input, seed) result(hash) +

+
+

Hash a character(*) string of default kind

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::input + +
+ + integer(kind=int64), + intent(in),optional + + ::seed + +
+ +

+ Return Value + integer(kind=int64) +

+ + +
+
+ +
+

private pure function fnv_1a_string_t(input, seed) result(hash) +

+
+

Hash a string_t array of default kind

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(string_t), + intent(in) + + ::input(:) + +
+ + integer(kind=int64), + intent(in),optional + + ::seed + +
+ +

+ Return Value + integer(kind=int64) +

+ + +
+
+ +
+
+
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/interface/get_value.html b/interface/get_value.html new file mode 100644 index 0000000000..5e86f80ed3 --- /dev/null +++ b/interface/get_value.html @@ -0,0 +1,696 @@ + + + + + + + + + + + + + get_value – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

get_value + Interface + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public interface get_value

+

get_value: fpm interface

+
+ + +

Module Procedures

+
+

private subroutine get_logical(table, key, var, error, whereAt) +

+
+

Function wrapper to get a logical variable from a toml table, returning an fpm error

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(toml_table), + intent(inout) + + ::table +

Instance of the TOML data structure

+
+ + character(len=*), + intent(in) + + ::key +

The key

+
+ + logical, + intent(inout) + + ::var +

The variable

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + character(len=*), + intent(in),optional + + ::whereAt +

Optional description

+
+ + +
+
+ +
+

private subroutine get_integer(table, key, var, error, whereAt) +

+
+

Function wrapper to get a default integer variable from a toml table, returning an fpm error

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(toml_table), + intent(inout) + + ::table +

Instance of the TOML data structure

+
+ + character(len=*), + intent(in) + + ::key +

The key

+
+ + integer, + intent(inout) + + ::var +

The variable

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + character(len=*), + intent(in),optional + + ::whereAt +

Optional description

+
+ + +
+
+ +
+

private subroutine get_integer_64(table, key, var, error, whereAt) +

+
+

Function wrapper to get a integer(int64) variable from a toml table, returning an fpm error

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(toml_table), + intent(inout) + + ::table +

Instance of the TOML data structure

+
+ + character(len=*), + intent(in) + + ::key +

The key

+
+ + integer(kind=int64), + intent(inout) + + ::var +

The variable

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + character(len=*), + intent(in),optional + + ::whereAt +

Optional description

+
+ + +
+
+ +
+

private subroutine get_char(table, key, var, error, whereAt) +

+
+

Function wrapper to get a default character variable from a toml table, returning an fpm error

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(toml_table), + intent(inout) + + ::table +

Instance of the TOML data structure

+
+ + character(len=*), + intent(in) + + ::key +

The key

+
+ + character(len=:), + intent(inout), + allocatable + ::var +

The variable

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + character(len=*), + intent(in),optional + + ::whereAt +

Optional description

+
+ + +
+
+ +
+

private subroutine get_string(table, key, var, error, whereAt) +

+
+

Function wrapper to get a default string variable from a toml table, returning an fpm error

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(toml_table), + intent(inout) + + ::table +

Instance of the TOML data structure

+
+ + character(len=*), + intent(in) + + ::key +

The key

+
+ + type(string_t), + intent(inout) + + ::var +

The variable

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + character(len=*), + intent(in),optional + + ::whereAt +

Optional description

+
+ + +
+
+ +
+
+
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/interface/len_trim.html b/interface/len_trim.html new file mode 100644 index 0000000000..a6f1a960d8 --- /dev/null +++ b/interface/len_trim.html @@ -0,0 +1,286 @@ + + + + + + + + + + + + + len_trim – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

len_trim + Interface + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public interface len_trim

+ + + + +

Module Procedures

+
+

private elemental function string_len_trim(string) result(n) +

+
+

Determine total trimmed length of string_t array

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(string_t), + intent(in) + + ::string + +
+ +

+ Return Value + integer +

+ + +
+
+ +
+

private pure function strings_len_trim(strings) result(n) +

+
+

Determine total trimmed length of string_t array

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(string_t), + intent(in) + + ::strings(:) + +
+ +

+ Return Value + integer +

+ + +
+
+ +
+
+
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/interface/new_version.html b/interface/new_version.html new file mode 100644 index 0000000000..e835b3d836 --- /dev/null +++ b/interface/new_version.html @@ -0,0 +1,321 @@ + + + + + + + + + + + + + new_version – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

new_version + Interface + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public interface new_version

+ + + + +

Module Procedures

+
+

private subroutine new_version_from_string(self, string, error) +

+
+

Create a new version from a string

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(version_t), + intent(out) + + ::self +

Instance of the versioning data

+
+ + character(len=*), + intent(in) + + ::string +

String describing the version information

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + +
+
+ +
+

private subroutine new_version_from_int(self, num) +

+
+

Create a new version from a string

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(version_t), + intent(out) + + ::self +

Instance of the versioning data

+
+ + integer, + intent(in) + + ::num(:) +

Subversion numbers to define version data

+
+ + +
+
+ +
+
+
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/interface/operator(.in.).html b/interface/operator(.in.).html new file mode 100644 index 0000000000..861cc41a2d --- /dev/null +++ b/interface/operator(.in.).html @@ -0,0 +1,257 @@ + + + + + + + + + + + + + operator(.in.) – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

operator(.in.) + Interface + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public interface operator(.in.)

+ + + + +

Module Procedures

+
+

public function string_array_contains(search_string, array) +

+
+ +

Check if array of TYPE(STRING_T) matches a particular CHARACTER string

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::search_string + +
+ + type(string_t), + intent(in) + + ::array(:) + +
+ +

+ Return Value + logical +

+ + +
+
+ +
+
+
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/interface/operator(==).html b/interface/operator(==).html new file mode 100644 index 0000000000..ada0b7c3df --- /dev/null +++ b/interface/operator(==).html @@ -0,0 +1,316 @@ + + + + + + + + + + + + + operator(==) – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

operator(==) + Interface + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public interface operator(==)

+ + + + +

Module Procedures

+
+

private pure function string_is_same(this, that) +

+
+

Check that two string objects are exactly identical

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(string_t), + intent(in) + + ::this +

two strings to be compared

+
+ + type(string_t), + intent(in) + + ::that +

two strings to be compared

+
+ +

+ Return Value + logical +

+ + +
+
+ +
+

private pure function string_arrays_same(this, that) +

+
+

Check that two allocatable string object arrays are exactly identical

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(string_t), + intent(in), + allocatable + ::this(:) +

two string arrays to be compared

+
+ + type(string_t), + intent(in), + allocatable + ::that(:) +

two string arrays to be compared

+
+ +

+ Return Value + logical +

+ + +
+
+ +
+
+
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/interface/resize.html b/interface/resize.html new file mode 100644 index 0000000000..c42b73c687 --- /dev/null +++ b/interface/resize.html @@ -0,0 +1,251 @@ + + + + + + + + + + + + + resize – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

resize + Interface + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public interface resize

+

Overloaded reallocation interface

+
+ + +

Module Procedures

+
+

private pure subroutine resize_dependency_node(var, n) +

+
+

Reallocate a list of dependencies

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(dependency_node_t), + intent(inout), + allocatable + ::var(:) +

Instance of the array to be resized

+
+ + integer, + intent(in),optional + + ::n +

Dimension of the final array size

+
+ + +
+
+ +
+
+
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/interface/resize~2.html b/interface/resize~2.html new file mode 100644 index 0000000000..664f66decb --- /dev/null +++ b/interface/resize~2.html @@ -0,0 +1,251 @@ + + + + + + + + + + + + + resize – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

resize + Interface + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public interface resize

+ + + + +

Module Procedures

+
+

private pure subroutine resize_dependency_config(var, n) +

+
+

Reallocate a list of dependencies

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(dependency_config_t), + intent(inout), + allocatable + ::var(:) +

Instance of the array to be resized

+
+ + integer, + intent(in),optional + + ::n +

Dimension of the final array size

+
+ + +
+
+ +
+
+
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/interface/resize~3.html b/interface/resize~3.html new file mode 100644 index 0000000000..ca339acd09 --- /dev/null +++ b/interface/resize~3.html @@ -0,0 +1,251 @@ + + + + + + + + + + + + + resize – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

resize + Interface + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public interface resize

+ + + + +

Module Procedures

+
+

private subroutine resize_string(list, n) +

+
+

increase the size of a TYPE(STRING_T) array by N elements

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(string_t), + intent(inout), + allocatable + ::list(:) +

Instance of the array to be resized

+
+ + integer, + intent(in),optional + + ::n +

Dimension of the final array size

+
+ + +
+
+ +
+
+
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/interface/resolve_metapackages.html b/interface/resolve_metapackages.html new file mode 100644 index 0000000000..c9602f96f2 --- /dev/null +++ b/interface/resolve_metapackages.html @@ -0,0 +1,281 @@ + + + + + + + + + + + + + resolve_metapackages – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

resolve_metapackages + Interface + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public interface resolve_metapackages

+ + + + +

Module Procedures

+
+

private subroutine resolve_metapackage_model(model, package, settings, error) +

+
+

Resolve all metapackages into the package config

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(fpm_model_t), + intent(inout) + + ::model + +
+ + type(package_config_t), + intent(inout) + + ::package + +
+ + class(fpm_build_settings), + intent(inout) + + ::settings + +
+ + type(error_t), + intent(out), + allocatable + ::error + +
+ + +
+
+ +
+
+
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/interface/set_string.html b/interface/set_string.html new file mode 100644 index 0000000000..1fdcaaeb7e --- /dev/null +++ b/interface/set_string.html @@ -0,0 +1,397 @@ + + + + + + + + + + + + + set_string – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

set_string + Interface + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public interface set_string

+ + + + +

Module Procedures

+
+

private subroutine set_character(table, key, var, error, whereAt) +

+
+

Function wrapper to set a character(len=:), allocatable variable to a toml table

+

Check the key is not empty

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(toml_table), + intent(inout) + + ::table +

Instance of the TOML data structure

+
+ + character(len=*), + intent(in) + + ::key +

List of keys to check.

+
+ + character(len=*), + intent(in),optional + + ::var +

The character variable

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + character(len=*), + intent(in),optional + + ::whereAt +

Optional description

+
+ + +
+
+ +
+

private subroutine set_string_type(table, key, var, error, whereAt) +

+
+

Function wrapper to set a character(len=:), allocatable variable to a toml table

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(toml_table), + intent(inout) + + ::table +

Instance of the TOML data structure

+
+ + character(len=*), + intent(in) + + ::key +

List of keys to check.

+
+ + type(string_t), + intent(in) + + ::var +

The character variable

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + character(len=*), + intent(in),optional + + ::whereAt +

Optional description

+
+ + +
+
+ +
+
+
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/interface/set_value.html b/interface/set_value.html new file mode 100644 index 0000000000..b52405ce97 --- /dev/null +++ b/interface/set_value.html @@ -0,0 +1,496 @@ + + + + + + + + + + + + + set_value – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

set_value + Interface + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public interface set_value

+

set_value: fpm interface

+
+ + +

Module Procedures

+
+

private subroutine set_logical(table, key, var, error, whereAt) +

+
+

Function wrapper to set a logical variable to a toml table, returning an fpm error

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(toml_table), + intent(inout) + + ::table +

Instance of the TOML data structure

+
+ + character(len=*), + intent(in) + + ::key +

The key

+
+ + logical, + intent(in) + + ::var +

The variable

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + character(len=*), + intent(in),optional + + ::whereAt +

Optional description

+
+ + +
+
+ +
+

private subroutine set_integer(table, key, var, error, whereAt) +

+
+

Function wrapper to set a default integer variable to a toml table, returning an fpm error

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(toml_table), + intent(inout) + + ::table +

Instance of the TOML data structure

+
+ + character(len=*), + intent(in) + + ::key +

The key

+
+ + integer, + intent(in) + + ::var +

The variable

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + character(len=*), + intent(in),optional + + ::whereAt +

Optional description

+
+ + +
+
+ +
+

private subroutine set_integer_64(table, key, var, error, whereAt) +

+
+

Function wrapper to set a default integer variable to a toml table, returning an fpm error

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(toml_table), + intent(inout) + + ::table +

Instance of the TOML data structure

+
+ + character(len=*), + intent(in) + + ::key +

The key

+
+ + integer(kind=int64), + intent(in) + + ::var +

The variable

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + character(len=*), + intent(in),optional + + ::whereAt +

Optional description

+
+ + +
+
+ +
+
+
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/interface/str.html b/interface/str.html new file mode 100644 index 0000000000..e548322e15 --- /dev/null +++ b/interface/str.html @@ -0,0 +1,331 @@ + + + + + + + + + + + + + str – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

str + Interface + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public interface str

+ + + + +

Module Procedures

+
+

private pure function str_int(i) result(s) +

+
+

Converts integer “i” to string

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + integer, + intent(in) + + ::i + +
+ +

+ Return Value + character(len=str_int_len) +

+ + +
+
+ +
+

private pure function str_int64(i) result(s) +

+
+

Converts integer “i” to string

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + integer(kind=int64), + intent(in) + + ::i + +
+ +

+ Return Value + character(len=str_int64_len) +

+ + +
+
+ +
+

private pure function str_logical(l) result(s) +

+
+

Converts logical “l” to string

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + logical, + intent(in) + + ::l + +
+ +

+ Return Value + character(len=str_logical_len) +

+ + +
+
+ +
+
+
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/interface/str_ends_with.html b/interface/str_ends_with.html new file mode 100644 index 0000000000..fd45b4f8f7 --- /dev/null +++ b/interface/str_ends_with.html @@ -0,0 +1,376 @@ + + + + + + + + + + + + + str_ends_with – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

str_ends_with + Interface + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public interface str_ends_with

+ + + + +

Module Procedures

+
+

private pure function str_ends_with_str(s, e) result(r) +

+
+

test if a CHARACTER string ends with a specified suffix

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::s + +
+ + character(len=*), + intent(in) + + ::e + +
+ +

+ Return Value + logical +

+ + +
+
+ +
+

private pure function str_ends_with_any(s, e) result(r) +

+
+

test if a CHARACTER string ends with any of an array of suffixs

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::s + +
+ + character(len=*), + intent(in) + + ::e(:) + +
+ +

+ Return Value + logical +

+ + +
+
+ +
+

private pure function str_ends_with_any_string(s, e) result(r) +

+
+

Test if a CHARACTER string ends with any of an array of string suffixs

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::s + +
+ + type(string_t), + intent(in) + + ::e(:) + +
+ +

+ Return Value + logical +

+ + +
+
+ +
+
+
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/interface/string_t.html b/interface/string_t.html new file mode 100644 index 0000000000..8b4caa9a2b --- /dev/null +++ b/interface/string_t.html @@ -0,0 +1,242 @@ + + + + + + + + + + + + + string_t – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

string_t + Interface + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public interface string_t

+ + + + +

Module Procedures

+
+

private function new_string_t(s) result(string) +

+
+

Helper function to generate a new string_t instance + (Required due to the allocatable component)

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::s + +
+ +

+ Return Value + type(string_t) +

+ + +
+
+ +
+
+
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/js/MathJax-config/.gitignore b/js/MathJax-config/.gitignore new file mode 100644 index 0000000000..e69de29bb2 diff --git a/js/svg-pan-zoom.min.js b/js/svg-pan-zoom.min.js new file mode 100644 index 0000000000..cadc36e331 --- /dev/null +++ b/js/svg-pan-zoom.min.js @@ -0,0 +1,3 @@ +// svg-pan-zoom v3.6.2 +// https://github.com/bumbu/svg-pan-zoom +!function s(r,a,l){function u(e,t){if(!a[e]){if(!r[e]){var o="function"==typeof require&&require;if(!t&&o)return o(e,!0);if(h)return h(e,!0);var n=new Error("Cannot find module '"+e+"'");throw n.code="MODULE_NOT_FOUND",n}var i=a[e]={exports:{}};r[e][0].call(i.exports,function(t){return u(r[e][1][t]||t)},i,i.exports,s,r,a,l)}return a[e].exports}for(var h="function"==typeof require&&require,t=0;tthis.options.maxZoom*n.zoom&&(t=this.options.maxZoom*n.zoom/this.getZoom());var i=this.viewport.getCTM(),s=e.matrixTransform(i.inverse()),r=this.svg.createSVGMatrix().translate(s.x,s.y).scale(t).translate(-s.x,-s.y),a=i.multiply(r);a.a!==i.a&&this.viewport.setCTM(a)},i.prototype.zoom=function(t,e){this.zoomAtPoint(t,a.getSvgCenterPoint(this.svg,this.width,this.height),e)},i.prototype.publicZoom=function(t,e){e&&(t=this.computeFromRelativeZoom(t)),this.zoom(t,e)},i.prototype.publicZoomAtPoint=function(t,e,o){if(o&&(t=this.computeFromRelativeZoom(t)),"SVGPoint"!==r.getType(e)){if(!("x"in e&&"y"in e))throw new Error("Given point is invalid");e=a.createSVGPoint(this.svg,e.x,e.y)}this.zoomAtPoint(t,e,o)},i.prototype.getZoom=function(){return this.viewport.getZoom()},i.prototype.getRelativeZoom=function(){return this.viewport.getRelativeZoom()},i.prototype.computeFromRelativeZoom=function(t){return t*this.viewport.getOriginalState().zoom},i.prototype.resetZoom=function(){var t=this.viewport.getOriginalState();this.zoom(t.zoom,!0)},i.prototype.resetPan=function(){this.pan(this.viewport.getOriginalState())},i.prototype.reset=function(){this.resetZoom(),this.resetPan()},i.prototype.handleDblClick=function(t){var e;if((this.options.preventMouseEventsDefault&&(t.preventDefault?t.preventDefault():t.returnValue=!1),this.options.controlIconsEnabled)&&-1<(t.target.getAttribute("class")||"").indexOf("svg-pan-zoom-control"))return!1;e=t.shiftKey?1/(2*(1+this.options.zoomScaleSensitivity)):2*(1+this.options.zoomScaleSensitivity);var o=a.getEventPoint(t,this.svg).matrixTransform(this.svg.getScreenCTM().inverse());this.zoomAtPoint(e,o)},i.prototype.handleMouseDown=function(t,e){this.options.preventMouseEventsDefault&&(t.preventDefault?t.preventDefault():t.returnValue=!1),r.mouseAndTouchNormalize(t,this.svg),this.options.dblClickZoomEnabled&&r.isDblClick(t,e)?this.handleDblClick(t):(this.state="pan",this.firstEventCTM=this.viewport.getCTM(),this.stateOrigin=a.getEventPoint(t,this.svg).matrixTransform(this.firstEventCTM.inverse()))},i.prototype.handleMouseMove=function(t){if(this.options.preventMouseEventsDefault&&(t.preventDefault?t.preventDefault():t.returnValue=!1),"pan"===this.state&&this.options.panEnabled){var e=a.getEventPoint(t,this.svg).matrixTransform(this.firstEventCTM.inverse()),o=this.firstEventCTM.translate(e.x-this.stateOrigin.x,e.y-this.stateOrigin.y);this.viewport.setCTM(o)}},i.prototype.handleMouseUp=function(t){this.options.preventMouseEventsDefault&&(t.preventDefault?t.preventDefault():t.returnValue=!1),"pan"===this.state&&(this.state="none")},i.prototype.fit=function(){var t=this.viewport.getViewBox(),e=Math.min(this.width/t.width,this.height/t.height);this.zoom(e,!0)},i.prototype.contain=function(){var t=this.viewport.getViewBox(),e=Math.max(this.width/t.width,this.height/t.height);this.zoom(e,!0)},i.prototype.center=function(){var t=this.viewport.getViewBox(),e=.5*(this.width-(t.width+2*t.x)*this.getZoom()),o=.5*(this.height-(t.height+2*t.y)*this.getZoom());this.getPublicInstance().pan({x:e,y:o})},i.prototype.updateBBox=function(){this.viewport.simpleViewBoxCache()},i.prototype.pan=function(t){var e=this.viewport.getCTM();e.e=t.x,e.f=t.y,this.viewport.setCTM(e)},i.prototype.panBy=function(t){var e=this.viewport.getCTM();e.e+=t.x,e.f+=t.y,this.viewport.setCTM(e)},i.prototype.getPan=function(){var t=this.viewport.getState();return{x:t.x,y:t.y}},i.prototype.resize=function(){var t=a.getBoundingClientRectNormalized(this.svg);this.width=t.width,this.height=t.height;var e=this.viewport;e.options.width=this.width,e.options.height=this.height,e.processCTM(),this.options.controlIconsEnabled&&(this.getPublicInstance().disableControlIcons(),this.getPublicInstance().enableControlIcons())},i.prototype.destroy=function(){var e=this;for(var t in this.beforeZoom=null,this.onZoom=null,this.beforePan=null,this.onPan=null,(this.onUpdatedCTM=null)!=this.options.customEventsHandler&&this.options.customEventsHandler.destroy({svgElement:this.svg,eventsListenerElement:this.options.eventsListenerElement,instance:this.getPublicInstance()}),this.eventListeners)(this.options.eventsListenerElement||this.svg).removeEventListener(t,this.eventListeners[t],!this.options.preventMouseEventsDefault&&h);this.disableMouseWheelZoom(),this.getPublicInstance().disableControlIcons(),this.reset(),c=c.filter(function(t){return t.svg!==e.svg}),delete this.options,delete this.viewport,delete this.publicInstance,delete this.pi,this.getPublicInstance=function(){return null}},i.prototype.getPublicInstance=function(){var o=this;return this.publicInstance||(this.publicInstance=this.pi={enablePan:function(){return o.options.panEnabled=!0,o.pi},disablePan:function(){return o.options.panEnabled=!1,o.pi},isPanEnabled:function(){return!!o.options.panEnabled},pan:function(t){return o.pan(t),o.pi},panBy:function(t){return o.panBy(t),o.pi},getPan:function(){return o.getPan()},setBeforePan:function(t){return o.options.beforePan=null===t?null:r.proxy(t,o.publicInstance),o.pi},setOnPan:function(t){return o.options.onPan=null===t?null:r.proxy(t,o.publicInstance),o.pi},enableZoom:function(){return o.options.zoomEnabled=!0,o.pi},disableZoom:function(){return o.options.zoomEnabled=!1,o.pi},isZoomEnabled:function(){return!!o.options.zoomEnabled},enableControlIcons:function(){return o.options.controlIconsEnabled||(o.options.controlIconsEnabled=!0,s.enable(o)),o.pi},disableControlIcons:function(){return o.options.controlIconsEnabled&&(o.options.controlIconsEnabled=!1,s.disable(o)),o.pi},isControlIconsEnabled:function(){return!!o.options.controlIconsEnabled},enableDblClickZoom:function(){return o.options.dblClickZoomEnabled=!0,o.pi},disableDblClickZoom:function(){return o.options.dblClickZoomEnabled=!1,o.pi},isDblClickZoomEnabled:function(){return!!o.options.dblClickZoomEnabled},enableMouseWheelZoom:function(){return o.enableMouseWheelZoom(),o.pi},disableMouseWheelZoom:function(){return o.disableMouseWheelZoom(),o.pi},isMouseWheelZoomEnabled:function(){return!!o.options.mouseWheelZoomEnabled},setZoomScaleSensitivity:function(t){return o.options.zoomScaleSensitivity=t,o.pi},setMinZoom:function(t){return o.options.minZoom=t,o.pi},setMaxZoom:function(t){return o.options.maxZoom=t,o.pi},setBeforeZoom:function(t){return o.options.beforeZoom=null===t?null:r.proxy(t,o.publicInstance),o.pi},setOnZoom:function(t){return o.options.onZoom=null===t?null:r.proxy(t,o.publicInstance),o.pi},zoom:function(t){return o.publicZoom(t,!0),o.pi},zoomBy:function(t){return o.publicZoom(t,!1),o.pi},zoomAtPoint:function(t,e){return o.publicZoomAtPoint(t,e,!0),o.pi},zoomAtPointBy:function(t,e){return o.publicZoomAtPoint(t,e,!1),o.pi},zoomIn:function(){return this.zoomBy(1+o.options.zoomScaleSensitivity),o.pi},zoomOut:function(){return this.zoomBy(1/(1+o.options.zoomScaleSensitivity)),o.pi},getZoom:function(){return o.getRelativeZoom()},setOnUpdatedCTM:function(t){return o.options.onUpdatedCTM=null===t?null:r.proxy(t,o.publicInstance),o.pi},resetZoom:function(){return o.resetZoom(),o.pi},resetPan:function(){return o.resetPan(),o.pi},reset:function(){return o.reset(),o.pi},fit:function(){return o.fit(),o.pi},contain:function(){return o.contain(),o.pi},center:function(){return o.center(),o.pi},updateBBox:function(){return o.updateBBox(),o.pi},resize:function(){return o.resize(),o.pi},getSizes:function(){return{width:o.width,height:o.height,realZoom:o.getZoom(),viewBox:o.viewport.getViewBox()}},destroy:function(){return o.destroy(),o.pi}}),this.publicInstance};var c=[];e.exports=function(t,e){var o=r.getSvg(t);if(null===o)return null;for(var n=c.length-1;0<=n;n--)if(c[n].svg===o)return c[n].instance.getPublicInstance();return c.push({svg:o,instance:new i(o,e)}),c[c.length-1].instance.getPublicInstance()}},{"./control-icons":1,"./shadow-viewport":2,"./svg-utilities":5,"./uniwheel":6,"./utilities":7}],5:[function(t,e,o){var l=t("./utilities"),s="unknown";document.documentMode&&(s="ie"),e.exports={svgNS:"http://www.w3.org/2000/svg",xmlNS:"http://www.w3.org/XML/1998/namespace",xmlnsNS:"http://www.w3.org/2000/xmlns/",xlinkNS:"http://www.w3.org/1999/xlink",evNS:"http://www.w3.org/2001/xml-events",getBoundingClientRectNormalized:function(t){if(t.clientWidth&&t.clientHeight)return{width:t.clientWidth,height:t.clientHeight};if(t.getBoundingClientRect())return t.getBoundingClientRect();throw new Error("Cannot get BoundingClientRect for SVG.")},getOrCreateViewport:function(t,e){var o=null;if(!(o=l.isElement(e)?e:t.querySelector(e))){var n=Array.prototype.slice.call(t.childNodes||t.children).filter(function(t){return"defs"!==t.nodeName&&"#text"!==t.nodeName});1===n.length&&"g"===n[0].nodeName&&null===n[0].getAttribute("transform")&&(o=n[0])}if(!o){var i="viewport-"+(new Date).toISOString().replace(/\D/g,"");(o=document.createElementNS(this.svgNS,"g")).setAttribute("id",i);var s=t.childNodes||t.children;if(s&&0 + + + + + + + + + + + + All Files – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + +
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/lists/modules.html b/lists/modules.html new file mode 100644 index 0000000000..646c2c6e17 --- /dev/null +++ b/lists/modules.html @@ -0,0 +1,408 @@ + + + + + + + + + + + + + All Modules – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+

Modules

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ModuleSource FileDescription
fpmfpm.f90
fpm_backendfpm_backend.F90

Uses a list of [[build_target_ptr]] and a valid [[fpm_model]] instance + to schedule and execute the compilation and linking of package targets.

Read more…
fpm_backend_consolefpm_backend_console.f90

This module provides a lightweight implementation for printing to the console + and updating previously-printed console lines. It used by [[fpm_backend_output]] + for pretty-printing build status and progress.

Read more…
fpm_backend_outputfpm_backend_output.f90

This module provides a derived type build_progress_t for printing build status + and progress messages to the console while the backend is building the package.

Read more…
fpm_cmd_exportexport.f90
fpm_cmd_installinstall.f90
fpm_cmd_newnew.f90

A type of the general command base class fpm_cmd_settings + was created for the “new” subcommand ==> type fpm_new_settings. + This procedure read the values that were set on the command line + from this type to decide what actions to take.

Read more…
fpm_cmd_publishpublish.f90

Upload a package to the registry using the publish command.

Read more…
fpm_cmd_updateupdate.f90
fpm_command_linefpm_command_line.f90

This module uses M_CLI2 to define + the command line interface. + To define a command line interface create a new command settings type + from the fpm_cmd_settings base class or the respective parent command + settings.

Read more…
fpm_compile_commandsfpm_compile_commands.F90Read more…
fpm_compilerfpm_compiler.F90

This module defines compiler options to use for the debug and release builds.

Read more…
fpm_dependencydependency.f90

Dependencies on the top-level can be specified from:

Read more…
fpm_downloaderdownloader.f90
fpm_environmentfpm_environment.f90

This module contains procedures that interact with the programming environment.

Read more…
fpm_errorerror.f90

Implementation of basic error handling.

fpm_filesystemfpm_filesystem.F90

This module contains general routines for interacting with the file system

Read more…
fpm_gitgit.f90

Implementation for interacting with git repositories.

fpm_installerinstaller.f90

Implementation of an installer object.

Read more…
fpm_manifestmanifest.f90

Package configuration data.

Read more…
fpm_manifest_buildbuild.f90

Implementation of the build configuration data.

Read more…
fpm_manifest_dependencydependency.f90

Implementation of the meta data for dependencies.

Read more…
fpm_manifest_exampleexample.f90

Implementation of the meta data for an example.

Read more…
fpm_manifest_executableexecutable.f90

Implementation of the meta data for an executables.

Read more…
fpm_manifest_fortranfortran.f90
fpm_manifest_installinstall.f90

Implementation of the installation configuration.

Read more…
fpm_manifest_librarylibrary.f90

Implementation of the meta data for libraries.

Read more…
fpm_manifest_metapackagesmeta.f90

Implementation of the metapackage configuration data.

Read more…
fpm_manifest_packagepackage.f90

Define the package data containing the meta data from the configuration file.

Read more…
fpm_manifest_preprocesspreprocess.f90

Implementation of the meta data for preprocessing.

Read more…
fpm_manifest_profileprofiles.f90

Implementation of the meta data for compiler flag profiles.

Read more…
fpm_manifest_testtest.f90

Implementation of the meta data for a test.

Read more…
fpm_metafpm_meta.f90

This is a wrapper data type that encapsulate all pre-processing information + (compiler flags, linker libraries, etc.) required to correctly enable a package + to use a core library.

Read more…
fpm_meta_basefpm_meta_base.f90
fpm_meta_blasfpm_meta_blas.f90
fpm_meta_hdf5fpm_meta_hdf5.f90
fpm_meta_minpackfpm_meta_minpack.f90
fpm_meta_mpifpm_meta_mpi.f90
fpm_meta_netcdffpm_meta_netcdf.f90
fpm_meta_openmpfpm_meta_openmp.f90
fpm_meta_stdlibfpm_meta_stdlib.f90
fpm_meta_utilfpm_meta_util.f90
fpm_modelfpm_model.f90

Defines the fpm model data types which encapsulate all information + required to correctly build a package and its dependencies.

Read more…
fpm_osfpm_os.F90
fpm_pkg_configfpm_pkg_config.f90

This module contains wrapper functions to interface with a pkg-config installation.

Read more…
fpm_releasefpm_release.F90

Module fpm_release contains public constants storing this build’s unique version IDs

Read more…
fpm_settingsfpm_settings.f90

Manages global settings which are defined in the global config file.

fpm_source_parsingfpm_source_parsing.f90

This module exposes two functions, [[parse_f_source]] and [[parse_c_source]], + which perform a rudimentary parsing of fortran and c source files + in order to extract information required for module dependency tracking.

Read more…
fpm_sourcesfpm_sources.f90

This module implements subroutines for building a list of + [[srcfile_t]] objects by looking for source files in the filesystem.

Read more…
fpm_stringsfpm_strings.f90

This module defines general procedures for string operations for both CHARACTER and + TYPE(STRING_T) variables

Read more…
fpm_targetsfpm_targets.f90

This module handles the construction of the build target list + from the sources list ([[targets_from_sources]]), the + resolution of module-dependencies between build targets + ([[resolve_module_dependencies]]), and the enumeration of + objects required for link targets ([[resolve_target_linking]]).

Read more…
fpm_tomltoml.f90

This module acts as a proxy to the toml-f public Fortran API and allows + to selectively expose components from the library to fpm. + The interaction with toml-f data types outside of this module should be + limited to tables, arrays and key-lists, most of the necessary interactions + are implemented in the building interface with the get_value and set_value + procedures.

Read more…
fpm_versioningversioning.f90

Implementation of versioning data for comparing packages

+ +
+
+
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/lists/procedures.html b/lists/procedures.html new file mode 100644 index 0000000000..23b3f8ea97 --- /dev/null +++ b/lists/procedures.html @@ -0,0 +1,1884 @@ + + + + + + + + + + + + + All Procedures – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+

Procedures

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ProcedureLocationProcedure TypeDescription
add_dependencyfpm_targetsSubroutine

Add pointer to dependeny in target%dependencies

add_executable_sourcesfpm_sourcesSubroutine

Add to sources using the executable and test entries in the manifest and +applies any executable-specific overrides such as executable%name. +Adds all sources (including modules) from each executable%source_dir +Compare lowercase strings to allow auto-discovery of pre-processed extensions

add_pkg_config_compile_optionsfpm_meta_utilSubroutine

Add pkgconfig compile options to a metapackage +Get version +Get libraries +Get compiler flags

add_sources_from_dirfpm_sourcesSubroutine

Add to sources by looking for source files in directory

add_tablefpm_tomlInterface

add_table: fpm interface

add_targetfpm_targetsInterface
append_clean_flagsfpm_compilerSubroutine

Append new flags to existing flags, removing duplicates and empty flags (string version)

append_clean_flags_arrayfpm_compilerSubroutine

Append new flags to existing flags, removing duplicates and empty flags (array version)

ar_is_samefpm_compilerFunction

Check that two archiver_t objects are equal +All checks passed!

assert_pkg_configfpm_pkg_configFunction

Check whether pkg-config is available on the local system

bad_name_errorfpm_errorFunction
basenamefpm_filesystemFunction

Extract filename from path with/without suffix

build_modelfpmSubroutine

Constructs a valid fpm model from command line settings and the toml manifest. +Add this dependency’s manifest macros +Add this dependency’s package-level macros

build_packagefpm_backendSubroutine

Top-level routine to build package described by model

build_progress_tfpm_backend_outputInterface

Constructor for build_progress_t

canon_pathfpm_filesystemFunction

Canonicalize path for comparison +* Handles path string redundancies +* Does not test existence of path

Read more…
cct_destroyfpm_compile_commandsSubroutine

Cleanup a compile command table

cct_dump_arrayfpm_compile_commandsSubroutine

Dump compile_command_table_t to a toml array

cct_dump_tomlfpm_compile_commandsSubroutine

Dump compile_command_table_t to toml table

cct_is_samefpm_compile_commandsFunction

Check that two compile_command_table_t objects are equal +All checks passed!

cct_load_tomlfpm_compile_commandsSubroutine

Read compile_command_table_t from toml table (no checks made at this stage)

cct_newfpm_compile_commandsFunction

Override default initializer (GCC 15 bug)

cct_registerfpm_compile_commandsSubroutine

Register a new compile command

cct_register_objectfpm_compile_commandsSubroutine
cct_writefpm_compile_commandsSubroutine

Write compile_commands.json file. Because Jonquil does not support non-named arrays, +create a custom json here.

change_directoryfpm_osSubroutine
check_and_read_pkg_datafpm_dependencySubroutine
check_compilerfpm_compilerFunction
check_flags_supportedfpm_compilerFunction

Check if the given compile and/or link flags are accepted by the compiler

check_fortran_source_runsfpm_compilerFunction

Run a single-source Fortran program using the current compiler +Compile a Fortran object +Create temporary source file +Write contents +Get flags +Intel: Needs -warn last for error on unknown command line arguments to work +Compile and link program +Run and retrieve exit code

Read more…
check_keysfpm_tomlSubroutine

Check if table contains only keys that are part of the list. If a key is +found that is not part of the list, an error is allocated.

check_modules_for_duplicatesfpmSubroutine
checkoutfpm_gitSubroutine
cmd_buildfpmSubroutine

Dump model to file

cmd_cleanfpmSubroutine

Delete the build directory including or excluding dependencies. Can be used +to clear the registry cache.

cmd_exportfpm_cmd_exportSubroutine

Entry point for the export subcommand +Read in manifest +Export manifest +Export dependency tree

Read more…
cmd_installfpm_cmd_installSubroutine

Entry point for the fpm-install subcommand

cmd_newfpm_cmd_newSubroutine

TOP DIRECTORY NAME PROCESSING +see if requested new directory already exists and process appropriately +temporarily change to new directory as a test. NB: System dependent

cmd_publishfpm_cmd_publishSubroutine

The publish command first builds the root package to obtain all the relevant information such as the +package version. It then creates a tarball of the package and uploads it to the registry. +Checks before uploading the package.

cmd_runfpmSubroutine
cmd_updatefpm_cmd_updateSubroutine

Entry point for the update subcommand

compile_cfpm_compilerSubroutine

Compile a C object

compile_command_destroyfpm_compile_commandsSubroutine

Cleanup compile command

compile_command_dump_tomlfpm_compile_commandsSubroutine

Dump compile_command_t to toml table

compile_command_is_samefpm_compile_commandsFunction

Check that two compile_command_t objects are equal +All checks passed!

compile_command_load_tomlfpm_compile_commandsSubroutine

Read compile_command_t from toml table (no checks made at this stage)

compile_command_tfpm_compile_commandsInterface
compile_cppfpm_compilerSubroutine

Compile a CPP object

compile_fortranfpm_compilerSubroutine

Compile a Fortran object

compiler_dumpfpm_compilerSubroutine

Dump dependency to toml table

compiler_is_samefpm_compilerFunction

Check that two compiler_t objects are equal +All checks passed!

compiler_loadfpm_compilerSubroutine

Read dependency from toml table (no checks made at this stage)

compiler_namefpm_compilerFunction

Return a compiler name string

convert_to_absolute_pathfpm_osSubroutine

Converts a path to an absolute, canonical path.

debugfpm_compilerInterface

Create debug printout

debug_archiverfpm_compilerFunction

String representation of an archiver object

debug_compilerfpm_compilerFunction

String representation of a compiler object

default_examplefpm_manifestSubroutine

Populate test in case we find the default example/ directory

default_executablefpm_manifestSubroutine

Populate executable in case we find the default app directory

default_libraryfpm_manifestSubroutine

Populate library in case we find the default src directory

default_testfpm_manifestSubroutine

Populate test in case we find the default test/ directory

delete_envfpm_environmentFunction

Deletes an environment variable for the current environment using the C standard library +Returns an error if the variable did not exist in the first place

Read more…
delete_filefpm_filesystemSubroutine

delete a file by filename

dependency_destroyfpm_manifest_dependencySubroutine

Clean memory

descriptor_namefpm_gitFunction

Code git descriptor to a string

destroyfpm_meta_baseSubroutine
destroy_dependency_nodefpm_dependencySubroutine

Destructor

dilatefpm_stringsFunction

Sample program:

Read more…
dirnamefpm_filesystemFunction

Extract dirname from path

dump_to_tomlfpm_gitSubroutine

Dump dependency to toml table

dump_to_tomlfpm_compilerSubroutine

Dump dependency to toml table

Read more…
enumerate_librariesfpm_compilerFunction

Enumerate libraries, based on compiler and platform

execute_and_read_outputfpm_filesystemSubroutine

Execute command line and return output as a string.

existsfpm_filesystemFunction

test if pathname already exists

f_stringfpm_stringsFunction

return Fortran character variable when given a C-like array of +single characters terminated with a C_NULL_CHAR character

fatal_errorfpm_errorSubroutine

Generic fatal runtime error

file_not_found_errorfpm_errorSubroutine

Error created when a file is missing or not found

file_parse_errorfpm_errorSubroutine

Error created when file parsing fails

file_scope_dumpfpm_manifest_profileSubroutine

Dump to toml table

file_scope_loadfpm_manifest_profileSubroutine

Read from toml table (no checks made at this stage)

file_scope_samefpm_manifest_profileFunction

All checks passed!

fileclosefpm_filesystemSubroutine

simple close of a LUN. On error show message and stop (by default)

fileopenfpm_filesystemSubroutine

procedure to open filename as a sequential “text” file

filewritefpm_filesystemSubroutine

procedure to write filedata to file filename

filter_executable_targetsfpm_targetsSubroutine
filter_library_targetsfpm_targetsSubroutine

Returns pointers to all library targets

filter_modulesfpm_targetsSubroutine
find_profilefpm_manifest_profileSubroutine

Look for profile with given configuration in array profiles

fnv_1afpm_stringsInterface
FPM_SCOPE_NAMEfpm_modelFunction

Return the character name of a scope flag

fpm_stopfpm_errorSubroutine
FPM_TARGET_NAMEfpm_targetsFunction

Target type name

FPM_UNIT_NAMEfpm_modelFunction

Return the character name of a unit flag

fpm_versionfpm_releaseFunction

Return the current fpm version from fpm_version_ID as a version type

get_absolute_pathfpm_osSubroutine

Determine the canonical, absolute path for the given path. +Expands home folder (~) on both Unix and Windows.

get_absolute_path_by_cdfpm_osSubroutine

Alternative to get_absolute_path that uses chdir/_chdir to determine the absolute path.

Read more…
get_command_arguments_quotedfpm_environmentFunction
get_command_line_settingsfpm_command_lineSubroutine

! canon_path is not converting “.”, etc. +& ‘ unknown help topic “’//trim(unnamed(i)).’not found in:’,manual]

get_compiler_idfpm_compilerFunction
get_current_directoryfpm_osSubroutine
get_debug_compile_flagsfpm_compilerSubroutine
get_default_c_compilerfpm_compilerSubroutine
get_default_cxx_compilerfpm_compilerSubroutine

Get C++ Compiler.

get_default_flagsfpm_compilerFunction
get_default_profilesfpm_manifest_profileFunction

Construct an array of built-in profiles

get_dos_pathfpm_filesystemFunction

Ensure a windows path is converted to an 8.3 DOS path if it contains spaces +No need to convert if there are no spaces

Read more…
get_envfpm_environmentFunction

get named environment variable value. It it is blank or + not set return the optional default value +!print , NAME, ” is not defined in the environment. Strange…” +!print , “This processor doesn’t support environment variables. Boooh!”

get_exe_name_with_suffixfpm_sourcesFunction

Build an executable name with suffix. Safe routine that always returns an allocated string

get_export_flagsfpm_compilerFunction

Generate library export flags for a shared library build

get_feature_flagfpm_compilerFunction
get_flagsfpm_manifest_profileSubroutine

Look for flags, c-flags, link-time-flags key-val pairs +and files table in a given table and create new profiles

get_fpm_envfpm_command_lineFunction

Get an environment variable for fpm, this routine ensures that every variable +used by fpm is prefixed with FPM_.

get_global_settingsfpm_settingsSubroutine

Obtain global settings from the global config file.

get_headerpad_flagsfpm_compilerFunction

Generate header padding flags for install_name_tool compatibility on macOS

get_homefpm_filesystemSubroutine

Get the HOME directory on Unix and the %USERPROFILE% directory on Windows.

get_idfpm_compilerFunction
get_include_flagfpm_compilerFunction
get_install_name_flagsfpm_compilerFunction

Generate install_name flag for a shared library build on macOS

get_library_dirsfpm_targetsSubroutine

Add link directories for all shared libraries in the dependency graph

get_listfpm_tomlSubroutine
get_local_prefixfpm_filesystemFunction

Determine the path prefix to the local folder. Used for installation, registry etc.

get_macrosfpm_compilerFunction

This function will parse and read the macros list and +return them as defined flags. +Set macro defintion symbol on the basis of compiler used +Check if macros are not allocated. +Split the macro name and value.

Read more…
get_main_flagsfpm_compilerSubroutine

Get special flags for the main linker

get_module_flagfpm_compilerFunction
get_os_typefpm_environmentFunction

Determine the OS type

Read more…
get_package_datafpm_manifestSubroutine

Obtain package meta data from a configuation file

get_package_dependenciesfpm_manifestSubroutine
get_registry_settingsfpm_settingsSubroutine

Read registry settings from the global config file.

get_release_compile_flagsfpm_compilerSubroutine
get_shared_flagfpm_compilerFunction
get_temp_filenamefpm_filesystemFunction

Get a unused temporary filename + Calls posix ‘tempnam’ - not recommended, but + we have no security concerns for this application + and use here is temporary. +Works with MinGW

get_valuefpm_tomlInterface

get_value: fpm interface

get_working_dirmainSubroutine

Save access to working directory in settings, in case setting have not been allocated

getlinefpm_filesystemSubroutine

subroutine getline(unit,line,iostat,iomsg)

Read more…
git_archivefpm_gitSubroutine

Archive a folder using git archive.

git_is_samefpm_gitFunction

Check that two git targets are equal +All checks passed!

git_matches_manifestfpm_gitFunction

Check that a cached dependency matches a manifest request

Read more…
git_revisionfpm_gitSubroutine
git_target_branchfpm_gitFunction

Target a branch in the git repository

git_target_defaultfpm_gitFunction

Default target

git_target_revisionfpm_gitFunction

Target a specific git revision

git_target_tagfpm_gitFunction

Target a git tag

globfpm_stringsFunction

glob(3f) compares given STRING for match to PATTERN which may + contain wildcard characters.

Read more…
handle_errormainSubroutine
has_listfpm_tomlFunction

Check if an instance of the TOML data structure contains a list

has_manifestmainFunction
has_valid_custom_prefixfpm_stringsFunction

Check that a module name is prefixed with a custom prefix: +1) It must be a valid FORTRAN name subset (<=63 chars, begin with letter, only alphanumeric allowed) +2) It must begin with the prefix +3) If longer, package name must be followed by default separator (“_”) plus at least one char

Read more…
has_valid_standard_prefixfpm_stringsFunction

Check that a module name is prefixed with the default package prefix: +1) It must be a valid FORTRAN name (<=63 chars, begin with letter, “_” is only allowed non-alphanumeric) +2) It must begin with the package name +3) If longer, package name must be followed by default separator plus at least one char

Read more…
infofpm_gitSubroutine

Show information on git target

infofpm_manifest_profileSubroutine

Write information on instance

info_profilefpm_manifest_profileFunction

Print a representation of profile_config_t

init_blasfpm_meta_blasSubroutine

Initialize blas metapackage for the current system +Cleanup +Set name

Read more…
init_hdf5fpm_meta_hdf5Subroutine

Initialize HDF5 metapackage for the current system +Cleanup +Set name

Read more…
init_minpackfpm_meta_minpackSubroutine

Initialize minpack metapackage for the current system +Cleanup

Read more…
init_mpifpm_meta_mpiSubroutine

Initialize MPI metapackage for the current system +Cleanup

Read more…
init_netcdffpm_meta_netcdfSubroutine

Initialize NetCDF metapackage for the current system +Cleanup +Set name

Read more…
init_openmpfpm_meta_openmpSubroutine

Initialize OpenMP metapackage for the current system +Cleanup

Read more…
init_stdlibfpm_meta_stdlibSubroutine

Initialize stdlib metapackage for the current system +Cleanup

Read more…
is_absolute_pathfpm_filesystemFunction

Returns .true. if provided path is absolute.

Read more…
is_dirfpm_filesystemFunction

test if a name matches an existing directory path

is_fortran_namefpm_stringsFunction
is_gnufpm_compilerFunction
is_hidden_filefpm_filesystemFunction

test if a file is hidden

is_intelfpm_compilerFunction
is_meta_packagefpm_manifest_metapackagesFunction

Check local schema for allowed entries

Read more…
is_unknownfpm_compilerFunction
is_valid_module_namefpm_stringsFunction

Check that a module name fits the current naming rules: +1) It must be a valid FORTRAN name (<=63 chars, begin with letter, “_” is only allowed non-alphanumeric) +2) It must begin with the package name +3) If longer, package name must be followed by default separator plus at least one char

Read more…
is_valid_module_prefixfpm_stringsFunction

Check that a custom module prefix fits the current naming rules: +1) Only alphanumeric characters (no spaces, dashes, underscores or other characters) +2) Does not begin with a number (Fortran-compatible syntax)

joinfpm_stringsFunction

JOIN(3f) appends the elements of a CHARACTER array into a single + CHARACTER variable, with elements 1 to N joined from left to right. + By default each element is trimmed of trailing spaces and the + default separator is a null string.

Read more…
join_pathfpm_filesystemFunction

Construct path by joining strings with os file separator

len_trimfpm_stringsInterface
lib_get_trailingfpm_meta_utilSubroutine

Given a library name and folder, find extension and prefix

library_filenamefpm_environmentFunction

Utility function: return library filename

link_executablefpm_compilerSubroutine

Link an executable

link_sharedfpm_compilerSubroutine

Link a shared library

list_filesfpm_filesystemSubroutine

Get file & directory names in directory dir using iso_c_binding.

Read more…
load_from_tomlfpm_gitSubroutine

Read dependency from toml table (no checks made at this stage)

Read more…
load_from_tomlfpm_compilerSubroutine

Read dependency from toml table (no checks made at this stage)

lowerfpm_stringsFunction

Changes a string to lowercase over optional specified column range

make_archivefpm_compilerSubroutine

Create an archive

Read more…
manifest_has_changedfpm_manifest_dependencyFunction

Check if two dependency configurations are different

Read more…
match_os_typefpm_manifest_profileSubroutine

Match os_type enum to a lowercase string with name of OS

mkdirfpm_filesystemSubroutine

Create a directory. Create subdirectories as needed

module_prefix_templatefpm_stringsFunction
module_prefix_typefpm_stringsFunction
MPI_TYPE_NAMEfpm_meta_mpiFunction

Return a name for the MPI library

name_is_jsonfpm_tomlFunction

Choose between JSON or TOML based on a file name

new_archiverfpm_compilerSubroutine

Create new archiver instance

new_build_configfpm_manifest_buildSubroutine

Construct a new build configuration from a TOML data structure

Read more…
new_compilerfpm_compilerSubroutine

Create new compiler instance

new_dependenciesfpm_manifest_dependencySubroutine

Construct new dependency array from a TOML data structure

Read more…
new_dependencyfpm_manifest_dependencySubroutine

Construct a new dependency configuration from a TOML data structure

Read more…
new_dependency_nodefpm_dependencySubroutine

Create a new dependency node from a configuration

new_dependency_treefpm_dependencySubroutine

Create a new dependency tree

new_examplefpm_manifest_exampleSubroutine

Construct a new example configuration from a TOML data structure

new_executablefpm_manifest_executableSubroutine

Construct a new executable configuration from a TOML data structure

new_fortran_configfpm_manifest_fortranSubroutine

Construct a new build configuration from a TOML data structure

new_install_configfpm_manifest_installSubroutine

Create a new installation configuration from a TOML data structure

new_installerfpm_installerSubroutine

Create a new instance of an installer

new_libraryfpm_manifest_librarySubroutine

Construct a new library configuration from a TOML data structure

new_meta_configfpm_manifest_metapackagesSubroutine

Construct a new build configuration from a TOML data structure

Read more…
new_meta_requestfpm_manifest_metapackagesSubroutine

Construct a new metapackage request from the dependencies table

Read more…
new_packagefpm_manifest_packageSubroutine

Construct a new package configuration from a TOML data structure

new_preprocessorsfpm_manifest_preprocessSubroutine

Construct new preprocess array from a TOML data structure.

new_profilefpm_manifest_profileFunction

Construct a new profile configuration from a TOML data structure

new_profilesfpm_manifest_profileSubroutine

Construct new profiles array from a TOML data structure

new_targetfpm_targetsFunction

Allocate a new target

new_testfpm_manifest_testSubroutine

Construct a new test configuration from a TOML data structure

new_versionfpm_versioningInterface
notabsfpm_stringsSubroutine

notabs(3f) - [fpm_strings:NONALPHA] expand tab characters + (LICENSE:PD)

Read more…
number_of_rowsfpm_filesystemFunction

Determine number or rows in a file given a LUN

operator(.in.)fpm_stringsInterface
operator(==)fpm_stringsInterface
os_delete_dirfpm_filesystemSubroutine

Delete directory using system OS remove directory commands

os_is_unixfpm_environmentFunction

Compare the output of get_os_type or the optional +passed INTEGER value to the value for OS_WINDOWS +and return .TRUE. if they match and .FALSE. otherwise

OS_NAMEfpm_environmentFunction

Return string describing the OS type flag

os_type_namefpm_manifest_profileFunction

Match lowercase string with name of OS to os_type enum

parent_dirfpm_filesystemFunction

Extract dirname from path

parse_c_sourcefpm_source_parsingFunction

Parsing of c, cpp source files

Read more…
parse_descriptorfpm_gitFunction

Parse git descriptor identifier from a string

parse_f_sourcefpm_source_parsingFunction

Parsing of free-form fortran source files

Read more…
parse_use_statementfpm_source_parsingSubroutine
pkgcfg_get_build_flagsfpm_pkg_configFunction

Get build flags (option to include flags from system directories, that +gfortran does not look into by default)

pkgcfg_get_libsfpm_pkg_configFunction

Get package libraries from pkg-config

pkgcfg_get_versionfpm_pkg_configFunction

Get package version from pkg-config

pkgcfg_has_packagefpm_pkg_configFunction

Check if pkgcfg has package

Read more…
pkgcfg_list_allfpm_pkg_configFunction

Return whole list of available pkg-cfg packages

Read more…
profile_dumpfpm_manifest_profileSubroutine

Dump to toml table

Read more…
profile_loadfpm_manifest_profileSubroutine

Read from toml table (no checks made at this stage)

Read more…
profile_samefpm_manifest_profileFunction

All checks passed!

read_linesfpm_filesystemFunction

read lines into an array of TYPE(STRING_T) variables

read_lines_expandedfpm_filesystemFunction

read lines into an array of TYPE(STRING_T) variables expanding tabs

read_package_filefpm_tomlSubroutine

Process the configuration file to a TOML data structure

regex_version_from_textfpm_versioningFunction
remove_characters_in_setfpm_stringsSubroutine
remove_newline_charactersfpm_stringsSubroutine
replacefpm_stringsFunction

Returns string with characters in charset replaced with target_char.

resizefpm_dependencyInterface

Overloaded reallocation interface

resizefpm_manifest_dependencyInterface
resizefpm_stringsInterface
resolve_metapackagesfpm_metaInterface
resolve_module_dependenciesfpm_targetsSubroutine

Add dependencies to source-based targets (FPM_TARGET_OBJECT) + based on any modules used by the corresponding source file.

Read more…
runfpm_filesystemSubroutine

Execute the specified system command. Optionally

Read more…
run_wrapperfpm_pkg_configSubroutine

Simple call to execute_command_line involving one mpi* wrapper

schedule_targetsfpm_backendSubroutine

Construct a build schedule from the sorted targets.

Read more…
separatorfpm_environmentFunction

sample usage

Read more…
set_cpp_preprocessor_flagsfpm_compilerSubroutine

Modify the flag_cpp_preprocessor on the basis of the compiler.

set_envfpm_environmentFunction

Set an environment variable for the current environment using the C standard library

Read more…
set_listfpm_tomlSubroutine

Set no key if array is not present

Read more…
set_stringfpm_tomlInterface
set_valuefpm_tomlInterface

set_value: fpm interface

show_modelfpm_modelSubroutine
sort_targetfpm_backendSubroutine

Topologically sort a target for scheduling by + recursing over its dependencies.

Read more…
splitfpm_stringsSubroutine

parse string on delimiter characters and store tokens into an allocatable array +given a line of structure ” par1 par2 par3 … parn ” store each par(n) into a separate variable in array.

Read more…
split_first_lastfpm_stringsSubroutine
split_lines_first_lastfpm_stringsSubroutine
strfpm_stringsInterface
str_begins_with_strfpm_stringsFunction

test if a CHARACTER string begins with a specified prefix

str_ends_withfpm_stringsInterface
string_array_containsfpm_stringsFunction

Check if array of TYPE(STRING_T) matches a particular CHARACTER string

string_catfpm_stringsFunction

Concatenate an array of type(string_t) into + a single CHARACTER variable

string_tfpm_stringsInterface
syntax_errorfpm_errorSubroutine
targets_from_sourcesfpm_targetsSubroutine

High-level wrapper to generate build target information

to_fortran_namefpm_stringsFunction

Returns string with special characters replaced with an underscore. +For now, only a hyphen is treated as a special character, but this can be +expanded to other characters if needed.

tokenize_flagsfpm_compilerSubroutine

Tokenize a string into an array of compiler flags

traverse_compilersfpm_manifest_profileSubroutine

Traverse compiler tables

traverse_ossfpm_manifest_profileSubroutine

Traverse operating system tables to obtain profiles

traverse_oss_for_sizefpm_manifest_profileSubroutine

Traverse operating system tables to obtain number of profiles

unix_pathfpm_filesystemFunction

Replace file system separators for unix

upperfpm_stringsFunction
validate_compiler_namefpm_manifest_profileSubroutine

Check if compiler name is a valid compiler name

validate_os_namefpm_manifest_profileSubroutine

Check if os_name is a valid name of a supported OS

validate_profile_tablefpm_manifest_profileSubroutine
warnwritefpm_filesystemSubroutine

write trimmed character data to a file if it does not exist

whichfpm_filesystemFunction

function which(command) result(pathname)

Read more…
windows_pathfpm_filesystemFunction

Replace file system separators for windows

with_qpfpm_compilerFunction

Check if the current compiler supports 128-bit real precision

with_xdpfpm_compilerFunction

Check if the current compiler supports 80-bit “extended” real precision

write_response_filefpm_compilerSubroutine

Response files allow to read command line options from files. +Whitespace is used to separate the arguments, we will use newlines +as separator to create readable response files which can be inspected +in case of errors.

+ +
+
+
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/lists/types.html b/lists/types.html new file mode 100644 index 0000000000..26b2823221 --- /dev/null +++ b/lists/types.html @@ -0,0 +1,406 @@ + + + + + + + + + + + + + All Types – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+

Derived Types

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeLocationExtendsDescription
archiver_tfpm_compilerserializable_t

Definition of archiver object

build_config_tfpm_manifest_buildserializable_t

Configuration data for build

build_progress_tfpm_backend_outputNone

Build progress object

build_target_ptrfpm_targetsNone

Wrapper type for constructing arrays of [[build_target_t]] pointers

build_target_tfpm_targetsNone

Type describing a generated build target

compile_command_tfpm_compile_commandsserializable_t

Definition of a build command

compile_command_table_tfpm_compile_commandsserializable_t
compiler_tfpm_compilerserializable_t

Definition of compiler object

console_tfpm_backend_consoleNone

Console object

dependency_config_tfpm_manifest_dependencyserializable_t

Configuration meta data for a dependency

dependency_node_tfpm_dependencydependency_config_t

Dependency node in the projects dependency tree

dependency_tree_tfpm_dependencyserializable_t

Respresentation of a projects dependencies

Read more…
downloader_tfpm_downloaderNone

This type could be entirely avoided but it is quite practical because it can be mocked for testing.

enum_descriptorfpm_gitNone

Possible git target

error_tfpm_errorNone

Data type defining an error

example_config_tfpm_manifest_exampleexecutable_config_t

Configuation meta data for an example

executable_config_tfpm_manifest_executableserializable_t

Configuation meta data for an executable

file_scope_flagfpm_manifest_profileserializable_t

Type storing file name - file scope compiler flags pairs

fortran_config_tfpm_manifest_fortranserializable_t

Configuration data for Fortran

fortran_features_tfpm_modelserializable_t

Enabled Fortran language features

fpm_build_settingsfpm_command_linefpm_cmd_settings
fpm_clean_settingsfpm_command_linefpm_cmd_settings
fpm_cmd_settingsfpm_command_lineNone
fpm_export_settingsfpm_command_linefpm_build_settings

Settings for exporting model data

fpm_global_settingsfpm_settingsNone
fpm_install_settingsfpm_command_linefpm_build_settings
fpm_model_tfpm_modelserializable_t

Type describing everything required to build + the root package and its dependencies.

fpm_new_settingsfpm_command_linefpm_cmd_settings
fpm_publish_settingsfpm_command_linefpm_build_settings
fpm_run_settingsfpm_command_linefpm_build_settings
fpm_test_settingsfpm_command_linefpm_run_settings
fpm_update_settingsfpm_command_linefpm_cmd_settings

Settings for interacting and updating with project dependencies

git_target_tfpm_gitserializable_t

Description of an git target

install_config_tfpm_manifest_installserializable_t

Configuration data for installation

installer_tfpm_installerNone

Declaration of the installer type

library_config_tfpm_manifest_libraryserializable_t

Configuration meta data for a library

metapackage_config_tfpm_manifest_metapackagesNone

Configuration data for metapackages

metapackage_request_tfpm_manifest_metapackagesNone

Configuration data for a single metapackage request

metapackage_tfpm_meta_baseNone

Type for describing a source file

package_config_tfpm_manifest_packageserializable_t

Package meta data

package_tfpm_modelserializable_t

Type for describing a single package

preprocess_config_tfpm_manifest_preprocessserializable_t

Configuration meta data for a preprocessor

profile_config_tfpm_manifest_profileserializable_t

Configuration meta data for a profile

serializable_tfpm_tomlNone

An abstract interface for any fpm class that should be fully serializable to/from TOML/JSON

srcfile_tfpm_modelserializable_t

Type for describing a source file

string_tfpm_stringsNone
test_config_tfpm_manifest_testexecutable_config_t

Configuation meta data for an test

version_tfpm_versioningNone
+ +
+
+
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/manifest-reference.md b/manifest-reference.md deleted file mode 100644 index 45cf3e6d62..0000000000 --- a/manifest-reference.md +++ /dev/null @@ -1,3 +0,0 @@ -# 301 - Moved - -This document now lives at https://fpm.fortran-lang.org/spec/manifest.html diff --git a/doc/media/favicon.ico b/media/favicon.ico similarity index 100% rename from doc/media/favicon.ico rename to media/favicon.ico diff --git a/module/fpm.html b/module/fpm.html new file mode 100644 index 0000000000..9359ed1eab --- /dev/null +++ b/module/fpm.html @@ -0,0 +1,520 @@ + + + + + + + + + + + + + fpm – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+
+ + +
+ +
+ +
+ + +
+ + + + + + + + +
+

Subroutines

+
+

public subroutine build_model(model, settings, package, error) +

+
+ +

Constructs a valid fpm model from command line settings and the toml manifest. +Add this dependency’s manifest macros +Add this dependency’s package-level macros

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(fpm_model_t), + intent(out) + + ::model + +
+ + class(fpm_build_settings), + intent(inout) + + ::settings + +
+ + type(package_config_t), + intent(inout), + target + ::package + +
+ + type(error_t), + intent(out), + allocatable + ::error + +
+ + +
+
+ +
+

public subroutine check_modules_for_duplicates(model, duplicates_found) +

+
+ + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(fpm_model_t), + intent(in) + + ::model + +
+ + logical + + + ::duplicates_found + +
+ + +
+
+ +
+

public subroutine cmd_build(settings) +

+
+ +

Dump model to file

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(fpm_build_settings), + intent(inout) + + ::settings + +
+ + +
+
+ +
+

public subroutine cmd_clean(settings) +

+
+ +

Delete the build directory including or excluding dependencies. Can be used +to clear the registry cache.

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(fpm_clean_settings), + intent(in) + + ::settings +

Settings for the clean command.

+
+ + +
+
+ +
+

public subroutine cmd_run(settings, test) +

+
+ + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(fpm_run_settings), + intent(inout) + + ::settings + +
+ + logical, + intent(in) + + ::test + +
+ + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_backend.html b/module/fpm_backend.html new file mode 100644 index 0000000000..3940981355 --- /dev/null +++ b/module/fpm_backend.html @@ -0,0 +1,470 @@ + + + + + + + + + + + + + fpm_backend – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_backend + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+
+ + +
+ +
+

Build backend

+

Uses a list of [[build_target_ptr]] and a valid [[fpm_model]] instance + to schedule and execute the compilation and linking of package targets.

+

The package build process ([[build_package]]) comprises three steps:

+
    +
  1. Target sorting: topological sort of the target dependency graph ([[sort_target]])
  2. +
  3. Target scheduling: group targets into schedule regions based on the sorting ([[schedule_targets]])
  4. +
  5. Target building: generate targets by compilation or linking
  6. +
+

@note Note + If compiled with OpenMP, targets will be build in parallel where possible.

+

Incremental compilation

+

The backend process supports incremental compilation whereby targets are not + re-compiled if their corresponding dependencies have not been modified.

+
    +
  • +

    Source-based targets (i.e. objects) are not re-compiled if the corresponding source + file is unmodified AND all of the target dependencies are not marked for re-compilation

    +
  • +
  • +

    Link targets (i.e. executables and libraries) are not re-compiled if the + target output file already exists AND all of the target dependencies are not marked for + re-compilation

    +
  • +
+

Source file modification is determined by a file digest (hash) which is calculated during + the source parsing phase (fpm_source_parsing) and cached to disk after a target is + successfully generated.

+
+ + +
+ + + + + + + + +
+

Subroutines

+
+

public subroutine build_package(targets, model, verbose, dry_run) +

+
+ +

Top-level routine to build package described by model

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(build_target_ptr), + intent(inout) + + ::targets(:) + +
+ + type(fpm_model_t), + intent(in) + + ::model + +
+ + logical, + intent(in) + + ::verbose + +
+ + logical, + intent(in) + + ::dry_run +

If dry_run, the build process is only mocked, but the list of compile_commands +is still created

+
+ + +
+
+ +
+

public subroutine schedule_targets(queue, schedule_ptr, targets) +

+
+ +

Construct a build schedule from the sorted targets.

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(build_target_ptr), + intent(out), + allocatable + ::queue(:) + +
+ + integer, + + allocatable + ::schedule_ptr(:) + +
+ + type(build_target_ptr), + intent(in) + + ::targets(:) + +
+ + +
+
+ +
+

public recursive subroutine sort_target(target, mock) +

+
+ +

Topologically sort a target for scheduling by + recursing over its dependencies.

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(build_target_t), + intent(inout), + target + ::target + +
+ + logical, + intent(in),optional + + ::mock +

Optionally sort ALL targets if this is a dry run

+
+ + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_backend_console.html b/module/fpm_backend_console.html new file mode 100644 index 0000000000..63c4fb2f51 --- /dev/null +++ b/module/fpm_backend_console.html @@ -0,0 +1,411 @@ + + + + + + + + + + + + + fpm_backend_console – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_backend_console + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+
+ + +
+ +
+

Build Backend Console

+

This module provides a lightweight implementation for printing to the console + and updating previously-printed console lines. It used by [[fpm_backend_output]] + for pretty-printing build status and progress.

+

@note Note + The implementation for updating previous lines relies on no other output + going to stdout/stderr except through the console_t object provided.

+

@note Note + All write statements to stdout are enclosed within OpenMP critical regions

+
+

Uses

+
+ +
+
+ + +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=*), + public, +parameter + ::COLOR_GREEN =ESC//"[32m" +

Escape code for green foreground color

+
+ + character(len=*), + public, +parameter + ::COLOR_RED =ESC//"[31m" +

Escape code for red foreground color

+
+ + character(len=*), + public, +parameter + ::COLOR_RESET =ESC//"[0m" +

Escape code to reset foreground color

+
+ + character(len=*), + public, +parameter + ::COLOR_YELLOW =ESC//"[93m" +

Escape code for yellow foreground color

+
+ + character(len=*), + public, +parameter + ::LINE_RESET =ESC//"[2K"//ESC//"[1G" +

Escape code for erasing current line

+
+ +
+
+ + + + +
+

Derived Types

+
+
+ +

+ type, public ::  + console_t + +

+
+
+

Console object

+ +

Components

+ + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + integer, + public + + ::n_line =1 +

Number of lines printed

+
+ + + + +

Type-Bound Procedures

+ + + + + + + + + + + +
procedure, public :: + update_line => console_update_line

Update a previously-written console line

procedure, public :: + write_line => console_write_line

Write a single line to the console

+
+
+ +
+
+ + + + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_backend_output.html b/module/fpm_backend_output.html new file mode 100644 index 0000000000..83d6848c0e --- /dev/null +++ b/module/fpm_backend_output.html @@ -0,0 +1,514 @@ + + + + + + + + + + + + + fpm_backend_output – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_backend_output + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+
+ + +
+ +
+

Build Backend Progress Output

+

This module provides a derived type build_progress_t for printing build status + and progress messages to the console while the backend is building the package.

+

The build_progress_t type supports two modes: normal and plain + where the former does ‘pretty’ output and the latter does not. + The normal mode is intended for typical interactive usage whereas + ‘plain’ mode is used with the --verbose flag or when stdout is not attached + to a terminal (e.g. when piping or redirecting stdout). In these cases, + the pretty output must be suppressed to avoid control codes being output.

+
+ + +
+ + + + +
+

Interfaces

+
+
+ +

public interface build_progress_t +

+
+
+

Constructor for build_progress_t

+
+
    +
  • +

    + private function new_build_progress(target_queue, plain_mode) result(progress) + +

    +

    Initialise a new build progress object

    + +

    Arguments

    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    TypeIntentOptional AttributesName
    + + type(build_target_ptr), + intent(in), + target + ::target_queue(:) +

    The queue of scheduled targets

    +
    + + logical, + intent(in),optional + + ::plain_mode +

    Enable ‘plain’ output for progress object

    +
    + +

    + Return Value + type(build_progress_t) +

    +

    Progress object to initialise

    + +
  • +
+
+ +
+
+ + +
+

Derived Types

+
+
+ +

+ type, public ::  + build_progress_t + +

+
+
+

Build progress object

+ +

Components

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + type(compile_command_table_t), + public + + ::compile_commands +

The compile_commands.json table

+
+ + type(console_t), + public + + ::console +

Console object for updating console lines

+
+ + integer, + public + + ::n_complete +

Number of completed targets

+
+ + integer, + public + + ::n_target +

Total number of targets scheduled

+
+ + integer, + public, + allocatable + ::output_lines(:) +

Store needed when updating previous console lines

+
+ + logical, + public + + ::plain_mode =.true. +

‘Plain’ output (no colors or updating)

+
+ + type(build_target_ptr), + public, + pointer + ::target_queue(:) +

Queue of scheduled build targets

+
+ + +

Constructor

+

Constructor for build_progress_t

+ + + + + + + +
+ private + + + function + new_build_progress + (target_queue, plain_mode) +

Initialise a new build progress object

+ + +

Type-Bound Procedures

+ + + + + + + + + + + + + + + + + + + +
procedure, public :: + compiling_status => output_status_compiling

Output ‘compiling’ status for build target

procedure, public :: + completed_status => output_status_complete

Output ‘complete’ status for build target

procedure, public :: + dump_commands => output_write_compile_commands

Output ‘compile_commands.json’ to build/ folder

procedure, public :: + success => output_progress_success

Output finished status for whole package

+
+
+ +
+
+ + + + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_cmd_export.html b/module/fpm_cmd_export.html new file mode 100644 index 0000000000..099566729f --- /dev/null +++ b/module/fpm_cmd_export.html @@ -0,0 +1,272 @@ + + + + + + + + + + + + + fpm_cmd_export – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_cmd_export + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+
+ + +
+ +
+ +
+ + +
+ + + + + + + + +
+

Subroutines

+
+

public subroutine cmd_export(settings) +

+
+ +

Entry point for the export subcommand +Read in manifest +Export manifest +Export dependency tree

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(fpm_export_settings), + intent(inout) + + ::settings +

Representation of the command line arguments

+
+ + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_cmd_install.html b/module/fpm_cmd_install.html new file mode 100644 index 0000000000..4973b93aff --- /dev/null +++ b/module/fpm_cmd_install.html @@ -0,0 +1,272 @@ + + + + + + + + + + + + + fpm_cmd_install – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_cmd_install + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+
+ + +
+ +
+ +
+ + +
+ + + + + + + + +
+

Subroutines

+
+

public subroutine cmd_install(settings) +

+
+ +

Entry point for the fpm-install subcommand

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(fpm_install_settings), + intent(inout) + + ::settings +

Representation of the command line settings

+
+ + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_cmd_new.html b/module/fpm_cmd_new.html new file mode 100644 index 0000000000..bd3056810f --- /dev/null +++ b/module/fpm_cmd_new.html @@ -0,0 +1,309 @@ + + + + + + + + + + + + + fpm_cmd_new – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_cmd_new + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+
+ + +
+ +
+

Definition of the “new” subcommand

+

A type of the general command base class fpm_cmd_settings + was created for the “new” subcommand ==> type fpm_new_settings. + This procedure read the values that were set on the command line + from this type to decide what actions to take.

+

It is virtually self-contained and so independant of the rest of the + application that it could function as a separate program.

+

The “new” subcommand options currently consist of a SINGLE top + directory name to create that must have a name that is an + allowable Fortran variable name. That should have been ensured + by the command line processing before this procedure is called. + So basically this routine has already had the options vetted and + just needs to conditionally create a few files.

+

As described in the documentation it will selectively + create the subdirectories app/, test/, src/, and example/ + and populate them with sample files.

+

It also needs to create an initial manifest file “fpm.toml”.

+

It then calls the system command “git init”.

+

It should test for file existence and not overwrite existing + files and inform the user if there were conflicts.

+

Any changes should be reflected in the documentation in + fpm_command_line.f90

+

FUTURE + A filename like “.” would need system commands or a standard routine + like realpath(3c) to process properly.

+

Perhaps allow more than one name on a single command. It is an arbitrary + restriction based on a concensus preference, not a required limitation.

+

Initially the name of the directory is used as the module name in the + src file so it must be an allowable Fortran variable name. If there are + complaints about it it might be changed. Handling unicode at this point + might be problematic as not all current compilers handle it. Other + utilities like content trackers (ie. git) or repositories like github + might also have issues with alternative names or names with spaces, etc. + So for the time being it seems prudent to encourage simple ASCII top directory + names (similiar to the primary programming language Fortran itself).

+

Should be able to create or pull more complicated initial examples + based on various templates. It should place or mention other relevant + documents such as a description of the manifest file format in user hands; + or how to access registered packages and local packages, + although some other command might provide that (and the help command should + be the first go-to for a CLI utility).

+
+ + +
+ + + + + + + + +
+

Subroutines

+
+

public subroutine cmd_new(settings) +

+
+ +

TOP DIRECTORY NAME PROCESSING +see if requested new directory already exists and process appropriately +temporarily change to new directory as a test. NB: System dependent

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(fpm_new_settings), + intent(in) + + ::settings + +
+ + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_cmd_publish.html b/module/fpm_cmd_publish.html new file mode 100644 index 0000000000..3375114a4b --- /dev/null +++ b/module/fpm_cmd_publish.html @@ -0,0 +1,276 @@ + + + + + + + + + + + + + fpm_cmd_publish – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_cmd_publish + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+
+ + +
+ +
+

Upload a package to the registry using the publish command.

+

To upload a package you need to provide a token that will be linked to your username and created for a namespace. +The token can be obtained from the registry website. It can be used as fpm publish --token <token>.

+
+ + +
+ + + + + + + + +
+

Subroutines

+
+

public subroutine cmd_publish(settings) +

+
+ +

The publish command first builds the root package to obtain all the relevant information such as the +package version. It then creates a tarball of the package and uploads it to the registry. +Checks before uploading the package.

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(fpm_publish_settings), + intent(inout) + + ::settings + +
+ + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_cmd_update.html b/module/fpm_cmd_update.html new file mode 100644 index 0000000000..ebdfd6b800 --- /dev/null +++ b/module/fpm_cmd_update.html @@ -0,0 +1,267 @@ + + + + + + + + + + + + + fpm_cmd_update – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_cmd_update + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+
+ + +
+ +
+ +
+ + +
+ + + + + + + + +
+

Subroutines

+
+

public subroutine cmd_update(settings) +

+
+ +

Entry point for the update subcommand

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(fpm_update_settings), + intent(in) + + ::settings +

Representation of the command line arguments

+
+ + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_command_line.html b/module/fpm_command_line.html new file mode 100644 index 0000000000..e87f76a01a --- /dev/null +++ b/module/fpm_command_line.html @@ -0,0 +1,3324 @@ + + + + + + + + + + + + + fpm_command_line – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_command_line + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

Definition of the command line interface

+

This module uses M_CLI2 to define + the command line interface. + To define a command line interface create a new command settings type + from the fpm_cmd_settings base class or the respective parent command + settings.

+

The subcommand is selected by the first non-option argument in the command + line. In the subcase block the actual command line is defined and transferred + to an instance of the fpm_cmd_settings, the actual type is used by the + fpm main program to determine which command entry point is chosen.

+

To add a new subcommand add a new case to select construct and specify the + wanted command line and the expected default values. + Some of the following points also apply if you add a new option or argument + to an existing fpm subcommand. + At this point you should create a help page for the new command in a simple + catman-like format as well in the set_help procedure. + Make sure to register new subcommands in the fpm-manual command by adding + them to the manual character array and in the help/manual case as well. + You should add the new command to the synopsis section of the fpm-list, + fpm-help and fpm --list help pages below to make sure the help output + is complete and consistent as well.

+
+ + +
+ + + + + + +
+

Derived Types

+
+
+ +

+ type, public, extends(fpm_cmd_settings) ::  + fpm_build_settings + +

+
+
+ + +

Components

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=:), + public, + allocatable + ::archiver + +
+ + logical, + public + + ::build_tests =.false. + +
+ + character(len=:), + public, + allocatable + ::c_compiler + +
+ + character(len=:), + public, + allocatable + ::cflag + +
+ + character(len=:), + public, + allocatable + ::compiler + +
+ + character(len=:), + public, + allocatable + ::cxx_compiler + +
+ + character(len=:), + public, + allocatable + ::cxxflag + +
+ + character(len=:), + public, + allocatable + ::dump + +
+ + character(len=:), + public, + allocatable + ::flag + +
+ + character(len=:), + public, + allocatable + ::ldflag + +
+ + logical, + public + + ::list =.false. + +
+ + character(len=:), + public, + allocatable + ::path_to_config + +
+ + character(len=:), + public, + allocatable + ::profile + +
+ + logical, + public + + ::prune =.true. + +
+ + logical, + public + + ::show_model =.false. + +
+ + logical, + public + + ::verbose =.true. + +
+ + character(len=:), + public, + allocatable + ::working_dir + +
+ + + + +
+
+ +
+
+ +

+ type, public, extends(fpm_cmd_settings) ::  + fpm_clean_settings + +

+
+
+ + +

Components

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + logical, + public + + ::clean_all =.false. + +
+ + logical, + public + + ::clean_skip =.false. + +
+ + character(len=:), + public, + allocatable + ::path_to_config + +
+ + logical, + public + + ::registry_cache =.false. + +
+ + logical, + public + + ::verbose =.true. + +
+ + character(len=:), + public, + allocatable + ::working_dir + +
+ + + + +
+
+ +
+
+ +

+ type, public, abstract ::  + fpm_cmd_settings + +

+
+
+ + +

Components

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=:), + public, + allocatable + ::path_to_config + +
+ + logical, + public + + ::verbose =.true. + +
+ + character(len=:), + public, + allocatable + ::working_dir + +
+ + + + +
+
+ +
+
+ +

+ type, public, extends(fpm_build_settings) ::  + fpm_export_settings + +

+
+
+

Settings for exporting model data

+ +

Components

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=:), + public, + allocatable + ::archiver + +
+ + logical, + public + + ::build_tests =.false. + +
+ + character(len=:), + public, + allocatable + ::c_compiler + +
+ + character(len=:), + public, + allocatable + ::cflag + +
+ + character(len=:), + public, + allocatable + ::compiler + +
+ + character(len=:), + public, + allocatable + ::cxx_compiler + +
+ + character(len=:), + public, + allocatable + ::cxxflag + +
+ + character(len=:), + public, + allocatable + ::dump + +
+ + character(len=:), + public, + allocatable + ::dump_dependencies + +
+ + character(len=:), + public, + allocatable + ::dump_manifest + +
+ + character(len=:), + public, + allocatable + ::dump_model + +
+ + character(len=:), + public, + allocatable + ::flag + +
+ + character(len=:), + public, + allocatable + ::ldflag + +
+ + logical, + public + + ::list =.false. + +
+ + character(len=:), + public, + allocatable + ::path_to_config + +
+ + character(len=:), + public, + allocatable + ::profile + +
+ + logical, + public + + ::prune =.true. + +
+ + logical, + public + + ::show_model =.false. + +
+ + logical, + public + + ::verbose =.true. + +
+ + character(len=:), + public, + allocatable + ::working_dir + +
+ + + + +
+
+ +
+
+ +

+ type, public, extends(fpm_build_settings) ::  + fpm_install_settings + +

+
+
+ + +

Components

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=:), + public, + allocatable + ::archiver + +
+ + character(len=:), + public, + allocatable + ::bindir + +
+ + logical, + public + + ::build_tests =.false. + +
+ + character(len=:), + public, + allocatable + ::c_compiler + +
+ + character(len=:), + public, + allocatable + ::cflag + +
+ + character(len=:), + public, + allocatable + ::compiler + +
+ + character(len=:), + public, + allocatable + ::cxx_compiler + +
+ + character(len=:), + public, + allocatable + ::cxxflag + +
+ + character(len=:), + public, + allocatable + ::dump + +
+ + character(len=:), + public, + allocatable + ::flag + +
+ + character(len=:), + public, + allocatable + ::includedir + +
+ + character(len=:), + public, + allocatable + ::ldflag + +
+ + character(len=:), + public, + allocatable + ::libdir + +
+ + logical, + public + + ::list =.false. + +
+ + logical, + public + + ::no_rebuild + +
+ + character(len=:), + public, + allocatable + ::path_to_config + +
+ + character(len=:), + public, + allocatable + ::prefix + +
+ + character(len=:), + public, + allocatable + ::profile + +
+ + logical, + public + + ::prune =.true. + +
+ + logical, + public + + ::show_model =.false. + +
+ + character(len=:), + public, + allocatable + ::testdir + +
+ + logical, + public + + ::verbose =.true. + +
+ + character(len=:), + public, + allocatable + ::working_dir + +
+ + + + +
+
+ +
+
+ +

+ type, public, extends(fpm_cmd_settings) ::  + fpm_new_settings + +

+
+
+ + +

Components

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + logical, + public + + ::backfill =.true. + +
+ + character(len=:), + public, + allocatable + ::name + +
+ + character(len=:), + public, + allocatable + ::path_to_config + +
+ + logical, + public + + ::verbose =.true. + +
+ + logical, + public + + ::with_bare =.false. + +
+ + logical, + public + + ::with_example =.false. + +
+ + logical, + public + + ::with_executable =.false. + +
+ + logical, + public + + ::with_full =.false. + +
+ + logical, + public + + ::with_lib =.true. + +
+ + logical, + public + + ::with_test =.false. + +
+ + character(len=:), + public, + allocatable + ::working_dir + +
+ + + + +
+
+ +
+
+ +

+ type, public, extends(fpm_build_settings) ::  + fpm_publish_settings + +

+
+
+ + +

Components

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=:), + public, + allocatable + ::archiver + +
+ + logical, + public + + ::build_tests =.false. + +
+ + character(len=:), + public, + allocatable + ::c_compiler + +
+ + character(len=:), + public, + allocatable + ::cflag + +
+ + character(len=:), + public, + allocatable + ::compiler + +
+ + character(len=:), + public, + allocatable + ::cxx_compiler + +
+ + character(len=:), + public, + allocatable + ::cxxflag + +
+ + character(len=:), + public, + allocatable + ::dump + +
+ + character(len=:), + public, + allocatable + ::flag + +
+ + logical, + public + + ::is_dry_run =.false. + +
+ + character(len=:), + public, + allocatable + ::ldflag + +
+ + logical, + public + + ::list =.false. + +
+ + character(len=:), + public, + allocatable + ::path_to_config + +
+ + character(len=:), + public, + allocatable + ::profile + +
+ + logical, + public + + ::prune =.true. + +
+ + logical, + public + + ::show_model =.false. + +
+ + logical, + public + + ::show_package_version =.false. + +
+ + logical, + public + + ::show_upload_data =.false. + +
+ + character(len=:), + public, + allocatable + ::token + +
+ + logical, + public + + ::verbose =.true. + +
+ + character(len=:), + public, + allocatable + ::working_dir + +
+ + + + +
+
+ +
+
+ +

+ type, public, extends(fpm_build_settings) ::  + fpm_run_settings + +

+
+
+ + +

Components

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=:), + public, + allocatable + ::archiver + +
+ + character(len=:), + public, + allocatable + ::args + +
+ + logical, + public + + ::build_tests =.false. + +
+ + character(len=:), + public, + allocatable + ::c_compiler + +
+ + character(len=:), + public, + allocatable + ::cflag + +
+ + character(len=:), + public, + allocatable + ::compiler + +
+ + character(len=:), + public, + allocatable + ::cxx_compiler + +
+ + character(len=:), + public, + allocatable + ::cxxflag + +
+ + character(len=:), + public, + allocatable + ::dump + +
+ + logical, + public + + ::example + +
+ + character(len=:), + public, + allocatable + ::flag + +
+ + character(len=:), + public, + allocatable + ::ldflag + +
+ + logical, + public + + ::list =.false. + +
+ + character(len=ibug), + public, + allocatable + ::name(:) + +
+ + character(len=:), + public, + allocatable + ::path_to_config + +
+ + character(len=:), + public, + allocatable + ::profile + +
+ + logical, + public + + ::prune =.true. + +
+ + character(len=:), + public, + allocatable + ::runner + +
+ + character(len=:), + public, + allocatable + ::runner_args + +
+ + logical, + public + + ::show_model =.false. + +
+ + logical, + public + + ::verbose =.true. + +
+ + character(len=:), + public, + allocatable + ::working_dir + +
+ + + + +

Type-Bound Procedures

+ + + + + + + + + + + +
procedure, public :: + name_ID
procedure, public :: + runner_command
+
+
+ +
+
+ +

+ type, public, extends(fpm_run_settings) ::  + fpm_test_settings + +

+
+
+ + +

Components

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=:), + public, + allocatable + ::archiver + +
+ + character(len=:), + public, + allocatable + ::args + +
+ + logical, + public + + ::build_tests =.false. + +
+ + character(len=:), + public, + allocatable + ::c_compiler + +
+ + character(len=:), + public, + allocatable + ::cflag + +
+ + character(len=:), + public, + allocatable + ::compiler + +
+ + character(len=:), + public, + allocatable + ::cxx_compiler + +
+ + character(len=:), + public, + allocatable + ::cxxflag + +
+ + character(len=:), + public, + allocatable + ::dump + +
+ + logical, + public + + ::example + +
+ + character(len=:), + public, + allocatable + ::flag + +
+ + character(len=:), + public, + allocatable + ::ldflag + +
+ + logical, + public + + ::list =.false. + +
+ + character(len=ibug), + public, + allocatable + ::name(:) + +
+ + character(len=:), + public, + allocatable + ::path_to_config + +
+ + character(len=:), + public, + allocatable + ::profile + +
+ + logical, + public + + ::prune =.true. + +
+ + character(len=:), + public, + allocatable + ::runner + +
+ + character(len=:), + public, + allocatable + ::runner_args + +
+ + logical, + public + + ::show_model =.false. + +
+ + logical, + public + + ::verbose =.true. + +
+ + character(len=:), + public, + allocatable + ::working_dir + +
+ + + + +

Type-Bound Procedures

+ + + + + + + + + + + +
procedure, public :: + name_ID
procedure, public :: + runner_command
+
+
+ +
+
+ +

+ type, public, extends(fpm_cmd_settings) ::  + fpm_update_settings + +

+
+
+

Settings for interacting and updating with project dependencies

+ +

Components

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + logical, + public + + ::clean + +
+ + character(len=:), + public, + allocatable + ::dump + +
+ + logical, + public + + ::fetch_only + +
+ + character(len=ibug), + public, + allocatable + ::name(:) + +
+ + character(len=:), + public, + allocatable + ::path_to_config + +
+ + logical, + public + + ::verbose =.true. + +
+ + character(len=:), + public, + allocatable + ::working_dir + +
+ + + + +
+
+ +
+
+ +
+

Functions

+
+

public function get_fpm_env(env, default) result(val) +

+
+ +

Get an environment variable for fpm, this routine ensures that every variable +used by fpm is prefixed with FPM_.

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::env + +
+ + character(len=*), + intent(in) + + ::default + +
+ +

+ Return Value + character(len=:), allocatable +

+ + +
+
+ +
+
+ +
+

Subroutines

+
+

public subroutine get_command_line_settings(cmd_settings) +

+
+ +

! canon_path is not converting “.”, etc. +& ‘ unknown help topic “’//trim(unnamed(i)).’not found in:’,manual]

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(fpm_cmd_settings), + intent(out), + allocatable + ::cmd_settings + +
+ + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_compile_commands.html b/module/fpm_compile_commands.html new file mode 100644 index 0000000000..5791d70cb0 --- /dev/null +++ b/module/fpm_compile_commands.html @@ -0,0 +1,1472 @@ + + + + + + + + + + + + + fpm_compile_commands – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_compile_commands + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

Store compiler commands in a compile_commands.json table

+
+

Uses

+
+ +
+
+ + +
+ + + + +
+

Interfaces

+
+
+ +

public interface compile_command_t +

+
+
    +
  • +

    + public function cct_new(directory, arguments, file) result(cct) + +

    + +

    Override default initializer (GCC 15 bug)

    + +

    Arguments

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    TypeIntentOptional AttributesName
    + + character(len=*), + intent(in) + + ::directory + +
    + + character(len=*), + intent(in),optional + + ::arguments(:) + +
    + + character(len=*), + intent(in) + + ::file + +
    + +

    + Return Value + type(compile_command_t) +

    + + +
  • +
+
+ +
+
+ + +
+

Derived Types

+
+
+ +

+ type, public, extends(serializable_t) ::  + compile_command_t + +

+
+
+

Definition of a build command

+ +

Components

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + type(string_t), + public, + allocatable + ::arguments(:) + +
+ + type(string_t), + public + + ::directory + +
+ + type(string_t), + public + + ::file + +
+ + +

Constructor

+ + + + + + + + +
+ public + + + function + cct_new + (directory, arguments, file) +

Override default initializer (GCC 15 bug)

+ + +

Type-Bound Procedures

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
procedure, public :: + destroy => compile_command_destroy

Operation

generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit
procedure, public :: + dump_to_toml => compile_command_dump_toml
generic, public :: + load => load_from_toml, load_from_file, load_from_unit
procedure, public :: + load_from_toml => compile_command_load_toml
generic, public :: + operator(==) => serializable_is_same
procedure, public :: + serializable_is_same => compile_command_is_same

Serialization interface

procedure, public, non_overridable :: + test_serialization

Test load/write roundtrip

+
+
+ +
+
+ +

+ type, public, extends(serializable_t) ::  + compile_command_table_t + +

+
+
+ + +

Components

+ + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + type(compile_command_t), + public, + allocatable + ::command(:) + +
+ + + + +

Type-Bound Procedures

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
procedure, public :: + destroy => cct_destroy

Operation

generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit
procedure, public :: + dump_to_toml => cct_dump_toml
generic, public :: + load => load_from_toml, load_from_file, load_from_unit
procedure, public :: + load_from_toml => cct_load_toml
generic, public :: + operator(==) => serializable_is_same
generic, public :: + register => cct_register, cct_register_object
procedure, public :: + serializable_is_same => cct_is_same

Serialization interface

procedure, public, non_overridable :: + test_serialization

Test load/write roundtrip

procedure, public :: + write => cct_write
+
+
+ +
+
+ +
+

Functions

+
+

public function cct_is_same(this, that) +

+
+ +

Check that two compile_command_table_t objects are equal +All checks passed!

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compile_command_table_t), + intent(in) + + ::this + +
+ + class(serializable_t), + intent(in) + + ::that + +
+ +

+ Return Value + logical +

+ + +
+
+ +
+

public function cct_new(directory, arguments, file) result(cct) +

+
+ +

Override default initializer (GCC 15 bug)

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::directory + +
+ + character(len=*), + intent(in),optional + + ::arguments(:) + +
+ + character(len=*), + intent(in) + + ::file + +
+ +

+ Return Value + type(compile_command_t) +

+ + +
+
+ +
+

public function compile_command_is_same(this, that) +

+
+ +

Check that two compile_command_t objects are equal +All checks passed!

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compile_command_t), + intent(in) + + ::this + +
+ + class(serializable_t), + intent(in) + + ::that + +
+ +

+ Return Value + logical +

+ + +
+
+ +
+
+ +
+

Subroutines

+
+

public elemental subroutine cct_destroy(self) +

+
+ +

Cleanup a compile command table

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compile_command_table_t), + intent(inout) + + ::self +

Instance of the serializable object

+
+ + +
+
+ +
+

public subroutine cct_dump_array(self, array, error) +

+
+ +

Dump compile_command_table_t to a toml array

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compile_command_table_t), + intent(inout) + + ::self +

Instance of the serializable object

+
+ + type(toml_array), + intent(inout) + + ::array +

Data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + +
+
+ +
+

public subroutine cct_dump_toml(self, table, error) +

+
+ +

Dump compile_command_table_t to toml table

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compile_command_table_t), + intent(inout) + + ::self +

Instance of the serializable object

+
+ + type(toml_table), + intent(inout) + + ::table +

Data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + +
+
+ +
+

public subroutine cct_load_toml(self, table, error) +

+
+ +

Read compile_command_table_t from toml table (no checks made at this stage)

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compile_command_table_t), + intent(inout) + + ::self +

Instance of the serializable object

+
+ + type(toml_table), + intent(inout) + + ::table +

Data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + +
+
+ +
+

public subroutine cct_register(self, command, target_os, error) +

+
+ +

Register a new compile command

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compile_command_table_t), + intent(inout) + + ::self +

Instance of the serializable object

+
+ + character(len=*), + intent(in) + + ::command +

Data structure

+
+ + integer, + intent(in) + + ::target_os +

The target OS of the compile_commands.json (may be cross-compiling)

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + +
+
+ +
+

public pure subroutine cct_register_object(self, command, error) +

+
+ + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compile_command_table_t), + intent(inout) + + ::self +

Instance of the serializable object

+
+ + type(compile_command_t), + intent(in) + + ::command +

Data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + +
+
+ +
+

public subroutine cct_write(self, filename, error) +

+
+ +

Write compile_commands.json file. Because Jonquil does not support non-named arrays, +create a custom json here.

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compile_command_table_t), + intent(inout) + + ::self +

Instance of the serializable object

+
+ + character(len=*), + intent(in) + + ::filename +

The file name

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + +
+
+ +
+

public elemental subroutine compile_command_destroy(self) +

+
+ +

Cleanup compile command

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compile_command_t), + intent(inout) + + ::self +

Instance of the serializable object

+
+ + +
+
+ +
+

public subroutine compile_command_dump_toml(self, table, error) +

+
+ +

Dump compile_command_t to toml table

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compile_command_t), + intent(inout) + + ::self +

Instance of the serializable object

+
+ + type(toml_table), + intent(inout) + + ::table +

Data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + +
+
+ +
+

public subroutine compile_command_load_toml(self, table, error) +

+
+ +

Read compile_command_t from toml table (no checks made at this stage)

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compile_command_t), + intent(inout) + + ::self +

Instance of the serializable object

+
+ + type(toml_table), + intent(inout) + + ::table +

Data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_compiler.html b/module/fpm_compiler.html new file mode 100644 index 0000000000..bc640715b3 --- /dev/null +++ b/module/fpm_compiler.html @@ -0,0 +1,5638 @@ + + + + + + + + + + + + + fpm_compiler – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_compiler + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+
+ + +
+ +
+

Define compiler command options

+

This module defines compiler options to use for the debug and release builds.

+
+ + +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + integer, + public, +parameter + ::compiler_enum =kind(id_unknown) + +
+ + character(len=*), + public, +parameter + ::flag_cray_fixed_form =" -ffixed" + +
+ + character(len=*), + public, +parameter + ::flag_cray_free_form =" -ffree" + +
+ + character(len=*), + public, +parameter + ::flag_cray_implicit_typing =" -el" + +
+ + character(len=*), + public, +parameter + ::flag_cray_no_implicit_typing =" -dl" + +
+ + character(len=*), + public, +parameter + ::flag_flang_new_openmp =" -fopenmp" + +
+ + character(len=*), + public, +parameter + ::flag_gnu_backtrace =" -fbacktrace" + +
+ + character(len=*), + public, +parameter + ::flag_gnu_check =" -fcheck=bounds -fcheck=array-temps" + +
+ + character(len=*), + public, +parameter + ::flag_gnu_coarray =" -fcoarray=single" + +
+ + character(len=*), + public, +parameter + ::flag_gnu_debug =" -g" + +
+ + character(len=*), + public, +parameter + ::flag_gnu_external =" -Wimplicit-interface" + +
+ + character(len=*), + public, +parameter + ::flag_gnu_fixed_form =" -ffixed-form" + +
+ + character(len=*), + public, +parameter + ::flag_gnu_free_form =" -ffree-form" + +
+ + character(len=*), + public, +parameter + ::flag_gnu_limit =" -fmax-errors=1" + +
+ + character(len=*), + public, +parameter + ::flag_gnu_no_implicit_external =" -Werror=implicit-interface" + +
+ + character(len=*), + public, +parameter + ::flag_gnu_no_implicit_typing =" -fimplicit-none" + +
+ + character(len=*), + public, +parameter + ::flag_gnu_openmp =" -fopenmp" + +
+ + character(len=*), + public, +parameter + ::flag_gnu_opt =" -O3 -funroll-loops" + +
+ + character(len=*), + public, +parameter + ::flag_gnu_pic =" -fPIC" + +
+ + character(len=*), + public, +parameter + ::flag_gnu_warn =" -Wall -Wextra" + +
+ + character(len=*), + public, +parameter + ::flag_ibmxl_backslash =" -qnoescape" + +
+ + character(len=*), + public, +parameter + ::flag_intel_align =" -align all" + +
+ + character(len=*), + public, +parameter + ::flag_intel_align_win =" /align:all" + +
+ + character(len=*), + public, +parameter + ::flag_intel_backtrace =" -traceback" + +
+ + character(len=*), + public, +parameter + ::flag_intel_backtrace_win =" /traceback" + +
+ + character(len=*), + public, +parameter + ::flag_intel_byterecl =" -assume byterecl" + +
+ + character(len=*), + public, +parameter + ::flag_intel_byterecl_win =" /assume:byterecl" + +
+ + character(len=*), + public, +parameter + ::flag_intel_check =" -check all" + +
+ + character(len=*), + public, +parameter + ::flag_intel_check_win =" /check:all" + +
+ + character(len=*), + public, +parameter + ::flag_intel_debug =" -O0 -g" + +
+ + character(len=*), + public, +parameter + ::flag_intel_debug_win =" /Od /Z7" + +
+ + character(len=*), + public, +parameter + ::flag_intel_fixed_form =" -fixed" + +
+ + character(len=*), + public, +parameter + ::flag_intel_fixed_form_win =" /fixed" + +
+ + character(len=*), + public, +parameter + ::flag_intel_fp =" -fp-model precise -pc64" + +
+ + character(len=*), + public, +parameter + ::flag_intel_fp_win =" /fp:precise" + +
+ + character(len=*), + public, +parameter + ::flag_intel_free_form =" -free" + +
+ + character(len=*), + public, +parameter + ::flag_intel_free_form_win =" /free" + +
+ + character(len=*), + public, +parameter + ::flag_intel_limit =" -error-limit 1" + +
+ + character(len=*), + public, +parameter + ::flag_intel_limit_win =" /error-limit:1" + +
+ + character(len=*), + public, +parameter + ::flag_intel_llvm_check =" -check all,nouninit" + +
+ + character(len=*), + public, +parameter + ::flag_intel_nogen =" -nogen-interfaces" + +
+ + character(len=*), + public, +parameter + ::flag_intel_nogen_win =" /nogen-interfaces" + +
+ + character(len=*), + public, +parameter + ::flag_intel_openmp =" -qopenmp" + +
+ + character(len=*), + public, +parameter + ::flag_intel_openmp_win =" /Qopenmp" + +
+ + character(len=*), + public, +parameter + ::flag_intel_opt =" -O3" + +
+ + character(len=*), + public, +parameter + ::flag_intel_opt_win =" /O3" + +
+ + character(len=*), + public, +parameter + ::flag_intel_pthread =" -reentrancy threaded" + +
+ + character(len=*), + public, +parameter + ::flag_intel_pthread_win =" /reentrancy:threaded" + +
+ + character(len=*), + public, +parameter + ::flag_intel_standard_compliance =" -standard-semantics" + +
+ + character(len=*), + public, +parameter + ::flag_intel_standard_compliance_win =" /standard-semantics" + +
+ + character(len=*), + public, +parameter + ::flag_intel_unknown_cmd_err =" -diag-error 10006" + +
+ + character(len=*), + public, +parameter + ::flag_intel_unknown_cmd_err_win =" /Qdiag-error:10006" + +
+ + character(len=*), + public, +parameter + ::flag_intel_warn =" -warn all" + +
+ + character(len=*), + public, +parameter + ::flag_intel_warn_win =" /warn:all" + +
+ + character(len=*), + public, +parameter + ::flag_lfortran_fixed_form =" --fixed-form" + +
+ + character(len=*), + public, +parameter + ::flag_lfortran_implicit_external =" --implicit-interface" + +
+ + character(len=*), + public, +parameter + ::flag_lfortran_implicit_typing =" --implicit-typing" + +
+ + character(len=*), + public, +parameter + ::flag_lfortran_openmp =" --openmp" + +
+ + character(len=*), + public, +parameter + ::flag_lfortran_opt =" --fast" + +
+ + character(len=*), + public, +parameter + ::flag_nag_backtrace =" -gline" + +
+ + character(len=*), + public, +parameter + ::flag_nag_check =" -C" + +
+ + character(len=*), + public, +parameter + ::flag_nag_coarray =" -coarray=single" + +
+ + character(len=*), + public, +parameter + ::flag_nag_debug =" -g -O0" + +
+ + character(len=*), + public, +parameter + ::flag_nag_fixed_form =" -fixed" + +
+ + character(len=*), + public, +parameter + ::flag_nag_free_form =" -free" + +
+ + character(len=*), + public, +parameter + ::flag_nag_no_implicit_typing =" -u" + +
+ + character(len=*), + public, +parameter + ::flag_nag_openmp =" -openmp" + +
+ + character(len=*), + public, +parameter + ::flag_nag_opt =" -O4" + +
+ + character(len=*), + public, +parameter + ::flag_nag_pic =" -PIC" + +
+ + character(len=*), + public, +parameter + ::flag_pgi_backslash =" -Mbackslash" + +
+ + character(len=*), + public, +parameter + ::flag_pgi_check =" -Mbounds -Mchkptr -Mchkstk" + +
+ + character(len=*), + public, +parameter + ::flag_pgi_debug =" -g" + +
+ + character(len=*), + public, +parameter + ::flag_pgi_fixed_form =" -Mfixed" + +
+ + character(len=*), + public, +parameter + ::flag_pgi_free_form =" -Mfree" + +
+ + character(len=*), + public, +parameter + ::flag_pgi_openmp =" -mp" + +
+ + character(len=*), + public, +parameter + ::flag_pgi_traceback =" -traceback" + +
+ + character(len=*), + public, +parameter + ::flag_pgi_warn =" -Minform=inform" + +
+ +
+
+ +
+

Enumerations

+
+

enum, bind(c)

+
+

Enumerators

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
enumerator::id_unknown = 0
enumerator::id_gcc = 1
enumerator::id_f95 = 2
enumerator::id_caf = 3
enumerator::id_intel_classic_nix = 4
enumerator::id_intel_classic_mac = 5
enumerator::id_intel_classic_windows = 6
enumerator::id_intel_llvm_nix = 7
enumerator::id_intel_llvm_windows = 8
enumerator::id_intel_llvm_unknown = 9
enumerator::id_pgi = 10
enumerator::id_nvhpc = 11
enumerator::id_nag = 12
enumerator::id_flang = 13
enumerator::id_flang_new = 14
enumerator::id_f18 = 15
enumerator::id_ibmxl = 16
enumerator::id_cray = 17
enumerator::id_lahey = 18
enumerator::id_lfortran = 19
+
+
+ +
+
+ +
+

Interfaces

+
+
+ +

public interface debug +

+
+
+

Create debug printout

+
+
    +
  • +

    + public pure function debug_compiler(self) result(repr) + +

    + +

    String representation of a compiler object

    + +

    Arguments

    + + + + + + + + + + + + + + + + + + + +
    TypeIntentOptional AttributesName
    + + type(compiler_t), + intent(in) + + ::self +

    Instance of the compiler object

    +
    + +

    + Return Value + character(len=:), allocatable +

    +

    Representation as string

    + +
  • +
  • +

    + public pure function debug_archiver(self) result(repr) + +

    + +

    String representation of an archiver object

    + +

    Arguments

    + + + + + + + + + + + + + + + + + + + +
    TypeIntentOptional AttributesName
    + + type(archiver_t), + intent(in) + + ::self +

    Instance of the archiver object

    +
    + +

    + Return Value + character(len=:), allocatable +

    +

    Representation as string

    + +
  • +
+
+ +
+
+ + +
+

Derived Types

+
+
+ +

+ type, public, extends(serializable_t) ::  + archiver_t + +

+
+
+

Definition of archiver object

+ +

Components

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=:), + public, + allocatable + ::ar +

Path to archiver

+
+ + logical, + public + + ::echo =.true. +

Print all command

+
+ + logical, + public + + ::use_response_file =.false. +

Use response files to pass arguments

+
+ + logical, + public + + ::verbose =.true. +

Verbose output of command

+
+ + + + +

Type-Bound Procedures

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit
procedure, public :: + dump_to_toml
generic, public :: + load => load_from_toml, load_from_file, load_from_unit
procedure, public :: + load_from_toml
procedure, public :: + make_archive

Create static archive

generic, public :: + operator(==) => serializable_is_same
procedure, public :: + serializable_is_same => ar_is_same

Serialization interface

procedure, public, non_overridable :: + test_serialization

Test load/write roundtrip

+
+
+ +
+
+ +

+ type, public, extends(serializable_t) ::  + compiler_t + +

+
+
+

Definition of compiler object

+ +

Components

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=:), + public, + allocatable + ::cc +

Path to the C compiler

+
+ + character(len=:), + public, + allocatable + ::cxx +

Path to the C++ compiler

+
+ + logical, + public + + ::echo =.true. +

Print all commands

+
+ + character(len=:), + public, + allocatable + ::fc +

Path to the Fortran compiler

+
+ + integer(kind=compiler_enum), + public + + ::id =id_unknown +

Identifier of the compiler

+
+ + logical, + public + + ::verbose =.true. +

Verbose output of command

+
+ + + + +

Type-Bound Procedures

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
procedure, public :: + check_flags_supported
procedure, public :: + check_fortran_source_runs

Fortran feature support

procedure, public :: + compile_c

Compile a C object

procedure, public :: + compile_cpp

Compile a CPP object

procedure, public :: + compile_fortran

Compile a Fortran object

generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit
procedure, public :: + dump_to_toml => compiler_dump
procedure, public :: + enumerate_libraries

Enumerate libraries, based on compiler and platform

procedure, public :: + get_default_flags

Get default compiler flags

procedure, public :: + get_export_flags

Get library export flags

procedure, public :: + get_feature_flag

Get feature flag

procedure, public :: + get_headerpad_flags

Generate header padding flags for macOS executables

procedure, public :: + get_include_flag

Get flag for include directories

procedure, public :: + get_install_name_flags

Get library install name flags

procedure, public :: + get_main_flags

Get flags for the main linking command

procedure, public :: + get_module_flag

Get flag for module output directories

procedure, public :: + is_gnu

Check whether this is a GNU compiler

procedure, public :: + is_intel

Check whether this is an Intel compiler

procedure, public :: + is_unknown

Check whether compiler is recognized

procedure, public :: + link => link_executable

Link executable

procedure, public :: + link_shared

Link a shared library

generic, public :: + load => load_from_toml, load_from_file, load_from_unit
procedure, public :: + load_from_toml => compiler_load
procedure, public :: + name => compiler_name

Return compiler name

generic, public :: + operator(==) => serializable_is_same
procedure, public :: + serializable_is_same => compiler_is_same

Serialization interface

procedure, public, non_overridable :: + test_serialization

Test load/write roundtrip

procedure, public :: + with_qp
procedure, public :: + with_xdp
+
+
+ +
+
+ +
+

Functions

+
+

public function ar_is_same(this, that) +

+
+ +

Check that two archiver_t objects are equal +All checks passed!

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(archiver_t), + intent(in) + + ::this + +
+ + class(serializable_t), + intent(in) + + ::that + +
+ +

+ Return Value + logical +

+ + +
+
+ +
+

public function check_compiler(compiler, expected) result(match) +

+
+ + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::compiler + +
+ + character(len=*), + intent(in) + + ::expected + +
+ +

+ Return Value + logical +

+ + +
+
+ +
+

public function check_flags_supported(self, compile_flags, link_flags) +

+
+ +

Check if the given compile and/or link flags are accepted by the compiler

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::self + +
+ + character(len=*), + intent(in),optional + + ::compile_flags + +
+ + character(len=*), + intent(in),optional + + ::link_flags + +
+ +

+ Return Value + logical +

+ + +
+
+ +
+

public function check_fortran_source_runs(self, input, compile_flags, link_flags) result(success) +

+
+ +

Run a single-source Fortran program using the current compiler +Compile a Fortran object +Create temporary source file +Write contents +Get flags +Intel: Needs -warn last for error on unknown command line arguments to work +Compile and link program +Run and retrieve exit code

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::self +

Instance of the compiler object

+
+ + character(len=*), + intent(in) + + ::input +

Program Source

+
+ + character(len=*), + intent(in),optional + + ::compile_flags +

Optional build and link flags

+
+ + character(len=*), + intent(in),optional + + ::link_flags +

Optional build and link flags

+
+ +

+ Return Value + logical +

+ + +
+
+ +
+

public function compiler_is_same(this, that) +

+
+ +

Check that two compiler_t objects are equal +All checks passed!

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::this + +
+ + class(serializable_t), + intent(in) + + ::that + +
+ +

+ Return Value + logical +

+ + +
+
+ +
+

public pure function compiler_name(self) result(name) +

+
+ +

Return a compiler name string

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::self +

Instance of the compiler object

+
+ +

+ Return Value + character(len=:), allocatable +

+

Representation as string

+ +
+
+ +
+

public pure function debug_archiver(self) result(repr) +

+
+ +

String representation of an archiver object

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(archiver_t), + intent(in) + + ::self +

Instance of the archiver object

+
+ +

+ Return Value + character(len=:), allocatable +

+

Representation as string

+ +
+
+ +
+

public pure function debug_compiler(self) result(repr) +

+
+ +

String representation of a compiler object

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(compiler_t), + intent(in) + + ::self +

Instance of the compiler object

+
+ +

+ Return Value + character(len=:), allocatable +

+

Representation as string

+ +
+
+ +
+

public function enumerate_libraries(self, prefix, libs) result(r) +

+
+ +

Enumerate libraries, based on compiler and platform

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::self + +
+ + character(len=*), + intent(in) + + ::prefix + +
+ + type(string_t), + intent(in) + + ::libs(:) + +
+ +

+ Return Value + character(len=:), allocatable +

+ + +
+
+ +
+

public function get_compiler_id(compiler) result(id) +

+
+ + + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::compiler + +
+ +

+ Return Value + integer(kind=compiler_enum) +

+ + +
+
+ +
+

public function get_default_flags(self, release) result(flags) +

+
+ + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::self + +
+ + logical, + intent(in) + + ::release + +
+ +

+ Return Value + character(len=:), allocatable +

+ + +
+
+ +
+

public function get_export_flags(self, target_dir, target_name) result(export_flags) +

+
+ +

Generate library export flags for a shared library build

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::self +

Instance of the compiler

+
+ + character(len=*), + intent(in) + + ::target_dir +

Path and package name

+
+ + character(len=*), + intent(in) + + ::target_name +

Path and package name

+
+ +

+ Return Value + character(len=:), allocatable +

+ + +
+
+ +
+

public function get_feature_flag(self, feature) result(flags) +

+
+ + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::self + +
+ + character(len=*), + intent(in) + + ::feature + +
+ +

+ Return Value + character(len=:), allocatable +

+ + +
+
+ +
+

public function get_headerpad_flags(self) result(flags) +

+
+ +

Generate header padding flags for install_name_tool compatibility on macOS

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::self + +
+ +

+ Return Value + character(len=:), allocatable +

+ + +
+
+ +
+

public function get_id(compiler) result(id) +

+
+ + + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::compiler + +
+ +

+ Return Value + integer(kind=compiler_enum) +

+ + +
+
+ +
+

public function get_include_flag(self, path) result(flags) +

+
+ + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::self + +
+ + character(len=*), + intent(in) + + ::path + +
+ +

+ Return Value + character(len=:), allocatable +

+ + +
+
+ +
+

public function get_install_name_flags(self, target_dir, target_name) result(flags) +

+
+ +

Generate install_name flag for a shared library build on macOS

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::self + +
+ + character(len=*), + intent(in) + + ::target_dir + +
+ + character(len=*), + intent(in) + + ::target_name + +
+ +

+ Return Value + character(len=:), allocatable +

+ + +
+
+ +
+

public function get_macros(id, macros_list, version) result(macros) +

+
+ +

This function will parse and read the macros list and +return them as defined flags. +Set macro defintion symbol on the basis of compiler used +Check if macros are not allocated. +Split the macro name and value.

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + integer(kind=compiler_enum), + intent(in) + + ::id + +
+ + type(string_t), + intent(in), + allocatable + ::macros_list(:) + +
+ + character(len=:), + intent(in), + allocatable + ::version + +
+ +

+ Return Value + character(len=:), allocatable +

+ + +
+
+ +
+

public function get_module_flag(self, path) result(flags) +

+
+ + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::self + +
+ + character(len=*), + intent(in) + + ::path + +
+ +

+ Return Value + character(len=:), allocatable +

+ + +
+
+ +
+

public function get_shared_flag(self) result(shared_flag) +

+
+ + + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::self + +
+ +

+ Return Value + character(len=:), allocatable +

+ + +
+
+ +
+

public pure function is_gnu(self) +

+
+ + + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::self + +
+ +

+ Return Value + logical +

+ + +
+
+ +
+

public pure function is_intel(self) +

+
+ + + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::self + +
+ +

+ Return Value + logical +

+ + +
+
+ +
+

public pure function is_unknown(self) +

+
+ + + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::self + +
+ +

+ Return Value + logical +

+ + +
+
+ +
+

public function with_qp(self) +

+
+ +

Check if the current compiler supports 128-bit real precision

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::self +

Instance of the compiler object

+
+ +

+ Return Value + logical +

+ + +
+
+ +
+

public function with_xdp(self) +

+
+ +

Check if the current compiler supports 80-bit “extended” real precision

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::self +

Instance of the compiler object

+
+ +

+ Return Value + logical +

+ + +
+
+ +
+
+ +
+

Subroutines

+
+

public subroutine append_clean_flags(flags, new_flags) +

+
+ +

Append new flags to existing flags, removing duplicates and empty flags (string version)

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=:), + intent(inout), + allocatable + ::flags + +
+ + character(len=*), + intent(in) + + ::new_flags + +
+ + +
+
+ +
+

public subroutine append_clean_flags_array(flags_array, new_flags_array) +

+
+ +

Append new flags to existing flags, removing duplicates and empty flags (array version)

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(string_t), + intent(inout), + allocatable + ::flags_array(:) + +
+ + type(string_t), + intent(in) + + ::new_flags_array(:) + +
+ + +
+
+ +
+

public subroutine compile_c(self, input, output, args, log_file, stat, table, dry_run) +

+
+ +

Compile a C object

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::self +

Instance of the compiler object

+
+ + character(len=*), + intent(in) + + ::input +

Source file input

+
+ + character(len=*), + intent(in) + + ::output +

Output file of object

+
+ + character(len=*), + intent(in) + + ::args +

Arguments for compiler

+
+ + character(len=*), + intent(in) + + ::log_file +

Compiler output log file

+
+ + integer, + intent(out) + + ::stat +

Status flag

+
+ + type(compile_command_table_t), + intent(inout),optional + + ::table +

Optional compile_commands table

+
+ + logical, + intent(in),optional + + ::dry_run +

Optional mocking

+
+ + +
+
+ +
+

public subroutine compile_cpp(self, input, output, args, log_file, stat, table, dry_run) +

+
+ +

Compile a CPP object

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::self +

Instance of the compiler object

+
+ + character(len=*), + intent(in) + + ::input +

Source file input

+
+ + character(len=*), + intent(in) + + ::output +

Output file of object

+
+ + character(len=*), + intent(in) + + ::args +

Arguments for compiler

+
+ + character(len=*), + intent(in) + + ::log_file +

Compiler output log file

+
+ + integer, + intent(out) + + ::stat +

Status flag

+
+ + type(compile_command_table_t), + intent(inout),optional + + ::table +

Optional compile_commands table

+
+ + logical, + intent(in),optional + + ::dry_run +

Optional mocking

+
+ + +
+
+ +
+

public subroutine compile_fortran(self, input, output, args, log_file, stat, table, dry_run) +

+
+ +

Compile a Fortran object

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::self +

Instance of the compiler object

+
+ + character(len=*), + intent(in) + + ::input +

Source file input

+
+ + character(len=*), + intent(in) + + ::output +

Output file of object

+
+ + character(len=*), + intent(in) + + ::args +

Arguments for compiler

+
+ + character(len=*), + intent(in) + + ::log_file +

Compiler output log file

+
+ + integer, + intent(out) + + ::stat +

Status flag

+
+ + type(compile_command_table_t), + intent(inout),optional + + ::table +

Optional compile_commands table

+
+ + logical, + intent(in),optional + + ::dry_run +

Optional mocking

+
+ + +
+
+ +
+

public subroutine compiler_dump(self, table, error) +

+
+ +

Dump dependency to toml table

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(inout) + + ::self +

Instance of the serializable object

+
+ + type(toml_table), + intent(inout) + + ::table +

Data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + +
+
+ +
+

public subroutine compiler_load(self, table, error) +

+
+ +

Read dependency from toml table (no checks made at this stage)

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(inout) + + ::self +

Instance of the serializable object

+
+ + type(toml_table), + intent(inout) + + ::table +

Data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + +
+
+ +
+

public subroutine dump_to_toml(self, table, error) +

+
+ +

Dump dependency to toml table

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(archiver_t), + intent(inout) + + ::self +

Instance of the serializable object

+
+ + type(toml_table), + intent(inout) + + ::table +

Data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + +
+
+ +
+

public subroutine get_debug_compile_flags(id, flags) +

+
+ + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + integer(kind=compiler_enum), + intent(in) + + ::id + +
+ + character(len=:), + intent(out), + allocatable + ::flags + +
+ + +
+
+ +
+

public subroutine get_default_c_compiler(f_compiler, c_compiler) +

+
+ + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::f_compiler + +
+ + character(len=:), + intent(out), + allocatable + ::c_compiler + +
+ + +
+
+ +
+

public subroutine get_default_cxx_compiler(f_compiler, cxx_compiler) +

+
+ +

Get C++ Compiler.

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::f_compiler + +
+ + character(len=:), + intent(out), + allocatable + ::cxx_compiler + +
+ + +
+
+ +
+

public subroutine get_main_flags(self, language, flags) +

+
+ +

Get special flags for the main linker

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::self + +
+ + character(len=*), + intent(in) + + ::language + +
+ + character(len=:), + intent(out), + allocatable + ::flags + +
+ + +
+
+ +
+

public subroutine get_release_compile_flags(id, flags) +

+
+ + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + integer(kind=compiler_enum), + intent(in) + + ::id + +
+ + character(len=:), + intent(out), + allocatable + ::flags + +
+ + +
+
+ +
+

public subroutine link_executable(self, output, args, log_file, stat, dry_run) +

+
+ +

Link an executable

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::self +

Instance of the compiler object

+
+ + character(len=*), + intent(in) + + ::output +

Output file of object

+
+ + character(len=*), + intent(in) + + ::args +

Arguments for compiler

+
+ + character(len=*), + intent(in) + + ::log_file +

Compiler output log file

+
+ + integer, + intent(out) + + ::stat +

Status flag

+
+ + logical, + intent(in),optional + + ::dry_run +

Optional mocking

+
+ + +
+
+ +
+

public subroutine link_shared(self, output, args, log_file, stat, dry_run) +

+
+ +

Link a shared library

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::self +

Instance of the compiler object

+
+ + character(len=*), + intent(in) + + ::output +

Output file of shared library object

+
+ + character(len=*), + intent(in) + + ::args +

Arguments for the compiler

+
+ + character(len=*), + intent(in) + + ::log_file +

Compiler output log file

+
+ + integer, + intent(out) + + ::stat +

Status flag

+
+ + logical, + intent(in),optional + + ::dry_run +

Optional mocking

+
+ + +
+
+ +
+

public subroutine load_from_toml(self, table, error) +

+
+ +

Read dependency from toml table (no checks made at this stage)

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(archiver_t), + intent(inout) + + ::self +

Instance of the serializable object

+
+ + type(toml_table), + intent(inout) + + ::table +

Data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + +
+
+ +
+

public subroutine make_archive(self, output, args, log_file, stat, dry_run) +

+
+ +

Create an archive

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(archiver_t), + intent(in) + + ::self +

Instance of the archiver object

+
+ + character(len=*), + intent(in) + + ::output +

Name of the archive to generate

+
+ + type(string_t), + intent(in) + + ::args(:) +

Object files to include into the archive

+
+ + character(len=*), + intent(in) + + ::log_file +

Compiler output log file

+
+ + integer, + intent(out) + + ::stat +

Status flag

+
+ + logical, + intent(in),optional + + ::dry_run +

Optional mocking

+
+ + +
+
+ +
+

public subroutine new_archiver(self, ar, echo, verbose) +

+
+ +

Create new archiver instance

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(archiver_t), + intent(out) + + ::self +

New instance of the archiver

+
+ + character(len=*), + intent(in) + + ::ar +

User provided archiver command

+
+ + logical, + intent(in) + + ::echo +

Echo compiler command

+
+ + logical, + intent(in) + + ::verbose +

Verbose mode: dump compiler output

+
+ + +
+
+ +
+

public subroutine new_compiler(self, fc, cc, cxx, echo, verbose) +

+
+ +

Create new compiler instance

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(compiler_t), + intent(out) + + ::self +

New instance of the compiler

+
+ + character(len=*), + intent(in) + + ::fc +

Fortran compiler name or path

+
+ + character(len=*), + intent(in) + + ::cc +

C compiler name or path

+
+ + character(len=*), + intent(in) + + ::cxx +

C++ Compiler name or path

+
+ + logical, + intent(in) + + ::echo +

Echo compiler command

+
+ + logical, + intent(in) + + ::verbose +

Verbose mode: dump compiler output

+
+ + +
+
+ +
+

public pure subroutine set_cpp_preprocessor_flags(id, flags) +

+
+ +

Modify the flag_cpp_preprocessor on the basis of the compiler.

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + integer(kind=compiler_enum), + intent(in) + + ::id + +
+ + character(len=:), + intent(inout), + allocatable + ::flags + +
+ + +
+
+ +
+

public subroutine tokenize_flags(flags, flags_array) +

+
+ +

Tokenize a string into an array of compiler flags

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::flags + +
+ + type(string_t), + intent(out), + allocatable + ::flags_array(:) + +
+ + +
+
+ +
+

public subroutine write_response_file(name, argv) +

+
+ +

Response files allow to read command line options from files. +Whitespace is used to separate the arguments, we will use newlines +as separator to create readable response files which can be inspected +in case of errors.

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::name + +
+ + type(string_t), + intent(in) + + ::argv(:) + +
+ + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_dependency.html b/module/fpm_dependency.html new file mode 100644 index 0000000000..00b6caf218 --- /dev/null +++ b/module/fpm_dependency.html @@ -0,0 +1,1260 @@ + + + + + + + + + + + + + fpm_dependency – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_dependency + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+
+ + +
+ +
+

Dependency management

+

Fetching dependencies and creating a dependency tree

+

Dependencies on the top-level can be specified from:

+
    +
  • package%dependencies
  • +
  • package%dev_dependencies
  • +
  • package%executable(:)%dependencies
  • +
  • package%test(:)%dependencies
  • +
+

Each dependency is fetched in some way and provides a path to its package +manifest. +The package%dependencies of the dependencies are resolved recursively.

+

To initialize the dependency tree all dependencies are recursively fetched +and stored in a flat data structure to avoid retrieving a package twice. +The data structure used to store this information should describe the current +status of the dependency tree. Important information are:

+
    +
  • name of the package
  • +
  • version of the package
  • +
  • path to the package root
  • +
+

Additionally, for version controlled dependencies the following should be +stored along with the package:

+
    +
  • the upstream url
  • +
  • the current checked out revision
  • +
+

Fetching a remote (version controlled) dependency turns it for our purpose +into a local path dependency which is handled by the same means.

+

Updating dependencies

+

For a given dependency tree all top-level dependencies can be updated. +We have two cases to consider, a remote dependency and a local dependency, +again, remote dependencies turn into local dependencies by fetching. +Therefore we will update remote dependencies by simply refetching them.

+

For remote dependencies we have to refetch if the revision in the manifest +changes or the upstream HEAD has changed (for branches and tags).

+
+

Note

+

For our purpose a tag is just a fancy branch name. Tags can be delete and + modified afterwards, therefore they do not differ too much from branches + from our perspective.

+
+

For the latter case we only know if we actually fetch from the upstream URL.

+

In case of local (and fetched remote) dependencies we have to read the package +manifest and compare its dependencies against our dependency tree, any change +requires updating the respective dependencies as well.

+

Handling dependency compatibilties

+

Currenly ignored. First come, first serve.

+
+ + +
+ + + + +
+

Interfaces

+
+
+ +

public interface resize +

+
+
+

Overloaded reallocation interface

+
+
    +
  • +

    + private pure subroutine resize_dependency_node(var, n) + +

    +

    Reallocate a list of dependencies

    + +

    Arguments

    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    TypeIntentOptional AttributesName
    + + type(dependency_node_t), + intent(inout), + allocatable + ::var(:) +

    Instance of the array to be resized

    +
    + + integer, + intent(in),optional + + ::n +

    Dimension of the final array size

    +
    + + +
  • +
+
+ +
+
+ + +
+

Derived Types

+
+
+ +

+ type, public, extends(dependency_config_t) ::  + dependency_node_t + +

+
+
+

Dependency node in the projects dependency tree

+ +

Components

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + logical, + public + + ::cached =.false. +

Dependency was loaded from a cache

+
+ + logical, + public + + ::done =.false. +

Dependency is handled

+
+ + type(git_target_t), + public, + allocatable + ::git +

Git descriptor

+
+ + character(len=:), + public, + allocatable + ::name +

Name of the dependency

+
+ + character(len=:), + public, + allocatable + ::namespace +

Namespace which the dependency belongs to. +Enables multiple dependencies with the same name. +Required for dependencies that are obtained via the official registry.

+
+ + type(string_t), + public, + allocatable + ::package_dep(:) +

Package dependencies of this node

+
+ + character(len=:), + public, + allocatable + ::path +

Local target

+
+ + type(preprocess_config_t), + public, + allocatable + ::preprocess(:) +

Requested macros for the dependency

+
+ + character(len=:), + public, + allocatable + ::proj_dir +

Installation prefix of this dependencies

+
+ + type(version_t), + public, + allocatable + ::requested_version +

The requested version of the dependency. +The latest version is used if not specified.

+
+ + character(len=:), + public, + allocatable + ::revision +

Checked out revision of the version control system

+
+ + logical, + public + + ::update =.false. +

Dependency should be updated

+
+ + type(version_t), + public, + allocatable + ::version +

Actual version of this dependency

+
+ + + + +

Type-Bound Procedures

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
procedure, public :: + add_preprocess

Add a preprocessor configuration

generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit
procedure, public :: + dump_to_toml => node_dump_to_toml
procedure, public :: + get_from_registry

Get dependency from the registry.

procedure, public :: + info

Print information on this instance

generic, public :: + load => load_from_toml, load_from_file, load_from_unit
procedure, public :: + load_from_toml => node_load_from_toml
generic, public :: + operator(==) => serializable_is_same
procedure, public :: + register

Update dependency from project manifest.

procedure, public :: + serializable_is_same => dependency_node_is_same

Serialization interface

procedure, public, non_overridable :: + test_serialization

Test load/write roundtrip

+
+
+ +
+
+ +

+ type, public, extends(serializable_t) ::  + dependency_tree_t + +

+
+
+

Respresentation of a projects dependencies

Read more… + +

Components

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=:), + public, + allocatable + ::cache +

Cache file

+
+ + type(dependency_node_t), + public, + allocatable + ::dep(:) +

Flattend list of all dependencies

+
+ + character(len=:), + public, + allocatable + ::dep_dir +

Installation prefix for dependencies

+
+ + integer, + public + + ::ndep =0 +

Number of currently registered dependencies

+
+ + character(len=:), + public, + allocatable + ::path_to_config +

Custom path to the global config file

+
+ + integer, + public + + ::unit =output_unit +

Unit for IO

+
+ + integer, + public + + ::verbosity =1 +

Verbosity of printout

+
+ + + + +

Type-Bound Procedures

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
generic, public :: + add => add_project, add_project_dependencies, add_dependencies, add_dependency, add_dependency_node

Overload procedure to add new dependencies to the tree

generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit
generic, public :: + dump_cache => dump_cache_to_file, dump_cache_to_unit, dump_cache_to_toml

Writing of dependency tree

procedure, public :: + dump_to_toml => tree_dump_to_toml
generic, public :: + find => find_name

Find a dependency in the tree

procedure, public :: + finished

Depedendncy resolution finished

generic, public :: + has => has_dependency

True if entity can be found

generic, public :: + load => load_from_toml, load_from_file, load_from_unit
generic, public :: + load_cache => load_cache_from_file, load_cache_from_unit, load_cache_from_toml

Reading of dependency tree

procedure, public :: + load_from_toml => tree_load_from_toml
procedure, public :: + local_link_order

Establish local link order for a node’s package dependencies

generic, public :: + operator(==) => serializable_is_same
generic, public :: + resolve => resolve_dependencies, resolve_dependency

Resolve dependencies

procedure, public :: + serializable_is_same => dependency_tree_is_same

Serialization interface

procedure, public, non_overridable :: + test_serialization

Test load/write roundtrip

generic, public :: + update => update_dependency, update_tree

Update dependency tree

+
+
+ +
+
+ + +
+

Subroutines

+
+

public subroutine check_and_read_pkg_data(json, node, download_url, version, error) +

+
+ + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(json_object), + intent(inout) + + ::json + +
+ + class(dependency_node_t), + intent(in) + + ::node + +
+ + character(len=:), + intent(out), + allocatable + ::download_url + +
+ + type(version_t), + intent(out) + + ::version + +
+ + type(error_t), + intent(out), + allocatable + ::error + +
+ + +
+
+ +
+

public elemental subroutine destroy_dependency_node(self) +

+
+ +

Destructor

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(dependency_node_t), + intent(inout) + + ::self + +
+ + +
+
+ +
+

public subroutine new_dependency_node(self, dependency, version, proj_dir, update) +

+
+ +

Create a new dependency node from a configuration

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(dependency_node_t), + intent(out) + + ::self +

Instance of the dependency node

+
+ + type(dependency_config_t), + intent(in) + + ::dependency +

Dependency configuration data

+
+ + type(version_t), + intent(in),optional + + ::version +

Version of the dependency

+
+ + character(len=*), + intent(in),optional + + ::proj_dir +

Installation prefix of the dependency

+
+ + logical, + intent(in),optional + + ::update +

Dependency should be updated

+
+ + +
+
+ +
+

public subroutine new_dependency_tree(self, verbosity, cache, path_to_config) +

+
+ +

Create a new dependency tree

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(dependency_tree_t), + intent(out) + + ::self +

Instance of the dependency tree

+
+ + integer, + intent(in),optional + + ::verbosity +

Verbosity of printout

+
+ + character(len=*), + intent(in),optional + + ::cache +

Name of the cache file

+
+ + character(len=*), + intent(in),optional + + ::path_to_config +

Path to the global config file.

+
+ + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_downloader.html b/module/fpm_downloader.html new file mode 100644 index 0000000000..caaf4faca5 --- /dev/null +++ b/module/fpm_downloader.html @@ -0,0 +1,269 @@ + + + + + + + + + + + + + fpm_downloader – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_downloader + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+
+ + +
+ +
+ +
+

Uses

+
+ +
+
+ + +
+ + + + + + +
+

Derived Types

+
+
+ +

+ type, public ::  + downloader_t + +

+
+
+

This type could be entirely avoided but it is quite practical because it can be mocked for testing.

+ + + + +

Type-Bound Procedures

+ + + + + + + + + + + + + + + + + + + +
procedure, public, nopass :: + get_file
procedure, public, nopass :: + get_pkg_data
procedure, public, nopass :: + unpack
procedure, public, nopass :: + upload_form
+
+
+ +
+
+ + + + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_environment.html b/module/fpm_environment.html new file mode 100644 index 0000000000..1c559289f5 --- /dev/null +++ b/module/fpm_environment.html @@ -0,0 +1,827 @@ + + + + + + + + + + + + + fpm_environment – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_environment + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+
+ + +
+ +
+

This module contains procedures that interact with the programming environment.

+
    +
  • [get_os_type] – Determine the OS type
  • +
  • [get_env] – return the value of an environment variable
  • +
+
+

Uses

+ +
+ + +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + integer, + public, +parameter + ::OS_CYGWIN =4 + +
+ + integer, + public, +parameter + ::OS_FREEBSD =6 + +
+ + integer, + public, +parameter + ::OS_LINUX =1 + +
+ + integer, + public, +parameter + ::OS_MACOS =2 + +
+ + integer, + public, +parameter + ::OS_OPENBSD =7 + +
+ + integer, + public, +parameter + ::OS_SOLARIS =5 + +
+ + integer, + public, +parameter + ::OS_UNKNOWN =0 + +
+ + integer, + public, +parameter + ::OS_WINDOWS =3 + +
+ +
+
+ + + + + +
+

Functions

+
+

public pure function OS_NAME(os) +

+
+ +

Return string describing the OS type flag

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + integer, + intent(in) + + ::os + +
+ +

+ Return Value + character(len=:), allocatable +

+ + +
+
+ +
+

public function delete_env(name) result(success) +

+
+ +

Deletes an environment variable for the current environment using the C standard library +Returns an error if the variable did not exist in the first place

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::name +

Variable name

+
+ +

+ Return Value + logical +

+ + +
+
+ +
+

public function get_command_arguments_quoted() result(args) +

+
+ + + +

Arguments

+ None +

+ Return Value + character(len=:), allocatable +

+ + +
+
+ +
+

public function get_env(NAME, DEFAULT) result(VALUE) +

+
+ +

get named environment variable value. It it is blank or + not set return the optional default value +!print , NAME, ” is not defined in the environment. Strange…” +!print , “This processor doesn’t support environment variables. Boooh!”

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::NAME +

name of environment variable to get the value of

+
+ + character(len=*), + intent(in),optional + + ::DEFAULT +

default value to return if the requested value is undefined or blank

+
+ +

+ Return Value + character(len=:), allocatable +

+

the returned value

+ +
+
+ +
+

public function get_os_type() result(r) +

+
+ +

Determine the OS type

Read more… + +

Arguments

+ None +

+ Return Value + integer +

+ + +
+
+ +
+

public pure function library_filename(package_name, shared, import, target_os) result(name) +

+
+ +

Utility function: return library filename

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::package_name + +
+ + logical, + intent(in) + + ::shared +

Whether it’s a shared library

+
+ + logical, + intent(in) + + ::import +

Whether it’s for linking (import library) or actual library

+
+ + integer, + intent(in) + + ::target_os +

Build target OS: one of OS_WINDOWS, OS_MACOS, …

+
+ +

+ Return Value + character(len=:), allocatable +

+ + +
+
+ +
+

public function os_is_unix(os) +

+
+ +

Compare the output of get_os_type or the optional +passed INTEGER value to the value for OS_WINDOWS +and return .TRUE. if they match and .FALSE. otherwise

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + integer, + intent(in),optional + + ::os + +
+ +

+ Return Value + logical +

+ + +
+
+ +
+

public function separator() result(sep) +

+
+ +

sample usage

Read more… + +

Arguments

+ None +

+ Return Value + character(len=1) +

+

ifort_bug*!character(len=1),save :: sep_cache=’ ‘

+ +
+
+ +
+

public function set_env(name, value, overwrite) +

+
+ +

Set an environment variable for the current environment using the C standard library

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::name +

Variable name

+
+ + character(len=*), + intent(in) + + ::value +

Variable value

+
+ + logical, + intent(in),optional + + ::overwrite +

Should a former value be overwritten? default = .true.

+
+ +

+ Return Value + logical +

+ + +
+
+ +
+
+ + + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_error.html b/module/fpm_error.html new file mode 100644 index 0000000000..10b9c70d31 --- /dev/null +++ b/module/fpm_error.html @@ -0,0 +1,716 @@ + + + + + + + + + + + + + fpm_error – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_error + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+
+ + +
+ +
+

Implementation of basic error handling.

+
+

Uses

+
+ +
+
+ + +
+ + + + + + +
+

Derived Types

+
+
+ +

+ type, public ::  + error_t + +

+
+
+

Data type defining an error

+ +

Components

+ + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=:), + public, + allocatable + ::message +

Error message

+
+ + + + +
+
+ +
+
+ +
+

Functions

+
+

public function bad_name_error(error, label, name) +

+
+ + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(error_t), + intent(out), + allocatable + ::error +

Instance of the error data

+
+ + character(len=*), + intent(in) + + ::label +

Error message label to add to message

+
+ + character(len=*), + intent(in) + + ::name +

name value to check

+
+ +

+ Return Value + logical +

+ + +
+
+ +
+
+ +
+

Subroutines

+
+

public subroutine fatal_error(error, message) +

+
+ +

Generic fatal runtime error

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(error_t), + intent(out), + allocatable + ::error +

Instance of the error data

+
+ + character(len=*), + intent(in) + + ::message +

Error message

+
+ + +
+
+ +
+

public subroutine file_not_found_error(error, file_name) +

+
+ +

Error created when a file is missing or not found

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(error_t), + intent(out), + allocatable + ::error +

Instance of the error data

+
+ + character(len=*), + intent(in) + + ::file_name +

Name of the missing file

+
+ + +
+
+ +
+

public subroutine file_parse_error(error, file_name, message, line_num, line_string, line_col) +

+
+ +

Error created when file parsing fails

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(error_t), + intent(out), + allocatable + ::error +

Instance of the error data

+
+ + character(len=*), + intent(in) + + ::file_name +

Name of file

+
+ + character(len=*), + intent(in) + + ::message +

Parse error message

+
+ + integer, + intent(in),optional + + ::line_num +

Line number of parse error

+
+ + character(len=*), + intent(in),optional + + ::line_string +

Line context string

+
+ + integer, + intent(in),optional + + ::line_col +

Line context column

+
+ + +
+
+ +
+

public subroutine fpm_stop(value, message) +

+
+ + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + integer, + intent(in) + + ::value +

value to use on STOP

+
+ + character(len=*), + intent(in) + + ::message +

Error message

+
+ + +
+
+ +
+

public subroutine syntax_error(error, message) +

+
+ + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(error_t), + intent(out), + allocatable + ::error +

Instance of the error data

+
+ + character(len=*), + intent(in) + + ::message +

Error message

+
+ + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_filesystem.html b/module/fpm_filesystem.html new file mode 100644 index 0000000000..7ca9fb7c47 --- /dev/null +++ b/module/fpm_filesystem.html @@ -0,0 +1,1972 @@ + + + + + + + + + + + + + fpm_filesystem – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_filesystem + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

This module contains general routines for interacting with the file system

+

Directories are not files for the Intel compilers. If so, also use this compiler-dependent extension

+
+ + +
+ + + + + + + +
+

Functions

+
+

public function basename(path, suffix) result(base) +

+
+ +

Extract filename from path with/without suffix

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::path + +
+ + logical, + intent(in),optional + + ::suffix + +
+ +

+ Return Value + character(len=:), allocatable +

+ + +
+
+ +
+

public function canon_path(path) +

+
+ +

Canonicalize path for comparison +* Handles path string redundancies +* Does not test existence of path

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::path + +
+ +

+ Return Value + character(len=:), allocatable +

+ + +
+
+ +
+

public function dirname(path) result(dir) +

+
+ +

Extract dirname from path

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::path + +
+ +

+ Return Value + character(len=:), allocatable +

+ + +
+
+ +
+

public function exists(filename) result(r) +

+
+ +

test if pathname already exists

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::filename + +
+ +

+ Return Value + logical +

+ + +
+
+ +
+

public function get_dos_path(path, error) +

+
+ +

Ensure a windows path is converted to an 8.3 DOS path if it contains spaces +No need to convert if there are no spaces

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::path + +
+ + type(error_t), + intent(out), + allocatable + ::error + +
+ +

+ Return Value + character(len=:), allocatable +

+ + +
+
+ +
+

public function get_local_prefix(os) result(prefix) +

+
+ +

Determine the path prefix to the local folder. Used for installation, registry etc.

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + integer, + intent(in),optional + + ::os +

Platform identifier

+
+ +

+ Return Value + character(len=:), allocatable +

+

Installation prefix

+ +
+
+ +
+

public function get_temp_filename() result(tempfile) +

+
+ +

Get a unused temporary filename + Calls posix ‘tempnam’ - not recommended, but + we have no security concerns for this application + and use here is temporary. +Works with MinGW

+ +

Arguments

+ None +

+ Return Value + character(len=:), allocatable +

+ + +
+
+ +
+

public function is_absolute_path(path, is_unix) +

+
+ +

Returns .true. if provided path is absolute.

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::path + +
+ + logical, + intent(in),optional + + ::is_unix + +
+ +

+ Return Value + logical +

+ + +
+
+ +
+

public function is_dir(dir) +

+
+ +

test if a name matches an existing directory path

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::dir + +
+ +

+ Return Value + logical +

+ + +
+
+ +
+

public function is_hidden_file(file_basename) result(r) +

+
+ +

test if a file is hidden

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::file_basename + +
+ +

+ Return Value + logical +

+ + +
+
+ +
+

public function join_path(a1, a2, a3, a4, a5) result(path) +

+
+ +

Construct path by joining strings with os file separator

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::a1 + +
+ + character(len=*), + intent(in) + + ::a2 + +
+ + character(len=*), + intent(in),optional + + ::a3 + +
+ + character(len=*), + intent(in),optional + + ::a4 + +
+ + character(len=*), + intent(in),optional + + ::a5 + +
+ +

+ Return Value + character(len=:), allocatable +

+ + +
+
+ +
+

public function number_of_rows(s) result(nrows) +

+
+ +

Determine number or rows in a file given a LUN

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + integer, + intent(in) + + ::s + +
+ +

+ Return Value + integer +

+ + +
+
+ +
+

public function parent_dir(path) result(dir) +

+
+ +

Extract dirname from path

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::path + +
+ +

+ Return Value + character(len=:), allocatable +

+ + +
+
+ +
+

public function read_lines(filename) result(lines) +

+
+ +

read lines into an array of TYPE(STRING_T) variables

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::filename + +
+ +

+ Return Value + type(string_t), allocatable, (:) +

+ + +
+
+ +
+

public function read_lines_expanded(filename) result(lines) +

+
+ +

read lines into an array of TYPE(STRING_T) variables expanding tabs

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::filename + +
+ +

+ Return Value + type(string_t), allocatable, (:) +

+ + +
+
+ +
+

public function unix_path(path) result(nixpath) +

+
+ +

Replace file system separators for unix

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::path + +
+ +

+ Return Value + character(len=:), allocatable +

+ + +
+
+ +
+

public function which(command) result(pathname) +

+
+
+
Author
John S. Urban
+
License
Public Domain
+
+ +

function which(command) result(pathname)

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::command + +
+ +

+ Return Value + character(len=:), allocatable +

+ + +
+
+ +
+

public function windows_path(path) result(winpath) +

+
+ +

Replace file system separators for windows

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::path + +
+ +

+ Return Value + character(len=:), allocatable +

+ + +
+
+ +
+
+ +
+

Subroutines

+
+

public subroutine delete_file(file) +

+
+ +

delete a file by filename

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::file + +
+ + +
+
+ +
+

public subroutine execute_and_read_output(cmd, output, error, verbose) +

+
+ +

Execute command line and return output as a string.

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::cmd +

Command to execute.

+
+ + character(len=:), + intent(out), + allocatable + ::output +

Command line output.

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error to handle.

+
+ + logical, + intent(in),optional + + ::verbose +

Print additional information if true.

+
+ + +
+
+ +
+

public subroutine fileclose(lun, ier) +

+
+ +

simple close of a LUN. On error show message and stop (by default)

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + integer, + intent(in) + + ::lun + +
+ + integer, + intent(out),optional + + ::ier + +
+ + +
+
+ +
+

public subroutine fileopen(filename, lun, ier) +

+
+ +

procedure to open filename as a sequential “text” file

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::filename + +
+ + integer, + intent(out) + + ::lun + +
+ + integer, + intent(out),optional + + ::ier + +
+ + +
+
+ +
+

public subroutine filewrite(filename, filedata) +

+
+ +

procedure to write filedata to file filename

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::filename + +
+ + character(len=*), + intent(in) + + ::filedata(:) + +
+ + +
+
+ +
+

public subroutine get_home(home, error) +

+
+ +

Get the HOME directory on Unix and the %USERPROFILE% directory on Windows.

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=:), + intent(out), + allocatable + ::home + +
+ + type(error_t), + intent(out), + allocatable + ::error + +
+ + +
+
+ +
+

public subroutine getline(unit, line, iostat, iomsg) +

+
+
+
Author
fpm(1) contributors
+
License
MIT
+
+ +

subroutine getline(unit,line,iostat,iomsg)

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + integer, + intent(in) + + ::unit +

Formatted IO unit

+
+ + character(len=:), + intent(out), + allocatable + ::line +

Line to read

+
+ + integer, + intent(out) + + ::iostat +

Status of operation

+
+ + character(len=:), + optional, + allocatable + ::iomsg +

Error message

+
+ + +
+
+ +
+

public recursive subroutine list_files(dir, files, recurse) +

+
+ +

Get file & directory names in directory dir using iso_c_binding.

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::dir + +
+ + type(string_t), + intent(out), + allocatable + ::files(:) + +
+ + logical, + intent(in),optional + + ::recurse + +
+ + +
+
+ +
+

public subroutine mkdir(dir, echo) +

+
+ +

Create a directory. Create subdirectories as needed

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::dir + +
+ + logical, + intent(in),optional + + ::echo + +
+ + +
+
+ +
+

public subroutine os_delete_dir(is_unix, dir, echo) +

+
+ +

Delete directory using system OS remove directory commands

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + logical, + intent(in) + + ::is_unix + +
+ + character(len=*), + intent(in) + + ::dir + +
+ + logical, + intent(in),optional + + ::echo + +
+ + +
+
+ +
+

public subroutine run(cmd, echo, exitstat, verbose, redirect) +

+
+
+
Author
fpm(1) contributors
+
License
MIT
+
+ +

Execute the specified system command. Optionally

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::cmd + +
+ + logical, + intent(in),optional + + ::echo + +
+ + integer, + intent(out),optional + + ::exitstat + +
+ + logical, + intent(in),optional + + ::verbose + +
+ + character(len=*), + intent(in),optional + + ::redirect + +
+ + +
+
+ +
+

public subroutine warnwrite(fname, data) +

+
+ +

write trimmed character data to a file if it does not exist

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::fname + +
+ + character(len=*), + intent(in) + + ::data(:) + +
+ + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_git.html b/module/fpm_git.html new file mode 100644 index 0000000000..e6b0373fdd --- /dev/null +++ b/module/fpm_git.html @@ -0,0 +1,1530 @@ + + + + + + + + + + + + + fpm_git – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_git + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

Implementation for interacting with git repositories.

+
+

Uses

+
+ +
+
+ + +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=*), + public, +parameter + ::compressed_package_name ='compressed_package' +

Name of the compressed package that is generated temporarily.

+
+ + type(enum_descriptor), + public, +parameter + ::git_descriptor =enum_descriptor() +

Actual enumerator for descriptors

+
+ + character(len=*), + public, +parameter + ::out_fmt ='("#", *(1x, g0))' +

Common output format for writing to the command line

+
+ +
+
+ + + + +
+

Derived Types

+
+
+ +

+ type, public ::  + enum_descriptor + +

+
+
+

Possible git target

+ +

Components

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + integer, + public + + ::branch =201 +

Branch in git repository

+
+ + integer, + public + + ::default =200 +

Default target

+
+ + integer, + public + + ::error =-999 +

Invalid descriptor

+
+ + integer, + public + + ::revision =203 +

Commit hash

+
+ + integer, + public + + ::tag =202 +

Tag in git repository

+
+ + + + +
+
+ +
+
+ +

+ type, public, extends(serializable_t) ::  + git_target_t + +

+
+
+

Description of an git target

+ +

Components

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + integer, + public + + ::descriptor =git_descriptor%default +

Kind of the git target

+
+ + character(len=:), + public, + allocatable + ::object +

Additional descriptor of the git object

+
+ + character(len=:), + public, + allocatable + ::url +

Target URL of the git repository

+
+ + + + +

Type-Bound Procedures

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
procedure, public :: + checkout

Fetch and checkout in local directory

generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit
procedure, public :: + dump_to_toml
procedure, public :: + info

Show information on instance

generic, public :: + load => load_from_toml, load_from_file, load_from_unit
procedure, public :: + load_from_toml
generic, public :: + operator(==) => serializable_is_same
procedure, public :: + serializable_is_same => git_is_same

Serialization interface

procedure, public, non_overridable :: + test_serialization

Test load/write roundtrip

+
+
+ +
+
+ +
+

Functions

+
+

public pure function descriptor_name(descriptor) result(name) +

+
+ +

Code git descriptor to a string

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + integer, + intent(in) + + ::descriptor + +
+ +

+ Return Value + character(len=:), allocatable +

+ + +
+
+ +
+

public function git_is_same(this, that) +

+
+ +

Check that two git targets are equal +All checks passed!

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(git_target_t), + intent(in) + + ::this + +
+ + class(serializable_t), + intent(in) + + ::that + +
+ +

+ Return Value + logical +

+ + +
+
+ +
+

public function git_matches_manifest(cached, manifest, verbosity, iunit) +

+
+ +

Check that a cached dependency matches a manifest request

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(git_target_t), + intent(in) + + ::cached +

Two input git targets

+
+ + type(git_target_t), + intent(in) + + ::manifest +

Two input git targets

+
+ + integer, + intent(in) + + ::verbosity + +
+ + integer, + intent(in) + + ::iunit + +
+ +

+ Return Value + logical +

+ + +
+
+ +
+

public function git_target_branch(url, branch) result(self) +

+
+ +

Target a branch in the git repository

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::url +

Target URL of the git repository

+
+ + character(len=*), + intent(in) + + ::branch +

Name of the branch of interest

+
+ +

+ Return Value + type(git_target_t) +

+

New git target

+ +
+
+ +
+

public function git_target_default(url) result(self) +

+
+ +

Default target

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::url +

Target URL of the git repository

+
+ +

+ Return Value + type(git_target_t) +

+

New git target

+ +
+
+ +
+

public function git_target_revision(url, sha1) result(self) +

+
+ +

Target a specific git revision

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::url +

Target URL of the git repository

+
+ + character(len=*), + intent(in) + + ::sha1 +

Commit hash of interest

+
+ +

+ Return Value + type(git_target_t) +

+

New git target

+ +
+
+ +
+

public function git_target_tag(url, tag) result(self) +

+
+ +

Target a git tag

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::url +

Target URL of the git repository

+
+ + character(len=*), + intent(in) + + ::tag +

Tag name of interest

+
+ +

+ Return Value + type(git_target_t) +

+

New git target

+ +
+
+ +
+

public pure function parse_descriptor(name) +

+
+ +

Parse git descriptor identifier from a string

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::name + +
+ +

+ Return Value + integer +

+ + +
+
+ +
+
+ +
+

Subroutines

+
+

public subroutine checkout(self, local_path, error) +

+
+ + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(git_target_t), + intent(in) + + ::self +

Instance of the git target

+
+ + character(len=*), + intent(in) + + ::local_path +

Local path to checkout in

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error

+
+ + +
+
+ +
+

public subroutine dump_to_toml(self, table, error) +

+
+ +

Dump dependency to toml table

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(git_target_t), + intent(inout) + + ::self +

Instance of the serializable object

+
+ + type(toml_table), + intent(inout) + + ::table +

Data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + +
+
+ +
+

public subroutine git_archive(source, destination, ref, additional_files, verbose, error) +

+
+ +

Archive a folder using git archive.

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::source +

Directory to archive.

+
+ + character(len=*), + intent(in) + + ::destination +

Destination of the archive.

+
+ + character(len=*), + intent(in) + + ::ref +

(Symbolic) Reference to be archived.

+
+ + character(len=*), + intent(in),optional + + ::additional_files(:) +

(Optional) list of additional untracked files to be added to the archive.

+
+ + logical, + intent(in) + + ::verbose +

Print additional information if true.

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling.

+
+ + +
+
+ +
+

public subroutine git_revision(local_path, object, error) +

+
+ + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::local_path +

Local path to checkout in

+
+ + character(len=:), + intent(out), + allocatable + ::object +

Git object reference

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error

+
+ + +
+
+ +
+

public subroutine info(self, unit, verbosity) +

+
+ +

Show information on git target

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(git_target_t), + intent(in) + + ::self +

Instance of the git target

+
+ + integer, + intent(in) + + ::unit +

Unit for IO

+
+ + integer, + intent(in),optional + + ::verbosity +

Verbosity of the printout

+
+ + +
+
+ +
+

public subroutine load_from_toml(self, table, error) +

+
+ +

Read dependency from toml table (no checks made at this stage)

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(git_target_t), + intent(inout) + + ::self +

Instance of the serializable object

+
+ + type(toml_table), + intent(inout) + + ::table +

Data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_installer.html b/module/fpm_installer.html new file mode 100644 index 0000000000..70bfc91ada --- /dev/null +++ b/module/fpm_installer.html @@ -0,0 +1,651 @@ + + + + + + + + + + + + + fpm_installer – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_installer + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+
+ + +
+ +
+

Implementation of an installer object.

+

The installer provides a way to install objects to their respective directories +in the installation prefix, a generic install command allows to install +to any directory within the prefix.

+
+ + +
+ + + + + + +
+

Derived Types

+
+
+ +

+ type, public ::  + installer_t + +

+
+
+

Declaration of the installer type

+ +

Components

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=:), + public, + allocatable + ::bindir +

Binary dir relative to the installation prefix

+
+ + character(len=:), + public, + allocatable + ::copy +

Command to copy objects into the installation prefix

+
+ + character(len=:), + public, + allocatable + ::includedir +

Include directory relative to the installation prefix

+
+ + character(len=:), + public, + allocatable + ::libdir +

Library directory relative to the installation prefix

+
+ + character(len=:), + public, + allocatable + ::move +

Command to move objects into the installation prefix

+
+ + integer, + public + + ::os +

Cached operating system

+
+ + character(len=:), + public, + allocatable + ::prefix +

Path to installation directory

+
+ + character(len=:), + public, + allocatable + ::testdir +

Test program directory relative to the installation prefix

+
+ + integer, + public + + ::unit =output_unit +

Output unit for informative printout

+
+ + integer, + public + + ::verbosity =1 +

Verbosity of the installer

+
+ + + + +

Type-Bound Procedures

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
procedure, public :: + install

Install a generic file into a subdirectory in the installation prefix

procedure, public :: + install_destination

Evaluate the installation path

procedure, public :: + install_executable

Install an executable in its correct subdirectory

procedure, public :: + install_header

Install a header/module in its correct subdirectory

procedure, public :: + install_library

Install a library in its correct subdirectory

procedure, public :: + install_test

Install a test program in its correct subdirectory

procedure, public :: + make_dir

Create a new directory in the prefix, type-bound for unit testing purposes

procedure, public :: + run

Run an installation command, type-bound for unit testing purposes

+
+
+ +
+
+ + +
+

Subroutines

+
+

public subroutine new_installer(self, prefix, bindir, libdir, includedir, testdir, verbosity, copy, move) +

+
+ +

Create a new instance of an installer

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(installer_t), + intent(out) + + ::self +

Instance of the installer

+
+ + character(len=*), + intent(in),optional + + ::prefix +

Path to installation directory

+
+ + character(len=*), + intent(in),optional + + ::bindir +

Binary dir relative to the installation prefix

+
+ + character(len=*), + intent(in),optional + + ::libdir +

Library directory relative to the installation prefix

+
+ + character(len=*), + intent(in),optional + + ::includedir +

Include directory relative to the installation prefix

+
+ + character(len=*), + intent(in),optional + + ::testdir +

Test directory relative to the installation prefix

+
+ + integer, + intent(in),optional + + ::verbosity +

Verbosity of the installer

+
+ + character(len=*), + intent(in),optional + + ::copy +

Copy command

+
+ + character(len=*), + intent(in),optional + + ::move +

Move command

+
+ + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_manifest.html b/module/fpm_manifest.html new file mode 100644 index 0000000000..0185c77202 --- /dev/null +++ b/module/fpm_manifest.html @@ -0,0 +1,604 @@ + + + + + + + + + + + + + fpm_manifest – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_manifest + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+
+ + +
+ +
+

Package configuration data.

+

This module provides the necessary procedure to translate a TOML document +to the corresponding Fortran type, while verifying it with respect to +its schema.

+

Additionally, the required data types for users of this module are reexported +to hide the actual implementation details.

+
+ + +
+ + + + + + + + +
+

Subroutines

+
+

public subroutine default_example(self, name) +

+
+ +

Populate test in case we find the default example/ directory

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(example_config_t), + intent(out) + + ::self +

Instance of the executable meta data

+
+ + character(len=*), + intent(in) + + ::name +

Name of the package

+
+ + +
+
+ +
+

public subroutine default_executable(self, name) +

+
+ +

Populate executable in case we find the default app directory

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(executable_config_t), + intent(out) + + ::self +

Instance of the executable meta data

+
+ + character(len=*), + intent(in) + + ::name +

Name of the package

+
+ + +
+
+ +
+

public subroutine default_library(self) +

+
+ +

Populate library in case we find the default src directory

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(library_config_t), + intent(out) + + ::self +

Instance of the library meta data

+
+ + +
+
+ +
+

public subroutine default_test(self, name) +

+
+ +

Populate test in case we find the default test/ directory

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(test_config_t), + intent(out) + + ::self +

Instance of the executable meta data

+
+ + character(len=*), + intent(in) + + ::name +

Name of the package

+
+ + +
+
+ +
+

public subroutine get_package_data(package, file, error, apply_defaults) +

+
+ +

Obtain package meta data from a configuation file

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(package_config_t), + intent(out) + + ::package +

Parsed package meta data

+
+ + character(len=*), + intent(in) + + ::file +

Name of the package configuration file

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error status of the operation

+
+ + logical, + intent(in),optional + + ::apply_defaults +

Apply package defaults (uses file system operations)

+
+ + +
+
+ +
+

public subroutine get_package_dependencies(package, main, deps) +

+
+ + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(package_config_t), + intent(in) + + ::package +

Parsed package meta data

+
+ + logical, + intent(in) + + ::main +

Is the main project

+
+ + type(dependency_config_t), + intent(out), + allocatable + ::deps(:) +

Unprocessed list of all dependencies listed in this manifest

+
+ + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_manifest_build.html b/module/fpm_manifest_build.html new file mode 100644 index 0000000000..893c4379bf --- /dev/null +++ b/module/fpm_manifest_build.html @@ -0,0 +1,528 @@ + + + + + + + + + + + + + fpm_manifest_build – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_manifest_build + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+
+ + +
+ +
+

Implementation of the build configuration data.

+

A build table can currently have the following fields

+
[build]
+auto-executables = bool
+auto-examples = bool
+auto-tests = bool
+link = ["lib"]
+
+
+

Uses

+
+ +
+
+ + +
+ + + + + + +
+

Derived Types

+
+
+ +

+ type, public, extends(serializable_t) ::  + build_config_t + +

+
+
+

Configuration data for build

+ +

Components

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + logical, + public + + ::auto_examples =.true. +

Automatic discovery of examples

+
+ + logical, + public + + ::auto_executables =.true. +

Automatic discovery of executables

+
+ + logical, + public + + ::auto_tests =.true. +

Automatic discovery of tests

+
+ + type(string_t), + public, + allocatable + ::external_modules(:) +

External modules to use

+
+ + type(string_t), + public, + allocatable + ::link(:) +

Libraries to link against

+
+ + logical, + public + + ::module_naming =.false. +

Enforcing of package module names

+
+ + type(string_t), + public + + ::module_prefix + +
+ + + + +

Type-Bound Procedures

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit
procedure, public :: + dump_to_toml
procedure, public :: + info

Print information on this instance

generic, public :: + load => load_from_toml, load_from_file, load_from_unit
procedure, public :: + load_from_toml
generic, public :: + operator(==) => serializable_is_same
procedure, public :: + serializable_is_same => build_conf_is_same

Serialization interface

procedure, public, non_overridable :: + test_serialization

Test load/write roundtrip

+
+
+ +
+
+ + +
+

Subroutines

+
+

public subroutine new_build_config(self, table, package_name, error) +

+
+ +

Construct a new build configuration from a TOML data structure

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(build_config_t), + intent(out) + + ::self +

Instance of the build configuration

+
+ + type(toml_table), + intent(inout) + + ::table +

Instance of the TOML data structure

+
+ + character(len=*), + intent(in) + + ::package_name +

Package name

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_manifest_dependency.html b/module/fpm_manifest_dependency.html new file mode 100644 index 0000000000..8f15204832 --- /dev/null +++ b/module/fpm_manifest_dependency.html @@ -0,0 +1,862 @@ + + + + + + + + + + + + + fpm_manifest_dependency – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_manifest_dependency + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+
+ + +
+ +
+

Implementation of the meta data for dependencies.

+

A dependency table can currently have the following fields

+
[dependencies]
+"dep1" = { git = "url" }
+"dep2" = { git = "url", branch = "name" }
+"dep3" = { git = "url", tag = "name" }
+"dep4" = { git = "url", rev = "sha1" }
+"dep0" = { path = "path" }
+
+ +

To reduce the amount of boilerplate code this module provides two constructors + for dependency types, one basic for an actual dependency (inline) table + and another to collect all dependency objects from a dependencies table, + which is handling the allocation of the objects and is forwarding the + individual dependency tables to their respective constructors. + The usual entry point should be the constructor for the super table.

+

This objects contains a target to retrieve required fpm projects to + build the target declaring the dependency. + Resolving a dependency will result in obtaining a new package configuration + data for the respective project.

+
+ + +
+ + + + +
+

Interfaces

+
+
+ +

public interface resize +

+
+
    +
  • +

    + private pure subroutine resize_dependency_config(var, n) + +

    +

    Reallocate a list of dependencies

    + +

    Arguments

    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    TypeIntentOptional AttributesName
    + + type(dependency_config_t), + intent(inout), + allocatable + ::var(:) +

    Instance of the array to be resized

    +
    + + integer, + intent(in),optional + + ::n +

    Dimension of the final array size

    +
    + + +
  • +
+
+ +
+
+ + +
+

Derived Types

+
+
+ +

+ type, public, extends(serializable_t) ::  + dependency_config_t + +

+
+
+

Configuration meta data for a dependency

+ +

Components

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + type(git_target_t), + public, + allocatable + ::git +

Git descriptor

+
+ + character(len=:), + public, + allocatable + ::name +

Name of the dependency

+
+ + character(len=:), + public, + allocatable + ::namespace +

Namespace which the dependency belongs to. +Enables multiple dependencies with the same name. +Required for dependencies that are obtained via the official registry.

+
+ + character(len=:), + public, + allocatable + ::path +

Local target

+
+ + type(preprocess_config_t), + public, + allocatable + ::preprocess(:) +

Requested macros for the dependency

+
+ + type(version_t), + public, + allocatable + ::requested_version +

The requested version of the dependency. +The latest version is used if not specified.

+
+ + + + +

Type-Bound Procedures

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
procedure, public :: + add_preprocess

Add a preprocessor configuration

generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit
procedure, public :: + dump_to_toml
procedure, public :: + info

Print information on this instance

generic, public :: + load => load_from_toml, load_from_file, load_from_unit
procedure, public :: + load_from_toml
generic, public :: + operator(==) => serializable_is_same
procedure, public :: + serializable_is_same => dependency_is_same

Serialization interface

procedure, public, non_overridable :: + test_serialization

Test load/write roundtrip

+
+
+ +
+
+ +
+

Functions

+
+

public function manifest_has_changed(cached, manifest, verbosity, iunit) result(has_changed) +

+
+ +

Check if two dependency configurations are different

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(dependency_config_t), + intent(in) + + ::cached +

Two instances of the dependency configuration

+
+ + class(dependency_config_t), + intent(in) + + ::manifest +

Two instances of the dependency configuration

+
+ + integer, + intent(in) + + ::verbosity +

Log verbosity

+
+ + integer, + intent(in) + + ::iunit +

Log verbosity

+
+ +

+ Return Value + logical +

+ + +
+
+ +
+
+ +
+

Subroutines

+
+

public elemental subroutine dependency_destroy(self) +

+
+ +

Clean memory

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(dependency_config_t), + intent(inout) + + ::self + +
+ + +
+
+ +
+

public subroutine new_dependencies(deps, table, root, meta, error) +

+
+ +

Construct new dependency array from a TOML data structure

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(dependency_config_t), + intent(out), + allocatable + ::deps(:) +

Instance of the dependency configuration

+
+ + type(toml_table), + intent(inout) + + ::table +

Instance of the TOML data structure

+
+ + character(len=*), + intent(in),optional + + ::root +

Root directory of the manifest

+
+ + type(metapackage_config_t), + intent(out),optional + + ::meta +

(optional) metapackages

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + +
+
+ +
+

public subroutine new_dependency(self, table, root, error) +

+
+ +

Construct a new dependency configuration from a TOML data structure

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(dependency_config_t), + intent(out) + + ::self +

Instance of the dependency configuration

+
+ + type(toml_table), + intent(inout) + + ::table +

Instance of the TOML data structure

+
+ + character(len=*), + intent(in),optional + + ::root +

Root directory of the manifest

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_manifest_example.html b/module/fpm_manifest_example.html new file mode 100644 index 0000000000..e06d5ba3d6 --- /dev/null +++ b/module/fpm_manifest_example.html @@ -0,0 +1,484 @@ + + + + + + + + + + + + + fpm_manifest_example – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_manifest_example + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+
+ + +
+ +
+

Implementation of the meta data for an example.

+

The example data structure is effectively a decorated version of an executable + and shares most of its properties, except for the defaults and can be + handled under most circumstances just like any other executable.

+

A example table can currently have the following fields

+
[[ example ]]
+name = "string"
+source-dir = "path"
+main = "file"
+link = ["lib"]
+[example.dependencies]
+
+
+ + +
+ + + + + + +
+

Derived Types

+
+
+ +

+ type, public, extends(executable_config_t) ::  + example_config_t + +

+
+
+

Configuation meta data for an example

+ +

Components

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + type(dependency_config_t), + public, + allocatable + ::dependency(:) +

Dependency meta data for this executable

+
+ + type(string_t), + public, + allocatable + ::link(:) +

Libraries to link against

+
+ + character(len=:), + public, + allocatable + ::main +

Name of the source file declaring the main program

+
+ + character(len=:), + public, + allocatable + ::name +

Name of the resulting executable

+
+ + character(len=:), + public, + allocatable + ::source_dir +

Source directory for collecting the executable

+
+ + + + +

Type-Bound Procedures

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit
procedure, public :: + dump_to_toml
procedure, public :: + info

Print information on this instance

generic, public :: + load => load_from_toml, load_from_file, load_from_unit
procedure, public :: + load_from_toml
generic, public :: + operator(==) => serializable_is_same
procedure, public :: + serializable_is_same => exe_is_same

Serialization interface

procedure, public, non_overridable :: + test_serialization

Test load/write roundtrip

+
+
+ +
+
+ + +
+

Subroutines

+
+

public subroutine new_example(self, table, error) +

+
+ +

Construct a new example configuration from a TOML data structure

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(example_config_t), + intent(out) + + ::self +

Instance of the example configuration

+
+ + type(toml_table), + intent(inout) + + ::table +

Instance of the TOML data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_manifest_executable.html b/module/fpm_manifest_executable.html new file mode 100644 index 0000000000..5b8de2126e --- /dev/null +++ b/module/fpm_manifest_executable.html @@ -0,0 +1,481 @@ + + + + + + + + + + + + + fpm_manifest_executable – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_manifest_executable + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+
+ + +
+ +
+

Implementation of the meta data for an executables.

+

An executable table can currently have the following fields

+
[[ executable ]]
+name = "string"
+source-dir = "path"
+main = "file"
+link = ["lib"]
+[executable.dependencies]
+
+
+

Uses

+ +
+ + +
+ + + + + + +
+

Derived Types

+
+
+ +

+ type, public, extends(serializable_t) ::  + executable_config_t + +

+
+
+

Configuation meta data for an executable

+ +

Components

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + type(dependency_config_t), + public, + allocatable + ::dependency(:) +

Dependency meta data for this executable

+
+ + type(string_t), + public, + allocatable + ::link(:) +

Libraries to link against

+
+ + character(len=:), + public, + allocatable + ::main +

Name of the source file declaring the main program

+
+ + character(len=:), + public, + allocatable + ::name +

Name of the resulting executable

+
+ + character(len=:), + public, + allocatable + ::source_dir +

Source directory for collecting the executable

+
+ + + + +

Type-Bound Procedures

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit
procedure, public :: + dump_to_toml
procedure, public :: + info

Print information on this instance

generic, public :: + load => load_from_toml, load_from_file, load_from_unit
procedure, public :: + load_from_toml
generic, public :: + operator(==) => serializable_is_same
procedure, public :: + serializable_is_same => exe_is_same

Serialization interface

procedure, public, non_overridable :: + test_serialization

Test load/write roundtrip

+
+
+ +
+
+ + +
+

Subroutines

+
+

public subroutine new_executable(self, table, error) +

+
+ +

Construct a new executable configuration from a TOML data structure

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(executable_config_t), + intent(out) + + ::self +

Instance of the executable configuration

+
+ + type(toml_table), + intent(inout) + + ::table +

Instance of the TOML data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_manifest_fortran.html b/module/fpm_manifest_fortran.html new file mode 100644 index 0000000000..6f29e55c1e --- /dev/null +++ b/module/fpm_manifest_fortran.html @@ -0,0 +1,432 @@ + + + + + + + + + + + + + fpm_manifest_fortran – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_manifest_fortran + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+
+ + +
+ +
+ +
+

Uses

+
+ +
+
+ + +
+ + + + + + +
+

Derived Types

+
+
+ +

+ type, public, extends(serializable_t) ::  + fortran_config_t + +

+
+
+

Configuration data for Fortran

+ +

Components

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + logical, + public + + ::implicit_external =.false. +

Enable implicit external interfaces

+
+ + logical, + public + + ::implicit_typing =.false. +

Enable default implicit typing

+
+ + character(len=:), + public, + allocatable + ::source_form +

Form to use for all Fortran sources

+
+ + + + +

Type-Bound Procedures

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit
procedure, public :: + dump_to_toml
generic, public :: + load => load_from_toml, load_from_file, load_from_unit
procedure, public :: + load_from_toml
generic, public :: + operator(==) => serializable_is_same
procedure, public :: + serializable_is_same => fortran_is_same

Serialization interface

procedure, public, non_overridable :: + test_serialization

Test load/write roundtrip

+
+
+ +
+
+ + +
+

Subroutines

+
+

public subroutine new_fortran_config(self, table, error) +

+
+ +

Construct a new build configuration from a TOML data structure

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(fortran_config_t), + intent(out) + + ::self +

Instance of the fortran configuration

+
+ + type(toml_table), + intent(inout) + + ::table +

Instance of the TOML data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_manifest_install.html b/module/fpm_manifest_install.html new file mode 100644 index 0000000000..ed6fb8f90f --- /dev/null +++ b/module/fpm_manifest_install.html @@ -0,0 +1,423 @@ + + + + + + + + + + + + + fpm_manifest_install – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_manifest_install + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+
+ + +
+ +
+

Implementation of the installation configuration.

+

An install table can currently have the following fields

+
library = bool
+
+
+

Uses

+
+ +
+
+ + +
+ + + + + + +
+

Derived Types

+
+
+ +

+ type, public, extends(serializable_t) ::  + install_config_t + +

+
+
+

Configuration data for installation

+ +

Components

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + logical, + public + + ::library =.false. +

Install library with this project

+
+ + logical, + public + + ::test =.false. +

Install tests with this project

+
+ + + + +

Type-Bound Procedures

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit
procedure, public :: + dump_to_toml
procedure, public :: + info

Print information on this instance

generic, public :: + load => load_from_toml, load_from_file, load_from_unit
procedure, public :: + load_from_toml
generic, public :: + operator(==) => serializable_is_same
procedure, public :: + serializable_is_same => install_conf_same

Serialization interface

procedure, public, non_overridable :: + test_serialization

Test load/write roundtrip

+
+
+ +
+
+ + +
+

Subroutines

+
+

public subroutine new_install_config(self, table, error) +

+
+ +

Create a new installation configuration from a TOML data structure

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(install_config_t), + intent(out) + + ::self +

Instance of the install configuration

+
+ + type(toml_table), + intent(inout) + + ::table +

Instance of the TOML data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_manifest_library.html b/module/fpm_manifest_library.html new file mode 100644 index 0000000000..a0f2dcb3d5 --- /dev/null +++ b/module/fpm_manifest_library.html @@ -0,0 +1,476 @@ + + + + + + + + + + + + + fpm_manifest_library – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_manifest_library + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+
+ + +
+ +
+

Implementation of the meta data for libraries.

+

A library table can currently have the following fields

+
[library]
+source-dir = "path"
+include-dir = ["path1","path2"]
+build-script = "file"
+
+
+

Uses

+
+ +
+
+ + +
+ + + + + + +
+

Derived Types

+
+
+ +

+ type, public, extends(serializable_t) ::  + library_config_t + +

+
+
+

Configuration meta data for a library

+ +

Components

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=:), + public, + allocatable + ::build_script +

Alternative build script to be invoked

+
+ + type(string_t), + public, + allocatable + ::include_dir(:) +

Include path prefix

+
+ + character(len=:), + public, + allocatable + ::lib_type +

Shared / Static / Monolithic library

+
+ + character(len=:), + public, + allocatable + ::source_dir +

Source path prefix

+
+ + + + +

Type-Bound Procedures

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit
procedure, public :: + dump_to_toml
procedure, public :: + info

Print information on this instance

generic, public :: + load => load_from_toml, load_from_file, load_from_unit
procedure, public :: + load_from_toml
procedure, public, non_overridable :: + monolithic

Check library types

generic, public :: + operator(==) => serializable_is_same
procedure, public :: + serializable_is_same => library_is_same

Serialization interface

procedure, public, non_overridable :: + shared
procedure, public, non_overridable :: + static
procedure, public, non_overridable :: + test_serialization

Test load/write roundtrip

+
+
+ +
+
+ + +
+

Subroutines

+
+

public subroutine new_library(self, table, error) +

+
+ +

Construct a new library configuration from a TOML data structure

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(library_config_t), + intent(out) + + ::self +

Instance of the library configuration

+
+ + type(toml_table), + intent(inout) + + ::table +

Instance of the TOML data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_manifest_metapackages.html b/module/fpm_manifest_metapackages.html new file mode 100644 index 0000000000..29b240e76c --- /dev/null +++ b/module/fpm_manifest_metapackages.html @@ -0,0 +1,737 @@ + + + + + + + + + + + + + fpm_manifest_metapackages – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_manifest_metapackages + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+
+ + +
+ +
+

Implementation of the metapackage configuration data.

+

A metapackage table can currently have the following fields

+
[metapackages]
+fpm = "0.1.0"
+openmp = bool
+stdlib = bool
+
+
+

Uses

+
+ +
+
+ + +
+ + + + + + +
+

Derived Types

+
+
+ +

+ type, public ::  + metapackage_config_t + +

+
+
+

Configuration data for metapackages

+ +

Components

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + type(metapackage_request_t), + public + + ::blas +

BLAS

+
+ + type(metapackage_request_t), + public + + ::hdf5 +

HDF5

+
+ + type(metapackage_request_t), + public + + ::minpack +

fortran-lang minpack

+
+ + type(metapackage_request_t), + public + + ::mpi +

Request MPI support

+
+ + type(metapackage_request_t), + public + + ::netcdf +

NetCDF

+
+ + type(metapackage_request_t), + public + + ::openmp +

Request OpenMP support

+
+ + type(metapackage_request_t), + public + + ::stdlib +

Request stdlib support

+
+ + + + +

Type-Bound Procedures

+ + + + + + + +
procedure, public :: + get_requests
+
+
+ +
+
+ +

+ type, public ::  + metapackage_request_t + +

+
+
+

Configuration data for a single metapackage request

+ +

Components

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=:), + public, + allocatable + ::name +

Metapackage name

+
+ + logical, + public + + ::on =.false. +

Request flag

+
+ + character(len=:), + public, + allocatable + ::version +

Version Specification string

+
+ + + + +
+
+ +
+
+ +
+

Functions

+
+

public function is_meta_package(key) +

+
+ +

Check local schema for allowed entries

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::key +

Instance of the TOML data structure

+
+ +

+ Return Value + logical +

+ + +
+
+ +
+
+ +
+

Subroutines

+
+

public subroutine new_meta_config(self, table, meta_allowed, error) +

+
+ +

Construct a new build configuration from a TOML data structure

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(metapackage_config_t), + intent(out) + + ::self +

Instance of the build configuration

+
+ + type(toml_table), + intent(inout) + + ::table +

Instance of the TOML data structure

+
+ + logical, + intent(in) + + ::meta_allowed(:) +

List of keys allowed to be metapackages

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + +
+
+ +
+

public subroutine new_meta_request(self, key, table, meta_allowed, error) +

+
+ +

Construct a new metapackage request from the dependencies table

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(metapackage_request_t), + intent(out) + + ::self + +
+ + character(len=*), + intent(in) + + ::key +

The package name

+
+ + type(toml_table), + intent(inout) + + ::table +

Instance of the TOML data structure

+
+ + logical, + intent(in),optional + + ::meta_allowed(:) +

List of keys allowed to be metapackages

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_manifest_package.html b/module/fpm_manifest_package.html new file mode 100644 index 0000000000..fb6ccebe2e --- /dev/null +++ b/module/fpm_manifest_package.html @@ -0,0 +1,749 @@ + + + + + + + + + + + + + fpm_manifest_package – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_manifest_package + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+
+ + +
+ +
+

Define the package data containing the meta data from the configuration file.

+

The package data defines a Fortran type corresponding to the respective + TOML document, after creating it from a package file no more interaction + with the TOML document is required.

+

Every configuration type provides it custom constructor (prefixed with new_) + and knows how to deserialize itself from a TOML document. + To ensure we find no untracked content in the package file all keywords are + checked and possible entries have to be explicitly allowed in the check + function. + If entries are mutally exclusive or interdependent inside the current table + the check function is required to enforce this schema on the data structure.

+

The package file root allows the following keywords

+
name = "string"
+version = "string"
+license = "string"
+author = "string"
+maintainer = "string"
+copyright = "string"
+[library]
+[dependencies]
+[dev-dependencies]
+[profiles]
+[build]
+[install]
+[fortran]
+[[ executable ]]
+[[ example ]]
+[[ test ]]
+[extra]
+
+
+ + +
+ + + + + + +
+

Derived Types

+
+
+ +

+ type, public, extends(serializable_t) ::  + package_config_t + +

+
+
+

Package meta data

+ +

Components

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=:), + public, + allocatable + ::author +

Author meta data

+
+ + type(build_config_t), + public + + ::build +

Build configuration data

+
+ + character(len=:), + public, + allocatable + ::copyright +

Copyright meta data

+
+ + type(dependency_config_t), + public, + allocatable + ::dependency(:) +

Dependency meta data

+
+ + type(dependency_config_t), + public, + allocatable + ::dev_dependency(:) +

Development dependency meta data

+
+ + type(example_config_t), + public, + allocatable + ::example(:) +

Example meta data

+
+ + type(executable_config_t), + public, + allocatable + ::executable(:) +

Executable meta data

+
+ + type(fortran_config_t), + public + + ::fortran +

Fortran meta data

+
+ + type(install_config_t), + public + + ::install +

Installation configuration data

+
+ + type(library_config_t), + public, + allocatable + ::library +

Library meta data

+
+ + character(len=:), + public, + allocatable + ::license +

License meta data

+
+ + character(len=:), + public, + allocatable + ::maintainer +

Maintainer meta data

+
+ + type(metapackage_config_t), + public + + ::meta +

Metapackage data

+
+ + character(len=:), + public, + allocatable + ::name +

Name of the package

+
+ + type(preprocess_config_t), + public, + allocatable + ::preprocess(:) +

Preprocess meta data

+
+ + type(profile_config_t), + public, + allocatable + ::profiles(:) +

Profiles meta data

+
+ + type(test_config_t), + public, + allocatable + ::test(:) +

Test meta data

+
+ + type(version_t), + public + + ::version +

Package version

+
+ + + + +

Type-Bound Procedures

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit
procedure, public :: + dump_to_toml
procedure, public :: + info

Print information on this instance

generic, public :: + load => load_from_toml, load_from_file, load_from_unit
procedure, public :: + load_from_toml
generic, public :: + operator(==) => serializable_is_same
procedure, public :: + serializable_is_same => manifest_is_same

Serialization interface

procedure, public, non_overridable :: + test_serialization

Test load/write roundtrip

+
+
+ +
+
+ + +
+

Subroutines

+
+

public subroutine new_package(self, table, root, error) +

+
+ +

Construct a new package configuration from a TOML data structure

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(package_config_t), + intent(out) + + ::self +

Instance of the package configuration

+
+ + type(toml_table), + intent(inout) + + ::table +

Instance of the TOML data structure

+
+ + character(len=*), + intent(in),optional + + ::root +

Root directory of the manifest

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_manifest_preprocess.html b/module/fpm_manifest_preprocess.html new file mode 100644 index 0000000000..aa3b36c1e6 --- /dev/null +++ b/module/fpm_manifest_preprocess.html @@ -0,0 +1,488 @@ + + + + + + + + + + + + + fpm_manifest_preprocess – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_manifest_preprocess + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+
+ + +
+ +
+

Implementation of the meta data for preprocessing.

+

A preprocess table can currently have the following fields

+
[preprocess]
+[preprocess.cpp]
+suffixes = ["F90", "f90"]
+directories = ["src/feature1", "src/models"]
+macros = []
+
+
+

Uses

+ +
+ + +
+ + + + + + +
+

Derived Types

+
+
+ +

+ type, public, extends(serializable_t) ::  + preprocess_config_t + +

+
+
+

Configuration meta data for a preprocessor

+ +

Components

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + type(string_t), + public, + allocatable + ::directories(:) +

Directories to search for files to be preprocessed

+
+ + type(string_t), + public, + allocatable + ::macros(:) +

Macros to be defined for the preprocessor

+
+ + character(len=:), + public, + allocatable + ::name +

Name of the preprocessor

+
+ + type(string_t), + public, + allocatable + ::suffixes(:) +

Suffixes of the files to be preprocessed

+
+ + + + +

Type-Bound Procedures

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
procedure, public :: + add_config
procedure, public :: + destroy

Operations

generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit
procedure, public :: + dump_to_toml
procedure, public :: + info

Print information on this instance

procedure, public :: + is_cpp

Properties

procedure, public :: + is_fypp
generic, public :: + load => load_from_toml, load_from_file, load_from_unit
procedure, public :: + load_from_toml
generic, public :: + new => new_cpp_config_with_macros, new_preprocess_config
generic, public :: + operator(==) => serializable_is_same
procedure, public :: + serializable_is_same => preprocess_is_same

Serialization interface

procedure, public, non_overridable :: + test_serialization

Test load/write roundtrip

+
+
+ +
+
+ + +
+

Subroutines

+
+

public subroutine new_preprocessors(preprocessors, table, error) +

+
+ +

Construct new preprocess array from a TOML data structure.

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(preprocess_config_t), + intent(out), + allocatable + ::preprocessors(:) +

Instance of the preprocess configuration

+
+ + type(toml_table), + intent(inout) + + ::table +

Instance of the TOML data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_manifest_profile.html b/module/fpm_manifest_profile.html new file mode 100644 index 0000000000..caea8c2653 --- /dev/null +++ b/module/fpm_manifest_profile.html @@ -0,0 +1,2489 @@ + + + + + + + + + + + + + fpm_manifest_profile – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_manifest_profile + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

Implementation of the meta data for compiler flag profiles.

+

A profiles table can currently have the following subtables: + Profile names - any string, if omitted, flags are appended to all matching profiles + Compiler - any from the following list, omitting it yields an error

+
    +
  • “gfortran”
  • +
  • “ifort”
  • +
  • “ifx”
  • +
  • “pgfortran”
  • +
  • “nvfortran”
  • +
  • “flang”
  • +
  • “caf”
  • +
  • “f95”
  • +
  • “lfortran”
  • +
  • “lfc”
  • +
  • “nagfor”
  • +
  • “crayftn”
  • +
  • “xlf90”
  • +
  • “ftn95”
  • +
+

OS - any from the following list, if omitted, the profile is used if and only + if there is no profile perfectly matching the current configuration

+
    +
  • “linux”
  • +
  • “macos”
  • +
  • “windows”
  • +
  • “cygwin”
  • +
  • “solaris”
  • +
  • “freebsd”
  • +
  • “openbsd”
  • +
  • “unknown”
  • +
+

Each of the subtables currently supports the following fields:

+
[profiles.debug.gfortran.linux]
+ flags="-Wall -g -Og"
+ c-flags="-g O1"
+ cxx-flags="-g O1"
+ link-time-flags="-xlinkopt"
+ files={"hello_world.f90"="-Wall -O3"}
+
+
+

Uses

+ +
+ + +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=*), + public, +parameter + ::DEFAULT_COMPILER ='gfortran' +

Name of the default compiler

+
+ + integer, + public, +parameter + ::OS_ALL =-1 + +
+ + character(len=:), + public, + allocatable + ::path + +
+ +
+
+ + + + +
+

Derived Types

+
+
+ +

+ type, public, extends(serializable_t) ::  + file_scope_flag + +

+
+
+

Type storing file name - file scope compiler flags pairs

+ +

Components

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=:), + public, + allocatable + ::file_name +

Name of the file

+
+ + character(len=:), + public, + allocatable + ::flags +

File scope flags

+
+ + + + +

Type-Bound Procedures

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit
procedure, public :: + dump_to_toml => file_scope_dump
generic, public :: + load => load_from_toml, load_from_file, load_from_unit
procedure, public :: + load_from_toml => file_scope_load
generic, public :: + operator(==) => serializable_is_same
procedure, public :: + serializable_is_same => file_scope_same

Serialization interface

procedure, public, non_overridable :: + test_serialization

Test load/write roundtrip

+
+
+ +
+
+ +

+ type, public, extends(serializable_t) ::  + profile_config_t + +

+
+
+

Configuration meta data for a profile

+ +

Components

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=:), + public, + allocatable + ::c_flags +

C compiler flags

+
+ + character(len=:), + public, + allocatable + ::compiler +

Name of the compiler

+
+ + character(len=:), + public, + allocatable + ::cxx_flags +

C++ compiler flags

+
+ + type(file_scope_flag), + public, + allocatable + ::file_scope_flags(:) +

File scope flags

+
+ + character(len=:), + public, + allocatable + ::flags +

Fortran compiler flags

+
+ + logical, + public + + ::is_built_in =.false. +

Is this profile one of the built-in ones?

+
+ + character(len=:), + public, + allocatable + ::link_time_flags +

Link time compiler flags

+
+ + integer, + public + + ::os_type =OS_ALL +

Value repesenting OS

+
+ + character(len=:), + public, + allocatable + ::profile_name +

Name of the profile

+
+ + + + +

Type-Bound Procedures

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit
procedure, public :: + dump_to_toml => profile_dump
procedure, public :: + info

Print information on this instance

generic, public :: + load => load_from_toml, load_from_file, load_from_unit
procedure, public :: + load_from_toml => profile_load
generic, public :: + operator(==) => serializable_is_same
procedure, public :: + serializable_is_same => profile_same

Serialization interface

procedure, public, non_overridable :: + test_serialization

Test load/write roundtrip

+
+
+ +
+
+ +
+

Functions

+
+

public function file_scope_same(this, that) +

+
+ +

All checks passed!

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(file_scope_flag), + intent(in) + + ::this + +
+ + class(serializable_t), + intent(in) + + ::that + +
+ +

+ Return Value + logical +

+ + +
+
+ +
+

public function get_default_profiles(error) result(default_profiles) +

+
+ +

Construct an array of built-in profiles

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ +

+ Return Value + type(profile_config_t), allocatable, (:) +

+ + +
+
+ +
+

public function info_profile(profile) result(s) +

+
+ +

Print a representation of profile_config_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(profile_config_t), + intent(in) + + ::profile +

Profile to be represented

+
+ +

+ Return Value + character(len=:), allocatable +

+

String representation of given profile

+ +
+
+ +
+

public function new_profile(profile_name, compiler, os_type, flags, c_flags, cxx_flags, link_time_flags, file_scope_flags, is_built_in) result(profile) +

+
+ +

Construct a new profile configuration from a TOML data structure

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::profile_name +

Name of the profile

+
+ + character(len=*), + intent(in) + + ::compiler +

Name of the compiler

+
+ + integer, + intent(in) + + ::os_type +

Type of the OS

+
+ + character(len=*), + intent(in),optional + + ::flags +

Fortran compiler flags

+
+ + character(len=*), + intent(in),optional + + ::c_flags +

C compiler flags

+
+ + character(len=*), + intent(in),optional + + ::cxx_flags +

C++ compiler flags

+
+ + character(len=*), + intent(in),optional + + ::link_time_flags +

Link time compiler flags

+
+ + type(file_scope_flag), + intent(in),optional + + ::file_scope_flags(:) +

File scope flags

+
+ + logical, + intent(in),optional + + ::is_built_in +

Is this profile one of the built-in ones?

+
+ +

+ Return Value + type(profile_config_t) +

+ + +
+
+ +
+

public function os_type_name(os_type) +

+
+ +

Match lowercase string with name of OS to os_type enum

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + integer, + intent(in) + + ::os_type +

Enum representing type of OS

+
+ +

+ Return Value + character(len=:), allocatable +

+

Name of operating system

+ +
+
+ +
+

public function profile_same(this, that) +

+
+ +

All checks passed!

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(profile_config_t), + intent(in) + + ::this + +
+ + class(serializable_t), + intent(in) + + ::that + +
+ +

+ Return Value + logical +

+ + +
+
+ +
+
+ +
+

Subroutines

+
+

public subroutine file_scope_dump(self, table, error) +

+
+ +

Dump to toml table

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(file_scope_flag), + intent(inout) + + ::self +

Instance of the serializable object

+
+ + type(toml_table), + intent(inout) + + ::table +

Data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + +
+
+ +
+

public subroutine file_scope_load(self, table, error) +

+
+ +

Read from toml table (no checks made at this stage)

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(file_scope_flag), + intent(inout) + + ::self +

Instance of the serializable object

+
+ + type(toml_table), + intent(inout) + + ::table +

Data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + +
+
+ +
+

public subroutine find_profile(profiles, profile_name, compiler, os_type, found_matching, chosen_profile) +

+
+ +

Look for profile with given configuration in array profiles

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(profile_config_t), + intent(in), + allocatable + ::profiles(:) +

Array of profiles

+
+ + character(len=:), + intent(in), + allocatable + ::profile_name +

Name of profile

+
+ + character(len=:), + intent(in), + allocatable + ::compiler +

Name of compiler

+
+ + integer, + intent(in) + + ::os_type +

Type of operating system (enum)

+
+ + logical, + intent(out) + + ::found_matching +

Boolean value containing true if matching profile was found

+
+ + type(profile_config_t), + intent(out) + + ::chosen_profile +

Last matching profile in the profiles array

+
+ + +
+
+ +
+

public subroutine get_flags(profile_name, compiler_name, os_type, key_list, table, profiles, profindex, os_valid) +

+
+ +

Look for flags, c-flags, link-time-flags key-val pairs +and files table in a given table and create new profiles

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=:), + intent(in), + allocatable + ::profile_name +

Name of profile

+
+ + character(len=:), + intent(in), + allocatable + ::compiler_name +

Name of compiler

+
+ + integer, + intent(in) + + ::os_type +

OS type

+
+ + type(toml_key), + intent(in), + allocatable + ::key_list(:) +

List of keys in the table

+
+ + type(toml_table), + intent(in), + pointer + ::table +

Table containing OS tables

+
+ + type(profile_config_t), + intent(inout), + allocatable + ::profiles(:) +

List of profiles

+
+ + integer, + intent(inout) + + ::profindex +

Index in the list of profiles

+
+ + logical, + intent(in) + + ::os_valid +

Was called with valid operating system

+
+ + +
+
+ +
+

public subroutine info(self, unit, verbosity) +

+
+ +

Write information on instance

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(profile_config_t), + intent(in) + + ::self +

Instance of the profile configuration

+
+ + integer, + intent(in) + + ::unit +

Unit for IO

+
+ + integer, + intent(in),optional + + ::verbosity +

Verbosity of the printout

+
+ + +
+
+ +
+

public subroutine match_os_type(os_name, os_type) +

+
+ +

Match os_type enum to a lowercase string with name of OS

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=:), + intent(in), + allocatable + ::os_name +

Name of operating system

+
+ + integer, + intent(out) + + ::os_type +

Enum representing type of OS

+
+ + +
+
+ +
+

public subroutine new_profiles(profiles, table, error) +

+
+ +

Construct new profiles array from a TOML data structure

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(profile_config_t), + intent(out), + allocatable + ::profiles(:) +

Instance of the dependency configuration

+
+ + type(toml_table), + intent(inout), + target + ::table +

Instance of the TOML data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + +
+
+ +
+

public subroutine profile_dump(self, table, error) +

+
+ +

Dump to toml table

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(profile_config_t), + intent(inout) + + ::self +

Instance of the serializable object

+
+ + type(toml_table), + intent(inout) + + ::table +

Data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + +
+
+ +
+

public subroutine profile_load(self, table, error) +

+
+ +

Read from toml table (no checks made at this stage)

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(profile_config_t), + intent(inout) + + ::self +

Instance of the serializable object

+
+ + type(toml_table), + intent(inout) + + ::table +

Data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + +
+
+ +
+

public subroutine traverse_compilers(profile_name, comp_list, table, error, profiles_size, profiles, profindex) +

+
+ +

Traverse compiler tables

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=:), + intent(in), + allocatable + ::profile_name +

Name of profile

+
+ + type(toml_key), + intent(in), + allocatable + ::comp_list(:) +

List of OSs in table with profile name given

+
+ + type(toml_table), + intent(in), + pointer + ::table +

Table containing compiler tables

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + integer, + intent(inout),optional + + ::profiles_size +

Number of profiles in list of profiles

+
+ + type(profile_config_t), + intent(inout),optional, + allocatable + ::profiles(:) +

List of profiles

+
+ + integer, + intent(inout),optional + + ::profindex +

Index in the list of profiles

+
+ + +
+
+ +
+

public subroutine traverse_oss(profile_name, compiler_name, os_list, table, profiles, profindex, error) +

+
+ +

Traverse operating system tables to obtain profiles

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=:), + intent(in), + allocatable + ::profile_name +

Name of profile

+
+ + character(len=:), + intent(in), + allocatable + ::compiler_name +

Name of compiler

+
+ + type(toml_key), + intent(in), + allocatable + ::os_list(:) +

List of OSs in table with profile name and compiler name given

+
+ + type(toml_table), + intent(in), + pointer + ::table +

Table containing OS tables

+
+ + type(profile_config_t), + intent(inout), + allocatable + ::profiles(:) +

List of profiles

+
+ + integer, + intent(inout) + + ::profindex +

Index in the list of profiles

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + +
+
+ +
+

public subroutine traverse_oss_for_size(profile_name, compiler_name, os_list, table, profiles_size, error) +

+
+ +

Traverse operating system tables to obtain number of profiles

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=:), + intent(in), + allocatable + ::profile_name +

Name of profile

+
+ + character(len=:), + intent(in), + allocatable + ::compiler_name +

Name of compiler

+
+ + type(toml_key), + intent(in), + allocatable + ::os_list(:) +

List of OSs in table with profile name and compiler name given

+
+ + type(toml_table), + intent(in), + pointer + ::table +

Table containing OS tables

+
+ + integer, + intent(inout) + + ::profiles_size +

Number of profiles in list of profiles

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + +
+
+ +
+

public subroutine validate_compiler_name(compiler_name, is_valid) +

+
+ +

Check if compiler name is a valid compiler name

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=:), + intent(in), + allocatable + ::compiler_name +

Name of a compiler

+
+ + logical, + intent(out) + + ::is_valid +

Boolean value of whether compiler_name is valid or not

+
+ + +
+
+ +
+

public subroutine validate_os_name(os_name, is_valid) +

+
+ +

Check if os_name is a valid name of a supported OS

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=:), + intent(in), + allocatable + ::os_name +

Name of an operating system

+
+ + logical, + intent(out) + + ::is_valid +

Boolean value of whether os_name is valid or not

+
+ + +
+
+ +
+

public subroutine validate_profile_table(profile_name, compiler_name, key_list, table, error, os_valid) +

+
+ + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=:), + intent(in), + allocatable + ::profile_name +

Name of profile

+
+ + character(len=:), + intent(in), + allocatable + ::compiler_name +

Name of compiler

+
+ + type(toml_key), + intent(in), + allocatable + ::key_list(:) +

List of keys in the table

+
+ + type(toml_table), + intent(in), + pointer + ::table +

Table containing OS tables

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + logical, + intent(in) + + ::os_valid +

Was called with valid operating system

+
+ + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_manifest_test.html b/module/fpm_manifest_test.html new file mode 100644 index 0000000000..11a0eb987c --- /dev/null +++ b/module/fpm_manifest_test.html @@ -0,0 +1,484 @@ + + + + + + + + + + + + + fpm_manifest_test – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_manifest_test + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+
+ + +
+ +
+

Implementation of the meta data for a test.

+

The test data structure is effectively a decorated version of an executable + and shares most of its properties, except for the defaults and can be + handled under most circumstances just like any other executable.

+

A test table can currently have the following fields

+
[[ test ]]
+name = "string"
+source-dir = "path"
+main = "file"
+link = ["lib"]
+[test.dependencies]
+
+
+ + +
+ + + + + + +
+

Derived Types

+
+
+ +

+ type, public, extends(executable_config_t) ::  + test_config_t + +

+
+
+

Configuation meta data for an test

+ +

Components

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + type(dependency_config_t), + public, + allocatable + ::dependency(:) +

Dependency meta data for this executable

+
+ + type(string_t), + public, + allocatable + ::link(:) +

Libraries to link against

+
+ + character(len=:), + public, + allocatable + ::main +

Name of the source file declaring the main program

+
+ + character(len=:), + public, + allocatable + ::name +

Name of the resulting executable

+
+ + character(len=:), + public, + allocatable + ::source_dir +

Source directory for collecting the executable

+
+ + + + +

Type-Bound Procedures

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit
procedure, public :: + dump_to_toml
procedure, public :: + info

Print information on this instance

generic, public :: + load => load_from_toml, load_from_file, load_from_unit
procedure, public :: + load_from_toml
generic, public :: + operator(==) => serializable_is_same
procedure, public :: + serializable_is_same => exe_is_same

Serialization interface

procedure, public, non_overridable :: + test_serialization

Test load/write roundtrip

+
+
+ +
+
+ + +
+

Subroutines

+
+

public subroutine new_test(self, table, error) +

+
+ +

Construct a new test configuration from a TOML data structure

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(test_config_t), + intent(out) + + ::self +

Instance of the test configuration

+
+ + type(toml_table), + intent(inout) + + ::table +

Instance of the TOML data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_meta.html b/module/fpm_meta.html new file mode 100644 index 0000000000..aa17ea2f01 --- /dev/null +++ b/module/fpm_meta.html @@ -0,0 +1,344 @@ + + + + + + + + + + + + + fpm_meta – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_meta + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+
+ + +
+ +
+

The fpm meta-package model

+

This is a wrapper data type that encapsulate all pre-processing information + (compiler flags, linker libraries, etc.) required to correctly enable a package + to use a core library.

+

Available core libraries

+
    +
  • OpenMP
  • +
  • MPI
  • +
  • HDF5
  • +
  • fortran-lang stdlib
  • +
  • fortran-lang minpack
  • +
+

@note Note + Core libraries are enabled in the [build] section of the fpm.toml manifest

+
+ + +
+ + + + +
+

Interfaces

+
+
+ +

public interface resolve_metapackages +

+
+
    +
  • +

    + private subroutine resolve_metapackage_model(model, package, settings, error) + +

    +

    Resolve all metapackages into the package config

    + +

    Arguments

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    TypeIntentOptional AttributesName
    + + type(fpm_model_t), + intent(inout) + + ::model + +
    + + type(package_config_t), + intent(inout) + + ::package + +
    + + class(fpm_build_settings), + intent(inout) + + ::settings + +
    + + type(error_t), + intent(out), + allocatable + ::error + +
    + + +
  • +
+
+ +
+
+ + + + + + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_meta_base.html b/module/fpm_meta_base.html new file mode 100644 index 0000000000..8fe7821fb7 --- /dev/null +++ b/module/fpm_meta_base.html @@ -0,0 +1,741 @@ + + + + + + + + + + + + + fpm_meta_base – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_meta_base + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+
+ + +
+ +
+ +
+ + +
+ + + + + + +
+

Derived Types

+
+
+ +

+ type, public ::  + metapackage_t + +

+
+
+

Type for describing a source file

+ +

Components

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + type(string_t), + public + + ::cflags + +
+ + type(string_t), + public + + ::cxxflags + +
+ + type(dependency_config_t), + public, + allocatable + ::dependency(:) +

List of Development dependency meta data. +Metapackage dependencies are never exported from the model

+
+ + type(string_t), + public, + allocatable + ::external_modules(:) + +
+ + type(string_t), + public + + ::fflags + +
+ + type(string_t), + public + + ::flags +

List of compiler flags and options to be added

+
+ + type(fortran_features_t), + public, + allocatable + ::fortran +

Special fortran features

+
+ + logical, + public + + ::has_build_flags =.false. + +
+ + logical, + public + + ::has_c_flags =.false. + +
+ + logical, + public + + ::has_cxx_flags =.false. + +
+ + logical, + public + + ::has_dependencies =.false. + +
+ + logical, + public + + ::has_external_modules =.false. + +
+ + logical, + public + + ::has_fortran_flags =.false. + +
+ + logical, + public + + ::has_include_dirs =.false. + +
+ + logical, + public + + ::has_link_flags =.false. + +
+ + logical, + public + + ::has_link_libraries =.false. + +
+ + logical, + public + + ::has_run_command =.false. + +
+ + type(string_t), + public, + allocatable + ::incl_dirs(:) + +
+ + type(string_t), + public + + ::link_flags + +
+ + type(string_t), + public, + allocatable + ::link_libs(:) + +
+ + character(len=:), + public, + allocatable + ::name +

Package name

+
+ + type(preprocess_config_t), + public, + allocatable + ::preprocess +

Preprocessor configuration

+
+ + type(string_t), + public + + ::run_command + +
+ + type(version_t), + public, + allocatable + ::version +

Package version (if supported)

+
+ + + + +

Type-Bound Procedures

+ + + + + + + + + + + +
procedure, public :: + destroy

Clean metapackage structure

generic, public :: + resolve => resolve_cmd, resolve_model, resolve_package_config
+
+
+ +
+
+ + +
+

Subroutines

+
+

public elemental subroutine destroy(this) +

+
+ + + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(metapackage_t), + intent(inout) + + ::this + +
+ + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_meta_blas.html b/module/fpm_meta_blas.html new file mode 100644 index 0000000000..686d843f09 --- /dev/null +++ b/module/fpm_meta_blas.html @@ -0,0 +1,316 @@ + + + + + + + + + + + + + fpm_meta_blas – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_meta_blas + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+
+ + +
+ +
+ +
+ + +
+ + + + + + + + +
+

Subroutines

+
+

public subroutine init_blas(this, compiler, all_meta, error) +

+
+ +

Initialize blas metapackage for the current system +Cleanup +Set name

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(metapackage_t), + intent(inout) + + ::this + +
+ + type(compiler_t), + intent(in) + + ::compiler + +
+ + type(metapackage_request_t), + intent(in) + + ::all_meta(:) + +
+ + type(error_t), + intent(out), + allocatable + ::error + +
+ + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_meta_hdf5.html b/module/fpm_meta_hdf5.html new file mode 100644 index 0000000000..f333b51013 --- /dev/null +++ b/module/fpm_meta_hdf5.html @@ -0,0 +1,316 @@ + + + + + + + + + + + + + fpm_meta_hdf5 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_meta_hdf5 + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+
+ + +
+ +
+ +
+ + +
+ + + + + + + + +
+

Subroutines

+
+

public subroutine init_hdf5(this, compiler, all_meta, error) +

+
+ +

Initialize HDF5 metapackage for the current system +Cleanup +Set name

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(metapackage_t), + intent(inout) + + ::this + +
+ + type(compiler_t), + intent(in) + + ::compiler + +
+ + type(metapackage_request_t), + intent(in) + + ::all_meta(:) + +
+ + type(error_t), + intent(out), + allocatable + ::error + +
+ + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_meta_minpack.html b/module/fpm_meta_minpack.html new file mode 100644 index 0000000000..33fa307e54 --- /dev/null +++ b/module/fpm_meta_minpack.html @@ -0,0 +1,312 @@ + + + + + + + + + + + + + fpm_meta_minpack – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_meta_minpack + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+
+ + +
+ +
+ +
+ + +
+ + + + + + + + +
+

Subroutines

+
+

public subroutine init_minpack(this, compiler, all_meta, error) +

+
+ +

Initialize minpack metapackage for the current system +Cleanup

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(metapackage_t), + intent(inout) + + ::this + +
+ + type(compiler_t), + intent(in) + + ::compiler + +
+ + type(metapackage_request_t), + intent(in) + + ::all_meta(:) + +
+ + type(error_t), + intent(out), + allocatable + ::error + +
+ + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_meta_mpi.html b/module/fpm_meta_mpi.html new file mode 100644 index 0000000000..e15b89f22a --- /dev/null +++ b/module/fpm_meta_mpi.html @@ -0,0 +1,378 @@ + + + + + + + + + + + + + fpm_meta_mpi – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_meta_mpi + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+
+ + +
+ +
+ +
+ + +
+ + + + + + + +
+

Functions

+
+

public pure function MPI_TYPE_NAME(mpilib) result(name) +

+
+ +

Return a name for the MPI library

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + integer, + intent(in) + + ::mpilib + +
+ +

+ Return Value + character(len=:), allocatable +

+ + +
+
+ +
+
+ +
+

Subroutines

+
+

public subroutine init_mpi(this, compiler, all_meta, error) +

+
+ +

Initialize MPI metapackage for the current system +Cleanup

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(metapackage_t), + intent(inout) + + ::this + +
+ + type(compiler_t), + intent(in) + + ::compiler + +
+ + type(metapackage_request_t), + intent(in) + + ::all_meta(:) + +
+ + type(error_t), + intent(out), + allocatable + ::error + +
+ + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_meta_netcdf.html b/module/fpm_meta_netcdf.html new file mode 100644 index 0000000000..4e08b97e12 --- /dev/null +++ b/module/fpm_meta_netcdf.html @@ -0,0 +1,315 @@ + + + + + + + + + + + + + fpm_meta_netcdf – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_meta_netcdf + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+
+ + +
+ +
+ +
+ + +
+ + + + + + + + +
+

Subroutines

+
+

public subroutine init_netcdf(this, compiler, all_meta, error) +

+
+ +

Initialize NetCDF metapackage for the current system +Cleanup +Set name

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(metapackage_t), + intent(inout) + + ::this + +
+ + type(compiler_t), + intent(in) + + ::compiler + +
+ + type(metapackage_request_t), + intent(in) + + ::all_meta(:) + +
+ + type(error_t), + intent(out), + allocatable + ::error + +
+ + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_meta_openmp.html b/module/fpm_meta_openmp.html new file mode 100644 index 0000000000..846afd9cd6 --- /dev/null +++ b/module/fpm_meta_openmp.html @@ -0,0 +1,312 @@ + + + + + + + + + + + + + fpm_meta_openmp – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_meta_openmp + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+
+ + +
+ +
+ +
+ + +
+ + + + + + + + +
+

Subroutines

+
+

public subroutine init_openmp(this, compiler, all_meta, error) +

+
+ +

Initialize OpenMP metapackage for the current system +Cleanup

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(metapackage_t), + intent(inout) + + ::this + +
+ + type(compiler_t), + intent(in) + + ::compiler + +
+ + type(metapackage_request_t), + intent(in) + + ::all_meta(:) + +
+ + type(error_t), + intent(out), + allocatable + ::error + +
+ + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_meta_stdlib.html b/module/fpm_meta_stdlib.html new file mode 100644 index 0000000000..d702ed625f --- /dev/null +++ b/module/fpm_meta_stdlib.html @@ -0,0 +1,314 @@ + + + + + + + + + + + + + fpm_meta_stdlib – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_meta_stdlib + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+
+ + +
+ +
+ +
+ + +
+ + + + + + + + +
+

Subroutines

+
+

public subroutine init_stdlib(this, compiler, all_meta, error) +

+
+ +

Initialize stdlib metapackage for the current system +Cleanup

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(metapackage_t), + intent(inout) + + ::this + +
+ + type(compiler_t), + intent(in) + + ::compiler + +
+ + type(metapackage_request_t), + intent(in) + + ::all_meta(:) + +
+ + type(error_t), + intent(out), + allocatable + ::error + +
+ + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_meta_util.html b/module/fpm_meta_util.html new file mode 100644 index 0000000000..3282066492 --- /dev/null +++ b/module/fpm_meta_util.html @@ -0,0 +1,431 @@ + + + + + + + + + + + + + fpm_meta_util – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_meta_util + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+
+ + +
+ +
+ +
+ + +
+ + + + + + + + +
+

Subroutines

+
+

public subroutine add_pkg_config_compile_options(this, name, include_flag, libdir, error) +

+
+ +

Add pkgconfig compile options to a metapackage +Get version +Get libraries +Get compiler flags

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(metapackage_t), + intent(inout) + + ::this + +
+ + character(len=*), + intent(in) + + ::name + +
+ + character(len=*), + intent(in) + + ::include_flag + +
+ + character(len=:), + + allocatable + ::libdir + +
+ + type(error_t), + intent(out), + allocatable + ::error + +
+ + +
+
+ +
+

public subroutine lib_get_trailing(lib_name, lib_dir, prefix, suffix, found) +

+
+ +

Given a library name and folder, find extension and prefix

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::lib_name + +
+ + character(len=*), + intent(in) + + ::lib_dir + +
+ + character(len=:), + intent(out), + allocatable + ::prefix + +
+ + character(len=:), + intent(out), + allocatable + ::suffix + +
+ + logical, + intent(out) + + ::found + +
+ + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_model.html b/module/fpm_model.html new file mode 100644 index 0000000000..58c41a0b67 --- /dev/null +++ b/module/fpm_model.html @@ -0,0 +1,1610 @@ + + + + + + + + + + + + + fpm_model – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_model + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

The fpm package model

+

Defines the fpm model data types which encapsulate all information + required to correctly build a package and its dependencies.

+

The process (see [[build_model(subroutine)]]) for generating a valid [[fpm_model]] involves + source files discovery (fpm_sources) and parsing (fpm_source_parsing).

+

Once a valid [[fpm_model]] has been constructed, it may be passed to [[fpm_targets:targets_from_sources]] to + generate a list of build targets for the backend.

+

Enumerations

+

Source type: FPM_UNIT_* + Describes the type of source file — determines build target generation

+

The logical order of precedence for assigning unit_type is as follows:

+
 if source-file contains program then
+   unit_type = FPM_UNIT_PROGRAM
+ else if source-file contains non-module subroutine/function then
+   unit_type = FPM_UNIT_SUBPROGRAM
+ else if source-file contains submodule then
+   unit_type = FPM_UNIT_SUBMODULE
+ else if source-file contains module then
+   unit_type = FPM_UNIT_MODULE
+ end if
+
+ +

@note Note + A source file is only designated FPM_UNIT_MODULE if it only contains modules - no non-module subprograms. + (This allows tree-shaking/pruning of build targets based on unused module dependencies.)

+

Source scope: FPM_SCOPE_* + Describes the scoping rules for using modules — controls module dependency resolution

+
+ + +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + integer, + public, +parameter + ::FPM_SCOPE_APP =3 +

Module-use scope is library/dependency and app modules

+
+ + integer, + public, +parameter + ::FPM_SCOPE_DEP =2 +

Module-use scope is library/dependency modules only

+
+ + integer, + public, +parameter + ::FPM_SCOPE_EXAMPLE =5 + +
+ + integer, + public, +parameter + ::FPM_SCOPE_LIB =1 +

Module-use scope is library/dependency modules only

+
+ + integer, + public, +parameter + ::FPM_SCOPE_TEST =4 +

Module-use scope is library/dependency and test modules

+
+ + integer, + public, +parameter + ::FPM_SCOPE_UNKNOWN =-1 +

Source has no module-use scope

+
+ + integer, + public, +parameter + ::FPM_UNIT_CHEADER =6 +

Source type is c header file

+
+ + integer, + public, +parameter + ::FPM_UNIT_CPPSOURCE =7 +

Souce type is c++ source file.

+
+ + integer, + public, +parameter + ::FPM_UNIT_CSOURCE =5 +

Source type is c source file

+
+ + integer, + public, +parameter + ::FPM_UNIT_MODULE =2 +

Source only contains one or more fortran modules

+
+ + integer, + public, +parameter + ::FPM_UNIT_PROGRAM =1 +

Source contains a fortran program

+
+ + integer, + public, +parameter + ::FPM_UNIT_SUBMODULE =3 +

Source contains one or more fortran submodules

+
+ + integer, + public, +parameter + ::FPM_UNIT_SUBPROGRAM =4 +

Source contains one or more fortran subprogram not within modules

+
+ + integer, + public, +parameter + ::FPM_UNIT_UNKNOWN =-1 +

Source type unknown

+
+ +
+
+ + + + +
+

Derived Types

+
+
+ +

+ type, public, extends(serializable_t) ::  + fortran_features_t + +

+
+
+

Enabled Fortran language features

+ +

Components

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + logical, + public + + ::implicit_external =.false. +

Use implicit external interface

+
+ + logical, + public + + ::implicit_typing =.false. +

Use default implicit typing

+
+ + character(len=:), + public, + allocatable + ::source_form +

Form to use for all Fortran sources

+
+ + + + +

Type-Bound Procedures

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit
procedure, public :: + dump_to_toml => fft_dump_to_toml
generic, public :: + load => load_from_toml, load_from_file, load_from_unit
procedure, public :: + load_from_toml => fft_load_from_toml
generic, public :: + operator(==) => serializable_is_same
procedure, public :: + serializable_is_same => fft_is_same

Serialization interface

procedure, public, non_overridable :: + test_serialization

Test load/write roundtrip

+
+
+ +
+
+ +

+ type, public, extends(serializable_t) ::  + fpm_model_t + +

+
+
+

Type describing everything required to build + the root package and its dependencies.

+ +

Components

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + type(archiver_t), + public + + ::archiver +

Archiver object

+
+ + character(len=:), + public, + allocatable + ::build_prefix +

Base directory for build

+
+ + character(len=:), + public, + allocatable + ::c_compile_flags +

Command line flags passed to C for compilation

+
+ + type(compiler_t), + public + + ::compiler +

Compiler object

+
+ + character(len=:), + public, + allocatable + ::cxx_compile_flags +

Command line flags passed to C++ for compilation

+
+ + type(dependency_tree_t), + public + + ::deps +

Project dependencies

+
+ + logical, + public + + ::enforce_module_names =.false. +

Whether module names should be prefixed with the package name

+
+ + type(string_t), + public, + allocatable + ::external_modules(:) +

External modules used

+
+ + character(len=:), + public, + allocatable + ::fortran_compile_flags +

Command line flags passed to fortran for compilation

+
+ + type(string_t), + public, + allocatable + ::include_dirs(:) +

Include directories

+
+ + logical, + public + + ::include_tests =.true. +

Whether tests should be added to the build list

+
+ + character(len=:), + public, + allocatable + ::link_flags +

Command line flags passed to the linker

+
+ + type(string_t), + public, + allocatable + ::link_libraries(:) +

Native libraries to link against

+
+ + type(string_t), + public + + ::module_prefix +

Prefix for all module names

+
+ + character(len=:), + public, + allocatable + ::package_name +

Name of root package

+
+ + type(package_t), + public, + allocatable + ::packages(:) +

Array of packages (including the root package)

+
+ + + + +

Type-Bound Procedures

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit
procedure, public :: + dump_to_toml => model_dump_to_toml
procedure, public :: + get_package_libraries_link

Get target link flags

generic, public :: + load => load_from_toml, load_from_file, load_from_unit
procedure, public :: + load_from_toml => model_load_from_toml
generic, public :: + operator(==) => serializable_is_same
procedure, public :: + serializable_is_same => model_is_same

Serialization interface

procedure, public, non_overridable :: + test_serialization

Test load/write roundtrip

+
+
+ +
+
+ +

+ type, public, extends(serializable_t) ::  + package_t + +

+
+
+

Type for describing a single package

+ +

Components

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + logical, + public + + ::enforce_module_names =.false. +

Module naming conventions

+
+ + type(fortran_features_t), + public + + ::features +

Language features

+
+ + type(string_t), + public + + ::module_prefix +

Prefix for all module names

+
+ + character(len=:), + public, + allocatable + ::name +

Name of package

+
+ + type(preprocess_config_t), + public + + ::preprocess +

List of macros.

+
+ + type(srcfile_t), + public, + allocatable + ::sources(:) +

Array of sources

+
+ + character(len=:), + public, + allocatable + ::version +

Package version number.

+
+ + + + +

Type-Bound Procedures

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit
procedure, public :: + dump_to_toml => package_dump_to_toml
procedure, public :: + has_library => package_has_library

Check if a package will create a library

generic, public :: + load => load_from_toml, load_from_file, load_from_unit
procedure, public :: + load_from_toml => package_load_from_toml
generic, public :: + operator(==) => serializable_is_same
procedure, public :: + serializable_is_same => package_is_same

Serialization interface

procedure, public, non_overridable :: + test_serialization

Test load/write roundtrip

+
+
+ +
+
+ +

+ type, public, extends(serializable_t) ::  + srcfile_t + +

+
+
+

Type for describing a source file

+ +

Components

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + integer(kind=int64), + public + + ::digest +

Current hash

+
+ + character(len=:), + public, + allocatable + ::exe_name +

Name of executable for FPM_UNIT_PROGRAM

+
+ + character(len=:), + public, + allocatable + ::file_name +

File path relative to cwd

+
+ + type(string_t), + public, + allocatable + ::include_dependencies(:) +

Files INCLUDEd by this source file

+
+ + type(string_t), + public, + allocatable + ::link_libraries(:) +

Native libraries to link against

+
+ + type(string_t), + public, + allocatable + ::modules_provided(:) +

Modules provided by this source file (lowerstring)

+
+ + type(string_t), + public, + allocatable + ::modules_used(:) +

Modules USEd by this source file (lowerstring)

+
+ + type(string_t), + public, + allocatable + ::parent_modules(:) +

Parent modules (submodules only)

+
+ + integer, + public + + ::unit_scope =FPM_SCOPE_UNKNOWN +

Target module-use scope

+
+ + integer, + public + + ::unit_type =FPM_UNIT_UNKNOWN +

Type of source unit

+
+ + + + +

Type-Bound Procedures

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit
procedure, public :: + dump_to_toml => srcfile_dump_to_toml
generic, public :: + load => load_from_toml, load_from_file, load_from_unit
procedure, public :: + load_from_toml => srcfile_load_from_toml
generic, public :: + operator(==) => serializable_is_same
procedure, public :: + serializable_is_same => srcfile_is_same

Serialization interface

procedure, public, non_overridable :: + test_serialization

Test load/write roundtrip

+
+
+ +
+
+ +
+

Functions

+
+

public function FPM_SCOPE_NAME(flag) result(name) +

+
+ +

Return the character name of a scope flag

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + integer, + intent(in) + + ::flag + +
+ +

+ Return Value + character(len=:), allocatable +

+ + +
+
+ +
+

public function FPM_UNIT_NAME(flag) result(name) +

+
+ +

Return the character name of a unit flag

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + integer, + intent(in) + + ::flag + +
+ +

+ Return Value + character(len=:), allocatable +

+ + +
+
+ +
+
+ +
+

Subroutines

+
+

public subroutine show_model(model) +

+
+ + + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(fpm_model_t), + intent(in) + + ::model + +
+ + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_os.html b/module/fpm_os.html new file mode 100644 index 0000000000..cbb9bc1608 --- /dev/null +++ b/module/fpm_os.html @@ -0,0 +1,535 @@ + + + + + + + + + + + + + fpm_os – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_os + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+
+ + +
+ +
+ +
+

Uses

+ +
+ + +
+ + + + + + + + +
+

Subroutines

+
+

public subroutine change_directory(path, error) +

+
+ + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::path + +
+ + type(error_t), + intent(out), + allocatable + ::error + +
+ + +
+
+ +
+

public subroutine convert_to_absolute_path(path, error) +

+
+ +

Converts a path to an absolute, canonical path.

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=:), + intent(inout), + allocatable + ::path + +
+ + type(error_t), + intent(out), + allocatable + ::error + +
+ + +
+
+ +
+

public subroutine get_absolute_path(path, absolute_path, error) +

+
+ +

Determine the canonical, absolute path for the given path. +Expands home folder (~) on both Unix and Windows.

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::path + +
+ + character(len=:), + intent(out), + allocatable + ::absolute_path + +
+ + type(error_t), + intent(out), + allocatable + ::error + +
+ + +
+
+ +
+

public subroutine get_absolute_path_by_cd(path, absolute_path, error) +

+
+ +

Alternative to get_absolute_path that uses chdir/_chdir to determine the absolute path.

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::path + +
+ + character(len=:), + intent(out), + allocatable + ::absolute_path + +
+ + type(error_t), + intent(out), + allocatable + ::error + +
+ + +
+
+ +
+

public subroutine get_current_directory(path, error) +

+
+ + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=:), + intent(out), + allocatable + ::path + +
+ + type(error_t), + intent(out), + allocatable + ::error + +
+ + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_pkg_config.html b/module/fpm_pkg_config.html new file mode 100644 index 0000000000..bac9b8e806 --- /dev/null +++ b/module/fpm_pkg_config.html @@ -0,0 +1,682 @@ + + + + + + + + + + + + + fpm_pkg_config – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_pkg_config + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+
+ + +
+ +
+

The fpm interface to pkg-config

+

This module contains wrapper functions to interface with a pkg-config installation.

+
+

Uses

+
+ +
+
+ + +
+ + + + + + + +
+

Functions

+
+

public function assert_pkg_config() +

+
+ +

Check whether pkg-config is available on the local system

+ +

Arguments

+ None +

+ Return Value + logical +

+ + +
+
+ +
+

public function pkgcfg_get_build_flags(name, allow_system, error) result(flags) +

+
+ +

Get build flags (option to include flags from system directories, that +gfortran does not look into by default)

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::name +

Package name

+
+ + logical, + intent(in) + + ::allow_system +

Should pkg-config look in system paths? This is necessary for gfortran +that doesn’t otherwise look into them

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error flag

+
+ +

+ Return Value + type(string_t), allocatable, (:) +

+

List of compile flags

+ +
+
+ +
+

public function pkgcfg_get_libs(package, error) result(libraries) +

+
+ +

Get package libraries from pkg-config

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::package +

Package name

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handler

+
+ +

+ Return Value + type(string_t), allocatable, (:) +

+

A list of libraries

+ +
+
+ +
+

public function pkgcfg_get_version(package, error) result(screen) +

+
+ +

Get package version from pkg-config

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::package +

Package name

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handler

+
+ +

+ Return Value + type(string_t) +

+ + +
+
+ +
+

public function pkgcfg_has_package(name) result(success) +

+
+ +

Check if pkgcfg has package

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::name +

Package name

+
+ +

+ Return Value + logical +

+ + +
+
+ +
+

public function pkgcfg_list_all(error, descriptions) result(modules) +

+
+ +

Return whole list of available pkg-cfg packages

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handler

+
+ + type(string_t), + intent(out),optional, + allocatable + ::descriptions(:) +

An optional list of package descriptions

+
+ +

+ Return Value + type(string_t), allocatable, (:) +

+

A list of all available packages

+ +
+
+ +
+
+ +
+

Subroutines

+
+

public subroutine run_wrapper(wrapper, args, verbose, exitcode, cmd_success, screen_output) +

+
+ +

Simple call to execute_command_line involving one mpi* wrapper

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(string_t), + intent(in) + + ::wrapper + +
+ + type(string_t), + intent(in),optional + + ::args(:) + +
+ + logical, + intent(in),optional + + ::verbose + +
+ + integer, + intent(out),optional + + ::exitcode + +
+ + logical, + intent(out),optional + + ::cmd_success + +
+ + type(string_t), + intent(out),optional + + ::screen_output + +
+ + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_release.html b/module/fpm_release.html new file mode 100644 index 0000000000..8279c68e22 --- /dev/null +++ b/module/fpm_release.html @@ -0,0 +1,242 @@ + + + + + + + + + + + + + fpm_release – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_release + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+
+ + +
+ +
+

Release parameters

+

Module fpm_release contains public constants storing this build’s unique version IDs

+
+

Uses

+
+ +
+
+ + +
+ + + + + + + +
+

Functions

+
+

public function fpm_version() +

+
+ +

Return the current fpm version from fpm_version_ID as a version type

+ +

Arguments

+ None +

+ Return Value + type(version_t) +

+ + +
+
+ +
+
+ + + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_settings.html b/module/fpm_settings.html new file mode 100644 index 0000000000..908615cdec --- /dev/null +++ b/module/fpm_settings.html @@ -0,0 +1,516 @@ + + + + + + + + + + + + + fpm_settings – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_settings + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+
+ + +
+ +
+

Manages global settings which are defined in the global config file.

+
+

Uses

+ +
+ + +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=*), + public, +parameter + ::official_registry_base_url ='https://fpm-registry.vercel.app' + +
+ +
+
+ + + + +
+

Derived Types

+
+
+ +

+ type, public ::  + fpm_global_settings + +

+
+
+ + +

Components

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=:), + public, + allocatable + ::config_file_name +

Name of the global config file. The default is config.toml.

+
+ + character(len=:), + public, + allocatable + ::path_to_config_folder +

Path to the global config file excluding the file name.

+
+ + type(fpm_registry_settings), + public, + allocatable + ::registry_settings +

Registry configs.

+
+ + + + +

Type-Bound Procedures

+ + + + + + + + + + + + + + + +
procedure, public :: + full_path
procedure, public :: + has_custom_location
procedure, public :: + path_to_config_folder_or_empty
+
+
+ +
+
+ + +
+

Subroutines

+
+

public subroutine get_global_settings(global_settings, error) +

+
+ +

Obtain global settings from the global config file.

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(fpm_global_settings), + intent(inout) + + ::global_settings +

Global settings to be obtained.

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error reading config file.

+
+ + +
+
+ +
+

public subroutine get_registry_settings(table, global_settings, error) +

+
+ +

Read registry settings from the global config file.

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(toml_table), + intent(inout), + target + ::table +

The [registry] subtable from the global config file.

+
+ + type(fpm_global_settings), + intent(inout) + + ::global_settings +

The global settings which can be filled with the registry settings.

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling.

+
+ + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_source_parsing.html b/module/fpm_source_parsing.html new file mode 100644 index 0000000000..f8d48d0c98 --- /dev/null +++ b/module/fpm_source_parsing.html @@ -0,0 +1,502 @@ + + + + + + + + + + + + + fpm_source_parsing – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_source_parsing + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+
+ + +
+ +
+

Parsing of package source files

+

This module exposes two functions, [[parse_f_source]] and [[parse_c_source]], + which perform a rudimentary parsing of fortran and c source files + in order to extract information required for module dependency tracking.

+

Both functions additionally calculate and store a file digest (hash) which + is used by the backend (fpm_backend) to skip compilation of unmodified sources.

+

Both functions return an instance of the srcfile_t type.

+

For more information, please read the documentation for each function:

+
    +
  • [[parse_f_source]]
  • +
  • [[parse_c_source]]
  • +
+
+

Uses

+ +
+ + +
+ + + + + + + +
+

Functions

+
+

public function parse_c_source(c_filename, error) result(c_source) +

+
+ +

Parsing of c, cpp source files

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::c_filename + +
+ + type(error_t), + intent(out), + allocatable + ::error + +
+ +

+ Return Value + type(srcfile_t) +

+ + +
+
+ +
+

public function parse_f_source(f_filename, error) result(f_source) +

+
+ +

Parsing of free-form fortran source files

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::f_filename + +
+ + type(error_t), + intent(out), + allocatable + ::error + +
+ +

+ Return Value + type(srcfile_t) +

+ + +
+
+ +
+
+ +
+

Subroutines

+
+

public subroutine parse_use_statement(f_filename, i, line, use_stmt, is_intrinsic, module_name, error) +

+
+ + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::f_filename +

Current file name and line number (for error messaging)

+
+ + integer, + intent(in) + + ::i + +
+ + character(len=*), + intent(in) + + ::line +

The line being parsed. MUST BE preprocessed with trim(adjustl()

+
+ + logical, + intent(out) + + ::use_stmt +

Does this line contain a use statement?

+
+ + logical, + intent(out) + + ::is_intrinsic +

Is the module in this statement intrinsic?

+
+ + character(len=:), + intent(out), + allocatable + ::module_name +

used module name

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_sources.html b/module/fpm_sources.html new file mode 100644 index 0000000000..41cd9e690d --- /dev/null +++ b/module/fpm_sources.html @@ -0,0 +1,539 @@ + + + + + + + + + + + + + fpm_sources – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_sources + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+
+ + +
+ +
+

Discovery of sources

+

This module implements subroutines for building a list of + [[srcfile_t]] objects by looking for source files in the filesystem.

+
+ + +
+ + + + + + + +
+

Functions

+
+

public function get_exe_name_with_suffix(source) result(suffixed) +

+
+ +

Build an executable name with suffix. Safe routine that always returns an allocated string

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(srcfile_t), + intent(in) + + ::source + +
+ +

+ Return Value + character(len=:), allocatable +

+ + +
+
+ +
+
+ +
+

Subroutines

+
+

public subroutine add_executable_sources(sources, executables, scope, auto_discover, with_f_ext, error) +

+
+ +

Add to sources using the executable and test entries in the manifest and +applies any executable-specific overrides such as executable%name. +Adds all sources (including modules) from each executable%source_dir +Compare lowercase strings to allow auto-discovery of pre-processed extensions

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(srcfile_t), + intent(inout), + allocatable, target + ::sources(:) +

List of [[srcfile_t]] objects to append to. Allocated if not allocated

+
+ + class(executable_config_t), + intent(in) + + ::executables(:) +

List of [[executable_config_t]] entries from manifest

+
+ + integer, + intent(in) + + ::scope +

Scope to apply to the discovered sources: either FPM_SCOPE_APP or FPM_SCOPE_TEST, see fpm_model

+
+ + logical, + intent(in) + + ::auto_discover +

If .false. only executables and tests specified in the manifest are added to sources

+
+ + type(string_t), + intent(in),optional + + ::with_f_ext(:) +

Additional user-defined (preprocessor) extensions that should be treated as Fortran sources

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + +
+
+ +
+

public subroutine add_sources_from_dir(sources, directory, scope, with_executables, with_f_ext, recurse, error) +

+
+ +

Add to sources by looking for source files in directory

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(srcfile_t), + intent(inout), + allocatable, target + ::sources(:) +

List of [[srcfile_t]] objects to append to. Allocated if not allocated

+
+ + character(len=*), + intent(in) + + ::directory +

Directory in which to search for source files

+
+ + integer, + intent(in) + + ::scope +

Scope to apply to the discovered sources, see fpm_model for enumeration

+
+ + logical, + intent(in),optional + + ::with_executables +

Executable sources (fortran programs) are ignored unless with_executables=.true.

+
+ + type(string_t), + intent(in),optional + + ::with_f_ext(:) +

Additional user-defined (preprocessor) extensions that should be treated as Fortran sources

+
+ + logical, + intent(in),optional + + ::recurse +

Whether to recursively search subdirectories, default is .true.

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_strings.html b/module/fpm_strings.html new file mode 100644 index 0000000000..47cddbbfa2 --- /dev/null +++ b/module/fpm_strings.html @@ -0,0 +1,2932 @@ + + + + + + + + + + + + + fpm_strings – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_strings + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

This module defines general procedures for string operations for both CHARACTER and + TYPE(STRING_T) variables

+

general routines for performing string operations

+

Types

+
    +
  • TYPE(STRING_T) define a type to contain strings of variable length
  • +
+

Type Conversions

+
    +
  • f_string return Fortran CHARACTER variable when given a C-like array of + single characters terminated with a C_NULL_CHAR CHARACTER
  • +
  • str Converts INTEGER or LOGICAL to CHARACTER string
  • +
+

Case

+
    +
  • lower Changes a string to lowercase over optional specified column range
  • +
+

Parsing and joining

+
    +
  • split parse string on delimiter characters and store tokens into an allocatable array
  • +
  • split_first_last Computes the first and last indices of tokens in input string, delimited by the characters in set, + and stores them into first and last output arrays.
  • +
  • string_cat Concatenate an array of type(string_t) into a single CHARACTER variable
  • +
  • join append an array of CHARACTER variables into a single CHARACTER variable
  • +
+

Testing

+
    +
  • str_ends_with test if a CHARACTER string or array ends with a specified suffix
  • +
  • string_array_contains Check if array of TYPE(STRING_T) matches a particular CHARACTER string
  • +
  • OPERATOR(.IN.) Check if array of TYPE(STRING_T) matches a particular CHARACTER string
  • +
  • glob function compares text strings, one of which can have wildcards (‘*’ or ‘?’).
  • +
  • is_fortran_name determine whether a string is an acceptable Fortran entity name
  • +
  • to_fortran_name replace allowed special but unusuable characters in names with underscore
  • +
+

Whitespace

+
    +
  • notabs subroutine to expand tab characters assuming a tab space every eight characters
  • +
  • dilate function to expand tab characters assuming a tab space every eight characters
  • +
  • len_trim Determine total trimmed length of STRING_T array
  • +
+

Miscellaneous

+
    +
  • fnv_1a Hash a CHARACTER(*) string of default kind or a TYPE(STRING_T) array
  • +
  • replace Returns string with characters in charset replaced with target_char.
  • +
  • resize increase the size of a TYPE(STRING_T) array by N elements
  • +
+

Module naming

+

License: Public Domain + Changes a string to upprtcase over optional specified column range + Author: Milan Curcic + Computes the first and last indices of tokens in input string, delimited + by the characters in set, and stores them into first and last output + arrays. + Author: Federico Perini + Computes the first and last indices of lines in input string, delimited + by either CR, LF, or CRLF, and stores them into first and last output + arrays. + Author: Milan Curcic + If back is absent, computes the leftmost token delimiter in string whose + position is > pos. If back is present and true, computes the rightmost + token delimiter in string whose position is < pos. The result is stored + in pos.

+
+

Uses

+
+ +
+
+ + +
+ + + + +
+

Interfaces

+
+
+ +

public interface fnv_1a +

+
+
    +
  • +

    + private pure function fnv_1a_char(input, seed) result(hash) + +

    +

    Hash a character(*) string of default kind

    + +

    Arguments

    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    TypeIntentOptional AttributesName
    + + character(len=*), + intent(in) + + ::input + +
    + + integer(kind=int64), + intent(in),optional + + ::seed + +
    + +

    + Return Value + integer(kind=int64) +

    + + +
  • +
  • +

    + private pure function fnv_1a_string_t(input, seed) result(hash) + +

    +

    Hash a string_t array of default kind

    + +

    Arguments

    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    TypeIntentOptional AttributesName
    + + type(string_t), + intent(in) + + ::input(:) + +
    + + integer(kind=int64), + intent(in),optional + + ::seed + +
    + +

    + Return Value + integer(kind=int64) +

    + + +
  • +
+
+ +
+
+ +

public interface len_trim +

+
+
    +
  • +

    + private elemental function string_len_trim(string) result(n) + +

    +

    Determine total trimmed length of string_t array

    + +

    Arguments

    + + + + + + + + + + + + + + + + + + + +
    TypeIntentOptional AttributesName
    + + type(string_t), + intent(in) + + ::string + +
    + +

    + Return Value + integer +

    + + +
  • +
  • +

    + private pure function strings_len_trim(strings) result(n) + +

    +

    Determine total trimmed length of string_t array

    + +

    Arguments

    + + + + + + + + + + + + + + + + + + + +
    TypeIntentOptional AttributesName
    + + type(string_t), + intent(in) + + ::strings(:) + +
    + +

    + Return Value + integer +

    + + +
  • +
+
+ +
+
+ +

public interface operator(.in.) +

+
+
    +
  • +

    + public function string_array_contains(search_string, array) + +

    + +

    Check if array of TYPE(STRING_T) matches a particular CHARACTER string

    + +

    Arguments

    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    TypeIntentOptional AttributesName
    + + character(len=*), + intent(in) + + ::search_string + +
    + + type(string_t), + intent(in) + + ::array(:) + +
    + +

    + Return Value + logical +

    + + +
  • +
+
+ +
+
+ +

public interface operator(==) +

+
+
    +
  • +

    + private pure function string_is_same(this, that) + +

    +

    Check that two string objects are exactly identical

    + +

    Arguments

    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    TypeIntentOptional AttributesName
    + + type(string_t), + intent(in) + + ::this +

    two strings to be compared

    +
    + + type(string_t), + intent(in) + + ::that +

    two strings to be compared

    +
    + +

    + Return Value + logical +

    + + +
  • +
  • +

    + private pure function string_arrays_same(this, that) + +

    +

    Check that two allocatable string object arrays are exactly identical

    + +

    Arguments

    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    TypeIntentOptional AttributesName
    + + type(string_t), + intent(in), + allocatable + ::this(:) +

    two string arrays to be compared

    +
    + + type(string_t), + intent(in), + allocatable + ::that(:) +

    two string arrays to be compared

    +
    + +

    + Return Value + logical +

    + + +
  • +
+
+ +
+
+ +

public interface resize +

+
+
    +
  • +

    + private subroutine resize_string(list, n) + +

    +

    increase the size of a TYPE(STRING_T) array by N elements

    + +

    Arguments

    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    TypeIntentOptional AttributesName
    + + type(string_t), + intent(inout), + allocatable + ::list(:) +

    Instance of the array to be resized

    +
    + + integer, + intent(in),optional + + ::n +

    Dimension of the final array size

    +
    + + +
  • +
+
+ +
+
+ +

public interface str +

+
+
    +
  • +

    + private pure function str_int(i) result(s) + +

    +

    Converts integer “i” to string

    + +

    Arguments

    + + + + + + + + + + + + + + + + + + + +
    TypeIntentOptional AttributesName
    + + integer, + intent(in) + + ::i + +
    + +

    + Return Value + character(len=str_int_len) +

    + + +
  • +
  • +

    + private pure function str_int64(i) result(s) + +

    +

    Converts integer “i” to string

    + +

    Arguments

    + + + + + + + + + + + + + + + + + + + +
    TypeIntentOptional AttributesName
    + + integer(kind=int64), + intent(in) + + ::i + +
    + +

    + Return Value + character(len=str_int64_len) +

    + + +
  • +
  • +

    + private pure function str_logical(l) result(s) + +

    +

    Converts logical “l” to string

    + +

    Arguments

    + + + + + + + + + + + + + + + + + + + +
    TypeIntentOptional AttributesName
    + + logical, + intent(in) + + ::l + +
    + +

    + Return Value + character(len=str_logical_len) +

    + + +
  • +
+
+ +
+
+ +

public interface str_ends_with +

+
+
    +
  • +

    + private pure function str_ends_with_str(s, e) result(r) + +

    +

    test if a CHARACTER string ends with a specified suffix

    + +

    Arguments

    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    TypeIntentOptional AttributesName
    + + character(len=*), + intent(in) + + ::s + +
    + + character(len=*), + intent(in) + + ::e + +
    + +

    + Return Value + logical +

    + + +
  • +
  • +

    + private pure function str_ends_with_any(s, e) result(r) + +

    +

    test if a CHARACTER string ends with any of an array of suffixs

    + +

    Arguments

    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    TypeIntentOptional AttributesName
    + + character(len=*), + intent(in) + + ::s + +
    + + character(len=*), + intent(in) + + ::e(:) + +
    + +

    + Return Value + logical +

    + + +
  • +
  • +

    + private pure function str_ends_with_any_string(s, e) result(r) + +

    +

    Test if a CHARACTER string ends with any of an array of string suffixs

    + +

    Arguments

    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    TypeIntentOptional AttributesName
    + + character(len=*), + intent(in) + + ::s + +
    + + type(string_t), + intent(in) + + ::e(:) + +
    + +

    + Return Value + logical +

    + + +
  • +
+
+ +
+
+ +

public interface string_t +

+
+
    +
  • +

    + private function new_string_t(s) result(string) + +

    +

    Helper function to generate a new string_t instance + (Required due to the allocatable component)

    + +

    Arguments

    + + + + + + + + + + + + + + + + + + + +
    TypeIntentOptional AttributesName
    + + character(len=*), + intent(in) + + ::s + +
    + +

    + Return Value + type(string_t) +

    + + +
  • +
+
+ +
+
+ + +
+

Derived Types

+
+
+ +

+ type, public ::  + string_t + +

+
+
+ + +

Components

+ + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=:), + public, + allocatable + ::s + +
+ + +

Constructor

+ + + + + + + + +
+ private + + + function + new_string_t + (s) +

Helper function to generate a new string_t instance + (Required due to the allocatable component)

+ + +
+
+ +
+
+ +
+

Functions

+
+

public function dilate(instr) result(outstr) +

+
+
+
Author
John S. Urban
+
License
Public Domain
+
+ +

Sample program:

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::instr + +
+ +

+ Return Value + character(len=:), allocatable +

+ + +
+
+ +
+

public function f_string(c_string) +

+
+ +

return Fortran character variable when given a C-like array of +single characters terminated with a C_NULL_CHAR character

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=1), + intent(in) + + ::c_string(:) + +
+ +

+ Return Value + character(len=:), allocatable +

+ + +
+
+ +
+

public function glob(tame, wild) +

+
+
+
Author
John S. Urban
+
License
Public Domain
+
+ +

glob(3f) compares given STRING for match to PATTERN which may + contain wildcard characters.

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*) + + + ::tame +

A string without wildcards to compare to the globbing expression

+
+ + character(len=*) + + + ::wild +

A (potentially) corresponding string with wildcards

+
+ +

+ Return Value + logical +

+

result of test

+ +
+
+ +
+

public function has_valid_custom_prefix(module_name, custom_prefix) result(valid) +

+
+ +

Check that a module name is prefixed with a custom prefix: +1) It must be a valid FORTRAN name subset (<=63 chars, begin with letter, only alphanumeric allowed) +2) It must begin with the prefix +3) If longer, package name must be followed by default separator (“_”) plus at least one char

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(string_t), + intent(in) + + ::module_name + +
+ + type(string_t), + intent(in) + + ::custom_prefix + +
+ +

+ Return Value + logical +

+ + +
+
+ +
+

public function has_valid_standard_prefix(module_name, package_name) result(valid) +

+
+ +

Check that a module name is prefixed with the default package prefix: +1) It must be a valid FORTRAN name (<=63 chars, begin with letter, “_” is only allowed non-alphanumeric) +2) It must begin with the package name +3) If longer, package name must be followed by default separator plus at least one char

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(string_t), + intent(in) + + ::module_name + +
+ + type(string_t), + intent(in) + + ::package_name + +
+ +

+ Return Value + logical +

+ + +
+
+ +
+

public elemental function is_fortran_name(line) result(lout) +

+
+ + + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::line + +
+ +

+ Return Value + logical +

+ + +
+
+ +
+

public function is_valid_module_name(module_name, package_name, custom_prefix, enforce_module_names) result(valid) +

+
+ +

Check that a module name fits the current naming rules: +1) It must be a valid FORTRAN name (<=63 chars, begin with letter, “_” is only allowed non-alphanumeric) +2) It must begin with the package name +3) If longer, package name must be followed by default separator plus at least one char

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(string_t), + intent(in) + + ::module_name + +
+ + type(string_t), + intent(in) + + ::package_name + +
+ + type(string_t), + intent(in) + + ::custom_prefix + +
+ + logical, + intent(in) + + ::enforce_module_names + +
+ +

+ Return Value + logical +

+ + +
+
+ +
+

public function is_valid_module_prefix(module_prefix) result(valid) +

+
+ +

Check that a custom module prefix fits the current naming rules: +1) Only alphanumeric characters (no spaces, dashes, underscores or other characters) +2) Does not begin with a number (Fortran-compatible syntax)

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(string_t), + intent(in) + + ::module_prefix + +
+ +

+ Return Value + logical +

+ + +
+
+ +
+

public pure function join(str, sep, trm, left, right, start, end) result(string) +

+
+
+
Author
John S. Urban
+
License
Public Domain
+
+ +

JOIN(3f) appends the elements of a CHARACTER array into a single + CHARACTER variable, with elements 1 to N joined from left to right. + By default each element is trimmed of trailing spaces and the + default separator is a null string.

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::str(:) + +
+ + character(len=*), + intent(in),optional + + ::sep + +
+ + logical, + intent(in),optional + + ::trm + +
+ + character(len=*), + intent(in),optional + + ::left + +
+ + character(len=*), + intent(in),optional + + ::right + +
+ + character(len=*), + intent(in),optional + + ::start + +
+ + character(len=*), + intent(in),optional + + ::end + +
+ +

+ Return Value + character(len=:), allocatable +

+ + +
+
+ +
+

public pure elemental function lower(str, begin, end) result(string) +

+
+
+
Author
John S. Urban
+
License
Public Domain
+
+ +

Changes a string to lowercase over optional specified column range

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::str + +
+ + integer, + intent(in),optional + + ::begin + +
+ + integer, + intent(in),optional + + ::end + +
+ +

+ Return Value + character(len=len(str)) +

+ + +
+
+ +
+

public function module_prefix_template(project_name, custom_prefix) result(prefix) +

+
+ + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(string_t), + intent(in) + + ::project_name + +
+ + type(string_t), + intent(in) + + ::custom_prefix + +
+ +

+ Return Value + type(string_t) +

+ + +
+
+ +
+

public function module_prefix_type(project_name, custom_prefix) result(ptype) +

+
+ + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(string_t), + intent(in) + + ::project_name + +
+ + type(string_t), + intent(in) + + ::custom_prefix + +
+ +

+ Return Value + type(string_t) +

+ + +
+
+ +
+

public pure function replace(string, charset, target_char) result(res) +

+
+ +

Returns string with characters in charset replaced with target_char.

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::string + +
+ + character(len=1), + intent(in) + + ::charset(:) + +
+ + character(len=1), + intent(in) + + ::target_char + +
+ +

+ Return Value + character(len=len(string)) +

+ + +
+
+ +
+

public pure function str_begins_with_str(s, e, case_sensitive) result(r) +

+
+ +

test if a CHARACTER string begins with a specified prefix

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::s + +
+ + character(len=*), + intent(in) + + ::e + +
+ + logical, + intent(in),optional + + ::case_sensitive + +
+ +

+ Return Value + logical +

+ + +
+
+ +
+

public function string_array_contains(search_string, array) +

+
+ +

Check if array of TYPE(STRING_T) matches a particular CHARACTER string

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::search_string + +
+ + type(string_t), + intent(in) + + ::array(:) + +
+ +

+ Return Value + logical +

+ + +
+
+ +
+

public function string_cat(strings, delim) result(cat) +

+
+ +

Concatenate an array of type(string_t) into + a single CHARACTER variable

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(string_t), + intent(in) + + ::strings(:) + +
+ + character(len=*), + intent(in),optional + + ::delim + +
+ +

+ Return Value + character(len=:), allocatable +

+ + +
+
+ +
+

public pure function to_fortran_name(string) result(res) +

+
+ +

Returns string with special characters replaced with an underscore. +For now, only a hyphen is treated as a special character, but this can be +expanded to other characters if needed.

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::string + +
+ +

+ Return Value + character(len=len(string)) +

+ + +
+
+ +
+

public pure elemental function upper(str, begin, end) result(string) +

+
+ + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::str + +
+ + integer, + intent(in),optional + + ::begin + +
+ + integer, + intent(in),optional + + ::end + +
+ +

+ Return Value + character(len=len(str)) +

+ + +
+
+ +
+
+ +
+

Subroutines

+
+

public impure elemental subroutine notabs(instr, outstr, ilen) +

+
+
+
Author
John S. Urban
+
License
Public Domain
+
+ +

notabs(3f) - [fpm_strings:NONALPHA] expand tab characters + (LICENSE:PD)

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::instr + +
+ + character(len=*), + intent(out) + + ::outstr + +
+ + integer, + intent(out) + + ::ilen + +
+ + +
+
+ +
+

public subroutine remove_characters_in_set(string, set, replace_with) +

+
+ + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=:), + intent(inout), + allocatable + ::string + +
+ + character(len=*), + intent(in) + + ::set + +
+ + character(len=1), + intent(in),optional + + ::replace_with + +
+ + +
+
+ +
+

public subroutine remove_newline_characters(string) +

+
+ + + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(string_t), + intent(inout) + + ::string + +
+ + +
+
+ +
+

public subroutine split(input_line, array, delimiters, order, nulls) +

+
+
+
Author
John S. Urban
+
License
Public Domain
+
+ +

parse string on delimiter characters and store tokens into an allocatable array +given a line of structure ” par1 par2 par3 … parn ” store each par(n) into a separate variable in array.

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::input_line +

input string to tokenize

+
+ + character(len=:), + intent(out), + allocatable + ::array(:) +

output array of tokens

+
+ + character(len=*), + intent(in),optional + + ::delimiters +

list of delimiter characters

+
+ + character(len=*), + intent(in),optional + + ::order +

order of output array sequential|[reverse|right]

+
+ + character(len=*), + intent(in),optional + + ::nulls +

return strings composed of delimiters or not ignore|return|ignoreend

+
+ + +
+
+ +
+

public pure subroutine split_first_last(string, set, first, last) +

+
+ + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::string + +
+ + character(len=*), + intent(in) + + ::set + +
+ + integer, + intent(out), + allocatable + ::first(:) + +
+ + integer, + intent(out), + allocatable + ::last(:) + +
+ + +
+
+ +
+

public pure subroutine split_lines_first_last(string, first, last) +

+
+ + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::string + +
+ + integer, + intent(out), + allocatable + ::first(:) + +
+ + integer, + intent(out), + allocatable + ::last(:) + +
+ + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_targets.html b/module/fpm_targets.html new file mode 100644 index 0000000000..0509f14e26 --- /dev/null +++ b/module/fpm_targets.html @@ -0,0 +1,1872 @@ + + + + + + + + + + + + + fpm_targets – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_targets + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

Build target handling

+

This module handles the construction of the build target list + from the sources list ([[targets_from_sources]]), the + resolution of module-dependencies between build targets + ([[resolve_module_dependencies]]), and the enumeration of + objects required for link targets ([[resolve_target_linking]]).

+

A build target ([[build_target_t]]) is a file to be generated + by the backend (compilation and linking).

+

@note Note + The current implementation is ignorant to the existence of + module files (.mod,.smod). Dependencies arising from modules + are based on the corresponding object files (.o) only.

+

For more information, please read the documentation for the procedures:

+
    +
  • [[build_target_list]]
  • +
  • [[resolve_module_dependencies]]
  • +
+

Enumerations

+

Target type: FPM_TARGET_* + Describes the type of build target — determines backend build rules

+
+ + +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + integer, + public, +parameter + ::FPM_TARGET_ARCHIVE =2 +

Target type is library archive

+
+ + integer, + public, +parameter + ::FPM_TARGET_CPP_OBJECT =5 +

Target type is cpp compiled object

+
+ + integer, + public, +parameter + ::FPM_TARGET_C_OBJECT =4 +

Target type is c compiled object

+
+ + integer, + public, +parameter + ::FPM_TARGET_EXECUTABLE =1 +

Target type is executable

+
+ + integer, + public, +parameter + ::FPM_TARGET_OBJECT =3 +

Target type is compiled object

+
+ + integer, + public, +parameter + ::FPM_TARGET_SHARED =6 +

Target type is a shared library

+
+ + integer, + public, +parameter + ::FPM_TARGET_UNKNOWN =-1 +

Target type is unknown (ignored)

+
+ +
+
+ + +
+

Interfaces

+
+
+ +

public interface add_target +

+
+
    +
  • +

    + private subroutine add_new_target(targets, package, type, output_name, source, link_libraries, features, preprocess, version, output_dir) + +

    +

    Allocate a new target and append to target list

    + +

    Arguments

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    TypeIntentOptional AttributesName
    + + type(build_target_ptr), + intent(inout), + allocatable + ::targets(:) + +
    + + character(len=*), + intent(in) + + ::package + +
    + + integer, + intent(in) + + ::type + +
    + + character(len=*), + intent(in) + + ::output_name + +
    + + type(srcfile_t), + intent(in),optional + + ::source + +
    + + type(string_t), + intent(in),optional + + ::link_libraries(:) + +
    + + type(fortran_features_t), + intent(in),optional + + ::features + +
    + + type(preprocess_config_t), + intent(in),optional + + ::preprocess + +
    + + character(len=*), + intent(in),optional + + ::version + +
    + + character(len=*), + intent(in),optional + + ::output_dir + +
    + + +
  • +
  • +

    + private subroutine add_old_target(targets, add_target) + +

    + + +

    Arguments

    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    TypeIntentOptional AttributesName
    + + type(build_target_ptr), + intent(inout), + allocatable + ::targets(:) + +
    + + type(build_target_ptr), + intent(in) + + ::add_target + +
    + + +
  • +
  • +

    + private subroutine add_old_targets(targets, add_targets) + +

    + + +

    Arguments

    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    TypeIntentOptional AttributesName
    + + type(build_target_ptr), + intent(inout), + allocatable + ::targets(:) + +
    + + type(build_target_ptr), + intent(in) + + ::add_targets(:) + +
    + + +
  • +
+
+ +
+
+ + +
+

Derived Types

+
+
+ +

+ type, public ::  + build_target_ptr + +

+
+
+

Wrapper type for constructing arrays of [[build_target_t]] pointers

+ +

Components

+ + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + type(build_target_t), + public, + pointer + ::ptr=> null() + +
+ + + + +
+
+ +
+
+ +

+ type, public ::  + build_target_t + +

+
+
+

Type describing a generated build target

+ +

Components

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=:), + public, + allocatable + ::compile_flags +

Compile flags for this build target

+
+ + type(build_target_ptr), + public, + allocatable + ::dependencies(:) +

Resolved build dependencies

+
+ + integer(kind=int64), + public, + allocatable + ::digest_cached +

Previous source file hash

+
+ + type(fortran_features_t), + public + + ::features +

Language features

+
+ + character(len=:), + public, + allocatable + ::link_flags +

Link flags for this build target

+
+ + type(string_t), + public, + allocatable + ::link_libraries(:) +

Native libraries to link against

+
+ + type(string_t), + public, + allocatable + ::link_objects(:) +

Objects needed to link this target

+
+ + type(string_t), + public, + allocatable + ::macros(:) +

List of macros

+
+ + character(len=:), + public, + allocatable + ::output_dir +

File path of output directory

+
+ + character(len=:), + public, + allocatable + ::output_file +

File path of build target object relative to cwd

+
+ + character(len=:), + public, + allocatable + ::output_log_file +

File path of build log file relative to cwd

+
+ + character(len=:), + public, + allocatable + ::output_name +

File path of build target object relative to output_dir

+
+ + character(len=:), + public, + allocatable + ::package_name +

Name of parent package

+
+ + integer, + public + + ::schedule =-1 +

Targets in the same schedule group are guaranteed to be independent

+
+ + logical, + public + + ::skip =.false. +

Flag set if build target will be skipped (not built)

+
+ + logical, + public + + ::sorted =.false. +

Flag set if build target is sorted for building

+
+ + type(srcfile_t), + public, + allocatable + ::source +

Primary source for this build target

+
+ + integer, + public + + ::target_type =FPM_TARGET_UNKNOWN +

Target type

+
+ + logical, + public + + ::touched =.false. +

Flag set when first visited to check for circular dependencies

+
+ + character(len=:), + public, + allocatable + ::version +

Version number

+
+ + + + +

Type-Bound Procedures

+ + + + + + + + + + + + + + + +
procedure, public :: + info

Print information on this instance

procedure, public :: + is_executable_target
procedure, public :: + set_output_dir

Set output directory

+
+
+ +
+
+ +
+

Functions

+
+

public pure function FPM_TARGET_NAME(type) result(msg) +

+
+ +

Target type name

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + integer, + intent(in) + + ::type + +
+ +

+ Return Value + character(len=:), allocatable +

+ + +
+
+ +
+

public function new_target(package, type, output_name, source, link_libraries, features, preprocess, version, output_dir) +

+
+ +

Allocate a new target

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::package + +
+ + integer, + intent(in) + + ::type + +
+ + character(len=*), + intent(in) + + ::output_name + +
+ + type(srcfile_t), + intent(in),optional + + ::source + +
+ + type(string_t), + intent(in),optional + + ::link_libraries(:) + +
+ + type(fortran_features_t), + intent(in),optional + + ::features + +
+ + type(preprocess_config_t), + intent(in),optional + + ::preprocess + +
+ + character(len=*), + intent(in),optional + + ::version + +
+ + character(len=*), + intent(in),optional + + ::output_dir + +
+ +

+ Return Value + type(build_target_ptr) +

+ + +
+
+ +
+
+ +
+

Subroutines

+
+

public subroutine add_dependency(target, dependency) +

+
+ +

Add pointer to dependeny in target%dependencies

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(build_target_t), + intent(inout) + + ::target + +
+ + type(build_target_t), + intent(in), + target + ::dependency + +
+ + +
+
+ +
+

public subroutine filter_executable_targets(targets, scope, list) +

+
+ + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(build_target_ptr), + intent(in) + + ::targets(:) + +
+ + integer, + intent(in) + + ::scope + +
+ + type(string_t), + intent(out), + allocatable + ::list(:) + +
+ + +
+
+ +
+

public subroutine filter_library_targets(targets, list) +

+
+ +

Returns pointers to all library targets

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(build_target_ptr), + intent(in) + + ::targets(:) + +
+ + type(build_target_ptr), + intent(out), + allocatable + ::list(:) + +
+ + +
+
+ +
+

public subroutine filter_modules(targets, list) +

+
+ + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(build_target_ptr), + intent(in) + + ::targets(:) + +
+ + type(string_t), + intent(out), + allocatable + ::list(:) + +
+ + +
+
+ +
+

public subroutine get_library_dirs(model, targets, shared_lib_dirs) +

+
+ +

Add link directories for all shared libraries in the dependency graph

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(fpm_model_t), + intent(in) + + ::model + +
+ + type(build_target_ptr), + intent(inout), + target + ::targets(:) + +
+ + type(string_t), + intent(out), + allocatable + ::shared_lib_dirs(:) + +
+ + +
+
+ +
+

public subroutine resolve_module_dependencies(targets, external_modules, error) +

+
+ +

Add dependencies to source-based targets (FPM_TARGET_OBJECT) + based on any modules used by the corresponding source file.

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(build_target_ptr), + intent(inout), + target + ::targets(:) + +
+ + type(string_t), + intent(in) + + ::external_modules(:) + +
+ + type(error_t), + intent(out), + allocatable + ::error + +
+ + +
+
+ +
+

public subroutine targets_from_sources(targets, model, prune, library, error) +

+
+ +

High-level wrapper to generate build target information

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(build_target_ptr), + intent(out), + allocatable + ::targets(:) +

The generated list of build targets

+
+ + type(fpm_model_t), + intent(inout), + target + ::model +

The package model from which to construct the target list

+
+ + logical, + intent(in) + + ::prune +

Enable tree-shaking/pruning of module dependencies

+
+ + type(library_config_t), + intent(in),optional + + ::library +

Library build configuration

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error structure

+
+ + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_toml.html b/module/fpm_toml.html new file mode 100644 index 0000000000..2f60d32610 --- /dev/null +++ b/module/fpm_toml.html @@ -0,0 +1,1892 @@ + + + + + + + + + + + + + fpm_toml – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_toml + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+
+ + +
+ +
+

Interface to TOML processing library

+

This module acts as a proxy to the toml-f public Fortran API and allows + to selectively expose components from the library to fpm. + The interaction with toml-f data types outside of this module should be + limited to tables, arrays and key-lists, most of the necessary interactions + are implemented in the building interface with the get_value and set_value + procedures.

+

This module allows to implement features necessary for fpm, which are + not yet available in upstream toml-f.

+

For more details on the library used see the + TOML-Fortran developer pages.

+
+

Uses

+
+ +
+
+ + +
+ + + + +
+

Interfaces

+
+
+ +

public interface add_table +

+
+
+

add_table: fpm interface

+
+
    +
  • +

    + private subroutine add_table_fpm(table, key, ptr, error, whereAt) + +

    +

    Function wrapper to add a toml table and return an fpm error

    +

    Nullify pointer

    + +

    Arguments

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    TypeIntentOptional AttributesName
    + + type(toml_table), + intent(inout) + + ::table +

    Instance of the TOML data structure

    +
    + + character(len=*), + intent(in) + + ::key +

    Table key

    +
    + + type(toml_table), + intent(out), + pointer + ::ptr +

    The character variable

    +
    + + type(error_t), + intent(out), + allocatable + ::error +

    Error handling

    +
    + + character(len=*), + intent(in),optional + + ::whereAt +

    Optional description

    +
    + + +
  • +
+
+ +
+
+ +

public interface get_value +

+
+
+

get_value: fpm interface

+
+
    +
  • +

    + private subroutine get_logical(table, key, var, error, whereAt) + +

    +

    Function wrapper to get a logical variable from a toml table, returning an fpm error

    + +

    Arguments

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    TypeIntentOptional AttributesName
    + + type(toml_table), + intent(inout) + + ::table +

    Instance of the TOML data structure

    +
    + + character(len=*), + intent(in) + + ::key +

    The key

    +
    + + logical, + intent(inout) + + ::var +

    The variable

    +
    + + type(error_t), + intent(out), + allocatable + ::error +

    Error handling

    +
    + + character(len=*), + intent(in),optional + + ::whereAt +

    Optional description

    +
    + + +
  • +
  • +

    + private subroutine get_integer(table, key, var, error, whereAt) + +

    +

    Function wrapper to get a default integer variable from a toml table, returning an fpm error

    + +

    Arguments

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    TypeIntentOptional AttributesName
    + + type(toml_table), + intent(inout) + + ::table +

    Instance of the TOML data structure

    +
    + + character(len=*), + intent(in) + + ::key +

    The key

    +
    + + integer, + intent(inout) + + ::var +

    The variable

    +
    + + type(error_t), + intent(out), + allocatable + ::error +

    Error handling

    +
    + + character(len=*), + intent(in),optional + + ::whereAt +

    Optional description

    +
    + + +
  • +
  • +

    + private subroutine get_integer_64(table, key, var, error, whereAt) + +

    +

    Function wrapper to get a integer(int64) variable from a toml table, returning an fpm error

    + +

    Arguments

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    TypeIntentOptional AttributesName
    + + type(toml_table), + intent(inout) + + ::table +

    Instance of the TOML data structure

    +
    + + character(len=*), + intent(in) + + ::key +

    The key

    +
    + + integer(kind=int64), + intent(inout) + + ::var +

    The variable

    +
    + + type(error_t), + intent(out), + allocatable + ::error +

    Error handling

    +
    + + character(len=*), + intent(in),optional + + ::whereAt +

    Optional description

    +
    + + +
  • +
  • +

    + private subroutine get_char(table, key, var, error, whereAt) + +

    +

    Function wrapper to get a default character variable from a toml table, returning an fpm error

    + +

    Arguments

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    TypeIntentOptional AttributesName
    + + type(toml_table), + intent(inout) + + ::table +

    Instance of the TOML data structure

    +
    + + character(len=*), + intent(in) + + ::key +

    The key

    +
    + + character(len=:), + intent(inout), + allocatable + ::var +

    The variable

    +
    + + type(error_t), + intent(out), + allocatable + ::error +

    Error handling

    +
    + + character(len=*), + intent(in),optional + + ::whereAt +

    Optional description

    +
    + + +
  • +
  • +

    + private subroutine get_string(table, key, var, error, whereAt) + +

    +

    Function wrapper to get a default string variable from a toml table, returning an fpm error

    + +

    Arguments

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    TypeIntentOptional AttributesName
    + + type(toml_table), + intent(inout) + + ::table +

    Instance of the TOML data structure

    +
    + + character(len=*), + intent(in) + + ::key +

    The key

    +
    + + type(string_t), + intent(inout) + + ::var +

    The variable

    +
    + + type(error_t), + intent(out), + allocatable + ::error +

    Error handling

    +
    + + character(len=*), + intent(in),optional + + ::whereAt +

    Optional description

    +
    + + +
  • +
+
+ +
+
+ +

public interface set_string +

+
+
    +
  • +

    + private subroutine set_character(table, key, var, error, whereAt) + +

    +

    Function wrapper to set a character(len=:), allocatable variable to a toml table

    +

    Check the key is not empty

    + +

    Arguments

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    TypeIntentOptional AttributesName
    + + type(toml_table), + intent(inout) + + ::table +

    Instance of the TOML data structure

    +
    + + character(len=*), + intent(in) + + ::key +

    List of keys to check.

    +
    + + character(len=*), + intent(in),optional + + ::var +

    The character variable

    +
    + + type(error_t), + intent(out), + allocatable + ::error +

    Error handling

    +
    + + character(len=*), + intent(in),optional + + ::whereAt +

    Optional description

    +
    + + +
  • +
  • +

    + private subroutine set_string_type(table, key, var, error, whereAt) + +

    +

    Function wrapper to set a character(len=:), allocatable variable to a toml table

    + +

    Arguments

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    TypeIntentOptional AttributesName
    + + type(toml_table), + intent(inout) + + ::table +

    Instance of the TOML data structure

    +
    + + character(len=*), + intent(in) + + ::key +

    List of keys to check.

    +
    + + type(string_t), + intent(in) + + ::var +

    The character variable

    +
    + + type(error_t), + intent(out), + allocatable + ::error +

    Error handling

    +
    + + character(len=*), + intent(in),optional + + ::whereAt +

    Optional description

    +
    + + +
  • +
+
+ +
+
+ +

public interface set_value +

+
+
+

set_value: fpm interface

+
+
    +
  • +

    + private subroutine set_logical(table, key, var, error, whereAt) + +

    +

    Function wrapper to set a logical variable to a toml table, returning an fpm error

    + +

    Arguments

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    TypeIntentOptional AttributesName
    + + type(toml_table), + intent(inout) + + ::table +

    Instance of the TOML data structure

    +
    + + character(len=*), + intent(in) + + ::key +

    The key

    +
    + + logical, + intent(in) + + ::var +

    The variable

    +
    + + type(error_t), + intent(out), + allocatable + ::error +

    Error handling

    +
    + + character(len=*), + intent(in),optional + + ::whereAt +

    Optional description

    +
    + + +
  • +
  • +

    + private subroutine set_integer(table, key, var, error, whereAt) + +

    +

    Function wrapper to set a default integer variable to a toml table, returning an fpm error

    + +

    Arguments

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    TypeIntentOptional AttributesName
    + + type(toml_table), + intent(inout) + + ::table +

    Instance of the TOML data structure

    +
    + + character(len=*), + intent(in) + + ::key +

    The key

    +
    + + integer, + intent(in) + + ::var +

    The variable

    +
    + + type(error_t), + intent(out), + allocatable + ::error +

    Error handling

    +
    + + character(len=*), + intent(in),optional + + ::whereAt +

    Optional description

    +
    + + +
  • +
  • +

    + private subroutine set_integer_64(table, key, var, error, whereAt) + +

    +

    Function wrapper to set a default integer variable to a toml table, returning an fpm error

    + +

    Arguments

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    TypeIntentOptional AttributesName
    + + type(toml_table), + intent(inout) + + ::table +

    Instance of the TOML data structure

    +
    + + character(len=*), + intent(in) + + ::key +

    The key

    +
    + + integer(kind=int64), + intent(in) + + ::var +

    The variable

    +
    + + type(error_t), + intent(out), + allocatable + ::error +

    Error handling

    +
    + + character(len=*), + intent(in),optional + + ::whereAt +

    Optional description

    +
    + + +
  • +
+
+ +
+
+ + +
+

Derived Types

+
+
+ +

+ type, public, abstract ::  + serializable_t + +

+
+
+

An abstract interface for any fpm class that should be fully serializable to/from TOML/JSON

+ + + + +

Type-Bound Procedures

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit
procedure(to_toml), public, deferred :: + dump_to_toml

Dump to TOML table, unit, file

generic, public :: + load => load_from_toml, load_from_file, load_from_unit
procedure(from_toml), public, deferred :: + load_from_toml

Load from TOML table, unit, file

generic, public :: + operator(==) => serializable_is_same
procedure(is_equal), public, deferred :: + serializable_is_same

Serializable entities need a way to check that they’re equal

procedure, public, non_overridable :: + test_serialization

Test load/write roundtrip

+
+
+ +
+
+ +
+

Functions

+
+

public function has_list(table, key) +

+
+ +

Check if an instance of the TOML data structure contains a list

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(toml_table), + intent(inout) + + ::table +

Instance of the TOML data structure

+
+ + character(len=*), + intent(in) + + ::key +

Key to read from

+
+ +

+ Return Value + logical +

+ + +
+
+ +
+

public function name_is_json(filename) +

+
+ +

Choose between JSON or TOML based on a file name

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::filename + +
+ +

+ Return Value + logical +

+ + +
+
+ +
+
+ +
+

Subroutines

+
+

public subroutine check_keys(table, valid_keys, error) +

+
+ +

Check if table contains only keys that are part of the list. If a key is +found that is not part of the list, an error is allocated.

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(toml_table), + intent(inout) + + ::table +

Instance of the TOML data structure

+
+ + character(len=*), + intent(in) + + ::valid_keys(:) +

List of keys to check.

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + +
+
+ +
+

public subroutine get_list(table, key, list, error) +

+
+ + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(toml_table), + intent(inout) + + ::table +

Instance of the TOML data structure

+
+ + character(len=*), + intent(in) + + ::key +

Key to read from

+
+ + type(string_t), + intent(out), + allocatable + ::list(:) +

List of strings to read

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + +
+
+ +
+

public subroutine read_package_file(table, manifest, error) +

+
+ +

Process the configuration file to a TOML data structure

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(toml_table), + intent(out), + allocatable + ::table +

TOML data structure

+
+ + character(len=*), + intent(in) + + ::manifest +

Name of the package configuration file

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error status of the operation

+
+ + +
+
+ +
+

public subroutine set_list(table, key, list, error) +

+
+ +

Set no key if array is not present

Read more… + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(toml_table), + intent(inout) + + ::table +

Instance of the toml table

+
+ + character(len=*), + intent(in) + + ::key +

Key to save to

+
+ + type(string_t), + intent(in), + allocatable + ::list(:) +

Instance of the string array

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + +
+
+ +
+
+ + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/module/fpm_versioning.html b/module/fpm_versioning.html new file mode 100644 index 0000000000..c8c44160ae --- /dev/null +++ b/module/fpm_versioning.html @@ -0,0 +1,523 @@ + + + + + + + + + + + + + fpm_versioning – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_versioning + Module + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+
+ + +
+ +
+

Implementation of versioning data for comparing packages

+
+

Uses

+
+ +
+
+ + +
+ + + + +
+

Interfaces

+
+
+ +

public interface new_version +

+
+
    +
  • +

    + private subroutine new_version_from_string(self, string, error) + +

    +

    Create a new version from a string

    + +

    Arguments

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    TypeIntentOptional AttributesName
    + + type(version_t), + intent(out) + + ::self +

    Instance of the versioning data

    +
    + + character(len=*), + intent(in) + + ::string +

    String describing the version information

    +
    + + type(error_t), + intent(out), + allocatable + ::error +

    Error handling

    +
    + + +
  • +
  • +

    + private subroutine new_version_from_int(self, num) + +

    +

    Create a new version from a string

    + +

    Arguments

    + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    TypeIntentOptional AttributesName
    + + type(version_t), + intent(out) + + ::self +

    Instance of the versioning data

    +
    + + integer, + intent(in) + + ::num(:) +

    Subversion numbers to define version data

    +
    + + +
  • +
+
+ +
+
+ + +
+

Derived Types

+
+
+ +

+ type, public ::  + version_t + +

+
+
+ + + + + +

Type-Bound Procedures

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
generic, public :: + operator(.match.) => match

Compare a version against a version constraint (x.x.0 <= v < x.x.HUGE)

generic, public :: + operator(/=) => not_equals
generic, public :: + operator(<) => less
generic, public :: + operator(<=) => less_equals
generic, public :: + operator(==) => equals
generic, public :: + operator(>) => greater
generic, public :: + operator(>=) => greater_equals
procedure, public :: + s

Create a printable string from a version data type

+
+
+ +
+
+ +
+

Functions

+
+

public function regex_version_from_text(text, what, error) result(ver) +

+
+ + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::text + +
+ + character(len=*), + intent(in) + + ::what + +
+ + type(error_t), + intent(out), + allocatable + ::error + +
+ +

+ Return Value + type(string_t) +

+ + +
+
+ +
+
+ + + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/page/Contributing.html b/page/Contributing.html new file mode 100644 index 0000000000..1252dba975 --- /dev/null +++ b/page/Contributing.html @@ -0,0 +1,254 @@ + + + + + + + + + + + + + Contributing Guidelines – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

Contributing Guidelines

+
+
+
+
    +
+
+
+ +
+
+
+
+ +
+ + +
+

Contributing to the Fortran Package Manager

+

Thank you for considering contributing to the Fortran Package Manager (fpm). +Please review and follow these guidelines to make the contribution process +simple and effective for all involved. It will help communicate that you +respect the time of the community developers. In return, the community will +help address your problem, evaluate changes, and guide you through your pull +requests.

+

By contributing to fpm, you certify that you own or are allowed to share the +content of your contribution under the fpm license.

+ +

Style

+

Please follow the +Fortran stdlib style guide +for any Fortran code that you contribute. +This allows us to focus on substance rather than style.

+

Reporting a bug

+

A bug is a demonstrable problem caused by the code in this repository. +Good bug reports are extremely valuable to us—thank you!

+

Before opening a bug report:

+
    +
  1. Check if the issue has already been reported + (issues).
  2. +
  3. Check if it is still an issue or it has been fixed? + Try to reproduce it with the latest version from the default branch.
  4. +
  5. Isolate the problem and create a minimal test case.
  6. +
+

A good bug report should include all information needed to reproduce the bug. +Please be as detailed as possible:

+
    +
  1. Which version of fpm are you using? Please be specific.
  2. +
  3. What are the steps to reproduce the issue?
  4. +
  5. What is the expected outcome?
  6. +
  7. What happens instead?
  8. +
+

This information will help the community diagnose the issue quickly and with +minimal back-and-forth.

+

Suggesting a feature

+

Before suggesting a new feature, take a moment to find out if it fits the scope +of the project, or if it has already been discussed. It is up to you to provide +a strong argument to convince the community of the benefits of this feature. +Please provide as much detail and context as possible. If applicable, include a +mocked-up snippet of what the output or behavior would look like with this +feature implemented. “Crazy”, out-of-the-box ideas are especially welcome. +It’s quite possible that we are not considering an unusually creative solution.

+

Workflow

+

fpm is a community project. There is no one single person making final +decisions. This is the workflow that we follow:

+
    +
  1. Open a new issue to + describe a bug or propose a new feature. + Refer to the earlier sections on how to write a good bug report or feature + request.
  2. +
  3. Discuss with the community and reach majority consensus about what should be + done about the bug or feature request. + We define “majority” loosely as 80%. + This means that at least 4 of 5 people engaged in the discussion should be + able to agree on the next step. + This allows us to have the community mostly agree while not getting stuck if + one person disagrees. + At this stage, the scope of the fix/feature, its behavior, and API if + applicable should be defined. + Only when you have community consensus on these items you should proceed to + writing code and opening a PR. + When actively working on code towards a PR, please assign yourself to the + issue on GitHub. + This is good collaborative practice to avoid duplicated effort and also + inform others what you are currently working on.
  4. +
  5. Open a new Pull Request (PR) with your contribution. + The body of the PR should at least include a bullet-point summary of the + changes, and a detailed description is encouraged. + If the PR completely addresses the issue you opened in step 1, include in + the PR description the following line: Fixes #<issue-number>.
  6. +
  7. Request reviewers to your PR. + For small bug fixes or documentation improvements, 1 to 2 reviewers is + sufficient. + For implementation of bigger features, request 3 to 4 or more reviewers. + Ideally, request reviewers that participated in step 2.
  8. +
  9. If your PR implements a feature that adds or changes the behavior of fpm, + your PR must also include appropriate changes to the documentation.
  10. +
+

This workflow can evolve and change over time as we learn how best to work +together. If you have an idea on how to improve the workflow itself, please +open an issue and we’ll discuss it.

+

General guidelines

+
    +
  • A PR should implement only one feature or bug fix.
  • +
  • Do not commit changes to files that are irrelevant to your feature or bug fix.
  • +
  • Smaller PRs are better than large PRs, and will lead to a shorter review and + merge cycle
  • +
  • Add tests for your feature or bug fix to be sure that it stays functional and useful
  • +
  • Be open to constructive criticism and requests for improving your code.
  • +
  • Again, please follow the + Fortran stdlib style guide.
  • +
+

For new contributors

+

If you have never created a pull request before, welcome :tada:. +You can learn how from +this great tutorial.

+

Don’t know where to start? +You can start by looking through the list of +open issues.

+
+
+
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/page/License.html b/page/License.html new file mode 100644 index 0000000000..99d88b35f5 --- /dev/null +++ b/page/License.html @@ -0,0 +1,163 @@ + + + + + + + + + + + + + License – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

License

+
+
+
+
    +
+
+
+ +
+
+
+
+ +
+ + +
+

MIT License

+

Copyright (c) 2020 fpm contributors

+

Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the “Software”), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions:

+

The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software.

+

THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.

+
+
+
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/page/Manifest.html b/page/Manifest.html new file mode 100644 index 0000000000..2ab49a61c9 --- /dev/null +++ b/page/Manifest.html @@ -0,0 +1,148 @@ + + + + + + + + + + + + + Manifest reference – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

Manifest reference

+
+
+
+
    +
+
+
+ +
+
+
+
+ +
+ + +
+

301 - Moved

+

This document now lives at https://fpm.fortran-lang.org/spec/manifest.html

+
+
+
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/page/Packaging.html b/page/Packaging.html new file mode 100644 index 0000000000..1ea6aeabec --- /dev/null +++ b/page/Packaging.html @@ -0,0 +1,756 @@ + + + + + + + + + + + + + Packaging with fpm – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

Packaging with fpm

+
+
+
+
    +
+
+
+ +
+
+
+
+ +
+ + +
+

Preparing your package for FPM

+

This document describes how you need to organize your application or library for +it to successfully build with the Fortran Package Manager (fpm).

+ +

What kind of package can fpm build?

+

You can use fpm to build:

+
    +
  • Applications (program only)
  • +
  • Libraries (modules only)
  • +
  • Combination of the two (programs and modules combined)
  • +
+

Let’s look at some examples of different kinds of package layouts that you can +use with fpm.

+

Example package layouts

+

This section describes some example package layouts that you can build with +fpm. You can use them to model the layout of your own package.

+

Single program

+

Let’s start with the simplest package imaginable—a single program without +dependencies or modules. Here’s what the layout of the top-level directory +looks like:

+
.
+├── app
+│   └── main.f90
+└── fpm.toml
+
+ +

We have one source file (main.f90) in one directory (app). Its contents +are:

+
program main
+    print *, 'Hello, World!'
+end program main
+
+ +

This program prints the usual greeting to the standard output, and nothing more.

+

There’s another important file in the top-level directory, fpm.toml. This is +fpm’s configuration file specific to your package. It includes all the data +that fpm needs to build your app. In our simple case, it looks like this:

+
name = "hello"
+version = "0.1.0"
+license = "MIT"
+author = "Jane Programmer"
+maintainer = "jane@example.com"
+copyright = "2020 Jane Programmer"
+
+ +

The preamble includes some metadata, such as license, author, and similar, +that you may have seen in other package manager configuration files. The one +option that matters here right now is:

+
name = "hello"
+
+ +

This line specifies the name of your package, which determines the name of the +executable file of your program. In this example, our program executable, once +built, will be called hello.

+

Let’s now build this program using fpm:

+
$ fpm build
+# gfortran (for build/debug/app/main.o)
+# gfortran (for build/debug/app/hello)
+
+ +

On the first line, we ran fpm build to compile and link the application. +The latter two lines are emitted by fpm, and indicate which command was +executed at each build step (gfortran), and which files have been output +by it: object file main.o, and executable hello.

+

We can now run the app with fpm run:

+
$ fpm run
+ Hello, World!
+
+ +

If your application needs to use a module internally, but you don’t intend +to build it as a library to be used in other projects, you can include the +module in your program source file as well. +For example:

+
$ cat app/main.f90
+module math_constants
+    real, parameter :: pi = 4 * atan(1.)
+end module math_constants
+
+program main
+    use math_constants, only: pi
+    print *, 'Hello, World!'
+    print *, 'pi = ', pi
+end program main
+
+ +

Now, run this using fpm run:

+
$ fpm run
+# gfortran (for build/debug/app/main.o)
+# gfortran (for build/debug/app/hello)
+ Hello, World!
+ pi =    3.14159274
+
+ +

Although we have named our program hello, which is the same name as the +package name in fpm.toml, you can name it anything you want as long as it’s +permitted by the language.

+

Notice that you can run fpm run, and if the package hasn’t been built yet, +fpm build will run automatically for you. This is true if the source files +have been updated since the last build. Thus, if you want to run your +application, you can skip the fpm build step, and go straight to fpm run.

+

When running your application using fpm run, the program’s exit code is +passed by fpm back to the operating system. So, it is possible to use Fortran +numbered stop and error stop codes to pass termination reasons back to the terminal.

+

Try running the following app with fpm run:

+
program main
+    use math_constants, only: pi
+
+    real :: angle
+
+    read(*,*,iostat=ierr) angle
+    if (ierr/=0) then
+       stop 2 ! Not real
+    elseif (angle>pi) then
+       stop 1
+    else
+       stop 0
+    endif
+end program main
+
+ +

and then checking that the error code matches. Note that error codes are passed to variable $? +on Unix/Mac systems, and to environment variable %errorlevel% on Windows.

+

In this last example, our source file defined a math_constants module inside +the same source file as the main program. Let’s see how we can define an fpm +package that makes this module available as a library.

+

Single-module library

+

The package layout for this example looks like this:

+
.
+├── fpm.toml
+└── src
+    └── math_constants.f90
+
+ +

In this example we’ll build a simple math constants library that exports +the number pi as a parameter:

+
$ cat src/math_constants.f90
+module math_constants
+    real, parameter :: pi = 4 * atan(1.)
+end module math_constants
+
+ +

and our fpm.toml is the same as before.

+

Now use fpm build to build the package:

+
$ fpm build
+# gfortran (for build/debug/library/math_constants.o build/debug/library/math_constants.mod)
+# ar (for build/debug/library/math_constants.a)
+ar: creating build/debug/library/math_constants.a
+
+ +

Based on the output of fpm build, fpm first ran gfortran to emit the +binary object (math_constants.o) and module (math_constants.mod) files. +Then it ran ar to create a static library archive math_constants.a. +build/debug/library is thus both your include and library path, should you +want to compile and link an external program with this library.

+

For modules in the top-level (src) directory, fpm requires that:

+
    +
  • The module has the same name as the source file.
  • +
  • There is only one module per file.
  • +
+

These two requirements simplify the build process for fpm. As Fortran +compilers emit module files (.mod) with the same name as the module itself +(but not the source file, .f90), naming the module the same as the source file +allows fpm to:

+
    +
  • Uniquely and exactly map a source file (.f90) to its object (.o) and +module (.mod) files.
  • +
  • Avoid conflicts with modules of the same name that could appear in dependency +packages (more on this in a bit).
  • +
+

Since this is a library without executable programs, fpm run here does +nothing.

+

In this example, our library is made of only one module. However, most +real-world libraries are likely to use multiple modules. Let’s see how you can +package your multi-module library.

+

Multi-module library

+

In this example, we’ll use another module to define a 64-bit real kind +parameter and make it available in math_constants to define pi with +higher precision. To make this exercise worthwhile, we’ll define another math +constant, Euler’s number.

+

Our package layout looks like this:

+
.
+├── fpm.toml
+└── src
+    ├── math_constants.f90
+    └── type_kinds.f90
+
+ +

And our source file contents are:

+
$ cat src/math_constants.f90
+module math_constants
+    use type_kinds, only: rk
+    real(rk), parameter :: pi = 4 * atan(1._rk)
+    real(rk), parameter :: e = exp(1._rk)
+end module math_constants
+
+$ cat src/type_kinds.f90
+module type_kinds
+    use iso_fortran_env, only: real64
+    integer, parameter :: rk = real64
+end module type_kinds
+
+ +

and there are no changes to our fpm.toml relative to previous examples.

+

Like before, notice that the module type_kinds is name exactly as the +source file that contains it. +This is important.

+

By now you know how to build the package:

+
$ fpm build
+# gfortran (for build/debug/library/type_kinds.o build/debug/library/type_kinds.mod)
+# gfortran (for build/debug/library/math_constants.o build/debug/library/math_constants.mod)
+# ar (for build/debug/library/math_constants.a)
+ar: creating build/debug/library/math_constants.a
+
+ +

Our build path now contains:

+
$ ls build/debug/library/
+math_constants.a  math_constants.mod  math_constants.o  type_kinds.mod  type_kinds.o
+
+ +

And the static library includes all the object files:

+
$ nm build/debug/library/math_constants.a
+
+math_constants.o:
+
+type_kinds.o:
+
+ +

The takeaways from this example are that:

+
    +
  • fpm automatically scanned the src directory for any source files.
  • +
  • It also resolved the dependency order between different modules.
  • +
+

Application and library

+

Let’s now combine the two previous examples into one: We’ll build the math +constants library and an executable program that uses it. We’ll use this +program as a demo, and to verify that defining higher-precision constants from +the previous example actually worked.

+

Here’s the package layout for your application + library package:

+
.
+├── app
+   └── main.f90
+├── fpm.toml
+└── src
+    ├── math_constants.f90
+    └── type_kinds.f90
+
+ +

Our fpm.toml remains unchanged and our executable program source file is:

+
$ cat app/main.f90
+program main
+    use math_constants, only: e, pi
+    print *, 'math_constants library demo'
+    print *, 'pi = ', pi
+    print *, 'e = ', e
+end program main
+
+ +

Let’s go straight to running the demo program:

+
$ fpm run
+# gfortran (for build/debug/library/type_kinds.o build/debug/library/type_kinds.mod)
+# gfortran (for build/debug/library/math_constants.o build/debug/library/math_constants.mod)
+# ar (for build/debug/library/math_constants.a)
+ar: creating build/debug/library/math_constants.a
+# gfortran (for build/debug/app/main.o)
+# gfortran (for build/debug/app/math_constants)
+ math_constants library demo
+ pi =    3.1415926535897931
+ e =    2.7182818284590451
+
+ +

The fpm build + run process works as expected, and our program correctly +outputs higher-precision constants.

+

So far we covered how fpm builds:

+
    +
  • A single program
  • +
  • A single-module library
  • +
  • A multi-module library
  • +
  • A program and a library
  • +
+

However, all our modules so far have been organized in the top level source +directory. More complex libraries may organize their modules in subdirectories. +Let’s see how we can build this with fpm.

+

Multi-level library

+

In this example, we’ll define our library as a collection of modules, two of +which are defined in a subdirectory:

+
.
+├── app
+   └── main.f90
+├── fpm.toml
+└── src
+    ├── math_constants
+       ├── derived.f90
+       └── fundamental.f90
+    ├── math_constants.f90
+    └── type_kinds.f90
+
+ +

First, fpm.toml and src/type_kinds.f90 remain unchanged relative to the +previous example.

+

The rest of the source files are:

+
$ cat src/math_constants.f90
+module math_constants
+    use math_constants_fundamental, only: e, pi
+    use math_constants_derived, only: half_pi, two_pi
+end module math_constants
+
+$ cat src/math_constants/fundamental.f90
+module math_constants_fundamental
+    use type_kinds, only: rk
+    real(rk), parameter :: pi = 4 * atan(1._rk)
+    real(rk), parameter :: e = exp(1._rk)
+end module math_constants_fundamental
+
+$ cat src/math_constants/derived.f90
+module math_constants_derived
+    use math_constants_fundamental, only: pi
+    use type_kinds, only: rk
+    real(rk), parameter :: two_pi = 2 * pi
+    real(rk), parameter :: half_pi = pi / 2
+end module math_constants_derived
+
+$ cat app/main.f90
+program main
+    use math_constants, only: e, pi, half_pi, two_pi
+    print *, 'math_constants library demo'
+    print *, 'pi = ', pi
+    print *, '2*pi = ', two_pi
+    print *, 'pi/2 = ', half_pi
+    print *, 'e = ', e
+end program main
+
+ +

Our top-level math_constants module now doesn’t define the constants, but +imports them from the two modules in the subdirectory. Constants e and pi +we define in the math_constants_fundamental module, and two_pi and half_pi +in the math_constants_derived module. From the main program, we access all +the constants from the top-level module math_constants.

+

Let’s build and run this package:

+
$ fpm run
+# gfortran (for build/debug/library/type_kinds.o build/debug/library/type_kinds.mod)
+# gfortran (for build/debug/library/math_constants_fundamental.o build/debug/library/math_constants_fundamental.mod)
+# gfortran (for build/debug/library/math_constants_derived.o build/debug/library/math_constants_derived.mod)
+# gfortran (for build/debug/library/math_constants.o build/debug/library/math_constants.mod)
+# ar (for build/debug/library/math_constants.a)
+ar: creating build/debug/library/math_constants.a
+# gfortran (for build/debug/app/main.o)
+# gfortran (for build/debug/app/math_constants)
+ math_constants library demo
+ pi =    3.1415926535897931
+ 2*pi =    6.2831853071795862
+ pi/2 =    1.5707963267948966
+ e =    2.7182818284590451
+
+ +

Again, fpm built and run the package as expected.

+

Recall from an earlier example that fpm required the modules in the top-level +src directory to be named the same as their source file. This is why +src/math_constants.f90 defines module math_constants.

+

For modules defined in subdirectories, there’s an additional requirement: module +name must contain the path components of the directory that its source file is +in. In our case, src/math_constants/fundamental.f90 defines the +math_constants_fundamental module. Likewise, src/math_constants/derived.f90 +defines the math_constants_derived module.

+

This rule applies generally to any number of nested directories and modules. +For example, src/a/b/c/d.f90 must define a module called a_b_c_d.

+

Takeaways from this example are that:

+
    +
  • You can place your module source files in any levels of subdirectories inside src.
  • +
  • The module name must include the path components and the source file name–for example, +src/a/b/c/d.f90 must define a module called a_b_c_d.
  • +
+

Be more explicit

+

So far we’ve let fpm use its defaults to determine the layout of our package. +It determined where our library sources would live, what the name of the +executable will be, and some other things. But we can be more explicit about it, +and make some changes to those things.

+

Let’s look at what the fpm.toml file from our last example would look like if +we specified everything.

+
name = "math_constants"
+version = "0.1.0"
+license = "MIT"
+author = "Jane Programmer"
+maintainer = "jane@example.com"
+copyright = "2020 Jane Programmer"
+
+[library]
+source-dir="src"
+
+[[ executable ]]
+name="math_constants"
+source-dir="app"
+main="main.f90"
+
+ +

You can see that by making these explicit in the fpm.toml we are able to +change many of the settings that fpm used by default. We can change the +folders where our sources are stored, we can change the name of our executable, +and we can change the name of the file our program is defined in.

+

Add some tests

+

fpm also provides support for unit testing. By default, fpm looks for a +program in test/main.f90 which it will compile and execute with the command +fpm test. The tests are treated pretty much exactly like the executables. +Let’s define one explicitly in our fpm.toml file. We’ll make sure that our +definition of pi satisfies the property sin(pi) == 0.0. Here’s the +fpm.toml file:

+
name = "math_constants"
+version = "0.1.0"
+license = "MIT"
+author = "Jane Programmer"
+maintainer = "jane@example.com"
+copyright = "2020 Jane Programmer"
+
+[library]
+source-dir="src"
+
+[[ executable ]]
+name="math_constants"
+source-dir="app"
+main="main.f90"
+
+[[ test ]]
+name="runTests"
+source-dir="test"
+main="main.f90"
+
+ +

where the contents of the main.f90 file are

+
program main
+    use math_constants, only: pi
+    print *, "sin(pi) = ", sin(pi)
+end program main
+
+ +

With this setup, we can run our tests.

+
$ fpm test
+# gfortran (for build/debug/library/type_kinds.o build/debug/library/type_kinds.mod)
+# gfortran (for build/debug/library/math_constants_fundamental.o build/debug/library/math_constants_fundamental.mod)
+# gfortran (for build/debug/library/math_constants_derived.o build/debug/library/math_constants_derived.mod)
+# gfortran (for build/debug/library/math_constants.o build/debug/library/math_constants.mod)
+# ar (for build/debug/library/math_constants.a)
+ar: creating build/debug/library/math_constants.a
+# gfortran (for build/debug/app/main.o)
+# gfortran (for build/debug/app/math_constants)
+# gfortran (for build/debug/test/main.o)
+# gfortran (for build/debug/test/runTests)
+ sin(pi) =    1.2246467991473532E-016
+
+ +

Adding dependencies

+

Inevitably, you’ll want to be able to include other libraries in your project. +fpm makes this incredibly simple, by taking care of fetching and compiling your +dependencies for you. You just tell it what your dependencies are, and where to +find them. Let’s add a dependency to our library. Now our fpm.toml file looks +like this:

+
name = "math_constants"
+version = "0.1.0"
+license = "MIT"
+author = "Jane Programmer"
+maintainer = "jane@example.com"
+copyright = "2020 Jane Programmer"
+
+[library]
+source-dir="src"
+
+[dependencies]
+helloff = { git = "https://gitlab.com/everythingfunctional/helloff.git" }
+
+[[ executable ]]
+name="math_constants"
+source-dir="app"
+main="main.f90"
+
+[[ test ]]
+name="runTests"
+source-dir="test"
+main="main.f90"
+
+ +

Now you can use any modules from this library anywhere in your code. Just like +this:

+
program main
+    use helloff, only: create_greeting
+    use math_constants, only: e, pi, half_pi, two_pi
+    print *, 'math_constants library demo'
+    print *, 'pi = ', pi
+    print *, '2*pi = ', two_pi
+    print *, 'pi/2 = ', half_pi
+    print *, 'e = ', e
+    print *, create_greeting("fpm")
+end program main
+
+ +

And now, fpm run will output the following:

+
 math_constants library demo
+ pi =    3.1415926535897931
+ 2*pi =    6.2831853071795862
+ pi/2 =    1.5707963267948966
+ e =    2.7182818284590451
+ Hello, fpm!
+
+ +

Additionally, any users of your library will now automatically depend on your +dependencies too. So if you don’t need that dependency for the library, like in +the above example, then you can specify it for the specific executable like +below. Then fpm will still fetch and compile it when building your executable, +but users of your library won’t have to.

+
name = "math_constants"
+version = "0.1.0"
+license = "MIT"
+author = "Jane Programmer"
+maintainer = "jane@example.com"
+copyright = "2020 Jane Programmer"
+
+[library]
+source-dir="src"
+
+[[ executable ]]
+name="math_constants"
+source-dir="app"
+main="main.f90"
+[executable.dependencies]
+helloff = { git = "https://gitlab.com/everythingfunctional/helloff.git" }
+
+[[ test ]]
+name="runTests"
+source-dir="test"
+main="main.f90"
+
+ +

You can also specify dependencies for your tests in a similar way, with +[test.dependencies] instead of [executable.dependencies]. There’s also +another option for test dependencies. The below example makes the dependencies +available for all the tests, but again your users won’t depend on these.

+
name = "math_constants"
+version = "0.1.0"
+license = "MIT"
+author = "Jane Programmer"
+maintainer = "jane@example.com"
+copyright = "2020 Jane Programmer"
+
+[library]
+source-dir="src"
+
+[dev-dependencies]
+helloff = { git = "https://gitlab.com/everythingfunctional/helloff.git" }
+
+[[ executable ]]
+name="math_constants"
+source-dir="app"
+main="main.f90"
+
+[[ test ]]
+name="runTests"
+source-dir="test"
+main="main.f90"
+
+ +

You can also be specific about which version of a dependency you’d like. You can +specify a branch to use like +helloff = { git = "https://gitlab.com/everythingfunctional/helloff.git", branch = "master" }, +or a tag like +helloff = { git = "https://gitlab.com/everythingfunctional/helloff.git", tag = "v1.2.3" }, +or even a specific commit like +helloff = { git = "https://gitlab.com/everythingfunctional/helloff.git", rev = "a1b2c3" }. +You can even specify the path to another folder, if for example you’ve got +another fpm package in the same repository. Like this: +helloff = { path = "helloff" }. Note that you should not specify paths +outside of your repository, or things won’t work for your users.

+

Custom build scripts

+

If there is something special about your library that makes fpm unable to build +it, you can provide your own build script. fpm will then simply call your build +script to build the library.

+

To specify a build script to be used, put it in the library section of your +fpm.toml file, like:

+
[library]
+source-dir="src"
+build-script="my_build_script"
+
+ +

fpm will set the following environment variables to specify some parameters to +the build script:

+
    +
  • FC – The Fortran compiler to be used.
  • +
  • FFLAGS – The flags that should be passed to the Fortran compiler.
  • +
  • BUILD_DIR – Where the compiled files should be placed.
  • +
  • INCLUDE_DIRS – The folders where any dependencies can be found, space separated. +It is then the responsibility of the build script to generate the appropriate +include flags.
  • +
+

Additionally, script will be called with the name of the archive (*.a file) +that should be produced as the command line argument.

+
+

Note: If the name of the build script is Makefile or ends with .mk, then +the make program will be used to run it. Not the the archive file is explicitly +specified as the target to be built

+

Note: All file and directory names are specified with their full canonical +path.

+
+
+
+
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/page/index.html b/page/index.html new file mode 100644 index 0000000000..11718fe591 --- /dev/null +++ b/page/index.html @@ -0,0 +1,146 @@ + + + + + + + + + + + + + Packaging and contributing – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

Packaging and contributing

+
+
+
+
    +
+
+
+ +
+
+
+
+ + +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/add_dependency~2.html b/proc/add_dependency~2.html new file mode 100644 index 0000000000..bec32c8dc3 --- /dev/null +++ b/proc/add_dependency~2.html @@ -0,0 +1,264 @@ + + + + + + + + + + + + + add_dependency – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

add_dependency + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine add_dependency(target, dependency) +

+ + +

Add pointer to dependeny in target%dependencies

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(build_target_t), + intent(inout) + + ::target + +
+ + type(build_target_t), + intent(in), + target + ::dependency + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
subroutine add_dependency(target, dependency)
+    type(build_target_t), intent(inout) :: target
+    type(build_target_t) , intent(in), target :: dependency
+
+    target%dependencies = [target%dependencies, build_target_ptr(dependency)]
+
+end subroutine add_dependency
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/add_executable_sources.html b/proc/add_executable_sources.html new file mode 100644 index 0000000000..40c9723333 --- /dev/null +++ b/proc/add_executable_sources.html @@ -0,0 +1,394 @@ + + + + + + + + + + + + + add_executable_sources – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

add_executable_sources + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine add_executable_sources(sources, executables, scope, auto_discover, with_f_ext, error) +

+ + +

Add to sources using the executable and test entries in the manifest and +applies any executable-specific overrides such as executable%name. +Adds all sources (including modules) from each executable%source_dir +Compare lowercase strings to allow auto-discovery of pre-processed extensions

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(srcfile_t), + intent(inout), + allocatable, target + ::sources(:) +

List of [[srcfile_t]] objects to append to. Allocated if not allocated

+
+ + class(executable_config_t), + intent(in) + + ::executables(:) +

List of [[executable_config_t]] entries from manifest

+
+ + integer, + intent(in) + + ::scope +

Scope to apply to the discovered sources: either FPM_SCOPE_APP or FPM_SCOPE_TEST, see fpm_model

+
+ + logical, + intent(in) + + ::auto_discover +

If .false. only executables and tests specified in the manifest are added to sources

+
+ + type(string_t), + intent(in),optional + + ::with_f_ext(:) +

Additional user-defined (preprocessor) extensions that should be treated as Fortran sources

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
subroutine add_executable_sources(sources,executables,scope,auto_discover,with_f_ext,error)
+    !> List of `[[srcfile_t]]` objects to append to. Allocated if not allocated
+    type(srcfile_t), allocatable, intent(inout), target :: sources(:)
+    !> List of `[[executable_config_t]]` entries from manifest
+    class(executable_config_t), intent(in) :: executables(:)
+    !> Scope to apply to the discovered sources: either `FPM_SCOPE_APP` or `FPM_SCOPE_TEST`, see [[fpm_model]]
+    integer, intent(in) :: scope
+    !> If `.false.` only executables and tests specified in the manifest are added to `sources`
+    logical, intent(in) :: auto_discover
+    !> Additional user-defined (preprocessor) extensions that should be treated as Fortran sources
+    type(string_t), intent(in), optional :: with_f_ext(:)
+    !> Error handling
+    type(error_t), allocatable, intent(out) :: error
+
+    integer :: i, j
+
+    type(string_t), allocatable :: exe_dirs(:)
+    type(srcfile_t) :: exe_source
+
+    call get_executable_source_dirs(exe_dirs,executables)
+
+    do i=1,size(exe_dirs)
+        call add_sources_from_dir(sources,exe_dirs(i)%s, scope, &
+                     with_executables=auto_discover, with_f_ext=with_f_ext,recurse=.false., error=error)
+
+        if (allocated(error)) then
+            return
+        end if
+    end do
+
+    exe_loop: do i=1,size(executables)
+
+        ! Check if executable already discovered automatically
+        !  and apply any overrides
+        do j=1,size(sources)
+
+            !> Compare lowercase strings to allow auto-discovery of pre-processed extensions
+            if (lower(basename(sources(j)%file_name,suffix=.true.)) == lower(executables(i)%main) .and.&
+                 canon_path(dirname(sources(j)%file_name)) == &
+                 canon_path(executables(i)%source_dir) ) then
+
+                sources(j)%exe_name = executables(i)%name
+                if (allocated(executables(i)%link)) then
+                    sources(j)%link_libraries = executables(i)%link
+                end if
+                sources(j)%unit_type = FPM_UNIT_PROGRAM
+                cycle exe_loop
+
+            end if
+
+        end do
+
+        ! Add if not already discovered (auto_discovery off)
+        associate(exe => executables(i))
+            exe_source = parse_source(join_path(exe%source_dir,exe%main),with_f_ext,error)
+            exe_source%exe_name = exe%name
+            if (allocated(exe%link)) then
+                exe_source%link_libraries = exe%link
+            end if
+            exe_source%unit_type = FPM_UNIT_PROGRAM
+            exe_source%unit_scope = scope
+        end associate
+
+        if (allocated(error)) return
+
+        if (.not.allocated(sources)) then
+            sources = [exe_source]
+        else
+            sources = [sources, exe_source]
+        end if
+
+    end do exe_loop
+
+end subroutine add_executable_sources
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/add_pkg_config_compile_options.html b/proc/add_pkg_config_compile_options.html new file mode 100644 index 0000000000..1c3454cd14 --- /dev/null +++ b/proc/add_pkg_config_compile_options.html @@ -0,0 +1,365 @@ + + + + + + + + + + + + + add_pkg_config_compile_options – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

add_pkg_config_compile_options + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine add_pkg_config_compile_options(this, name, include_flag, libdir, error) +

+ + +

Add pkgconfig compile options to a metapackage +Get version +Get libraries +Get compiler flags

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(metapackage_t), + intent(inout) + + ::this + +
+ + character(len=*), + intent(in) + + ::name + +
+ + character(len=*), + intent(in) + + ::include_flag + +
+ + character(len=:), + + allocatable + ::libdir + +
+ + type(error_t), + intent(out), + allocatable + ::error + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
    subroutine add_pkg_config_compile_options(this, name, include_flag, libdir, error)
+        class(metapackage_t), intent(inout) :: this
+        character(len=*), intent(in) :: name
+        character(len=*), intent(in) :: include_flag
+        type(error_t), allocatable, intent(out) :: error
+
+        character(len=:), allocatable :: libdir
+        type(string_t) :: log, current_include_dir, current_lib
+        type(string_t), allocatable :: libs(:), flags(:)
+        integer :: i
+
+        !> Get version
+        if (.not. allocated(this%version)) then
+            log = pkgcfg_get_version(name, error)
+            if (allocated(error)) return
+            allocate(this%version)
+            call new_version(this%version, log%s, error)
+            if (allocated(error)) return
+        end if
+
+        !> Get libraries
+        libs = pkgcfg_get_libs(name, error)
+        if (allocated(error)) return
+
+        libdir = ""
+        do i = 1, size(libs)
+            if (str_begins_with_str(libs(i)%s, '-l')) then
+                current_lib = string_t(libs(i)%s(3:))
+                if (len_trim(current_lib%s) == 0) cycle
+                this%has_link_libraries = .true.
+                this%link_libs = [this%link_libs, current_lib]
+            else ! -L and others: concatenate
+                this%has_link_flags = .true.
+                this%link_flags = string_t(trim(this%link_flags%s)//' '//libs(i)%s)
+
+                ! Also save library dir
+                if (str_begins_with_str(libs(i)%s, '-L')) then
+                    libdir = libs(i)%s(3:)
+                elseif (str_begins_with_str(libs(i)%s, '/LIBPATH')) then
+                    libdir = libs(i)%s(9:)
+                end if
+            end if
+        end do
+
+        !> Get compiler flags
+        flags = pkgcfg_get_build_flags(name, .true., error)
+        if (allocated(error)) return
+
+        do i = 1, size(flags)
+            if (str_begins_with_str(flags(i)%s, include_flag)) then
+                current_include_dir = string_t(flags(i)%s(len(include_flag)+1:))
+                if (len_trim(current_include_dir%s) == 0) cycle
+                this%has_include_dirs = .true.
+                this%incl_dirs = [this%incl_dirs, current_include_dir]
+            else
+                this%has_build_flags = .true.
+                this%flags = string_t(trim(this%flags%s)//' '//flags(i)%s)
+            end if
+        end do
+    end subroutine add_pkg_config_compile_options
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/add_sources_from_dir.html b/proc/add_sources_from_dir.html new file mode 100644 index 0000000000..075564301a --- /dev/null +++ b/proc/add_sources_from_dir.html @@ -0,0 +1,412 @@ + + + + + + + + + + + + + add_sources_from_dir – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

add_sources_from_dir + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine add_sources_from_dir(sources, directory, scope, with_executables, with_f_ext, recurse, error) +

+ + +

Add to sources by looking for source files in directory

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(srcfile_t), + intent(inout), + allocatable, target + ::sources(:) +

List of [[srcfile_t]] objects to append to. Allocated if not allocated

+
+ + character(len=*), + intent(in) + + ::directory +

Directory in which to search for source files

+
+ + integer, + intent(in) + + ::scope +

Scope to apply to the discovered sources, see fpm_model for enumeration

+
+ + logical, + intent(in),optional + + ::with_executables +

Executable sources (fortran programs) are ignored unless with_executables=.true.

+
+ + type(string_t), + intent(in),optional + + ::with_f_ext(:) +

Additional user-defined (preprocessor) extensions that should be treated as Fortran sources

+
+ + logical, + intent(in),optional + + ::recurse +

Whether to recursively search subdirectories, default is .true.

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
subroutine add_sources_from_dir(sources,directory,scope,with_executables,with_f_ext,recurse,error)
+    !> List of `[[srcfile_t]]` objects to append to. Allocated if not allocated
+    type(srcfile_t), allocatable, intent(inout), target :: sources(:)
+    !> Directory in which to search for source files
+    character(*), intent(in) :: directory
+    !> Scope to apply to the discovered sources, see [[fpm_model]] for enumeration
+    integer, intent(in) :: scope
+    !> Executable sources (fortran `program`s) are ignored unless `with_executables=.true.`
+    logical, intent(in), optional :: with_executables
+    !> Additional user-defined (preprocessor) extensions that should be treated as Fortran sources
+    type(string_t), intent(in), optional :: with_f_ext(:)
+    !> Whether to recursively search subdirectories, default is `.true.`
+    logical, intent(in), optional :: recurse
+    !> Error handling
+    type(error_t), allocatable, intent(out) :: error
+
+    integer :: i
+    logical, allocatable :: is_source(:), exclude_source(:)
+    logical :: recurse_
+    type(string_t), allocatable :: file_names(:)
+    type(string_t), allocatable :: src_file_names(:),f_ext(:)
+    type(string_t), allocatable :: existing_src_files(:)
+    type(srcfile_t), allocatable :: dir_sources(:)
+
+    recurse_ = .true.
+    if (present(recurse)) recurse_ = recurse
+    ! Scan directory for sources
+    call list_files(directory, file_names,recurse=recurse_)
+
+    if (allocated(sources)) then
+        allocate(existing_src_files(size(sources)))
+        do i=1,size(sources)
+            existing_src_files(i)%s = canon_path(sources(i)%file_name)
+        end do
+    else
+        allocate(existing_src_files(0))
+    end if
+
+    ! Get legal fortran suffixes
+    call list_fortran_suffixes(f_ext,with_f_ext)
+
+    is_source = [(.not.(is_hidden_file(basename(file_names(i)%s))) .and. &
+                 .not.(canon_path(file_names(i)%s) .in. existing_src_files) .and. &
+                 (str_ends_with(lower(file_names(i)%s), f_ext) .or. &
+                 str_ends_with(lower(file_names(i)%s), c_suffixes) ),i=1,size(file_names))]
+
+
+    src_file_names = pack(file_names,is_source)
+
+    allocate(dir_sources(size(src_file_names)))
+    allocate(exclude_source(size(src_file_names)))
+
+    do i = 1, size(src_file_names)
+
+        dir_sources(i) = parse_source(src_file_names(i)%s,with_f_ext,error)
+        if (allocated(error)) return
+
+        dir_sources(i)%unit_scope = scope
+        allocate(dir_sources(i)%link_libraries(0))
+
+        ! Exclude executables unless specified otherwise
+        exclude_source(i) = (dir_sources(i)%unit_type == FPM_UNIT_PROGRAM)
+        if (dir_sources(i)%unit_type == FPM_UNIT_PROGRAM .and. &
+            & present(with_executables)) then
+            if (with_executables) then
+
+                exclude_source(i) = .false.
+
+            end if
+        end if
+
+    end do
+
+    if (.not.allocated(sources)) then
+        sources = pack(dir_sources,.not.exclude_source)
+    else
+        sources = [sources, pack(dir_sources,.not.exclude_source)]
+    end if
+
+end subroutine add_sources_from_dir
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/append_clean_flags.html b/proc/append_clean_flags.html new file mode 100644 index 0000000000..8143710bbb --- /dev/null +++ b/proc/append_clean_flags.html @@ -0,0 +1,354 @@ + + + + + + + + + + + + + append_clean_flags – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

append_clean_flags + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine append_clean_flags(flags, new_flags) +

+ + +

Append new flags to existing flags, removing duplicates and empty flags (string version)

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=:), + intent(inout), + allocatable + ::flags + +
+ + character(len=*), + intent(in) + + ::new_flags + +
+ +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + type(string_t), + public, + allocatable + ::flags_array(:) + +
+ + integer, + public + + ::i + +
+ + type(string_t), + public, + allocatable + ::new_flags_array(:) + +
+ +
+
+ + + + + + + + + +
+

Source Code

+
subroutine append_clean_flags(flags, new_flags)
+    character(:), intent(inout), allocatable :: flags
+    character(*), intent(in) :: new_flags
+
+    type(string_t), allocatable :: flags_array(:), new_flags_array(:)
+    integer :: i
+
+    call tokenize_flags(flags, flags_array)
+    call tokenize_flags(new_flags, new_flags_array)
+
+    call append_clean_flags_array(flags_array, new_flags_array)
+
+    do i = 1, size(flags_array)
+        flags = flags // " " // flags_array(i)%s
+    end do
+end subroutine append_clean_flags
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/append_clean_flags_array.html b/proc/append_clean_flags_array.html new file mode 100644 index 0000000000..d3e202d057 --- /dev/null +++ b/proc/append_clean_flags_array.html @@ -0,0 +1,320 @@ + + + + + + + + + + + + + append_clean_flags_array – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

append_clean_flags_array + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine append_clean_flags_array(flags_array, new_flags_array) +

+ + +

Append new flags to existing flags, removing duplicates and empty flags (array version)

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(string_t), + intent(inout), + allocatable + ::flags_array(:) + +
+ + type(string_t), + intent(in) + + ::new_flags_array(:) + +
+ +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + integer, + public + + ::i + +
+ +
+
+ + + + + + + + + +
+

Source Code

+
subroutine append_clean_flags_array(flags_array, new_flags_array)
+    type(string_t), allocatable, intent(inout) :: flags_array(:)
+    type(string_t), intent(in) :: new_flags_array(:)
+
+    integer :: i
+
+    do i = 1, size(new_flags_array)
+        if (string_array_contains(new_flags_array(i)%s, flags_array)) cycle
+        ! Filter out empty flags and arguments
+        if (new_flags_array(i)%s == "") cycle
+        if (trim(new_flags_array(i)%s) == "-l") cycle
+        if (trim(new_flags_array(i)%s) == "-L") cycle
+        if (trim(new_flags_array(i)%s) == "-I") cycle
+        if (trim(new_flags_array(i)%s) == "-J") cycle
+        if (trim(new_flags_array(i)%s) == "-M") cycle
+        flags_array = [flags_array, new_flags_array(i)]
+    end do
+end subroutine append_clean_flags_array
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/ar_is_same.html b/proc/ar_is_same.html new file mode 100644 index 0000000000..f4828fe85a --- /dev/null +++ b/proc/ar_is_same.html @@ -0,0 +1,292 @@ + + + + + + + + + + + + + ar_is_same – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

ar_is_same + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function ar_is_same(this, that) +

+ + +

Check that two archiver_t objects are equal +All checks passed!

+ +

Type Bound

+

archiver_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(archiver_t), + intent(in) + + ::this + +
+ + class(serializable_t), + intent(in) + + ::that + +
+ +

Return Value + + + logical + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
logical function ar_is_same(this,that)
+    class(archiver_t), intent(in) :: this
+    class(serializable_t), intent(in) :: that
+
+    ar_is_same = .false.
+
+    select type (other=>that)
+       type is (archiver_t)
+          if (allocated(this%ar).neqv.allocated(other%ar)) return
+          if (allocated(this%ar)) then
+            if (.not.(this%ar==other%ar)) return
+          end if
+          if (.not.(this%use_response_file.eqv.other%use_response_file)) return
+          if (.not.(this%echo.eqv.other%echo)) return
+          if (.not.(this%verbose.eqv.other%verbose)) return
+
+       class default
+          ! Not the same type
+          return
+    end select
+
+    !> All checks passed!
+    ar_is_same = .true.
+
+end function ar_is_same
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/assert_pkg_config.html b/proc/assert_pkg_config.html new file mode 100644 index 0000000000..80bde6abae --- /dev/null +++ b/proc/assert_pkg_config.html @@ -0,0 +1,235 @@ + + + + + + + + + + + + + assert_pkg_config – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

assert_pkg_config + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function assert_pkg_config() +

+ + +

Check whether pkg-config is available on the local system

+ + +

Arguments

+ None +
+

Return Value + + + logical + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
logical function assert_pkg_config()
+
+   integer :: exitcode
+   logical :: success
+   type(string_t) :: log
+
+   call run_wrapper(wrapper=string_t('pkg-config'),args=[string_t('-h')], &
+                    exitcode=exitcode,cmd_success=success,screen_output=log)
+   
+   assert_pkg_config = exitcode==0 .and. success 
+    
+end function assert_pkg_config
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/bad_name_error.html b/proc/bad_name_error.html new file mode 100644 index 0000000000..2a628aecce --- /dev/null +++ b/proc/bad_name_error.html @@ -0,0 +1,301 @@ + + + + + + + + + + + + + bad_name_error – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

bad_name_error + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function bad_name_error(error, label, name) +

+ + + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(error_t), + intent(out), + allocatable + ::error +

Instance of the error data

+
+ + character(len=*), + intent(in) + + ::label +

Error message label to add to message

+
+ + character(len=*), + intent(in) + + ::name +

name value to check

+
+ +

Return Value + + + logical + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
    function bad_name_error(error, label,name)
+
+        !> Instance of the error data
+        type(error_t), allocatable, intent(out) :: error
+
+        !> Error message label to add to message
+        character(len=*), intent(in) :: label
+
+        !> name value to check
+        character(len=*), intent(in) :: name
+
+        logical :: bad_name_error
+
+        if(.not.is_fortran_name(to_fortran_name(name)))then
+           bad_name_error=.true.
+           allocate(error)
+           error%message = 'manifest file syntax error: '//label//' name must be composed only of &
+           &alphanumerics, "-" and "_"  and start with a letter ::'//name
+        else
+          bad_name_error=.false.
+        endif
+
+    end function bad_name_error
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/basename.html b/proc/basename.html new file mode 100644 index 0000000000..fa2b5a3062 --- /dev/null +++ b/proc/basename.html @@ -0,0 +1,293 @@ + + + + + + + + + + + + + basename – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

basename + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function basename(path, suffix) result(base) +

+ + +

Extract filename from path with/without suffix

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::path + +
+ + logical, + intent(in),optional + + ::suffix + +
+ +

Return Value + + + character(len=:), allocatable + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
function basename(path,suffix) result (base)
+
+    character(*), intent(In) :: path
+    logical, intent(in), optional :: suffix
+    character(:), allocatable :: base
+
+    character(:), allocatable :: file_parts(:)
+    logical :: with_suffix
+
+    if (.not.present(suffix)) then
+        with_suffix = .true.
+    else
+        with_suffix = suffix
+    end if
+
+    call split(path,file_parts,delimiters='\/')
+    if(size(file_parts)>0)then
+       base = trim(file_parts(size(file_parts)))
+    else
+       base = ''
+    endif
+    if(.not.with_suffix)then
+        call split(base,file_parts,delimiters='.')
+        if(size(file_parts)>=2)then
+           base = trim(file_parts(size(file_parts)-1))
+        endif
+    endif
+
+end function basename
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/build_model.html b/proc/build_model.html new file mode 100644 index 0000000000..d32421c4d6 --- /dev/null +++ b/proc/build_model.html @@ -0,0 +1,521 @@ + + + + + + + + + + + + + build_model – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

build_model + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine build_model(model, settings, package, error) +

+ + +

Constructs a valid fpm model from command line settings and the toml manifest. +Add this dependency’s manifest macros +Add this dependency’s package-level macros

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(fpm_model_t), + intent(out) + + ::model + +
+ + class(fpm_build_settings), + intent(inout) + + ::settings + +
+ + type(package_config_t), + intent(inout), + target + ::package + +
+ + type(error_t), + intent(out), + allocatable + ::error + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
subroutine build_model(model, settings, package, error)
+    type(fpm_model_t), intent(out) :: model
+    class(fpm_build_settings), intent(inout) :: settings
+    type(package_config_t), intent(inout), target :: package
+    type(error_t), allocatable, intent(out) :: error
+
+    integer :: i, j
+    type(package_config_t), target  :: dependency
+    type(package_config_t), pointer :: manifest
+    character(len=:), allocatable :: file_name, lib_dir
+    logical :: has_cpp
+    logical :: duplicates_found
+    type(string_t) :: include_dir
+
+    model%package_name = package%name
+
+    allocate(model%include_dirs(0))
+    allocate(model%link_libraries(0))
+    allocate(model%external_modules(0))
+
+    call new_compiler(model%compiler, settings%compiler, settings%c_compiler, &
+        & settings%cxx_compiler, echo=settings%verbose, verbose=settings%verbose)
+    call new_archiver(model%archiver, settings%archiver, &
+        & echo=settings%verbose, verbose=settings%verbose)
+
+    if (model%compiler%is_unknown()) then
+        write(*, '(*(a:,1x))') &
+            "<WARN>", "Unknown compiler", model%compiler%fc, "requested!", &
+            "Defaults for this compiler might be incorrect"
+    end if
+
+    call new_compiler_flags(model,settings)
+    model%build_prefix         = join_path("build", basename(model%compiler%fc))
+    model%include_tests        = settings%build_tests
+    model%enforce_module_names = package%build%module_naming
+    model%module_prefix        = package%build%module_prefix
+
+    ! Resolve meta-dependencies into the package and the model
+    call resolve_metapackages(model,package,settings,error)
+    if (allocated(error)) return
+    
+    ! Create dependencies
+    call new_dependency_tree(model%deps, cache=join_path("build", "cache.toml"), &
+    & path_to_config=settings%path_to_config)
+
+    ! Build and resolve model dependencies
+    call model%deps%add(package, error)
+    if (allocated(error)) return
+
+    ! Update dependencies where needed
+    call model%deps%update(error)
+    if (allocated(error)) return
+
+    ! build/ directory should now exist
+    if (.not.exists("build/.gitignore")) then
+      call filewrite(join_path("build", ".gitignore"),["*"])
+    end if
+
+    allocate(model%packages(model%deps%ndep))
+
+    has_cpp = .false.
+    do i = 1, model%deps%ndep
+        associate(dep => model%deps%dep(i))
+            file_name = join_path(dep%proj_dir, "fpm.toml")
+
+            ! The main package manifest should not be reloaded, because it may have been 
+            ! affected by model dependencies and metapackages
+            if (i==1) then 
+                manifest => package
+            else
+                
+                call get_package_data(dependency, file_name, error, apply_defaults=.true.)
+                if (allocated(error)) exit                
+                
+                manifest => dependency
+            end if            
+            
+            model%packages(i)%name = manifest%name
+            associate(features => model%packages(i)%features)
+                features%implicit_typing = manifest%fortran%implicit_typing
+                features%implicit_external = manifest%fortran%implicit_external
+                features%source_form = manifest%fortran%source_form
+            end associate
+            model%packages(i)%version = package%version%s()
+
+            !> Add this dependency's manifest macros
+            if (allocated(manifest%preprocess)) then
+                do j = 1, size(manifest%preprocess)
+                    call model%packages(i)%preprocess%add_config(manifest%preprocess(j))
+                end do
+            end if
+
+            !> Add this dependency's package-level macros
+            if (allocated(dep%preprocess)) then
+                do j = 1, size(dep%preprocess)
+                    call model%packages(i)%preprocess%add_config(dep%preprocess(j))
+                end do
+            end if
+
+            if (model%packages(i)%preprocess%is_cpp()) has_cpp = .true.
+
+            if (.not.allocated(model%packages(i)%sources)) allocate(model%packages(i)%sources(0))
+
+            if (allocated(manifest%library)) then
+
+                if (allocated(manifest%library%source_dir)) then
+                    lib_dir = join_path(dep%proj_dir, manifest%library%source_dir)
+                    if (is_dir(lib_dir)) then
+                        call add_sources_from_dir(model%packages(i)%sources, lib_dir, FPM_SCOPE_LIB, &
+                            with_f_ext=model%packages(i)%preprocess%suffixes, error=error)
+                        if (allocated(error)) exit
+                    end if
+                end if
+
+                if (allocated(manifest%library%include_dir)) then
+                    do j=1,size(manifest%library%include_dir)
+                        include_dir%s = join_path(dep%proj_dir, manifest%library%include_dir(j)%s)
+                        if (is_dir(include_dir%s)) then
+                            model%include_dirs = [model%include_dirs, include_dir]
+                        end if
+                    end do
+                end if
+
+            end if
+
+            if (allocated(manifest%build%link)) then
+                model%link_libraries = [model%link_libraries, manifest%build%link]
+            end if
+
+            if (allocated(manifest%build%external_modules)) then
+                model%external_modules = [model%external_modules, manifest%build%external_modules]
+            end if
+
+            ! Copy naming conventions from this dependency's manifest
+            model%packages(i)%enforce_module_names = manifest%build%module_naming
+            model%packages(i)%module_prefix        = manifest%build%module_prefix
+
+        end associate
+    end do
+    if (allocated(error)) return
+
+    ! Add optional flags
+    if (has_cpp) call set_cpp_preprocessor_flags(model%compiler%id, model%fortran_compile_flags)
+
+    ! Add sources from executable directories
+    if (is_dir('app') .and. package%build%auto_executables) then
+        call add_sources_from_dir(model%packages(1)%sources,'app', FPM_SCOPE_APP, &
+                                   with_executables=.true., with_f_ext=model%packages(1)%preprocess%suffixes,&
+                                   error=error)
+
+        if (allocated(error)) then
+            return
+        end if
+
+    end if
+    if (is_dir('example') .and. package%build%auto_examples) then
+        call add_sources_from_dir(model%packages(1)%sources,'example', FPM_SCOPE_EXAMPLE, &
+                                  with_executables=.true., &
+                                  with_f_ext=model%packages(1)%preprocess%suffixes,error=error)
+
+        if (allocated(error)) then
+            return
+        end if
+
+    end if
+    if (is_dir('test') .and. package%build%auto_tests) then
+        call add_sources_from_dir(model%packages(1)%sources,'test', FPM_SCOPE_TEST, &
+                                  with_executables=.true., &
+                                  with_f_ext=model%packages(1)%preprocess%suffixes,error=error)
+
+        if (allocated(error)) then
+            return
+        endif
+
+    end if
+    if (allocated(package%executable)) then
+        call add_executable_sources(model%packages(1)%sources, package%executable, FPM_SCOPE_APP, &
+                                     auto_discover=package%build%auto_executables, &
+                                     with_f_ext=model%packages(1)%preprocess%suffixes, &
+                                     error=error)
+
+        if (allocated(error)) then
+            return
+        end if
+
+    end if
+    if (allocated(package%example)) then
+        call add_executable_sources(model%packages(1)%sources, package%example, FPM_SCOPE_EXAMPLE, &
+                                     auto_discover=package%build%auto_examples, &
+                                     with_f_ext=model%packages(1)%preprocess%suffixes, &
+                                     error=error)
+
+        if (allocated(error)) then
+            return
+        end if
+
+    end if
+    if (allocated(package%test)) then
+        call add_executable_sources(model%packages(1)%sources, package%test, FPM_SCOPE_TEST, &
+                                     auto_discover=package%build%auto_tests, &
+                                     with_f_ext=model%packages(1)%preprocess%suffixes, &
+                                     error=error)
+
+        if (allocated(error)) then
+            return
+        endif
+
+    endif
+
+    if (settings%verbose) then
+        write(*,*)'<INFO> BUILD_NAME: ',model%build_prefix
+        write(*,*)'<INFO> COMPILER:  ',model%compiler%fc
+        write(*,*)'<INFO> C COMPILER:  ',model%compiler%cc
+        write(*,*)'<INFO> CXX COMPILER: ',model%compiler%cxx
+        write(*,*)'<INFO> COMPILER OPTIONS:  ', model%fortran_compile_flags
+        write(*,*)'<INFO> C COMPILER OPTIONS:  ', model%c_compile_flags
+        write(*,*)'<INFO> CXX COMPILER OPTIONS: ', model%cxx_compile_flags
+        write(*,*)'<INFO> LINKER OPTIONS:  ', model%link_flags
+        write(*,*)'<INFO> INCLUDE DIRECTORIES:  [', string_cat(model%include_dirs,','),']'
+    end if
+
+    ! Check for invalid module names
+    call check_module_names(model, error)
+    if (allocated(error)) return
+
+    ! Check for duplicate modules
+    duplicates_found = .false.
+    call check_modules_for_duplicates(model, duplicates_found)
+    if (duplicates_found) then
+        call fpm_stop(1,'*build_model*:Error: One or more duplicate module names found.')
+    end if
+end subroutine build_model
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/build_package.html b/proc/build_package.html new file mode 100644 index 0000000000..0fbf4afdd9 --- /dev/null +++ b/proc/build_package.html @@ -0,0 +1,400 @@ + + + + + + + + + + + + + build_package – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

build_package + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine build_package(targets, model, verbose, dry_run) +

+ + +

Top-level routine to build package described by model

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(build_target_ptr), + intent(inout) + + ::targets(:) + +
+ + type(fpm_model_t), + intent(in) + + ::model + +
+ + logical, + intent(in) + + ::verbose + +
+ + logical, + intent(in) + + ::dry_run +

If dry_run, the build process is only mocked, but the list of compile_commands +is still created

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
subroutine build_package(targets,model,verbose,dry_run)
+    type(build_target_ptr), intent(inout) :: targets(:)
+    type(fpm_model_t), intent(in) :: model
+    logical, intent(in) :: verbose
+    
+    !> If dry_run, the build process is only mocked, but the list of compile_commands 
+    !> is still created
+    logical, intent(in) :: dry_run
+ 
+    integer :: i, j
+    type(build_target_ptr), allocatable :: queue(:)
+    integer, allocatable :: schedule_ptr(:), stat(:)
+    logical :: build_failed, skip_current
+    type(string_t), allocatable :: build_dirs(:)
+    type(string_t) :: temp
+    type(error_t), allocatable :: error
+
+    type(build_progress_t) :: progress
+    logical :: plain_output
+
+    ! Need to make output directory for include (mod) files
+    allocate(build_dirs(0))
+    do i = 1, size(targets)
+       associate(target => targets(i)%ptr)
+          if (target%output_dir .in. build_dirs) cycle
+          temp%s = target%output_dir
+          build_dirs = [build_dirs, temp]
+       end associate
+    end do
+
+    do i = 1, size(build_dirs)
+       if (.not.dry_run) call mkdir(build_dirs(i)%s,verbose)
+    end do
+
+    ! Perform depth-first topological sort of targets
+    do i=1,size(targets)
+
+        call sort_target(targets(i)%ptr, dry_run)
+
+    end do
+
+    ! Construct build schedule queue
+    call schedule_targets(queue, schedule_ptr, targets)
+
+    ! Check if queue is empty
+    if (.not.verbose .and. size(queue) < 1 .and. .not.dry_run) then
+        write(stderr, '(a)') 'Project is up to date'
+        return
+    end if
+
+    ! Initialise build status flags
+    allocate(stat(size(queue)),source=0)
+    build_failed = .false.
+
+    ! Set output mode
+#ifndef FPM_BOOTSTRAP
+    plain_output = (.not.(c_isatty()==1)) .or. verbose
+#else
+    plain_output = .true.
+#endif
+
+    progress = build_progress_t(queue,plain_output)
+
+    ! Loop over parallel schedule regions
+    do i=1,size(schedule_ptr)-1
+
+        ! Build targets in schedule region i
+        !$omp parallel do default(shared) private(skip_current) schedule(dynamic,1)
+        do j=schedule_ptr(i),(schedule_ptr(i+1)-1)
+
+            ! Check if build already failed
+            !$omp atomic read
+            skip_current = build_failed
+
+            if (.not.skip_current) then
+                if (.not.dry_run) call progress%compiling_status(j)
+                call build_target(model,queue(j)%ptr,verbose,dry_run, &
+                                  progress%compile_commands,stat(j))
+                if (.not.dry_run) call progress%completed_status(j,stat(j))
+            end if
+
+            ! Set global flag if this target failed to build
+            if (stat(j) /= 0) then
+                !$omp atomic write
+                build_failed = .true.
+            end if
+
+        end do
+
+        ! Check if this schedule region failed: exit with message if failed
+        if (build_failed) then
+            write(*,*)
+            do j=1,size(stat)
+                if (stat(j) /= 0) Then
+                    call print_build_log(queue(j)%ptr)
+                end if
+            end do
+            do j=1,size(stat)
+                if (stat(j) /= 0) then
+                    write(stderr,'(*(g0:,1x))') '<ERROR> Compilation failed for object "',basename(queue(j)%ptr%output_file),'"'
+                end if
+            end do
+            call fpm_stop(1,'stopping due to failed compilation')
+        end if
+
+    end do
+
+    if (.not.dry_run) call progress%success()
+    call progress%dump_commands(error)
+    if (allocated(error)) call fpm_stop(1,'error writing compile_commands.json: '//trim(error%message))
+
+end subroutine build_package
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/canon_path.html b/proc/canon_path.html new file mode 100644 index 0000000000..e9f316e348 --- /dev/null +++ b/proc/canon_path.html @@ -0,0 +1,345 @@ + + + + + + + + + + + + + canon_path – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

canon_path + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function canon_path(path) +

+ + +

Canonicalize path for comparison +* Handles path string redundancies +* Does not test existence of path

+

To be replaced by realpath/_fullname in stdlib_os

+

FIXME: Lot’s of ugly hacks following here

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::path + +
+ +

Return Value + + + character(len=:), allocatable + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
function canon_path(path)
+    character(len=*), intent(in) :: path
+    character(len=:), allocatable :: canon_path
+    character(len=:), allocatable :: nixpath
+
+    integer :: istart, iend, nn, last
+    logical :: is_path, absolute
+
+    nixpath = unix_path(path)
+
+    istart = 0
+    nn = 0
+    iend = 0
+    absolute = nixpath(1:1) == "/"
+    if (absolute) then
+        canon_path = "/"
+    else
+        canon_path = ""
+    end if
+
+    do while(iend < len(nixpath))
+        call next(nixpath, istart, iend, is_path)
+        if (is_path) then
+            select case(nixpath(istart:iend))
+            case(".", "") ! always drop empty paths
+            case("..")
+                if (nn > 0) then
+                    last = scan(canon_path(:len(canon_path)-1), "/", back=.true.)
+                    canon_path = canon_path(:last)
+                    nn = nn - 1
+                else
+                    if (.not. absolute) then
+                        canon_path = canon_path // nixpath(istart:iend) // "/"
+                    end if
+                end if
+            case default
+                nn = nn + 1
+                canon_path = canon_path // nixpath(istart:iend) // "/"
+            end select
+        end if
+    end do
+
+    if (len(canon_path) == 0) canon_path = "."
+    if (len(canon_path) > 1 .and. canon_path(len(canon_path):) == "/") then
+        canon_path = canon_path(:len(canon_path)-1)
+    end if
+
+contains
+
+    subroutine next(string, istart, iend, is_path)
+        character(len=*), intent(in) :: string
+        integer, intent(inout) :: istart
+        integer, intent(inout) :: iend
+        logical, intent(inout) :: is_path
+
+        integer :: ii, nn
+        character :: tok
+
+        nn = len(string)
+
+        if (iend >= nn) then
+            istart = nn
+            iend = nn
+            return
+        end if
+
+        ii = min(iend + 1, nn)
+        tok = string(ii:ii)
+
+        is_path = tok /= '/'
+
+        if (.not.is_path) then
+            is_path = .false.
+            istart = ii
+            iend = ii
+            return
+        end if
+
+        istart = ii
+        do ii = min(iend + 1, nn), nn
+            tok = string(ii:ii)
+            select case(tok)
+            case('/')
+                exit
+            case default
+                iend = ii
+                cycle
+            end select
+        end do
+
+    end subroutine next
+end function canon_path
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/cct_destroy.html b/proc/cct_destroy.html new file mode 100644 index 0000000000..98e1597208 --- /dev/null +++ b/proc/cct_destroy.html @@ -0,0 +1,252 @@ + + + + + + + + + + + + + cct_destroy – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

cct_destroy + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public elemental subroutine cct_destroy(self) +

+ + +

Cleanup a compile command table

+ +

Type Bound

+

compile_command_table_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compile_command_table_t), + intent(inout) + + ::self +

Instance of the serializable object

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
    elemental subroutine cct_destroy(self)
+
+        !> Instance of the serializable object
+        class(compile_command_table_t), intent(inout) :: self
+        
+        if (allocated(self%command)) deallocate(self%command)
+        
+    end subroutine cct_destroy
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/cct_dump_array.html b/proc/cct_dump_array.html new file mode 100644 index 0000000000..4dc383b8c0 --- /dev/null +++ b/proc/cct_dump_array.html @@ -0,0 +1,384 @@ + + + + + + + + + + + + + cct_dump_array – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

cct_dump_array + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine cct_dump_array(self, array, error) +

+ + +

Dump compile_command_table_t to a toml array

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compile_command_table_t), + intent(inout) + + ::self +

Instance of the serializable object

+
+ + type(toml_array), + intent(inout) + + ::array +

Data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + integer, + public + + ::ii + +
+ + type(toml_table), + public, + pointer + ::item + +
+ + integer, + public + + ::stat + +
+ +
+
+ + + + + + + + + +
+

Source Code

+
    subroutine cct_dump_array(self, array, error)
+        !> Instance of the serializable object
+        class(compile_command_table_t), intent(inout) :: self
+
+        !> Data structure
+        type(toml_array), intent(inout) :: array
+
+        !> Error handling
+        type(error_t), allocatable, intent(out) :: error      
+        
+        integer :: ii, stat
+        type(toml_table), pointer :: item  
+        
+        if (.not.allocated(self%command)) return
+        
+        do ii = 1, size(self%command)
+            associate (cmd => self%command(ii))
+            
+               ! Set node for this command
+               call add_table(array, item, stat)
+               if (stat /= toml_stat%success) then
+                   call fatal_error(error, "Cannot store entry in compile_command_table_t array")
+                   return
+               end if                    
+               call cmd%dump_to_toml(item, error)
+               if (allocated(error)) return
+
+            endassociate
+        end do                
+        
+    end subroutine cct_dump_array
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/cct_dump_toml.html b/proc/cct_dump_toml.html new file mode 100644 index 0000000000..a90eb3d9e0 --- /dev/null +++ b/proc/cct_dump_toml.html @@ -0,0 +1,380 @@ + + + + + + + + + + + + + cct_dump_toml – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

cct_dump_toml + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine cct_dump_toml(self, table, error) +

+ + +

Dump compile_command_table_t to toml table

+ +

Type Bound

+

compile_command_table_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compile_command_table_t), + intent(inout) + + ::self +

Instance of the serializable object

+
+ + type(toml_table), + intent(inout) + + ::table +

Data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + type(toml_array), + public, + pointer + ::array + +
+ + integer, + public + + ::ii + +
+ + integer, + public + + ::stat + +
+ +
+
+ + + + + + + + + +
+

Source Code

+
    subroutine cct_dump_toml(self, table, error)
+
+        !> Instance of the serializable object
+        class(compile_command_table_t), intent(inout) :: self
+
+        !> Data structure
+        type(toml_table), intent(inout) :: table
+
+        !> Error handling
+        type(error_t), allocatable, intent(out) :: error
+        
+        integer :: stat, ii
+        type(toml_array), pointer :: array
+        
+        ! Create array
+        call add_array(table, 'compile_commands', array, stat=stat)
+        if (stat/=toml_stat%success .or. .not.associated(array)) then 
+            call fatal_error(error,"compile_command_table_t cannot create entry")
+            return
+        end if
+        
+        ! Dump to it
+        call cct_dump_array(self, array, error)
+
+    end subroutine cct_dump_toml        
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/cct_is_same.html b/proc/cct_is_same.html new file mode 100644 index 0000000000..31dbde4a73 --- /dev/null +++ b/proc/cct_is_same.html @@ -0,0 +1,342 @@ + + + + + + + + + + + + + cct_is_same – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

cct_is_same + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function cct_is_same(this, that) +

+ + +

Check that two compile_command_table_t objects are equal +All checks passed!

+ +

Type Bound

+

compile_command_table_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compile_command_table_t), + intent(in) + + ::this + +
+ + class(serializable_t), + intent(in) + + ::that + +
+ +

Return Value + + + logical + +

+ +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + integer, + public + + ::i + +
+ +
+
+ + + + + + + + + +
+

Source Code

+
    logical function cct_is_same(this,that)
+        class(compile_command_table_t), intent(in) :: this
+        class(serializable_t), intent(in) :: that
+        
+        integer :: i
+
+        cct_is_same = .false.
+
+        select type (other=>that)
+           type is (compile_command_table_t)
+            
+              if (allocated(this%command).neqv.allocated(other%command)) return 
+              if (allocated(this%command)) then
+                  if (.not.(size  (this%command)  ==size  (other%command))) return
+                  if (.not.(ubound(this%command,1)==ubound(other%command,1))) return
+                  if (.not.(lbound(this%command,1)==lbound(other%command,1))) return
+                  do i=lbound(this%command,1),ubound(this%command,1)
+                     if (.not.this%command(i)==other%command(i)) return
+                  end do
+              end if
+
+           class default
+              ! Not the same type
+              return
+        end select
+
+        !> All checks passed!
+        cct_is_same = .true.
+
+    end function cct_is_same        
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/cct_load_toml.html b/proc/cct_load_toml.html new file mode 100644 index 0000000000..0e0e74ae73 --- /dev/null +++ b/proc/cct_load_toml.html @@ -0,0 +1,437 @@ + + + + + + + + + + + + + cct_load_toml – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

cct_load_toml + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine cct_load_toml(self, table, error) +

+ + +

Read compile_command_table_t from toml table (no checks made at this stage)

+ +

Type Bound

+

compile_command_table_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compile_command_table_t), + intent(inout) + + ::self +

Instance of the serializable object

+
+ + type(toml_table), + intent(inout) + + ::table +

Data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + type(toml_array), + public, + pointer + ::array + +
+ + type(toml_table), + public, + pointer + ::elem + +
+ + integer, + public + + ::i + +
+ + integer, + public + + ::n + +
+ + integer, + public + + ::stat + +
+ +
+
+ + + + + + + + + +
+

Source Code

+
    subroutine cct_load_toml(self, table, error)
+
+        !> Instance of the serializable object
+        class(compile_command_table_t), intent(inout) :: self
+
+        !> Data structure
+        type(toml_table), intent(inout) :: table
+        
+        !> Error handling
+        type(error_t), allocatable, intent(out) :: error
+        
+        integer :: stat, i, n
+        type(toml_array), pointer :: array
+        type(toml_table), pointer :: elem
+                
+        call self%destroy()
+        
+        call get_value(table, key='compile_commands', ptr=array, requested=.true.,stat=stat)
+
+        if (stat/=toml_stat%success .or. .not.associated(array)) then 
+            
+            call fatal_error(error, "TOML table has no 'compile_commands' key")
+            return
+            
+        else
+            
+            n = len(array)               
+            if (n<=0) return
+                    
+            allocate(self%command(n))
+            
+            do i = 1, n
+                call get_value(array, pos=i, ptr=elem, stat=stat)
+                if (stat /= toml_stat%success .or. .not.associated(elem)) then
+                    call fatal_error(error, "Entry in 'compile_commands' field cannot be read")
+                    return
+                end if
+                
+                call self%command(i)%load(elem, error)
+                if (allocated(error)) return
+                
+            end do            
+            
+        end if
+
+    end subroutine cct_load_toml
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/cct_new.html b/proc/cct_new.html new file mode 100644 index 0000000000..8670f8940d --- /dev/null +++ b/proc/cct_new.html @@ -0,0 +1,362 @@ + + + + + + + + + + + + + cct_new – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

cct_new + Function + +

+
+
+
+ +
+ +
+
+ + +
+ +
+ + +
+

public function cct_new(directory, arguments, file) result(cct) +

+ + +

Override default initializer (GCC 15 bug)

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::directory + +
+ + character(len=*), + intent(in),optional + + ::arguments(:) + +
+ + character(len=*), + intent(in) + + ::file + +
+ +

Return Value + + + type(compile_command_t) + +

+ +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + integer, + public + + ::i + +
+ + integer, + public + + ::n + +
+ +
+
+ + + + + + + + + +
+

Source Code

+
    type(compile_command_t) function cct_new(directory,arguments,file) result(cct)
+        character(len=*), intent(in) :: directory,file
+        character(len=*), optional, intent(in) :: arguments(:)
+        
+        integer :: i,n
+        
+        cct%directory = string_t(trim(directory))
+        cct%file = string_t(trim(file))
+        
+        if (present(arguments)) then 
+           n = size(arguments)
+        else
+           n = 0
+        endif
+        allocate(cct%arguments(n))
+        do i=1,n
+            cct%arguments(i) = string_t(trim(arguments(i)))
+        end do
+        
+    end function cct_new  
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/cct_register.html b/proc/cct_register.html new file mode 100644 index 0000000000..abc7f60339 --- /dev/null +++ b/proc/cct_register.html @@ -0,0 +1,507 @@ + + + + + + + + + + + + + cct_register – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

cct_register + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine cct_register(self, command, target_os, error) +

+ + +

Register a new compile command

+ +

Type Bound

+

compile_command_table_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compile_command_table_t), + intent(inout) + + ::self +

Instance of the serializable object

+
+ + character(len=*), + intent(in) + + ::command +

Data structure

+
+ + integer, + intent(in) + + ::target_os +

The target OS of the compile_commands.json (may be cross-compiling)

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=:), + public, + allocatable + ::args(:) + +
+ + type(compile_command_t), + public + + ::cmd + +
+ + character(len=:), + public, + allocatable + ::cwd + +
+ + integer, + public + + ::i + +
+ + integer, + public + + ::n + +
+ + logical, + public + + ::sh_success + +
+ + character(len=:), + public, + allocatable + ::source_file + +
+ +
+
+ + + + + + + + + +
+

Source Code

+
    subroutine cct_register(self, command, target_os, error)
+
+        !> Instance of the serializable object
+        class(compile_command_table_t), intent(inout) :: self
+
+        !> Data structure
+        character(len=*), intent(in) :: command
+        
+        !> The target OS of the compile_commands.json (may be cross-compiling)
+        integer, intent(in) :: target_os
+        
+        !> Error handling
+        type(error_t), allocatable, intent(out) :: error    
+        
+        ! Local variables
+        type(compile_command_t) :: cmd
+        character(len=:), allocatable :: args(:), cwd, source_file
+        logical :: sh_success
+        integer :: i,n
+        
+        ! Early check
+        if (len_trim(command) <= 0) then
+            call syntax_error(error, "compile_command_table_t trying to register an empty command")
+            return
+        end if
+
+        ! Tokenize the input command into args(:)
+        if (target_os==OS_WINDOWS) then 
+            args = ms_split(command, ucrt=.true., success=sh_success)
+        else
+            args = sh_split(command, join_spaced=.false., keep_quotes=.true., success=sh_success)
+        end if
+        n = size(args)
+        
+        if (n==0 .or. .not.sh_success) then 
+            call syntax_error(error, "compile_command_table_t failed tokenizing: <"//command//">")
+            return
+        end if
+        
+        ! Get current working directory
+        call get_current_directory(cwd, error)
+        if (allocated(error)) return
+
+        ! Try to find the source file
+        allocate(character(len=0) :: source_file)
+        find_source_file: do i = 1, n-1
+            if (args(i) == "-c") then
+                source_file = trim(args(i+1))
+                exit find_source_file
+            end if
+        end do find_source_file
+
+        ! Fallback: use last argument if not found
+        if (len_trim(source_file)==0) source_file = trim(args(n))
+
+        ! Fill in the compile_command_t. 
+        ! Use non-default initializer due to gcc 15 bug
+        cmd = compile_command_t(cwd, args, source_file)
+        
+        ! Add it to the structure
+        !$omp critical (command_update)
+        call cct_register_object(self, cmd, error)
+        !$omp end critical (command_update)
+
+    end subroutine cct_register
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/cct_register_object.html b/proc/cct_register_object.html new file mode 100644 index 0000000000..7cf872d8d6 --- /dev/null +++ b/proc/cct_register_object.html @@ -0,0 +1,291 @@ + + + + + + + + + + + + + cct_register_object – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

cct_register_object + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public pure subroutine cct_register_object(self, command, error) +

+ + + +

Type Bound

+

compile_command_table_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compile_command_table_t), + intent(inout) + + ::self +

Instance of the serializable object

+
+ + type(compile_command_t), + intent(in) + + ::command +

Data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
    pure subroutine cct_register_object(self, command, error)
+    
+        !> Instance of the serializable object
+        class(compile_command_table_t), intent(inout) :: self
+
+        !> Data structure
+        type(compile_command_t), intent(in) :: command
+        
+        !> Error handling
+        type(error_t), allocatable, intent(out) :: error    
+        
+        if (allocated(self%command)) then         
+           self%command = [self%command, command]
+        else
+           allocate(self%command(1), source=command) 
+        end if        
+        
+    end subroutine cct_register_object
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/cct_write.html b/proc/cct_write.html new file mode 100644 index 0000000000..0353090578 --- /dev/null +++ b/proc/cct_write.html @@ -0,0 +1,416 @@ + + + + + + + + + + + + + cct_write – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

cct_write + Subroutine + +

+
+
+
+ +
+ +
+
+ + +
+ +
+ + +
+

public subroutine cct_write(self, filename, error) +

+ + +

Write compile_commands.json file. Because Jonquil does not support non-named arrays, +create a custom json here.

+ +

Type Bound

+

compile_command_table_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compile_command_table_t), + intent(inout) + + ::self +

Instance of the serializable object

+
+ + character(len=*), + intent(in) + + ::filename +

The file name

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + type(toml_array), + public + + ::array + +
+ + type(json_ser_config), + public + + ::cfg + +
+ + integer, + public + + ::lun + +
+ + integer, + public + + ::stat + +
+ +
+
+ + + + + + + + + +
+

Source Code

+
    subroutine cct_write(self, filename, error)
+
+        !> Instance of the serializable object
+        class(compile_command_table_t), intent(inout) :: self
+
+        !> The file name
+        character(*), intent(in) :: filename
+
+        !> Error handling
+        type(error_t), allocatable, intent(out) :: error
+        
+        type(toml_array) :: array
+        type(json_ser_config) :: cfg
+        integer :: stat, lun
+        
+        ! Init array
+        array = toml_array()
+        
+        ! Dump information to the array
+        call cct_dump_array(self, array, error)
+        if (allocated(error)) return
+        
+        ! Open file and write to it
+        open(newunit=lun,file=filename,form='formatted',action='write',status='replace',iostat=stat)
+        if (stat/=0) then 
+            call fatal_error(error, 'cannot open file '//filename//' for writing')
+            return
+        end if
+        
+        ! Ensure the array has no key
+        if (allocated(array%key)) deallocate(array%key)
+        
+        cfg%indent = repeat(' ',3)
+        write (lun, '(A)', iostat=stat, err=1) json_serialize(array, cfg)                
+        close(lun,iostat=stat)
+        
+        1 if (stat/=0) then 
+            call fatal_error(error, 'cannot close file '//filename//' after writing')
+            return
+        end if
+
+    end subroutine cct_write
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/change_directory.html b/proc/change_directory.html new file mode 100644 index 0000000000..ce5907bf20 --- /dev/null +++ b/proc/change_directory.html @@ -0,0 +1,272 @@ + + + + + + + + + + + + + change_directory – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

change_directory + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine change_directory(path, error) +

+ + + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::path + +
+ + type(error_t), + intent(out), + allocatable + ::error + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
    subroutine change_directory(path, error)
+        character(len=*), intent(in) :: path
+        type(error_t), allocatable, intent(out) :: error
+
+        character(kind=c_char, len=1), allocatable :: cpath(:)
+        integer :: stat
+
+        allocate (cpath(len(path) + 1))
+        call f_c_character(path, cpath, len(path) + 1)
+
+        stat = chdir_(cpath)
+
+        if (stat /= 0) then
+            call fatal_error(error, "Failed to change directory to '"//path//"'")
+        end if
+    end subroutine change_directory
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/check_and_read_pkg_data.html b/proc/check_and_read_pkg_data.html new file mode 100644 index 0000000000..8405a65d8a --- /dev/null +++ b/proc/check_and_read_pkg_data.html @@ -0,0 +1,289 @@ + + + + + + + + + + + + + check_and_read_pkg_data – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

check_and_read_pkg_data + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine check_and_read_pkg_data(json, node, download_url, version, error) +

+ + + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(json_object), + intent(inout) + + ::json + +
+ + class(dependency_node_t), + intent(in) + + ::node + +
+ + character(len=:), + intent(out), + allocatable + ::download_url + +
+ + type(version_t), + intent(out) + + ::version + +
+ + type(error_t), + intent(out), + allocatable + ::error + +
+ +
+ + + + + + + + + + + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/check_compiler.html b/proc/check_compiler.html new file mode 100644 index 0000000000..9ab858a9f5 --- /dev/null +++ b/proc/check_compiler.html @@ -0,0 +1,272 @@ + + + + + + + + + + + + + check_compiler – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

check_compiler + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function check_compiler(compiler, expected) result(match) +

+ + + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::compiler + +
+ + character(len=*), + intent(in) + + ::expected + +
+ +

Return Value + + + logical + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
function check_compiler(compiler, expected) result(match)
+    character(len=*), intent(in) :: compiler
+    character(len=*), intent(in) :: expected
+    logical :: match
+    match = compiler == expected
+    if (.not. match) then
+        match = index(basename(compiler), expected) > 0
+    end if
+end function check_compiler
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/check_flags_supported.html b/proc/check_flags_supported.html new file mode 100644 index 0000000000..937ed44836 --- /dev/null +++ b/proc/check_flags_supported.html @@ -0,0 +1,336 @@ + + + + + + + + + + + + + check_flags_supported – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

check_flags_supported + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function check_flags_supported(self, compile_flags, link_flags) +

+ + +

Check if the given compile and/or link flags are accepted by the compiler

+ +

Type Bound

+

compiler_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::self + +
+ + character(len=*), + intent(in),optional + + ::compile_flags + +
+ + character(len=*), + intent(in),optional + + ::link_flags + +
+ +

Return Value + + + logical + +

+ +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=*), + public, +parameter + ::hello_world ="print *, 'Hello, World!'; end" + +
+ +
+
+ + + + + + + + + +
+

Source Code

+
logical function check_flags_supported(self, compile_flags, link_flags)
+    class(compiler_t), intent(in) :: self
+    character(len=*), optional, intent(in) :: compile_flags, link_flags
+
+    ! Minimal program that always compiles
+    character(len=*), parameter :: hello_world = "print *, 'Hello, World!'; end"
+
+    check_flags_supported = self%check_fortran_source_runs(hello_world, compile_flags, link_flags)
+
+end function check_flags_supported
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/check_fortran_source_runs.html b/proc/check_fortran_source_runs.html new file mode 100644 index 0000000000..5ca6399ca7 --- /dev/null +++ b/proc/check_fortran_source_runs.html @@ -0,0 +1,540 @@ + + + + + + + + + + + + + check_fortran_source_runs – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

check_fortran_source_runs + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function check_fortran_source_runs(self, input, compile_flags, link_flags) result(success) +

+ + +

Run a single-source Fortran program using the current compiler +Compile a Fortran object +Create temporary source file +Write contents +Get flags +Intel: Needs -warn last for error on unknown command line arguments to work +Compile and link program +Run and retrieve exit code

+

Successful exit on 0 exit code

+

Delete files

+ +

Type Bound

+

compiler_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::self +

Instance of the compiler object

+
+ + character(len=*), + intent(in) + + ::input +

Program Source

+
+ + character(len=*), + intent(in),optional + + ::compile_flags +

Optional build and link flags

+
+ + character(len=*), + intent(in),optional + + ::link_flags +

Optional build and link flags

+
+ +

Return Value + + + logical + +

+ +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=:), + public, + allocatable + ::exe + +
+ + character(len=:), + public, + allocatable + ::flags + +
+ + character(len=:), + public, + allocatable + ::ldflags + +
+ + character(len=:), + public, + allocatable + ::logf + +
+ + character(len=:), + public, + allocatable + ::object + +
+ + character(len=:), + public, + allocatable + ::source + +
+ + integer, + public + + ::stat + +
+ + integer, + public + + ::unit + +
+ +
+
+ + + + + + + + + +
+

Source Code

+
logical function check_fortran_source_runs(self, input, compile_flags, link_flags) result(success)
+    !> Instance of the compiler object
+    class(compiler_t), intent(in) :: self
+    !> Program Source
+    character(len=*), intent(in) :: input
+    !> Optional build and link flags
+    character(len=*), optional, intent(in) :: compile_flags, link_flags
+
+    integer :: stat,unit
+    character(:), allocatable :: source,object,logf,exe,flags,ldflags
+
+    success = .false.
+
+    !> Create temporary source file
+    exe    = get_temp_filename()
+    source = exe//'.f90'
+    object = exe//'.o'
+    logf   = exe//'.log'
+    open(newunit=unit, file=source, action='readwrite', iostat=stat)
+    if (stat/=0) return
+
+    !> Write contents
+    write(unit,*) input
+    close(unit)
+
+    !> Get flags
+    flags    = self%get_default_flags(release=.false.)
+    ldflags  = self%get_default_flags(release=.false.)
+
+    if (present(compile_flags)) flags = flags//" "//compile_flags
+    if (present(link_flags)) ldflags = ldflags//" "//link_flags
+
+    !> Intel: Needs -warn last for error on unknown command line arguments to work
+    if (self%id == id_intel_llvm_nix) then
+        flags = flags//" "//flag_intel_warn
+        ldflags = ldflags//" "//flag_intel_warn
+    elseif (self%id == id_intel_llvm_windows) then
+        flags = flags//" "//flag_intel_warn_win
+        ldflags = ldflags//" "//flag_intel_warn_win
+    end if
+
+    !> Compile and link program
+    call self%compile_fortran(source, object, flags, logf, stat)
+    if (stat==0) &
+    call self%link(exe, ldflags//" "//object, logf, stat)
+
+    !> Run and retrieve exit code
+    if (stat==0) &
+    call run(exe,echo=.false., exitstat=stat, verbose=.false., redirect=logf)
+
+    !> Successful exit on 0 exit code
+    success = stat==0
+
+    !> Delete files
+    open(newunit=unit, file=source, action='readwrite', iostat=stat)
+    close(unit,status='delete')
+    open(newunit=unit, file=object, action='readwrite', iostat=stat)
+    close(unit,status='delete')
+    open(newunit=unit, file=logf, action='readwrite', iostat=stat)
+    close(unit,status='delete')
+    open(newunit=unit, file=exe, action='readwrite', iostat=stat)
+    close(unit,status='delete')
+
+end function check_fortran_source_runs
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/check_keys.html b/proc/check_keys.html new file mode 100644 index 0000000000..569ce8bfd4 --- /dev/null +++ b/proc/check_keys.html @@ -0,0 +1,322 @@ + + + + + + + + + + + + + check_keys – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

check_keys + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine check_keys(table, valid_keys, error) +

+ + +

Check if table contains only keys that are part of the list. If a key is +found that is not part of the list, an error is allocated.

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(toml_table), + intent(inout) + + ::table +

Instance of the TOML data structure

+
+ + character(len=*), + intent(in) + + ::valid_keys(:) +

List of keys to check.

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
    subroutine check_keys(table, valid_keys, error)
+
+        !> Instance of the TOML data structure
+        type(toml_table), intent(inout) :: table
+
+        !> List of keys to check.
+        character(len=*), intent(in) :: valid_keys(:)
+
+        !> Error handling
+        type(error_t), allocatable, intent(out) :: error
+
+        type(toml_key), allocatable :: keys(:)
+        type(toml_table), pointer :: child
+        character(:), allocatable :: name, value, valid_keys_string
+        integer :: ikey, ivalid
+
+        call table%get_key(name)
+        call table%get_keys(keys)
+
+        do ikey = 1, size(keys)
+            if (.not. any(keys(ikey)%key == valid_keys)) then
+                ! Generate error message
+                valid_keys_string = new_line('a')//new_line('a')
+                do ivalid = 1, size(valid_keys)
+                    valid_keys_string = valid_keys_string//trim(valid_keys(ivalid))//new_line('a')
+                end do
+                allocate (error)
+                error%message = "Key '"//keys(ikey)%key//"' not allowed in the '"// &
+                & name//"' table."//new_line('a')//new_line('a')//'Valid keys: '//valid_keys_string
+                return
+            end if
+
+            ! Check if value can be mapped or else (wrong type) show error message with the error location.
+            ! Right now, it can only be mapped to a string or to a child node, but this can be extended in the future.
+            call get_value(table, keys(ikey)%key, value)
+            if (.not. allocated(value)) then
+
+                ! If value is not a string, check if it is a child node
+                call get_value(table, keys(ikey)%key, child)
+
+                if (.not.associated(child)) then
+                    allocate (error)
+                    error%message = "'"//name//"' has an invalid '"//keys(ikey)%key//"' entry."
+                    return
+                endif
+            end if
+        end do
+
+    end subroutine check_keys
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/check_modules_for_duplicates.html b/proc/check_modules_for_duplicates.html new file mode 100644 index 0000000000..53a1216b3e --- /dev/null +++ b/proc/check_modules_for_duplicates.html @@ -0,0 +1,298 @@ + + + + + + + + + + + + + check_modules_for_duplicates – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

check_modules_for_duplicates + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine check_modules_for_duplicates(model, duplicates_found) +

+ + + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(fpm_model_t), + intent(in) + + ::model + +
+ + logical + + + ::duplicates_found + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
subroutine check_modules_for_duplicates(model, duplicates_found)
+    type(fpm_model_t), intent(in) :: model
+    integer :: maxsize
+    integer :: i,j,k,l,m,modi
+    type(string_t), allocatable :: modules(:)
+    logical :: duplicates_found
+    ! Initialise the size of array
+    maxsize = 0
+    ! Get number of modules provided by each source file of every package
+    do i=1,size(model%packages)
+      do j=1,size(model%packages(i)%sources)
+        if (allocated(model%packages(i)%sources(j)%modules_provided)) then
+          maxsize = maxsize + size(model%packages(i)%sources(j)%modules_provided)
+        end if
+      end do
+    end do
+    ! Allocate array to contain distinct names of modules
+    allocate(modules(maxsize))
+
+    ! Initialise index to point at start of the newly allocated array
+    modi = 1
+
+    ! Loop through modules provided by each source file of every package
+    ! Add it to the array if it is not already there
+    ! Otherwise print out warning about duplicates
+    do k=1,size(model%packages)
+      do l=1,size(model%packages(k)%sources)
+        if (allocated(model%packages(k)%sources(l)%modules_provided)) then
+          do m=1,size(model%packages(k)%sources(l)%modules_provided)
+            if (model%packages(k)%sources(l)%modules_provided(m)%s.in.modules(:modi-1)) then
+              write(stderr, *) "Warning: Module ",model%packages(k)%sources(l)%modules_provided(m)%s, &
+                " in ",model%packages(k)%sources(l)%file_name," is a duplicate"
+              duplicates_found = .true.
+            else
+              modules(modi) = model%packages(k)%sources(l)%modules_provided(m)
+              modi = modi + 1
+            end if
+          end do
+        end if
+      end do
+    end do
+end subroutine check_modules_for_duplicates
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/checkout.html b/proc/checkout.html new file mode 100644 index 0000000000..1e2443ea00 --- /dev/null +++ b/proc/checkout.html @@ -0,0 +1,398 @@ + + + + + + + + + + + + + checkout – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

checkout + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine checkout(self, local_path, error) +

+ + + +

Type Bound

+

git_target_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(git_target_t), + intent(in) + + ::self +

Instance of the git target

+
+ + character(len=*), + intent(in) + + ::local_path +

Local path to checkout in

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error

+
+ +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=:), + public, + allocatable + ::object + +
+ + integer, + public + + ::stat + +
+ + character(len=:), + public, + allocatable + ::workdir + +
+ +
+
+ + + + + + + + + +
+

Source Code

+
    subroutine checkout(self, local_path, error)
+
+        !> Instance of the git target
+        class(git_target_t), intent(in) :: self
+
+        !> Local path to checkout in
+        character(*), intent(in) :: local_path
+
+        !> Error
+        type(error_t), allocatable, intent(out) :: error
+
+        integer :: stat
+        character(len=:), allocatable :: object, workdir
+
+        if (allocated(self%object)) then
+            object = self%object
+        else
+            object = 'HEAD'
+        end if
+        workdir = "--work-tree="//local_path//" --git-dir="//join_path(local_path, ".git")
+
+        call execute_command_line("git init "//local_path, exitstat=stat)
+
+        if (stat /= 0) then
+            call fatal_error(error,'Error while initiating git repository for remote dependency')
+            return
+        end if
+
+        call execute_command_line("git "//workdir//" fetch --depth=1 "// &
+                                  self%url//" "//object, exitstat=stat)
+
+        if (stat /= 0) then
+            call fatal_error(error,'Error while fetching git repository for remote dependency')
+            return
+        end if
+
+        call execute_command_line("git "//workdir//" checkout -qf FETCH_HEAD", exitstat=stat)
+
+        if (stat /= 0) then
+            call fatal_error(error,'Error while checking out git repository for remote dependency')
+            return
+        end if
+
+    end subroutine checkout
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/cmd_build.html b/proc/cmd_build.html new file mode 100644 index 0000000000..8794dab865 --- /dev/null +++ b/proc/cmd_build.html @@ -0,0 +1,285 @@ + + + + + + + + + + + + + cmd_build – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

cmd_build + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine cmd_build(settings) +

+ + +

Dump model to file

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(fpm_build_settings), + intent(inout) + + ::settings + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
subroutine cmd_build(settings)
+type(fpm_build_settings), intent(inout) :: settings
+
+type(package_config_t) :: package
+type(fpm_model_t) :: model
+type(build_target_ptr), allocatable :: targets(:)
+type(error_t), allocatable :: error
+
+integer :: i
+
+call get_package_data(package, "fpm.toml", error, apply_defaults=.true.)
+if (allocated(error)) then
+    call fpm_stop(1,'*cmd_build* Package error: '//error%message)
+end if
+
+call build_model(model, settings, package, error)
+if (allocated(error)) then
+    call fpm_stop(1,'*cmd_build* Model error: '//error%message)
+end if
+
+call targets_from_sources(targets, model, settings%prune, package%library, error)
+if (allocated(error)) then
+    call fpm_stop(1,'*cmd_build* Target error: '//error%message)
+end if
+
+!> Dump model to file
+if (len_trim(settings%dump)>0) then
+    call model%dump(trim(settings%dump),error,json=name_is_json(trim(settings%dump)))
+    if (allocated(error)) call fpm_stop(1,'*cmd_build* Model dump error: '//error%message)
+endif
+
+if(settings%list)then
+    do i=1,size(targets)
+        write(stderr,*) targets(i)%ptr%output_file
+    enddo
+endif
+if (settings%show_model) then
+    call show_model(model)
+else
+    call build_package(targets,model,verbose=settings%verbose,dry_run=settings%list)
+endif
+
+end subroutine cmd_build
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/cmd_clean.html b/proc/cmd_clean.html new file mode 100644 index 0000000000..73573a12a8 --- /dev/null +++ b/proc/cmd_clean.html @@ -0,0 +1,276 @@ + + + + + + + + + + + + + cmd_clean – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

cmd_clean + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine cmd_clean(settings) +

+ + +

Delete the build directory including or excluding dependencies. Can be used +to clear the registry cache.

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(fpm_clean_settings), + intent(in) + + ::settings +

Settings for the clean command.

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
subroutine cmd_clean(settings)
+    !> Settings for the clean command.
+    class(fpm_clean_settings), intent(in) :: settings
+
+    character :: user_response
+    type(fpm_global_settings) :: global_settings
+    type(error_t), allocatable :: error
+
+    ! Clear registry cache
+    if (settings%registry_cache) then
+        call get_global_settings(global_settings, error) 
+        if (allocated(error)) return
+
+        call os_delete_dir(os_is_unix(), global_settings%registry_settings%cache_path)
+    end if
+
+    if (is_dir('build')) then
+        ! Remove the entire build directory
+        if (settings%clean_all) then
+            call os_delete_dir(os_is_unix(), 'build'); return
+        ! Remove the build directory but skip dependencies
+        else if (settings%clean_skip) then
+            call delete_skip(os_is_unix()); return
+        end if
+
+        ! Prompt to remove the build directory but skip dependencies
+        write(stdout, '(A)', advance='no') "Delete build, excluding dependencies (y/n)? "
+        read(stdin, '(A1)') user_response
+        if (lower(user_response) == 'y') call delete_skip(os_is_unix())
+    else
+        write (stdout, '(A)') "fpm: No build directory found."
+    end if
+end subroutine cmd_clean
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/cmd_export.html b/proc/cmd_export.html new file mode 100644 index 0000000000..3c01ce0ba3 --- /dev/null +++ b/proc/cmd_export.html @@ -0,0 +1,303 @@ + + + + + + + + + + + + + cmd_export – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

cmd_export + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine cmd_export(settings) +

+ + +

Entry point for the export subcommand +Read in manifest +Export manifest +Export dependency tree

+

Generate dependency tree +Export dependency tree +Export full model

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(fpm_export_settings), + intent(inout) + + ::settings +

Representation of the command line arguments

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
  subroutine cmd_export(settings)
+    !> Representation of the command line arguments
+    type(fpm_export_settings), intent(inout) :: settings
+    type(package_config_t) :: package
+    type(dependency_tree_t) :: deps
+    type(fpm_model_t) :: model
+    type(error_t), allocatable :: error
+
+    character(len=:), allocatable :: filename
+
+    if (len_trim(settings%dump_manifest)<=0 .and. &
+        len_trim(settings%dump_model)<=0 .and. &
+        len_trim(settings%dump_dependencies)<=0) then
+        call fpm_stop(0,'*cmd_export* exiting: no manifest/model/dependencies keyword provided')
+    end if
+
+    !> Read in manifest
+    call get_package_data(package, "fpm.toml", error, apply_defaults=.true.)
+    call handle_error(error)
+
+    !> Export manifest
+    if (len_trim(settings%dump_manifest)>0) then
+       filename = trim(settings%dump_manifest)
+       call package%dump(filename, error, json=name_is_json(filename))
+    end if
+
+    !> Export dependency tree
+    if (len_trim(settings%dump_dependencies)>0) then
+
+        !> Generate dependency tree
+        filename = join_path("build", "cache.toml")
+        call new_dependency_tree(deps, cache=filename, verbosity=merge(2, 1, settings%verbose))
+        call deps%add(package, error)
+        call handle_error(error)
+
+        !> Export dependency tree
+        filename = settings%dump_dependencies
+        call deps%dump(filename, error, json=name_is_json(filename))
+        call handle_error(error)
+    end if
+
+    !> Export full model
+    if (len_trim(settings%dump_model)>0) then
+
+        call build_model(model, settings%fpm_build_settings, package, error)
+        if (allocated(error)) then
+            call fpm_stop(1,'*cmd_export* Model error: '//error%message)
+        end if
+
+        filename = settings%dump_model
+        call model%dump(filename, error, json=name_is_json(filename))
+        call handle_error(error)
+    end if
+
+  end subroutine cmd_export
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/cmd_install.html b/proc/cmd_install.html new file mode 100644 index 0000000000..96abfa26d9 --- /dev/null +++ b/proc/cmd_install.html @@ -0,0 +1,315 @@ + + + + + + + + + + + + + cmd_install – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

cmd_install + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine cmd_install(settings) +

+ + +

Entry point for the fpm-install subcommand

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(fpm_install_settings), + intent(inout) + + ::settings +

Representation of the command line settings

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
  subroutine cmd_install(settings)
+    !> Representation of the command line settings
+    type(fpm_install_settings), intent(inout) :: settings
+    type(package_config_t) :: package
+    type(error_t), allocatable :: error
+    type(fpm_model_t) :: model
+    type(build_target_ptr), allocatable :: targets(:), libraries(:)
+    type(installer_t) :: installer
+    type(string_t), allocatable :: list(:)
+    logical :: installable
+    integer :: ntargets,i
+
+    call get_package_data(package, "fpm.toml", error, apply_defaults=.true.)
+    call handle_error(error)
+    
+    call build_model(model, settings, package, error)
+    call handle_error(error)
+
+    ! ifx bug: does not resolve allocatable -> optional
+    if (allocated(package%library)) then 
+       call targets_from_sources(targets, model, settings%prune, package%library, error)
+    else
+       call targets_from_sources(targets, model, settings%prune, error=error) 
+    endif
+    call handle_error(error)
+
+    call install_info(output_unit, settings%list, targets, ntargets)
+    if (settings%list) return
+
+    installable = (allocated(package%library) .and. package%install%library) &
+                   .or. allocated(package%executable) .or. ntargets>0
+    
+    if (.not.installable) then
+      call fatal_error(error, "Project does not contain any installable targets")
+      call handle_error(error)
+    end if
+
+    if (.not.settings%no_rebuild) then
+      call build_package(targets,model,verbose=settings%verbose,dry_run=settings%list)
+    end if
+
+    call new_installer(installer, prefix=settings%prefix, &
+      bindir=settings%bindir, libdir=settings%libdir, testdir=settings%testdir, &
+      includedir=settings%includedir, &
+      verbosity=merge(2, 1, settings%verbose))
+
+    if (allocated(package%library) .and. package%install%library) then
+      call filter_library_targets(targets, libraries)
+
+      if (size(libraries) > 0) then
+        do i=1,size(libraries)
+           call installer%install_library(libraries(i)%ptr, error)
+           call handle_error(error)
+        end do
+
+        call install_module_files(installer, targets, error)
+        call handle_error(error)
+      end if
+    end if
+    
+    if (allocated(package%executable) .or. ntargets>0) then
+      call install_executables(installer, targets, error)
+      call handle_error(error)
+    end if
+
+    if (allocated(package%test) .and. (package%install%test .or. model%include_tests)) then 
+        
+        call install_tests(installer, targets, error)
+        call handle_error(error)
+        
+    end if
+
+  end subroutine cmd_install
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/cmd_new.html b/proc/cmd_new.html new file mode 100644 index 0000000000..bd9927aba9 --- /dev/null +++ b/proc/cmd_new.html @@ -0,0 +1,907 @@ + + + + + + + + + + + + + cmd_new – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

cmd_new + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine cmd_new(settings) +

+ + +

TOP DIRECTORY NAME PROCESSING +see if requested new directory already exists and process appropriately +temporarily change to new directory as a test. NB: System dependent

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(fpm_new_settings), + intent(in) + + ::settings + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
subroutine cmd_new(settings)
+type(fpm_new_settings), intent(in) :: settings
+integer,parameter            :: tfc = selected_char_kind('DEFAULT')
+character(len=:,kind=tfc),allocatable :: bname          ! baeename of NAME
+character(len=:,kind=tfc),allocatable :: tomlfile(:)
+character(len=:,kind=tfc),allocatable :: littlefile(:)
+
+    !> TOP DIRECTORY NAME PROCESSING
+    !> see if requested new directory already exists and process appropriately
+    if(exists(settings%name) .and. .not.settings%backfill )then
+        write(stderr,'(*(g0,1x))')&
+        & '<ERROR>',settings%name,'already exists.'
+        write(stderr,'(*(g0,1x))')&
+        & '        perhaps you wanted to add --backfill ?'
+        return
+    elseif(is_dir(settings%name) .and. settings%backfill )then
+        write(*,'(*(g0))')'backfilling ',settings%name
+    elseif(exists(settings%name) )then
+        write(stderr,'(*(g0,1x))')&
+        & '<ERROR>',settings%name,'already exists and is not a directory.'
+        return
+    else
+        ! make new directory
+        call mkdir(settings%name)
+    endif
+
+    !> temporarily change to new directory as a test. NB: System dependent
+    call run('cd '//settings%name)
+    ! NOTE: need some system routines to handle filenames like "."
+    ! like realpath() or getcwd().
+    bname=basename(settings%name)
+
+    littlefile=[character(len=80) :: '# '//bname, 'My cool new project!']
+
+    ! create NAME/README.md
+    call warnwrite(join_path(settings%name, 'README.md'), littlefile)
+
+    ! start building NAME/fpm.toml
+    if(settings%with_full)then
+        tomlfile=[character(len=80) :: &
+        &'  # This is your fpm(Fortran Package Manager) manifest file                     ',&
+        &'  # ("fpm.toml"). It is heavily annotated to help guide you though              ',&
+        &'  # customizing a package build, although the defaults are sufficient           ',&
+        &'  # for many basic packages.                                                    ',&
+        &'  #                                                                             ',&
+        &'  # The manifest file is not only used to provide metadata identifying          ',&
+        &'  # your project (so it can be used by others as a dependency). It can          ',&
+        &'  # specify where your library and program sources live, what the name          ',&
+        &'  # of the executable(s) will be, what files to build, dependencies on          ',&
+        &'  # other fpm packages, and what external libraries are required.               ',&
+        &'  #                                                                             ',&
+        &'  # The manifest format must conform to the TOML configuration file             ',&
+        &'  # standard.                                                                   ',&
+        &'  #                                                                             ',&
+        &'  # TOML files support flexible use of white-space and commenting of the        ',&
+        &'  # configuration data, but for clarity in this sample active directives        ',&
+        &'  # begin in column one. Inactive example directives are commented              ',&
+        &'  # out with a pound character ("#") but begin in column one as well.           ',&
+        &'  # Commentary begins with a pound character in column three.                   ',&
+        &'  #                                                                             ',&
+        &'  # This file draws heavily upon the following references:                      ',&
+        &'  #                                                                             ',&
+        &'  # The fpm home page at                                                        ',&
+        &'  #     https://github.com/fortran-lang/fpm                                     ',&
+        &'  # A complete list of keys and their attributes at                             ',&
+        &'  #     https://github.com/fortran-lang/fpm/blob/main/manifest-reference.md     ',&
+        &'  # examples of fpm project packaging at                                        ',&
+        &'  #     https://github.com/fortran-lang/fpm/blob/main/PACKAGING.md              ',&
+        &'  # The Fortran TOML file interface and it''s references at                     ',&
+        &'  #     https://github.com/toml-f/toml-f                                        ',&
+        &'  #                                                                             ',&
+        &'  #-----------------------                                                      ',&
+        &'  # project Identification                                                      ',&
+        &'  #-----------------------                                                      ',&
+        &'  # We begin with project metadata at the manifest root. This data is designed  ',&
+        &'  # to aid others when searching for the project in a repository and to         ',&
+        &'  # identify how and when to contact the package supporters.                    ',&
+        &'                                                                                ',&
+        &'name = "'//bname//'"',&
+        &'  # The project name (required) is how the project will be referred to.         ',&
+        &'  # The name is used by other packages using it as a dependency. It also        ',&
+        &'  # is used as the default name of any library built and the optional           ',&
+        &'  # default executable built from app/main.f90. It must conform to the rules    ',&
+        &'  # for a Fortran variable name.                                                ',&
+        &'                                                                                ',&
+        &'version = "0.1.0"                                                               ',&
+        &'  # The project version number is a string. A recommended scheme for            ',&
+        &'  # specifying versions is the Semantic Versioning scheme.                      ',&
+        &'                                                                                ',&
+        &'license = "license"                                                             ',&
+        &'  # Licensing information specified using SPDX identifiers is preferred         ',&
+        &'  # (eg. "Apache-2.0 OR MIT" or "LGPL-3.0-or-later").                           ',&
+        &'                                                                                ',&
+        &'maintainer = "jane.doe@example.com"                                             ',&
+        &'  # Information on the project maintainer and means to reach out to them.       ',&
+        &'                                                                                ',&
+        &'author = "Jane Doe"                                                             ',&
+        &'  # Information on the project author.                                          ',&
+        &'                                                                                ',&
+        &'copyright = "Copyright 2020 Jane Doe"                                           ',&
+        &'  # A statement clarifying the Copyright status of the project.                 ',&
+        &'                                                                                ',&
+        &'#description = "A short project summary in plain text"                          ',&
+        &'  # The description provides a short summary on the project. It should be       ',&
+        &'  # plain text and not use any markup formatting.                               ',&
+        &'                                                                                ',&
+        &'#categories = ["fortran", "graphics"]                                           ',&
+        &'  # Categories associated with the project. Listing only one is preferred.      ',&
+        &'                                                                                ',&
+        &'#keywords = ["hdf5", "mpi"]                                                     ',&
+        &'  # The keywords field is an array of strings describing the project.           ',&
+        &'                                                                                ',&
+        &'#homepage = "https://stdlib.fortran-lang.org"                                   ',&
+        &'  # URL to the webpage of the project.                                          ',&
+        &'                                                                                ',&
+        &'  # -----------------------------------------                                   ',&
+        &'  # We are done with identifying the project.                                   ',&
+        &'  # -----------------------------------------                                   ',&
+        &'  #                                                                             ',&
+        &'  # Now lets start describing how the project should be built.                  ',&
+        &'  #                                                                             ',&
+        &'  # Note tables would go here but we will not be talking about them (much)!!'    ,&
+        &'  #                                                                             ',&
+        &'  # Tables are a way to explicitly specify large numbers of programs in         ',&
+        &'  # a compact format instead of individual per-program entries in the           ',&
+        &'  # [[executable]], [[test]], and [[example]] sections to follow but            ',&
+        &'  # will not be discussed further except for the following notes:               ',&
+        &'  #                                                                             ',&
+        &'  # + Tables must appear (here) before any sections are declared. Once a        ',&
+        &'  #   section is specified in a TOML file everything afterwards must be         ',&
+        &'  #   values for that section or the beginning of a new section. A simple       ',&
+        &'  #   example looks like:                                                       ',&
+        &'                                                                                ',&
+        &'#executable = [                                                                 ',&
+        &'#  { name = "a-prog" },                                                         ',&
+        &'#  { name = "app-tool", source-dir = "tool" },                                  ',&
+        &'#  { name = "fpm-man", source-dir = "tool", main="fman.f90" }                   ',&
+        &'#]                                                                              ',&
+        &'                                                                                ',&
+        &'  # This would be in lieue of the [[executable]] section found later in this    ',&
+        &'  # configuration file.                                                         ',&
+        &'  # + See the reference documents (at the beginning of this document)           ',&
+        &'  #   for more information on tables if you have long lists of programs         ',&
+        &'  #   to build and are not simply depending on auto-detection.                  ',&
+        &'  #                                                                             ',&
+        &'  # Now lets begin the TOML sections (lines beginning with "[") ...             ',&
+        &'  #                                                                             ',&
+        &'                                                                                ',&
+        &'[install] # Options for the "install" subcommand                                ',&
+        &'                                                                                ',&
+        &'  # When you run the "install" subcommand only executables are installed by     ',&
+        &'  # default on the local system. Library projects that will be used outside of  ',&
+        &'  # "fpm" can set the "library" boolean to also allow installing the module     ',&
+        &'  # files and library archive. Without this being set to "true" an "install"    ',&
+        &'  # subcommand ignores parameters that specify library installation.            ',&
+        &'                                                                                ',&
+        &'  # If your project sets `[library] type = "shared"`, enabling this option      ',&
+        &'  # will install the compiled `.so`, `.dylib`, or `.dll` files into the         ',&
+        &'  # appropriate `lib/` folder. This applies equally to static archives.         ',&
+        &'  #                                                                             ',&
+        &'  # For shared libraries, installing is typically required for runtime usage.   ',&
+        &'                                                                                ',&
+        &'library = false                                                                 ',&
+        &'                                                                                ',&
+        &'[build] # General Build Options                                                 ',&
+        &'                                                                                ',&
+        &'  ###  Automatic target discovery                                               ',&
+        &'  #                                                                             ',&
+        &'  # Normally fpm recursively searches the app/, example/, and test/ directories ',&
+        &'  # for program sources and builds them. To disable this automatic discovery of ',&
+        &'  # program targets set the following to "false":                               ',&
+        &'                                                                                ',&
+        &'#auto-executables = true                                                        ',&
+        &'#auto-examples = true                                                           ',&
+        &'#auto-tests = true                                                              ',&
+        &'                                                                                ',&
+        &'  ### Package-level External Library Links                                      ',&
+        &'  #                                                                             ',&
+        &'  # To declare link-time dependencies on external libraries a list of           ',&
+        &'  # native libraries can be specified with the "link" entry. You may            ',&
+        &'  # have one library name or a list of strings in case several                  ',&
+        &'  # libraries should be linked. This list of library dependencies is            ',&
+        &'  # exported to dependent packages. You may have to alter your library          ',&
+        &'  # search-path to ensure the libraries can be accessed. Typically,             ',&
+        &'  # this is done with the LD_LIBRARY_PATH environment variable on ULS           ',&
+        &'  # (Unix-Like Systems). You only specify the core name of the library          ',&
+        &'  # (as is typical with most programming environments, where you                ',&
+        &'  # would specify "-lz" on your load command to link against the zlib           ',&
+        &'  # compression library even though the library file would typically be         ',&
+        &'  # a file called "libz.a" "or libz.so"). So to link against that library       ',&
+        &'  # you would specify:                                                          ',&
+        &'                                                                                ',&
+        &'#link = "z"                                                                     ',&
+        &'                                                                                ',&
+        &'  # Note that in some cases the order of the libraries matters:                 ',&
+        &'                                                                                ',&
+        &'#link = ["blas", "lapack"]                                                      ',&
+        &'']
+    endif
+
+    if(settings%with_bare)then
+    elseif(settings%with_lib)then
+        call mkdir(join_path(settings%name,'src') )
+        ! create next section of fpm.toml
+        if(settings%with_full)then
+            tomlfile=[character(len=80) ::  tomlfile, &
+            &'[library]                                                                       ',&
+            &'                                                                                ',&
+            &'  # You can change the name of the directory to search for your library         ',&
+            &'  # source from the default of "src/". Library targets are exported             ',&
+            &'  # and usable by other projects.                                               ',&
+            &'                                                                                ',&
+            &'source-dir="src"                                                                ',&
+            &'                                                                                ',&
+            &'  # this can be a list:                                                         ',&
+            &'                                                                                ',&
+            &'#source-dir=["src", "src2"]                                                     ',&
+            &'                                                                                ',&
+            &'  # More complex libraries may organize their modules in subdirectories.        ',&
+            &'  # For modules in a top-level directory fpm requires (but does not             ',&
+            &'  # enforce) that:                                                              ',&
+            &'  #                                                                             ',&
+            &'  #  + The module has the same name as the source file. This is important.      ',&
+            &'  #  + There should be only one module per file.                                ',&
+            &'  #                                                                             ',&
+            &'  # These two requirements simplify the build process for fpm. As Fortran       ',&
+            &'  # compilers emit module files (.mod) with the same name as the module         ',&
+            &'  # itself (but not the source file, .f90), naming the module the same          ',&
+            &'  # as the source file allows fpm to:                                           ',&
+            &'  #                                                                             ',&
+            &'  #  + Uniquely and exactly map a source file (.f90) to its object (.o)         ',&
+            &'  #    and module (.mod) files.                                                 ',&
+            &'  #  + Avoid conflicts with modules of the same name that could appear          ',&
+            &'  #    in dependency packages.                                                  ',&
+            &'  #                                                                             ',&
+            &'  ### Multi-level library source                                                ',&
+            &'  # You can place your module source files in any number of levels of           ',&
+            &'  # subdirectories inside your source directory, but there are certain naming   ',&
+            &'  # conventions to be followed -- module names must contain the path components ',&
+            &'  # of the directory that its source file is in.                                ',&
+            &'  #                                                                             ',&
+            &'  # This rule applies generally to any number of nested directories and         ',&
+            &'  # modules. For example, src/a/b/c/d.f90 must define a module called a_b_c_d.  ',&
+            &'  # Again, this is not enforced but may be required in future releases.         ',&
+            &'                                                                                ',&
+            &'  ### Library type                                                              ',&
+            &'  # Set `type = "shared"` to build dynamic libraries (.so/.dylib/.dll)          ',&
+            &'  # instead of a static archive. You can also set `type = "static"` to          ',&
+            &'  # generate per-package archives, or use `type = "monolithic"` (default)       ',&
+            &'  # to bundle all sources and dependencies into a single archive.               ',&
+            &'  #                                                                             ',&
+            &'  # Supported types:                                                            ',&
+            &'  #                                                                             ',&
+            &'  #  + "monolithic": Single archive with used sources and dependencies.         ',&
+            &'  #  + "static":    One full archive per package (for external integration).    ',&
+            &'  #  + "shared":    One shared library per package, for dynamic linking.        ',&
+            &'  #                                                                             ',&
+            &'  # Shared libraries are useful for plugin systems, dynamic linking, or         ',&
+            &'  # language bindings. Static per-package archives may aid external reuse.      ',&
+            &'  #                                                                             ',&
+            &'  # When running with `fpm run`, shared library paths are automatically         ',&
+            &'  # added to the environment (e.g. `LD_LIBRARY_PATH`, `PATH`) at runtime.       ',&
+            &'  #                                                                             ',&            
+            &'  # Note: library files are not installed unless `[install] library=true`       ',&
+            &'  # is also enabled.                                                            ',&
+            &'  #                                                                             ',&
+            &'  # Example:                                                                    ',&
+            &'                                                                                ',&            
+            &'type = "shared"                                                                 ',&
+            &'                                                                                ',&
+            &'']
+        endif
+        ! create placeholder module src/bname.f90
+        littlefile=[character(len=80) ::          &
+        &'module '//to_fortran_name(bname),       &
+        &'  implicit none',                       &
+        &'  private',                             &
+        &'',                                      &
+        &'  public :: say_hello',                 &
+        &'contains',                              &
+        &'  subroutine say_hello',                &
+        &'    print *, "Hello, '//bname//'!"',    &
+        &'  end subroutine say_hello',            &
+        &'end module '//to_fortran_name(bname)]
+        ! create NAME/src/NAME.f90
+        call warnwrite(join_path(settings%name, 'src', bname//'.f90'),&
+         & littlefile)
+    endif
+
+    if(settings%with_full)then
+        tomlfile=[character(len=80) ::  tomlfile ,&
+        &'[dependencies]                                                                  ',&
+        &'                                                                                ',&
+        &'  # Inevitably, you will want to be able to include other packages in           ',&
+        &'  # a project. Fpm makes this incredibly simple, by taking care of              ',&
+        &'  # fetching and compiling your dependencies for you. You just tell it          ',&
+        &'  # what your dependencies names are, and where to find them.                   ',&
+        &'  #                                                                             ',&
+        &'  # If you are going to distribute your package only place dependencies         ',&
+        &'  # here someone using your package as a remote dependency needs built.         ',&
+        &'  # You can define dependencies just for developer executables in the           ',&
+        &'  # next section, or even for specific executables as we will see below         ',&
+        &'  # (Then fpm will still fetch and compile it when building your                ',&
+        &'  # developer executables, but users of your library will not have to).         ',&
+        &'  #                                                                             ',&
+        &'  ## GLOBAL DEPENDENCIES (exported with your project)                           ',&
+        &'  #                                                                             ',&
+        &'  # Typically, dependencies are defined by specifying the project''s            ',&
+        &'  # git repository.                                                             ',&
+        &'  #                                                                             ',&
+        &'  # You can be specific about which version of a dependency you would           ',&
+        &'  # like. By default the latest default branch is used. You can           ',&
+        &'  # optionally specify a branch, a tag or a commit value.                       ',&
+        &'  #                                                                             ',&
+        &'  # So here are several alternates for specifying a remote dependency (you      ',&
+        &'  # can have at most one of "branch", "rev" or "tag" present):                  ',&
+        &'                                                                                ',&
+        &'#stdlib = { git = "https://github.com/LKedward/stdlib-fpm.git" }                ',&
+        &'#stdlib = {git="https://github.com/LKedward/stdlib-fpm.git",branch = "master" },',&
+        &'#stdlib = {git="https://github.com/LKedward/stdlib-fpm.git", tag = "v0.1.0" },  ',&
+        &'#stdlib = {git="https://github.com/LKedward/stdlib-fpm.git", rev = "5a9b7a8" }. ',&
+        &'                                                                                ',&
+        &'  # There may be multiple packages listed:                                      ',&
+        &'                                                                                ',&
+        &'#M_strings = { git = "https://github.com/urbanjost/M_strings.git" }             ',&
+        &'#M_time    = { git = "https://github.com/urbanjost/M_time.git" }                ',&
+        &'                                                                                ',&
+        &'  #                                                                             ',&
+        &'  # You can even specify the local path to another project if it is in          ',&
+        &'  # a sub-folder (If for example you have got another fpm package **in          ',&
+        &'  # the same repository**) like this:                                           ',&
+        &'                                                                                ',&
+        &'#M_strings = { path = "M_strings" }                                             ',&
+        &'                                                                                ',&
+        &'  # This tells fpm that we depend on a crate called M_strings which is found    ',&
+        &'  # in the M_strings folder (relative to the fpm.toml it’s written in).         ',&
+        &'  #                                                                             ',&
+        &'  # For a more verbose layout use normal tables rather than inline tables       ',&
+        &'  # to specify dependencies:                                                    ',&
+        &'                                                                                ',&
+        &'#[dependencies.toml-f]                                                          ',&
+        &'#git = "https://github.com/toml-f/toml-f"                                       ',&
+        &'#rev = "2f5eaba864ff630ba0c3791126a3f811b6e437f3"                               ',&
+        &'                                                                                ',&
+        &'  # Now you can use any modules from these libraries anywhere in your           ',&
+        &'  # code -- whether is in your library source or a program source.              ',&
+        &'                                                                                ',&
+        &'[dev-dependencies]                                                              ',&
+        &'                                                                                ',&
+        &'  ## Dependencies Only for Development                                          ',&
+        &'  #                                                                             ',&
+        &'  # You can specify dependencies your library or application does not           ',&
+        &'  # depend on in a similar way. The difference is that these will not           ',&
+        &'  # be exported as part of your project to those using it as a remote           ',&
+        &'  # dependency.                                                                 ',&
+        &'  #                                                                             ',&
+        &'  # Currently, like a global dependency it will still be available for          ',&
+        &'  # all codes. It is up to the developer to ensure that nothing except          ',&
+        &'  # developer test programs rely upon it.                                       ',&
+        &'                                                                                ',&
+        &'#M_msg    = { git = "https://github.com/urbanjost/M_msg.git" }                  ',&
+        &'#M_verify = { git = "https://github.com/urbanjost/M_verify.git" }               ',&
+        &'']
+    endif
+    if(settings%with_bare)then
+    elseif(settings%with_executable)then
+        ! create next section of fpm.toml
+        call mkdir(join_path(settings%name, 'app'))
+        ! create NAME/app or stop
+        if(settings%with_full)then
+           tomlfile=[character(len=80) ::  tomlfile, &
+           &'  #-----------------------------------                                          ',&
+           &'  ## Application-specific declarations                                          ',&
+           &'  #-----------------------------------                                          ',&
+           &'  # Now lets begin entries for the TOML tables (lines beginning with "[[")      ',&
+           &'  # that describe the program sources -- applications, tests, and examples.     ',&
+           &'  #                                                                             ',&
+           &'  # First we will configuration individual applications run with "fpm run".     ',&
+           &'  #                                                                             ',&
+           &'  #   + the "name" entry for the executable to be built must always             ',&
+           &'  #     be specified. The name must satisfy the rules for a Fortran             ',&
+           &'  #     variable name. This will be the name of the binary installed by         ',&
+           &'  #     the "install" subcommand and used on the "run" subcommand.              ',&
+           &'  #   + The source directory for each executable can be adjusted by the         ',&
+           &'  #     "source-dir" entry.                                                     ',&
+           &'  #   + The basename of the source file containing the program body can         ',&
+           &'  #     be specified with the "main" entry.                                     ',&
+           &'  #   + Executables can also specify their own external package and             ',&
+           &'  #     library link dependencies.                                              ',&
+           &'  #                                                                             ',&
+           &'  #     Currently, like a global dependency any external package dependency     ',&
+           &'  #     will be available for all codes. It is up to the developer to ensure    ',&
+           &'  #     that nothing except the application programs specified rely upon it.    ',&
+           &'  #                                                                             ',&
+           &'  # Note if your application needs to use a module internally, but you do not   ',&
+           &'  # intend to build it as a library to be used in other projects, you can       ',&
+           &'  # include the module in your program source file or directory as well.        ',&
+           &'                                                                                ',&
+           &'[[executable]]                                                                  ',&
+           &'name="'//bname//'"',&
+           &'source-dir="app"                                                                ',&
+           &'main="main.f90"                                                                 ',&
+           &'                                                                                ',&
+           &'  # You may repeat this pattern to define additional applications. For instance,',&
+           &'  # the following sample illustrates all accepted options, where "link" and     ',&
+           &'  # "executable.dependencies" keys are the same as the global external library  ',&
+           &'  # links and package dependencies described previously except they apply       ',&
+           &'  # only to this executable:                                                    ',&
+           &'                                                                                ',&
+           &'#[[ executable ]]                                                               ',&
+           &'#name = "app-name"                                                              ',&
+           &'#source-dir = "prog"                                                            ',&
+           &'#main = "program.f90"                                                           ',&
+           &'#link = "z"                                                                     ',&
+           &'#[executable.dependencies]                                                      ',&
+           &'#M_CLI   = { git = "https://github.com/urbanjost/M_CLI.git" }                   ',&
+           &'#helloff = { git = "https://gitlab.com/everythingfunctional/helloff.git" }      ',&
+           &'#M_path  = { git = "https://github.com/urbanjost/M_path.git" }                  ',&
+           &'']
+        endif
+
+        if(exists(bname//'/src/'))then
+            littlefile=[character(len=80) ::          &
+            &'program main',                          &
+            &'  use '//to_fortran_name(bname)//', only: say_hello',    &
+            &'  implicit none',                       &
+            &'',                                      &
+            &'  call say_hello()',                    &
+            &'end program main']
+        else
+            littlefile=[character(len=80) ::                 &
+            &'program main',                                 &
+            &'  implicit none',                              &
+            &'',                                             &
+            &'  print *, "hello from project '//bname//'"',  &
+            &'end program main']
+        endif
+        call warnwrite(join_path(settings%name, 'app/main.f90'), littlefile)
+    endif
+
+    if(settings%with_bare)then
+    elseif(settings%with_test)then
+
+       ! create NAME/test or stop
+       call mkdir(join_path(settings%name, 'test'))
+        ! create next section of fpm.toml
+        if(settings%with_full)then
+           tomlfile=[character(len=80) ::  tomlfile ,&
+           &'[[test]]                                                                        ',&
+           &'                                                                                ',&
+           &'  # The same declarations can be made for test programs, which are              ',&
+           &'  # executed with the "fpm test" command and are not build when your            ',&
+           &'  # package is used as a dependency by other packages. These are                ',&
+           &'  # typically unit tests of the package only used during package                ',&
+           &'  # development.                                                                ',&
+           &'                                                                                ',&
+           &'name="runTests"                                                                 ',&
+           &'source-dir="test"                                                               ',&
+           &'main="check.f90"                                                                ',&
+           &'                                                                                ',&
+           &'  # you may repeat this pattern to add additional explicit test program         ',&
+           &'  # parameters. The following example contains a sample of all accepted         ',&
+           &'  # options.                                                                    ',&
+           &'                                                                                ',&
+           &'#[[ test ]]                                                                     ',&
+           &'#name = "tester"                                                                ',&
+           &'#source-dir="test"                                                              ',&
+           &'#main="tester.f90"                                                              ',&
+           &'#link = ["blas", "lapack"]                                                      ',&
+           &'#[test.dependencies]                                                            ',&
+           &'#M_CLI2  = { git = "https://github.com/urbanjost/M_CLI2.git" }                  ',&
+           &'#M_io    = { git = "https://github.com/urbanjost/M_io.git" }                    ',&
+           &'#M_system= { git = "https://github.com/urbanjost/M_system.git" }                ',&
+           &'']
+        endif
+
+        littlefile=[character(len=80) ::       &
+        &'program check',                      &
+        &'implicit none',                      &
+        &'',                                   &
+        &'print *, "Put some tests in here!"', &
+        &'end program check']
+        ! create NAME/test/check.f90
+        call warnwrite(join_path(settings%name, 'test/check.f90'), littlefile)
+    endif
+
+    if(settings%with_bare)then
+    elseif(settings%with_example)then
+
+       ! create NAME/example or stop
+       call mkdir(join_path(settings%name, 'example'))
+        ! create next section of fpm.toml
+        if(settings%with_full)then
+           tomlfile=[character(len=80) ::  tomlfile, &
+           &'[[example]]                                                                     ',&
+           &'                                                                                ',&
+           &'  # Example applications for a project are defined here.                        ',&
+           &'  # These are run via "fpm run --example NAME" and like the                     ',&
+           &'  # test applications, are not built when this package is used as a             ',&
+           &'  # dependency by other packages.                                               ',&
+           &'                                                                                ',&
+           &'name="demo"                                                                     ',&
+           &'source-dir="example"                                                            ',&
+           &'main="demo.f90"                                                                 ',&
+           &'                                                                                ',&
+           &'  #                                                                             ',&
+           &'  # you may add additional programs to the example table. The following         ',&
+           &'  # example contains a sample of all accepted options                           ',&
+           &'                                                                                ',&
+           &'#[[ example ]]                                                                  ',&
+           &'#name = "example-tool"                                                          ',&
+           &'#source-dir="example"                                                           ',&
+           &'#main="tool.f90"                                                                ',&
+           &'#link = "z"                                                                     ',&
+           &'#[example.dependencies]                                                         ',&
+           &'#M_kracken95  = { git = "https://github.com/urbanjost/M_kracken95.git" }        ',&
+           &'#datetime = {git = "https://github.com/wavebitscientific/datetime-fortran.git" }',&
+           &'']
+        endif
+
+        littlefile=[character(len=80) ::          &
+        &'program demo',                          &
+        &'implicit none',                         &
+        &'',                                      &
+        &'print *, "Put some examples in here!"', &
+        &'end program demo']
+        ! create NAME/example/demo.f90
+        call warnwrite(join_path(settings%name, 'example/demo.f90'), littlefile)
+    endif
+
+    ! now that built it write NAME/fpm.toml
+    if( allocated(tomlfile) )then
+        call validate_toml_data(tomlfile)
+        call warnwrite(join_path(settings%name, 'fpm.toml'), tomlfile)
+    else
+        call create_verified_basic_manifest(join_path(settings%name, 'fpm.toml'))
+    endif
+    ! assumes git(1) is installed and in path
+    if(which('git')/='')then
+      call run('git init ' // settings%name)
+    endif
+contains
+
+function git_metadata(what) result(returned)
+!> get metadata values such as email address and git name from git(1) or return appropriate default
+  use fpm_filesystem, only : get_temp_filename, getline
+  character(len=*), intent(in)  :: what     ! keyword designating what git metatdata to query
+  character(len=:), allocatable :: returned ! value to return for requested keyword
+  character(len=:), allocatable :: command
+  character(len=:), allocatable :: temp_filename
+  character(len=:), allocatable :: iomsg
+  character(len=:), allocatable :: temp_value
+  integer :: stat, unit
+  temp_filename = get_temp_filename()
+  ! for known keywords set default value for RETURNED and associated git(1) command for query
+  select case(what)
+  case('uname')
+    returned = "Jane Doe"
+    command = "git config --get user.name > " // temp_filename
+  case('email')
+    returned = "jane.doe@example.com"
+    command = "git config --get user.email > " // temp_filename
+  case default
+    write(stderr,'(*(g0,1x))')&
+    & '<ERROR> *git_metadata* unknown metadata name ',trim(what)
+    returned=''
+    return
+  end select
+  ! Execute command if git(1) is in command path
+  if(which('git')/='')then
+     call run(command, exitstat=stat)
+     if (stat /= 0) then ! If command failed just return default
+        return
+     else ! Command did not return an error so try to read expected output file
+        open(file=temp_filename, newunit=unit,iostat=stat)
+        if(stat == 0)then
+           ! Read file into a scratch variable until status of doing so is checked
+           call getline(unit, temp_value, stat, iomsg)
+           if (stat == 0 .and. temp_value /= '') then
+              ! Return output from successful command
+              returned=temp_value
+           endif
+        endif
+        ! Always do the CLOSE because a failed open has unpredictable results.
+        ! Add IOSTAT so a failed close does not cause program to stop
+        close(unit, status="delete",iostat=stat)
+     endif
+  endif
+end function git_metadata
+
+subroutine create_verified_basic_manifest(filename)
+!> create a basic but verified default manifest file
+use tomlf, only : toml_table, toml_serialize
+use fpm_toml, only : set_value
+use fpm_manifest_package, only : package_config_t, new_package
+use fpm_error, only : error_t
+implicit none
+character(len=*),intent(in) :: filename
+   type(toml_table)            :: table
+   type(package_config_t)      :: package
+   type(error_t), allocatable  :: error
+   integer                     :: lun
+   character(len=8)            :: date
+   character(:), allocatable   :: output
+
+    if(exists(filename))then
+       write(stderr,'(*(g0,1x))')'<INFO>  ',filename,&
+       & 'already exists. Not overwriting'
+       return
+    endif
+    !> get date to put into metadata in manifest file "fpm.toml"
+    call date_and_time(DATE=date)
+    table = toml_table()
+    call fileopen(filename,lun) ! fileopen stops on error
+
+    call set_value(table, "name",       BNAME)
+    call set_value(table, "version",    "0.1.0")
+    call set_value(table, "license",    "license")
+    call set_value(table, "author",     git_metadata('uname'))
+    call set_value(table, "maintainer", git_metadata('email'))
+    call set_value(table, "copyright",  'Copyright '//date(1:4)//', '//git_metadata('uname'))
+    ! continue building of manifest
+    ! ...
+    call new_package(package, table, error=error)
+    if (allocated(error)) call fpm_stop( 3,'')
+    output = toml_serialize(table)
+    if(settings%verbose)then
+       print '(a)', output
+    endif
+    write(lun, '(a)') output
+    call fileclose(lun) ! fileopen stops on error
+
+end subroutine create_verified_basic_manifest
+
+
+subroutine validate_toml_data(input)
+!> verify a string array is a valid fpm.toml file
+!
+use tomlf, only : toml_table, toml_load, toml_serialize
+implicit none
+character(kind=tfc,len=:),intent(in),allocatable :: input(:)
+character(len=1), parameter                      :: nl = new_line('a')
+type(toml_table), allocatable                    :: table
+character(kind=tfc, len=:), allocatable          :: joined_string
+
+! you have to add a newline character by using the intrinsic
+! function `new_line("a")` to get the lines processed correctly.
+joined_string = join(input,right=nl)
+
+if (allocated(table)) deallocate(table)
+call toml_load(table, joined_string)
+if (allocated(table)) then
+   if(settings%verbose)then
+      ! If the TOML file is successfully parsed the table will be allocated and
+      ! can be written by `toml_serialize` to the standard output
+      print '(a)', toml_serialize(table)
+   endif
+   call table%destroy
+endif
+
+end subroutine validate_toml_data
+
+end subroutine cmd_new
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/cmd_publish.html b/proc/cmd_publish.html new file mode 100644 index 0000000000..717391e79f --- /dev/null +++ b/proc/cmd_publish.html @@ -0,0 +1,232 @@ + + + + + + + + + + + + + cmd_publish – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

cmd_publish + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine cmd_publish(settings) +

+ + +

The publish command first builds the root package to obtain all the relevant information such as the +package version. It then creates a tarball of the package and uploads it to the registry. +Checks before uploading the package.

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(fpm_publish_settings), + intent(inout) + + ::settings + +
+ +
+ + + + + + + + + + + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/cmd_run.html b/proc/cmd_run.html new file mode 100644 index 0000000000..9088e9da52 --- /dev/null +++ b/proc/cmd_run.html @@ -0,0 +1,453 @@ + + + + + + + + + + + + + cmd_run – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

cmd_run + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine cmd_run(settings, test) +

+ + + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(fpm_run_settings), + intent(inout) + + ::settings + +
+ + logical, + intent(in) + + ::test + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
subroutine cmd_run(settings,test)
+    class(fpm_run_settings), intent(inout) :: settings
+    logical, intent(in) :: test
+
+    integer :: i, j, col_width
+    logical :: found(size(settings%name))
+    type(error_t), allocatable :: error
+    type(package_config_t) :: package
+    type(fpm_model_t) :: model
+    type(build_target_ptr), allocatable :: targets(:)
+    type(string_t) :: exe_cmd
+    type(string_t), allocatable :: executables(:)
+    type(build_target_t), pointer :: exe_target
+    type(srcfile_t), pointer :: exe_source
+    integer :: run_scope,firsterror
+    integer, allocatable :: stat(:),target_ID(:)
+    character(len=:),allocatable :: line,run_cmd,library_path
+
+    call get_package_data(package, "fpm.toml", error, apply_defaults=.true.)
+    if (allocated(error)) then
+        call fpm_stop(1, '*cmd_run* Package error: '//error%message)
+    end if
+
+    call build_model(model, settings, package, error)
+    if (allocated(error)) then
+        call fpm_stop(1, '*cmd_run* Model error: '//error%message)
+    end if
+
+    call targets_from_sources(targets, model, settings%prune, package%library, error)
+    if (allocated(error)) then
+        call fpm_stop(1, '*cmd_run* Targets error: '//error%message)
+    end if
+
+    if (test) then
+       run_scope = FPM_SCOPE_TEST
+    else
+       run_scope = merge(FPM_SCOPE_EXAMPLE, FPM_SCOPE_APP, settings%example)
+    end if
+
+    ! Enumerate executable targets to run
+    col_width = -1
+    found(:) = .false.
+    allocate(executables(size(targets)),target_ID(size(targets)))
+    enumerate: do i=1,size(targets)
+        exe_target => targets(i)%ptr
+        if (should_be_run(settings,run_scope,exe_target)) then  
+            
+            exe_source => exe_target%dependencies(1)%ptr%source
+                
+            col_width = max(col_width,len(basename(exe_target%output_file))+2)
+            
+            ! Priority by name ID, or 0 if no name present (run first)
+            j              = settings%name_ID(exe_source%exe_name)
+            target_ID(i)   = j
+            if (j>0) found(j) = .true.
+            
+            exe_cmd%s      = exe_target%output_file
+            executables(i) = exe_cmd
+            
+        else
+            target_ID(i)   = huge(target_ID(i))
+        endif
+    end do enumerate
+    
+    ! sort executables by ascending name ID, resize
+    call sort_executables(target_ID,executables)
+    
+    ! Check if any apps/tests were found
+    if (col_width < 0) then
+        if (test) then
+            call fpm_stop(0,'No tests to run')
+        else
+            call fpm_stop(0,'No executables to run')
+        end if
+    end if
+
+    ! Check all names are valid
+    ! or no name and found more than one file    
+    if ( any(.not.found) ) then
+        line=join(settings%name)
+        if(line/='.')then ! do not report these special strings
+           if(any(.not.found))then
+              write(stderr,'(A)',advance="no")'<ERROR>*cmd_run*:specified names '
+              do j=1,size(settings%name)
+                  if (.not.found(j)) write(stderr,'(A)',advance="no") '"'//trim(settings%name(j))//'" '
+              end do
+              write(stderr,'(A)') 'not found.'
+              write(stderr,*)
+           else if(settings%verbose)then
+              write(stderr,'(A)',advance="yes")'<INFO>when more than one executable is available'
+              write(stderr,'(A)',advance="yes")'      program names must be specified.'
+           endif
+        endif
+
+        call compact_list_all()
+
+        if(line=='.' .or. line==' ')then ! do not report these special strings
+           call fpm_stop(0,'')
+        else
+           call fpm_stop(1,'')
+        endif
+
+    end if
+
+    call build_package(targets,model,verbose=settings%verbose,dry_run=settings%list)
+
+    if (settings%list) then
+         call compact_list()
+    else
+
+        ! Save current library path and set a new one that includes the local 
+        ! dynamic library folders
+        library_path = save_library_path()                
+        call set_library_path(model, targets, error)
+        if (allocated(error)) call fpm_stop(1, '*cmd_run* Run error: '//error%message)
+
+        allocate(stat(size(executables)))
+        do i=1,size(executables)
+            if (exists(executables(i)%s)) then
+                
+                ! Prepare command line
+                                              run_cmd = executables(i)%s
+                if (settings%runner/=' ')     run_cmd = settings%runner_command()//' '//run_cmd
+                if (allocated(settings%args)) run_cmd = run_cmd//" "//settings%args
+                
+                ! System Integrity Protection will not propagate the .dylib environment variables
+                ! to the child process: add paths manually
+                if (get_os_type()==OS_MACOS)  run_cmd = "env DYLD_LIBRARY_PATH=" // &
+                                                         get_env("DYLD_LIBRARY_PATH","") // &
+                                                         " " // run_cmd
+
+                call run(run_cmd,echo=settings%verbose,exitstat=stat(i))                
+                
+            else
+                call fpm_stop(1,'*cmd_run*:'//executables(i)%s//' not found')
+            end if
+        end do
+
+        if (any(stat /= 0)) then
+            do i=1,size(stat)
+                if (stat(i) /= 0) then
+                    write(stderr,'(*(g0:,1x))') '<ERROR> Execution for object "',basename(executables(i)%s),&
+                                                '" returned exit code ',stat(i)
+                end if
+            end do
+            firsterror = findloc(stat/=0,value=.true.,dim=1)
+            call fpm_stop(stat(firsterror),'*cmd_run*:stopping due to failed executions')
+        end if
+        
+        ! Restore original library path
+        call restore_library_path(library_path, error)
+        if (allocated(error)) call fpm_stop(1, '*cmd_run* Environment error: '//error%message)                         
+
+    end if
+
+    contains
+
+    subroutine compact_list_all()
+    integer, parameter :: LINE_WIDTH = 80
+    integer :: ii, jj, nCol
+        jj = 1
+        nCol = LINE_WIDTH/col_width
+        write(stderr,*) 'Available names:'
+        do ii=1,size(targets)
+
+            exe_target => targets(ii)%ptr
+
+            if (exe_target%target_type == FPM_TARGET_EXECUTABLE .and. &
+                allocated(exe_target%dependencies)) then
+
+                exe_source => exe_target%dependencies(1)%ptr%source
+
+                if (exe_source%unit_scope == run_scope) then
+                    write(stderr,'(A)',advance=(merge("yes","no ",modulo(jj,nCol)==0))) &
+                        & [character(len=col_width) :: basename(exe_target%output_file, suffix=.false.)]
+                    jj = jj + 1
+                end if
+            end if
+        end do
+        write(stderr,*)
+    end subroutine compact_list_all
+
+    subroutine compact_list()
+    integer, parameter :: LINE_WIDTH = 80
+    integer :: ii, jj, nCol
+        jj = 1
+        nCol = LINE_WIDTH/col_width
+        write(stderr,*) 'Matched names:'
+        do ii=1,size(executables)
+            write(stderr,'(A)',advance=(merge("yes","no ",modulo(jj,nCol)==0))) &
+                & [character(len=col_width) :: basename(executables(ii)%s, suffix=.false.)]
+            jj = jj + 1
+        end do
+        write(stderr,*)
+    end subroutine compact_list
+
+end subroutine cmd_run
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/cmd_update.html b/proc/cmd_update.html new file mode 100644 index 0000000000..5b5951c464 --- /dev/null +++ b/proc/cmd_update.html @@ -0,0 +1,294 @@ + + + + + + + + + + + + + cmd_update – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

cmd_update + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine cmd_update(settings) +

+ + +

Entry point for the update subcommand

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(fpm_update_settings), + intent(in) + + ::settings +

Representation of the command line arguments

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
  subroutine cmd_update(settings)
+    !> Representation of the command line arguments
+    type(fpm_update_settings), intent(in) :: settings
+
+    type(package_config_t) :: package
+    type(dependency_tree_t) :: deps
+    type(error_t), allocatable :: error
+    integer :: ii
+    character(len=:), allocatable :: cache
+
+    call get_package_data(package, "fpm.toml", error, apply_defaults=.true.)
+    call handle_error(error)
+
+    if (.not. exists("build")) then
+      call mkdir("build")
+      call filewrite(join_path("build", ".gitignore"),["*"])
+    end if
+
+    cache = join_path("build", "cache.toml")
+    if (settings%clean) call delete_file(cache)
+
+    call new_dependency_tree(deps, cache=cache, verbosity=merge(2, 1, settings%verbose), &
+    & path_to_config=settings%path_to_config)
+
+    call deps%add(package, error)
+    call handle_error(error)
+
+    ! Force-update all dependencies if `--clean`
+    if (settings%clean) then
+        do ii = 1, deps%ndep
+            deps%dep(ii)%update = .true.
+        end do
+    end if
+
+    if (settings%fetch_only) return
+
+    if (size(settings%name) == 0) then
+      call deps%update(error)
+      call handle_error(error)
+    else
+      do ii = 1, size(settings%name)
+        call deps%update(trim(settings%name(ii)), error)
+        call handle_error(error)
+      end do
+    end if
+
+    if (len_trim(settings%dump)>0) then
+        call deps%dump(trim(settings%dump), error, json=name_is_json(trim(settings%dump)))
+        call handle_error(error)
+    end if
+
+  end subroutine cmd_update
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/compile_c.html b/proc/compile_c.html new file mode 100644 index 0000000000..8a238f8209 --- /dev/null +++ b/proc/compile_c.html @@ -0,0 +1,472 @@ + + + + + + + + + + + + + compile_c – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

compile_c + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine compile_c(self, input, output, args, log_file, stat, table, dry_run) +

+ + +

Compile a C object

+ +

Type Bound

+

compiler_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::self +

Instance of the compiler object

+
+ + character(len=*), + intent(in) + + ::input +

Source file input

+
+ + character(len=*), + intent(in) + + ::output +

Output file of object

+
+ + character(len=*), + intent(in) + + ::args +

Arguments for compiler

+
+ + character(len=*), + intent(in) + + ::log_file +

Compiler output log file

+
+ + integer, + intent(out) + + ::stat +

Status flag

+
+ + type(compile_command_table_t), + intent(inout),optional + + ::table +

Optional compile_commands table

+
+ + logical, + intent(in),optional + + ::dry_run +

Optional mocking

+
+ +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=:), + public, + allocatable + ::command + +
+ + type(error_t), + public, + allocatable + ::error + +
+ + logical, + public + + ::mock + +
+ +
+
+ + + + + + + + + +
+

Source Code

+
subroutine compile_c(self, input, output, args, log_file, stat, table, dry_run)
+    !> Instance of the compiler object
+    class(compiler_t), intent(in) :: self
+    !> Source file input
+    character(len=*), intent(in) :: input
+    !> Output file of object
+    character(len=*), intent(in) :: output
+    !> Arguments for compiler
+    character(len=*), intent(in) :: args
+    !> Compiler output log file
+    character(len=*), intent(in) :: log_file
+    !> Status flag
+    integer, intent(out) :: stat
+    !> Optional compile_commands table
+    type(compile_command_table_t), optional, intent(inout) :: table    
+    !> Optional mocking
+    logical, optional, intent(in) :: dry_run    
+    
+    character(len=:), allocatable :: command 
+    type(error_t), allocatable :: error
+    logical :: mock
+    
+    ! Check if we're actually building this file
+    mock = .false.
+    if (present(dry_run)) mock = dry_run    
+    
+    ! Set command
+    command = self%cc // " -c " // input // " " // args // " -o " // output
+
+    ! Execute command
+    if (.not.mock) then 
+       call run(command, echo=self%echo, verbose=self%verbose, redirect=log_file, exitstat=stat)
+       if (stat/=0) return
+    endif
+        
+    ! Optionally register compile command 
+    if (present(table)) then 
+        call table%register(command, get_os_type(), error)
+        stat = merge(-1,0,allocated(error))
+    endif        
+    
+end subroutine compile_c
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/compile_command_destroy.html b/proc/compile_command_destroy.html new file mode 100644 index 0000000000..365e685bc7 --- /dev/null +++ b/proc/compile_command_destroy.html @@ -0,0 +1,254 @@ + + + + + + + + + + + + + compile_command_destroy – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

compile_command_destroy + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public elemental subroutine compile_command_destroy(self) +

+ + +

Cleanup compile command

+ +

Type Bound

+

compile_command_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compile_command_t), + intent(inout) + + ::self +

Instance of the serializable object

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
    elemental subroutine compile_command_destroy(self)
+    
+        !> Instance of the serializable object
+        class(compile_command_t), intent(inout) :: self    
+        
+        if (allocated(self%directory%s))deallocate(self%directory%s)
+        if (allocated(self%arguments))deallocate(self%arguments)
+        if (allocated(self%file%s))deallocate(self%file%s)
+    
+    end subroutine compile_command_destroy
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/compile_command_dump_toml.html b/proc/compile_command_dump_toml.html new file mode 100644 index 0000000000..13548e4bbe --- /dev/null +++ b/proc/compile_command_dump_toml.html @@ -0,0 +1,293 @@ + + + + + + + + + + + + + compile_command_dump_toml – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

compile_command_dump_toml + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine compile_command_dump_toml(self, table, error) +

+ + +

Dump compile_command_t to toml table

+ +

Type Bound

+

compile_command_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compile_command_t), + intent(inout) + + ::self +

Instance of the serializable object

+
+ + type(toml_table), + intent(inout) + + ::table +

Data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
    subroutine compile_command_dump_toml(self, table, error)
+
+        !> Instance of the serializable object
+        class(compile_command_t), intent(inout) :: self
+
+        !> Data structure
+        type(toml_table), intent(inout) :: table
+
+        !> Error handling
+        type(error_t), allocatable, intent(out) :: error
+
+        call set_list(table, "arguments", self%arguments, error)
+        if (allocated(error)) return
+        call set_string(table, "directory", self%directory, error, 'compile_command_t')
+        if (allocated(error)) return
+        call set_string(table, "file", self%file, error, 'compile_command_t')
+        if (allocated(error)) return    
+
+    end subroutine compile_command_dump_toml
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/compile_command_is_same.html b/proc/compile_command_is_same.html new file mode 100644 index 0000000000..12cac960fa --- /dev/null +++ b/proc/compile_command_is_same.html @@ -0,0 +1,289 @@ + + + + + + + + + + + + + compile_command_is_same – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

compile_command_is_same + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function compile_command_is_same(this, that) +

+ + +

Check that two compile_command_t objects are equal +All checks passed!

+ +

Type Bound

+

compile_command_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compile_command_t), + intent(in) + + ::this + +
+ + class(serializable_t), + intent(in) + + ::that + +
+ +

Return Value + + + logical + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
    logical function compile_command_is_same(this,that)
+        class(compile_command_t), intent(in) :: this
+        class(serializable_t), intent(in) :: that
+
+        compile_command_is_same = .false.
+
+        select type (other=>that)
+           type is (compile_command_t)
+
+              if (.not.this%directory==other%directory) return
+              if (.not.this%arguments==other%arguments) return
+              if (.not.this%file==other%file) return
+
+           class default
+              ! Not the same type
+              return
+        end select
+
+        !> All checks passed!
+        compile_command_is_same = .true.
+
+    end function compile_command_is_same
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/compile_command_load_toml.html b/proc/compile_command_load_toml.html new file mode 100644 index 0000000000..09e2d04daa --- /dev/null +++ b/proc/compile_command_load_toml.html @@ -0,0 +1,295 @@ + + + + + + + + + + + + + compile_command_load_toml – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

compile_command_load_toml + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine compile_command_load_toml(self, table, error) +

+ + +

Read compile_command_t from toml table (no checks made at this stage)

+ +

Type Bound

+

compile_command_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compile_command_t), + intent(inout) + + ::self +

Instance of the serializable object

+
+ + type(toml_table), + intent(inout) + + ::table +

Data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
    subroutine compile_command_load_toml(self, table, error)
+
+        !> Instance of the serializable object
+        class(compile_command_t), intent(inout) :: self
+
+        !> Data structure
+        type(toml_table), intent(inout) :: table
+        
+        !> Error handling
+        type(error_t), allocatable, intent(out) :: error
+        
+        call self%destroy()
+        
+        call get_list(table, "arguments", self%arguments, error)
+        if (allocated(error)) return           
+        
+        ! Return unallocated value if not present
+        call get_value(table, "directory", self%directory%s)
+        call get_value(table, "file", self%file%s)
+
+    end subroutine compile_command_load_toml
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/compile_cpp.html b/proc/compile_cpp.html new file mode 100644 index 0000000000..4b8c3d53af --- /dev/null +++ b/proc/compile_cpp.html @@ -0,0 +1,472 @@ + + + + + + + + + + + + + compile_cpp – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

compile_cpp + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine compile_cpp(self, input, output, args, log_file, stat, table, dry_run) +

+ + +

Compile a CPP object

+ +

Type Bound

+

compiler_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::self +

Instance of the compiler object

+
+ + character(len=*), + intent(in) + + ::input +

Source file input

+
+ + character(len=*), + intent(in) + + ::output +

Output file of object

+
+ + character(len=*), + intent(in) + + ::args +

Arguments for compiler

+
+ + character(len=*), + intent(in) + + ::log_file +

Compiler output log file

+
+ + integer, + intent(out) + + ::stat +

Status flag

+
+ + type(compile_command_table_t), + intent(inout),optional + + ::table +

Optional compile_commands table

+
+ + logical, + intent(in),optional + + ::dry_run +

Optional mocking

+
+ +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=:), + public, + allocatable + ::command + +
+ + type(error_t), + public, + allocatable + ::error + +
+ + logical, + public + + ::mock + +
+ +
+
+ + + + + + + + + +
+

Source Code

+
subroutine compile_cpp(self, input, output, args, log_file, stat, table, dry_run)
+    !> Instance of the compiler object
+    class(compiler_t), intent(in) :: self
+    !> Source file input
+    character(len=*), intent(in) :: input
+    !> Output file of object
+    character(len=*), intent(in) :: output
+    !> Arguments for compiler
+    character(len=*), intent(in) :: args
+    !> Compiler output log file
+    character(len=*), intent(in) :: log_file
+    !> Status flag
+    integer, intent(out) :: stat
+    !> Optional compile_commands table
+    type(compile_command_table_t), optional, intent(inout) :: table    
+    !> Optional mocking
+    logical, optional, intent(in) :: dry_run    
+    
+    character(len=:), allocatable :: command 
+    type(error_t), allocatable :: error
+    logical :: mock
+        
+    ! Check if we're actually building this file
+    mock = .false.
+    if (present(dry_run)) mock = dry_run        
+        
+    ! Set command
+    command = self%cxx // " -c " // input // " " // args // " -o " // output
+
+    ! Execute command
+    if (.not.mock) then 
+       call run(command, echo=self%echo, verbose=self%verbose, redirect=log_file, exitstat=stat)
+       if (stat/=0) return
+    endif
+        
+    ! Optionally register compile command 
+    if (present(table)) then 
+        call table%register(command, get_os_type(), error)
+        stat = merge(-1,0,allocated(error))
+    endif               
+        
+end subroutine compile_cpp
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/compile_fortran.html b/proc/compile_fortran.html new file mode 100644 index 0000000000..effcc64d66 --- /dev/null +++ b/proc/compile_fortran.html @@ -0,0 +1,472 @@ + + + + + + + + + + + + + compile_fortran – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

compile_fortran + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine compile_fortran(self, input, output, args, log_file, stat, table, dry_run) +

+ + +

Compile a Fortran object

+ +

Type Bound

+

compiler_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::self +

Instance of the compiler object

+
+ + character(len=*), + intent(in) + + ::input +

Source file input

+
+ + character(len=*), + intent(in) + + ::output +

Output file of object

+
+ + character(len=*), + intent(in) + + ::args +

Arguments for compiler

+
+ + character(len=*), + intent(in) + + ::log_file +

Compiler output log file

+
+ + integer, + intent(out) + + ::stat +

Status flag

+
+ + type(compile_command_table_t), + intent(inout),optional + + ::table +

Optional compile_commands table

+
+ + logical, + intent(in),optional + + ::dry_run +

Optional mocking

+
+ +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=:), + public, + allocatable + ::command + +
+ + type(error_t), + public, + allocatable + ::error + +
+ + logical, + public + + ::mock + +
+ +
+
+ + + + + + + + + +
+

Source Code

+
subroutine compile_fortran(self, input, output, args, log_file, stat, table, dry_run)
+    !> Instance of the compiler object
+    class(compiler_t), intent(in) :: self
+    !> Source file input
+    character(len=*), intent(in) :: input
+    !> Output file of object
+    character(len=*), intent(in) :: output
+    !> Arguments for compiler
+    character(len=*), intent(in) :: args
+    !> Compiler output log file
+    character(len=*), intent(in) :: log_file
+    !> Status flag
+    integer, intent(out) :: stat
+    !> Optional compile_commands table
+    type(compile_command_table_t), optional, intent(inout) :: table    
+    !> Optional mocking
+    logical, optional, intent(in) :: dry_run
+    
+    character(len=:), allocatable :: command 
+    type(error_t), allocatable :: error
+    logical :: mock
+    
+    ! Check if we're actually building this file
+    mock = .false.
+    if (present(dry_run)) mock = dry_run
+    
+    ! Set command
+    command = self%fc // " -c " // input // " " // args // " -o " // output
+
+    ! Execute command
+    if (.not.mock) then 
+       call run(command, echo=self%echo, verbose=self%verbose, redirect=log_file, exitstat=stat)
+       if (stat/=0) return
+    endif
+        
+    ! Optionally register compile command 
+    if (present(table)) then 
+        call table%register(command, get_os_type(), error)
+        stat = merge(-1,0,allocated(error))
+    endif    
+        
+end subroutine compile_fortran
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/compiler_dump.html b/proc/compiler_dump.html new file mode 100644 index 0000000000..58c5a609b5 --- /dev/null +++ b/proc/compiler_dump.html @@ -0,0 +1,346 @@ + + + + + + + + + + + + + compiler_dump – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

compiler_dump + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine compiler_dump(self, table, error) +

+ + +

Dump dependency to toml table

+ +

Type Bound

+

compiler_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(inout) + + ::self +

Instance of the serializable object

+
+ + type(toml_table), + intent(inout) + + ::table +

Data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + integer, + public + + ::ierr + +
+ +
+
+ + + + + + + + + +
+

Source Code

+
subroutine compiler_dump(self, table, error)
+
+    !> Instance of the serializable object
+    class(compiler_t), intent(inout) :: self
+
+    !> Data structure
+    type(toml_table), intent(inout) :: table
+
+    !> Error handling
+    type(error_t), allocatable, intent(out) :: error
+
+    integer :: ierr
+
+    call set_value(table, "id", self%id, error, 'compiler_t')
+    if (allocated(error)) return
+    call set_string(table, "fc", self%fc, error, 'compiler_t')
+    if (allocated(error)) return
+    call set_string(table, "cc", self%cc, error, 'compiler_t')
+    if (allocated(error)) return
+    call set_string(table, "cxx", self%cxx, error, 'compiler_t')
+    if (allocated(error)) return
+    call set_value(table, "echo", self%echo, error, 'compiler_t')
+    if (allocated(error)) return
+    call set_value(table, "verbose", self%verbose, error, 'compiler_t')
+    if (allocated(error)) return
+
+end subroutine compiler_dump
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/compiler_is_same.html b/proc/compiler_is_same.html new file mode 100644 index 0000000000..dcfd3eff78 --- /dev/null +++ b/proc/compiler_is_same.html @@ -0,0 +1,301 @@ + + + + + + + + + + + + + compiler_is_same – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

compiler_is_same + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function compiler_is_same(this, that) +

+ + +

Check that two compiler_t objects are equal +All checks passed!

+ +

Type Bound

+

compiler_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::this + +
+ + class(serializable_t), + intent(in) + + ::that + +
+ +

Return Value + + + logical + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
logical function compiler_is_same(this,that)
+    class(compiler_t), intent(in) :: this
+    class(serializable_t), intent(in) :: that
+
+    compiler_is_same = .false.
+
+    select type (other=>that)
+       type is (compiler_t)
+
+          if (.not.(this%id==other%id)) return
+          if (allocated(this%fc).neqv.allocated(other%fc)) return
+          if (allocated(this%fc)) then
+            if (.not.(this%fc==other%fc)) return
+          end if
+          if (allocated(this%cc).neqv.allocated(other%cc)) return
+          if (allocated(this%cc)) then
+            if (.not.(this%cc==other%cc)) return
+          end if
+          if (allocated(this%cxx).neqv.allocated(other%cxx)) return
+          if (allocated(this%cxx)) then
+            if (.not.(this%cxx==other%cxx)) return
+          end if
+          if (.not.(this%echo.eqv.other%echo)) return
+          if (.not.(this%verbose.eqv.other%verbose)) return
+
+       class default
+          ! Not the same type
+          return
+    end select
+
+    !> All checks passed!
+    compiler_is_same = .true.
+
+end function compiler_is_same
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/compiler_load.html b/proc/compiler_load.html new file mode 100644 index 0000000000..2cfe17556c --- /dev/null +++ b/proc/compiler_load.html @@ -0,0 +1,296 @@ + + + + + + + + + + + + + compiler_load – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

compiler_load + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine compiler_load(self, table, error) +

+ + +

Read dependency from toml table (no checks made at this stage)

+ +

Type Bound

+

compiler_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(inout) + + ::self +

Instance of the serializable object

+
+ + type(toml_table), + intent(inout) + + ::table +

Data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
subroutine compiler_load(self, table, error)
+
+    !> Instance of the serializable object
+    class(compiler_t), intent(inout) :: self
+
+    !> Data structure
+    type(toml_table), intent(inout) :: table
+
+    !> Error handling
+    type(error_t), allocatable, intent(out) :: error
+
+    call get_value(table, "id", self%id, error, 'compiler_t')
+    if (allocated(error)) return
+    call get_value(table, "fc", self%fc)
+    call get_value(table, "cc", self%cc)
+    call get_value(table, "cxx", self%cxx)
+    call get_value(table, "echo", self%echo, error, 'compiler_t')
+    if (allocated(error)) return
+    call get_value(table, "verbose", self%verbose, error, 'compiler_t')
+    if (allocated(error)) return
+
+end subroutine compiler_load
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/compiler_name.html b/proc/compiler_name.html new file mode 100644 index 0000000000..6a7a9618fa --- /dev/null +++ b/proc/compiler_name.html @@ -0,0 +1,280 @@ + + + + + + + + + + + + + compiler_name – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

compiler_name + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public pure function compiler_name(self) result(name) +

+ + +

Return a compiler name string

+ +

Type Bound

+

compiler_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::self +

Instance of the compiler object

+
+ +

Return Value + + + character(len=:), allocatable + +

+

Representation as string

+
+ + + + + + + + + + + +
+

Source Code

+
pure function compiler_name(self) result(name)
+   !> Instance of the compiler object
+   class(compiler_t), intent(in) :: self
+   !> Representation as string
+   character(len=:), allocatable :: name
+
+   select case (self%id)
+       case(id_gcc); name = "gfortran"
+       case(id_f95); name = "f95"
+       case(id_caf); name = "caf"
+       case(id_intel_classic_nix);     name = "ifort"
+       case(id_intel_classic_mac);     name = "ifort"
+       case(id_intel_classic_windows); name = "ifort"
+       case(id_intel_llvm_nix);     name = "ifx"
+       case(id_intel_llvm_windows); name = "ifx"
+       case(id_intel_llvm_unknown); name = "ifx"
+       case(id_pgi);       name = "pgfortran"
+       case(id_nvhpc);     name = "nvfortran"
+       case(id_nag);       name = "nagfor"
+       case(id_flang);     name = "flang"
+       case(id_flang_new); name = "flang-new"
+       case(id_f18);       name = "f18"
+       case(id_ibmxl);     name = "xlf90"
+       case(id_cray);      name = "crayftn"
+       case(id_lahey);     name = "lfc"
+       case(id_lfortran);  name = "lFortran"
+       case default;       name = "invalid/unknown"
+   end select
+end function compiler_name
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/convert_to_absolute_path.html b/proc/convert_to_absolute_path.html new file mode 100644 index 0000000000..08efde9a1b --- /dev/null +++ b/proc/convert_to_absolute_path.html @@ -0,0 +1,245 @@ + + + + + + + + + + + + + convert_to_absolute_path – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

convert_to_absolute_path + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine convert_to_absolute_path(path, error) +

+ + +

Converts a path to an absolute, canonical path.

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=:), + intent(inout), + allocatable + ::path + +
+ + type(error_t), + intent(out), + allocatable + ::error + +
+ +
+ + + + + + + + + + + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/debug_archiver.html b/proc/debug_archiver.html new file mode 100644 index 0000000000..4d550559c5 --- /dev/null +++ b/proc/debug_archiver.html @@ -0,0 +1,257 @@ + + + + + + + + + + + + + debug_archiver – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

debug_archiver + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public pure function debug_archiver(self) result(repr) +

+ + +

String representation of an archiver object

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(archiver_t), + intent(in) + + ::self +

Instance of the archiver object

+
+ +

Return Value + + + character(len=:), allocatable + +

+

Representation as string

+
+ + + + + + + + + + + +
+

Source Code

+
pure function debug_archiver(self) result(repr)
+    !> Instance of the archiver object
+    type(archiver_t), intent(in) :: self
+    !> Representation as string
+    character(len=:), allocatable :: repr
+
+    repr = 'ar="'//self%ar//'"'
+end function debug_archiver
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/debug_compiler.html b/proc/debug_compiler.html new file mode 100644 index 0000000000..b4a3e5c1fd --- /dev/null +++ b/proc/debug_compiler.html @@ -0,0 +1,257 @@ + + + + + + + + + + + + + debug_compiler – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

debug_compiler + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public pure function debug_compiler(self) result(repr) +

+ + +

String representation of a compiler object

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(compiler_t), + intent(in) + + ::self +

Instance of the compiler object

+
+ +

Return Value + + + character(len=:), allocatable + +

+

Representation as string

+
+ + + + + + + + + + + +
+

Source Code

+
pure function debug_compiler(self) result(repr)
+    !> Instance of the compiler object
+    type(compiler_t), intent(in) :: self
+    !> Representation as string
+    character(len=:), allocatable :: repr
+
+    repr = 'fc="'//self%fc//'", cc="'//self%cc//'"'
+end function debug_compiler
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/default_example.html b/proc/default_example.html new file mode 100644 index 0000000000..2fa7c0b1c4 --- /dev/null +++ b/proc/default_example.html @@ -0,0 +1,270 @@ + + + + + + + + + + + + + default_example – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

default_example + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine default_example(self, name) +

+ + +

Populate test in case we find the default example/ directory

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(example_config_t), + intent(out) + + ::self +

Instance of the executable meta data

+
+ + character(len=*), + intent(in) + + ::name +

Name of the package

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
    subroutine default_example(self, name)
+
+        !> Instance of the executable meta data
+        type(example_config_t), intent(out) :: self
+
+        !> Name of the package
+        character(len=*), intent(in) :: name
+
+        self%name = name // "-demo"
+        self%source_dir = "example"
+        self%main = "main.f90"
+
+    end subroutine default_example
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/default_executable.html b/proc/default_executable.html new file mode 100644 index 0000000000..7fb64b7493 --- /dev/null +++ b/proc/default_executable.html @@ -0,0 +1,270 @@ + + + + + + + + + + + + + default_executable – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

default_executable + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine default_executable(self, name) +

+ + +

Populate executable in case we find the default app directory

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(executable_config_t), + intent(out) + + ::self +

Instance of the executable meta data

+
+ + character(len=*), + intent(in) + + ::name +

Name of the package

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
    subroutine default_executable(self, name)
+
+        !> Instance of the executable meta data
+        type(executable_config_t), intent(out) :: self
+
+        !> Name of the package
+        character(len=*), intent(in) :: name
+
+        self%name = name
+        self%source_dir = "app"
+        self%main = "main.f90"
+
+    end subroutine default_executable
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/default_library.html b/proc/default_library.html new file mode 100644 index 0000000000..bbf64e8eaf --- /dev/null +++ b/proc/default_library.html @@ -0,0 +1,251 @@ + + + + + + + + + + + + + default_library – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

default_library + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine default_library(self) +

+ + +

Populate library in case we find the default src directory

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(library_config_t), + intent(out) + + ::self +

Instance of the library meta data

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
    subroutine default_library(self)
+
+        !> Instance of the library meta data
+        type(library_config_t), intent(out) :: self
+
+        self%source_dir = "src"
+        self%include_dir = [string_t("include")]
+
+    end subroutine default_library
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/default_test.html b/proc/default_test.html new file mode 100644 index 0000000000..fdd8863223 --- /dev/null +++ b/proc/default_test.html @@ -0,0 +1,270 @@ + + + + + + + + + + + + + default_test – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

default_test + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine default_test(self, name) +

+ + +

Populate test in case we find the default test/ directory

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(test_config_t), + intent(out) + + ::self +

Instance of the executable meta data

+
+ + character(len=*), + intent(in) + + ::name +

Name of the package

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
    subroutine default_test(self, name)
+
+        !> Instance of the executable meta data
+        type(test_config_t), intent(out) :: self
+
+        !> Name of the package
+        character(len=*), intent(in) :: name
+
+        self%name = name // "-test"
+        self%source_dir = "test"
+        self%main = "main.f90"
+
+    end subroutine default_test
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/delete_env.html b/proc/delete_env.html new file mode 100644 index 0000000000..749675fb86 --- /dev/null +++ b/proc/delete_env.html @@ -0,0 +1,280 @@ + + + + + + + + + + + + + delete_env – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

delete_env + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function delete_env(name) result(success) +

+ + +

Deletes an environment variable for the current environment using the C standard library +Returns an error if the variable did not exist in the first place

+

C strings

+

Call setenv

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::name +

Variable name

+
+ +

Return Value + + + logical + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
logical function delete_env(name) result(success)
+
+   !> Variable name
+   character(*), intent(in) :: name
+   
+   ! Local variables
+   integer(c_int) :: cerr
+   character(kind=c_char,len=1), allocatable :: c_name(:)
+   
+   interface
+      integer(c_int) function c_unsetenv(envname) bind(C,name="c_unsetenv")
+         import c_int, c_char
+         implicit none
+         !> Pointer to the name string
+         character(kind=c_char,len=1), intent(in) :: envname(*)
+      end function c_unsetenv      
+   end interface
+   
+   !> C strings
+   call f2cs(name,c_name)
+   
+   !> Call setenv
+#ifndef FPM_BOOTSTRAP   
+   cerr = c_unsetenv(c_name)
+#endif
+   success = cerr==0_c_int
+   
+end function delete_env
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/delete_file.html b/proc/delete_file.html new file mode 100644 index 0000000000..75f7e1bd72 --- /dev/null +++ b/proc/delete_file.html @@ -0,0 +1,252 @@ + + + + + + + + + + + + + delete_file – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

delete_file + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine delete_file(file) +

+ + +

delete a file by filename

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::file + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
subroutine delete_file(file)
+    character(len=*), intent(in) :: file
+    logical :: exist
+    integer :: unit
+    inquire(file=file, exist=exist)
+    if (exist) then
+        open(file=file, newunit=unit)
+        close(unit, status="delete")
+    end if
+end subroutine delete_file
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/dependency_destroy.html b/proc/dependency_destroy.html new file mode 100644 index 0000000000..e116c1484e --- /dev/null +++ b/proc/dependency_destroy.html @@ -0,0 +1,252 @@ + + + + + + + + + + + + + dependency_destroy – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

dependency_destroy + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public elemental subroutine dependency_destroy(self) +

+ + +

Clean memory

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(dependency_config_t), + intent(inout) + + ::self + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
    elemental subroutine dependency_destroy(self)
+        class(dependency_config_t), intent(inout) :: self
+
+        if (allocated(self%name)) deallocate(self%name)
+        if (allocated(self%path)) deallocate(self%path)
+        if (allocated(self%namespace)) deallocate(self%namespace)
+        if (allocated(self%requested_version)) deallocate(self%requested_version)
+        if (allocated(self%git)) deallocate(self%git)
+
+    end subroutine dependency_destroy
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/descriptor_name.html b/proc/descriptor_name.html new file mode 100644 index 0000000000..8d4ff72653 --- /dev/null +++ b/proc/descriptor_name.html @@ -0,0 +1,262 @@ + + + + + + + + + + + + + descriptor_name – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

descriptor_name + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public pure function descriptor_name(descriptor) result(name) +

+ + +

Code git descriptor to a string

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + integer, + intent(in) + + ::descriptor + +
+ +

Return Value + + + character(len=:), allocatable + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
    pure function descriptor_name(descriptor) result(name)
+       integer, intent(in) :: descriptor
+       character(len=:), allocatable :: name
+
+       select case (descriptor)
+          case (git_descriptor%default);   name = "default"
+          case (git_descriptor%branch);    name = "branch"
+          case (git_descriptor%tag);       name = "tag"
+          case (git_descriptor%revision);  name = "revision"
+          case default;                    name = "ERROR"
+       end select
+
+    end function descriptor_name
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/destroy_dependency_node.html b/proc/destroy_dependency_node.html new file mode 100644 index 0000000000..5af6744f97 --- /dev/null +++ b/proc/destroy_dependency_node.html @@ -0,0 +1,259 @@ + + + + + + + + + + + + + destroy_dependency_node – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

destroy_dependency_node + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public elemental subroutine destroy_dependency_node(self) +

+ + +

Destructor

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(dependency_node_t), + intent(inout) + + ::self + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
    elemental subroutine destroy_dependency_node(self)
+
+        class(dependency_node_t), intent(inout) :: self
+
+        integer :: ierr
+
+        call dependency_destroy(self)
+
+        deallocate(self%version,stat=ierr)
+        deallocate(self%proj_dir,stat=ierr)
+        deallocate(self%revision,stat=ierr)
+        deallocate(self%package_dep,stat=ierr)
+        self%done = .false.
+        self%update = .false.
+        self%cached = .false.
+
+    end subroutine destroy_dependency_node
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/destroy~2.html b/proc/destroy~2.html new file mode 100644 index 0000000000..690e396863 --- /dev/null +++ b/proc/destroy~2.html @@ -0,0 +1,264 @@ + + + + + + + + + + + + + destroy – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

destroy + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public elemental subroutine destroy(this) +

+ + + +

Type Bound

+

metapackage_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(metapackage_t), + intent(inout) + + ::this + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
    elemental subroutine destroy(this)
+        class(metapackage_t), intent(inout) :: this
+        this%has_link_libraries = .false.
+        this%has_link_flags = .false.
+        this%has_build_flags = .false.
+        this%has_fortran_flags = .false.
+        this%has_c_flags = .false.
+        this%has_cxx_flags = .false.
+        this%has_include_dirs = .false.
+        this%has_dependencies = .false.
+        this%has_run_command = .false.
+        this%has_external_modules = .false.
+        if (allocated(this%fortran)) deallocate(this%fortran)
+        if (allocated(this%preprocess)) deallocate(this%preprocess)
+        if (allocated(this%name)) deallocate(this%name)
+        if (allocated(this%version)) deallocate(this%version)
+        if (allocated(this%flags%s)) deallocate(this%flags%s)
+        if (allocated(this%link_libs)) deallocate(this%link_libs)
+        if (allocated(this%incl_dirs)) deallocate(this%incl_dirs)
+        if (allocated(this%external_modules)) deallocate(this%external_modules)
+    end subroutine destroy
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/dilate.html b/proc/dilate.html new file mode 100644 index 0000000000..c0018904ee --- /dev/null +++ b/proc/dilate.html @@ -0,0 +1,310 @@ + + + + + + + + + + + + + dilate – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

dilate + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function dilate(instr) result(outstr) +

+ + +

NAME

+
dilate(3f) - [M_strings:NONALPHA] expand tab characters
+(LICENSE:PD)
+
+ +

SYNOPSIS

+
function dilate(INSTR) result(OUTSTR)
+
+ character(len=*),intent=(in)  :: INSTR
+ character(len=:),allocatable  :: OUTSTR
+
+ +

DESCRIPTION

+
 dilate() converts tabs in INSTR to spaces in OUTSTR.  It assumes a
+ tab is set every 8 characters. Trailing spaces are removed.
+
+ In addition, trailing carriage returns and line feeds are removed
+ (they are usually a problem created by going to and from MSWindows).
+
+ +

OPTIONS

+
 instr     Input line to remove tabs from
+
+ +

RESULTS

+
 outstr    Output string with tabs expanded.
+
+ +

EXAMPLES

+

Sample program:

+
program demo_dilate
+
+use M_strings, only : dilate
+implicit none
+character(len=:),allocatable :: in
+integer                      :: i
+   in='  this is my string  '
+   ! change spaces to tabs to make a sample input
+   do i=1,len(in)
+      if(in(i:i) == ' ')in(i:i)=char(9)
+   enddo
+   write(*,'(a)')in,dilate(in)
+end program demo_dilate
+
+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::instr + +
+ +

Return Value + + + character(len=:), allocatable + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
function dilate(instr) result(outstr)
+
+   character(len=*), intent(in)  :: instr        ! input line to scan for tab characters
+   character(len=:), allocatable :: outstr       ! tab-expanded version of INSTR produced
+   integer                       :: i
+   integer                       :: icount
+   integer                       :: lgth
+   icount = 0
+   do i = 1, len(instr)
+      if (instr(i:i) == char(9)) icount = icount + 1
+   end do
+   allocate (character(len=(len(instr) + 8*icount)) :: outstr)
+   call notabs(instr, outstr, lgth)
+   outstr = outstr(:lgth)
+
+end function dilate
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/dirname.html b/proc/dirname.html new file mode 100644 index 0000000000..449c6db6c9 --- /dev/null +++ b/proc/dirname.html @@ -0,0 +1,256 @@ + + + + + + + + + + + + + dirname – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

dirname + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function dirname(path) result(dir) +

+ + +

Extract dirname from path

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::path + +
+ +

Return Value + + + character(len=:), allocatable + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
function dirname(path) result (dir)
+    character(*), intent(in) :: path
+    character(:), allocatable :: dir
+
+    dir = path(1:scan(path,'/\',back=.true.))
+
+end function dirname
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/dump_to_toml~3.html b/proc/dump_to_toml~3.html new file mode 100644 index 0000000000..1baae1ac5d --- /dev/null +++ b/proc/dump_to_toml~3.html @@ -0,0 +1,340 @@ + + + + + + + + + + + + + dump_to_toml – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

dump_to_toml + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine dump_to_toml(self, table, error) +

+ + +

Dump dependency to toml table

+ +

Type Bound

+

git_target_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(git_target_t), + intent(inout) + + ::self +

Instance of the serializable object

+
+ + type(toml_table), + intent(inout) + + ::table +

Data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + integer, + public + + ::ierr + +
+ +
+
+ + + + + + + + + +
+

Source Code

+
    subroutine dump_to_toml(self, table, error)
+
+        !> Instance of the serializable object
+        class(git_target_t), intent(inout) :: self
+
+        !> Data structure
+        type(toml_table), intent(inout) :: table
+
+        !> Error handling
+        type(error_t), allocatable, intent(out) :: error
+
+        integer :: ierr
+
+        call set_string(table, "descriptor", descriptor_name(self%descriptor), error, 'git_target_t')
+        if (allocated(error)) return
+        call set_string(table, "url", self%url, error, 'git_target_t')
+        if (allocated(error)) return
+        call set_string(table, "object", self%object, error, 'git_target_t')
+        if (allocated(error)) return
+
+    end subroutine dump_to_toml
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/dump_to_toml~8.html b/proc/dump_to_toml~8.html new file mode 100644 index 0000000000..afc714d0aa --- /dev/null +++ b/proc/dump_to_toml~8.html @@ -0,0 +1,297 @@ + + + + + + + + + + + + + dump_to_toml – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

dump_to_toml + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine dump_to_toml(self, table, error) +

+ + +

Dump dependency to toml table

+

Path to archiver

+ +

Type Bound

+

archiver_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(archiver_t), + intent(inout) + + ::self +

Instance of the serializable object

+
+ + type(toml_table), + intent(inout) + + ::table +

Data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
subroutine dump_to_toml(self, table, error)
+
+    !> Instance of the serializable object
+    class(archiver_t), intent(inout) :: self
+
+    !> Data structure
+    type(toml_table), intent(inout) :: table
+
+    !> Error handling
+    type(error_t), allocatable, intent(out) :: error
+
+    !> Path to archiver
+    call set_string(table, "ar", self%ar, error, 'archiver_t')
+    if (allocated(error)) return
+    call set_value(table, "use-response-file", self%use_response_file, error, 'archiver_t')
+    if (allocated(error)) return
+    call set_value(table, "echo", self%echo, error, 'archiver_t')
+    if (allocated(error)) return
+    call set_value(table, "verbose", self%verbose, error, 'archiver_t')
+    if (allocated(error)) return
+
+end subroutine dump_to_toml
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/enumerate_libraries.html b/proc/enumerate_libraries.html new file mode 100644 index 0000000000..3a704500b4 --- /dev/null +++ b/proc/enumerate_libraries.html @@ -0,0 +1,359 @@ + + + + + + + + + + + + + enumerate_libraries – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

enumerate_libraries + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function enumerate_libraries(self, prefix, libs) result(r) +

+ + +

Enumerate libraries, based on compiler and platform

+ +

Type Bound

+

compiler_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::self + +
+ + character(len=*), + intent(in) + + ::prefix + +
+ + type(string_t), + intent(in) + + ::libs(:) + +
+ +

Return Value + + + character(len=:), allocatable + +

+ +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=:), + public, + allocatable + ::joined + +
+ +
+
+ + + + + + + + + +
+

Source Code

+
function enumerate_libraries(self, prefix, libs) result(r)
+    class(compiler_t), intent(in) :: self
+    character(len=*), intent(in) :: prefix
+    type(string_t), intent(in) :: libs(:)
+    character(len=:), allocatable :: r
+
+    character(len=:), allocatable :: joined
+
+    if (size(libs) == 0) then
+        r = prefix
+        return
+    end if
+
+    select case (self%id)
+
+    case (id_intel_classic_windows, id_intel_llvm_windows)
+        ! Windows Intel uses `.lib` files directly
+        joined = string_cat(libs, ".lib ") // ".lib"
+        r = trim(prefix) // " " // trim(joined)
+
+    case (id_nag, id_ibmxl)
+        ! NAG and IBMXL need -Wl, wrapper around linker flags
+        joined = string_cat(libs, " -Wl,")
+        r = trim(prefix) // " -Wl," // trim(joined)
+
+    case default
+        ! Generic Unix-style linker flags: use `-lfoo`
+        joined = string_cat(libs, " -l")
+        r = trim(prefix) // " -l" // trim(joined)
+
+    end select
+
+end function enumerate_libraries
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/execute_and_read_output.html b/proc/execute_and_read_output.html new file mode 100644 index 0000000000..df1e0d9552 --- /dev/null +++ b/proc/execute_and_read_output.html @@ -0,0 +1,275 @@ + + + + + + + + + + + + + execute_and_read_output – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

execute_and_read_output + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine execute_and_read_output(cmd, output, error, verbose) +

+ + +

Execute command line and return output as a string.

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::cmd +

Command to execute.

+
+ + character(len=:), + intent(out), + allocatable + ::output +

Command line output.

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error to handle.

+
+ + logical, + intent(in),optional + + ::verbose +

Print additional information if true.

+
+ +
+ + + + + + + + + + + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/exists.html b/proc/exists.html new file mode 100644 index 0000000000..bc6d0f7f46 --- /dev/null +++ b/proc/exists.html @@ -0,0 +1,237 @@ + + + + + + + + + + + + + exists – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

exists + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function exists(filename) result(r) +

+ + +

test if pathname already exists

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::filename + +
+ +

Return Value + + + logical + +

+ +
+ + + + + + + + + + + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/f_string.html b/proc/f_string.html new file mode 100644 index 0000000000..6e7bcefb40 --- /dev/null +++ b/proc/f_string.html @@ -0,0 +1,281 @@ + + + + + + + + + + + + + f_string – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

f_string + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function f_string(c_string) +

+
+

Uses

+
+ +
+
+ + +

return Fortran character variable when given a C-like array of +single characters terminated with a C_NULL_CHAR character

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=1), + intent(in) + + ::c_string(:) + +
+ +

Return Value + + + character(len=:), allocatable + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
function f_string(c_string)
+    use iso_c_binding
+    character(len=1), intent(in) :: c_string(:)
+    character(:), allocatable :: f_string
+
+    integer :: i, n
+
+    i = 0
+    do while(c_string(i+1) /= C_NULL_CHAR)
+      i = i + 1
+    end do
+    n = i
+
+    allocate(character(n) :: f_string)
+    do i=1,n
+      f_string(i:i) = c_string(i)
+    end do
+
+end function f_string
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/fatal_error.html b/proc/fatal_error.html new file mode 100644 index 0000000000..257ff9e7d3 --- /dev/null +++ b/proc/fatal_error.html @@ -0,0 +1,269 @@ + + + + + + + + + + + + + fatal_error – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fatal_error + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine fatal_error(error, message) +

+ + +

Generic fatal runtime error

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(error_t), + intent(out), + allocatable + ::error +

Instance of the error data

+
+ + character(len=*), + intent(in) + + ::message +

Error message

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
    subroutine fatal_error(error, message)
+
+        !> Instance of the error data
+        type(error_t), allocatable, intent(out) :: error
+
+        !> Error message
+        character(len=*), intent(in) :: message
+
+        allocate(error)
+        error%message = message
+
+    end subroutine fatal_error
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/file_not_found_error.html b/proc/file_not_found_error.html new file mode 100644 index 0000000000..17a6a4a408 --- /dev/null +++ b/proc/file_not_found_error.html @@ -0,0 +1,269 @@ + + + + + + + + + + + + + file_not_found_error – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

file_not_found_error + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine file_not_found_error(error, file_name) +

+ + +

Error created when a file is missing or not found

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(error_t), + intent(out), + allocatable + ::error +

Instance of the error data

+
+ + character(len=*), + intent(in) + + ::file_name +

Name of the missing file

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
    subroutine file_not_found_error(error, file_name)
+
+        !> Instance of the error data
+        type(error_t), allocatable, intent(out) :: error
+
+        !> Name of the missing file
+        character(len=*), intent(in) :: file_name
+
+        allocate(error)
+        error%message = "'"//file_name//"' could not be found, check if the file exists"
+
+    end subroutine file_not_found_error
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/file_parse_error.html b/proc/file_parse_error.html new file mode 100644 index 0000000000..3d89f230df --- /dev/null +++ b/proc/file_parse_error.html @@ -0,0 +1,383 @@ + + + + + + + + + + + + + file_parse_error – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

file_parse_error + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine file_parse_error(error, file_name, message, line_num, line_string, line_col) +

+ + +

Error created when file parsing fails

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(error_t), + intent(out), + allocatable + ::error +

Instance of the error data

+
+ + character(len=*), + intent(in) + + ::file_name +

Name of file

+
+ + character(len=*), + intent(in) + + ::message +

Parse error message

+
+ + integer, + intent(in),optional + + ::line_num +

Line number of parse error

+
+ + character(len=*), + intent(in),optional + + ::line_string +

Line context string

+
+ + integer, + intent(in),optional + + ::line_col +

Line context column

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
    subroutine file_parse_error(error, file_name, message, line_num, &
+                                 line_string, line_col)
+
+        !> Instance of the error data
+        type(error_t), allocatable, intent(out) :: error
+
+        !> Name of file
+        character(len=*), intent(in) :: file_name
+
+        !> Parse error message
+        character(len=*), intent(in) :: message
+
+        !> Line number of parse error
+        integer, intent(in), optional :: line_num
+
+        !> Line context string
+        character(len=*), intent(in), optional :: line_string
+
+        !> Line context column
+        integer, intent(in), optional :: line_col
+
+        character(50) :: temp_string
+
+        allocate(error)
+        error%message = 'Parse error: '//message//new_line('a')
+
+        error%message = error%message//file_name
+
+        if (present(line_num)) then
+
+            write(temp_string,'(I0)') line_num
+
+            error%message = error%message//':'//trim(temp_string)
+
+        end if
+
+        if (present(line_col)) then
+
+            if (line_col > 0) then
+
+                write(temp_string,'(I0)') line_col
+                error%message = error%message//':'//trim(temp_string)
+
+            end if
+
+        end if
+
+        if (present(line_string)) then
+
+            error%message = error%message//new_line('a')
+            error%message = error%message//'   | '//line_string
+
+            if (present(line_col)) then
+
+                if (line_col > 0) then
+
+                    error%message = error%message//new_line('a')
+                    error%message = error%message//'   | '//repeat(' ',line_col-1)//'^'
+
+                end if
+
+            end if
+
+        end if
+
+    end subroutine file_parse_error
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/file_scope_dump.html b/proc/file_scope_dump.html new file mode 100644 index 0000000000..7f69c7bc64 --- /dev/null +++ b/proc/file_scope_dump.html @@ -0,0 +1,291 @@ + + + + + + + + + + + + + file_scope_dump – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

file_scope_dump + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine file_scope_dump(self, table, error) +

+ + +

Dump to toml table

+ +

Type Bound

+

file_scope_flag

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(file_scope_flag), + intent(inout) + + ::self +

Instance of the serializable object

+
+ + type(toml_table), + intent(inout) + + ::table +

Data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
    subroutine file_scope_dump(self, table, error)
+
+       !> Instance of the serializable object
+       class(file_scope_flag), intent(inout) :: self
+
+       !> Data structure
+       type(toml_table), intent(inout) :: table
+
+       !> Error handling
+       type(error_t), allocatable, intent(out) :: error
+
+       call set_string(table, "file-name", self%file_name, error)
+       if (allocated(error)) return
+       call set_string(table, "flags", self%flags, error)
+       if (allocated(error)) return
+
+     end subroutine file_scope_dump
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/file_scope_load.html b/proc/file_scope_load.html new file mode 100644 index 0000000000..09cb31d00b --- /dev/null +++ b/proc/file_scope_load.html @@ -0,0 +1,289 @@ + + + + + + + + + + + + + file_scope_load – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

file_scope_load + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine file_scope_load(self, table, error) +

+ + +

Read from toml table (no checks made at this stage)

+ +

Type Bound

+

file_scope_flag

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(file_scope_flag), + intent(inout) + + ::self +

Instance of the serializable object

+
+ + type(toml_table), + intent(inout) + + ::table +

Data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
     subroutine file_scope_load(self, table, error)
+
+        !> Instance of the serializable object
+        class(file_scope_flag), intent(inout) :: self
+
+        !> Data structure
+        type(toml_table), intent(inout) :: table
+
+        !> Error handling
+        type(error_t), allocatable, intent(out) :: error
+
+        call get_value(table, "file-name", self%file_name)
+        call get_value(table, "flags", self%flags)
+
+     end subroutine file_scope_load
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/file_scope_same.html b/proc/file_scope_same.html new file mode 100644 index 0000000000..5e4c769e5f --- /dev/null +++ b/proc/file_scope_same.html @@ -0,0 +1,292 @@ + + + + + + + + + + + + + file_scope_same – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

file_scope_same + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function file_scope_same(this, that) +

+ + +

All checks passed!

+ +

Type Bound

+

file_scope_flag

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(file_scope_flag), + intent(in) + + ::this + +
+ + class(serializable_t), + intent(in) + + ::that + +
+ +

Return Value + + + logical + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
      logical function file_scope_same(this,that)
+          class(file_scope_flag), intent(in) :: this
+          class(serializable_t), intent(in) :: that
+
+          file_scope_same = .false.
+
+          select type (other=>that)
+             type is (file_scope_flag)
+                if (allocated(this%file_name).neqv.allocated(other%file_name)) return
+                if (allocated(this%file_name)) then
+                    if (.not.(this%file_name==other%file_name)) return
+                endif
+                if (allocated(this%flags).neqv.allocated(other%flags)) return
+                if (allocated(this%flags)) then
+                    if (.not.(this%flags==other%flags)) return
+                endif
+
+             class default
+                ! Not the same type
+                return
+          end select
+
+          !> All checks passed!
+          file_scope_same = .true.
+
+    end function file_scope_same
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/fileclose.html b/proc/fileclose.html new file mode 100644 index 0000000000..f9f3eba825 --- /dev/null +++ b/proc/fileclose.html @@ -0,0 +1,273 @@ + + + + + + + + + + + + + fileclose – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fileclose + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine fileclose(lun, ier) +

+ + +

simple close of a LUN. On error show message and stop (by default)

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + integer, + intent(in) + + ::lun + +
+ + integer, + intent(out),optional + + ::ier + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
subroutine fileclose(lun,ier)
+integer,intent(in)    :: lun
+integer,intent(out),optional :: ier
+character(len=256)    :: message
+integer               :: ios
+    if(lun/=-1)then
+        close(unit=lun,iostat=ios,iomsg=message)
+        if(ios/=0)then
+            if(present(ier))then
+               ier=ios
+            else
+               call fpm_stop(4,'*fileclose*:'//trim(message))
+            endif
+        endif
+    endif
+end subroutine fileclose
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/fileopen.html b/proc/fileopen.html new file mode 100644 index 0000000000..651c72ea73 --- /dev/null +++ b/proc/fileopen.html @@ -0,0 +1,306 @@ + + + + + + + + + + + + + fileopen – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fileopen + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine fileopen(filename, lun, ier) +

+ + +

procedure to open filename as a sequential “text” file

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::filename + +
+ + integer, + intent(out) + + ::lun + +
+ + integer, + intent(out),optional + + ::ier + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
subroutine fileopen(filename,lun,ier)
+
+character(len=*),intent(in)   :: filename
+integer,intent(out)           :: lun
+integer,intent(out),optional  :: ier
+integer                       :: ios
+character(len=256)            :: message
+
+    message=' '
+    ios=0
+    if(filename/=' ')then
+        open(file=filename, &
+        & newunit=lun, &
+        & form='formatted', &    ! FORM    = FORMATTED | UNFORMATTED
+        & access='sequential', & ! ACCESS  = SEQUENTIAL| DIRECT | STREAM
+        & action='write', &      ! ACTION  = READ|WRITE| READWRITE
+        & position='rewind', &   ! POSITION= ASIS      | REWIND | APPEND
+        & status='new', &        ! STATUS  = NEW| REPLACE| OLD| SCRATCH| UNKNOWN
+        & iostat=ios, &
+        & iomsg=message)
+    else
+        lun=stdout
+        ios=0
+    endif
+    if(ios/=0)then
+        lun=-1
+        if(present(ier))then
+           ier=ios
+        else
+           call fpm_stop(3,'*fileopen*:'//filename//':'//trim(message))
+        endif
+    endif
+
+end subroutine fileopen
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/filewrite.html b/proc/filewrite.html new file mode 100644 index 0000000000..67516fbb4b --- /dev/null +++ b/proc/filewrite.html @@ -0,0 +1,278 @@ + + + + + + + + + + + + + filewrite – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

filewrite + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine filewrite(filename, filedata) +

+ + +

procedure to write filedata to file filename

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::filename + +
+ + character(len=*), + intent(in) + + ::filedata(:) + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
subroutine filewrite(filename,filedata)
+
+character(len=*),intent(in)           :: filename
+character(len=*),intent(in)           :: filedata(:)
+integer                               :: lun, i, ios
+character(len=256)                    :: message
+    call fileopen(filename,lun)
+    if(lun/=-1)then ! program currently stops on error on open, but might
+                      ! want it to continue so -1 (unallowed LUN) indicates error
+       ! write file
+       do i=1,size(filedata)
+           write(lun,'(a)',iostat=ios,iomsg=message)trim(filedata(i))
+           if(ios/=0)then
+               call fpm_stop(5,'*filewrite*:'//filename//':'//trim(message))
+           endif
+       enddo
+    endif
+    ! close file
+    call fileclose(lun)
+
+end subroutine filewrite
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/filter_executable_targets.html b/proc/filter_executable_targets.html new file mode 100644 index 0000000000..5222dd0567 --- /dev/null +++ b/proc/filter_executable_targets.html @@ -0,0 +1,289 @@ + + + + + + + + + + + + + filter_executable_targets – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

filter_executable_targets + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine filter_executable_targets(targets, scope, list) +

+ + + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(build_target_ptr), + intent(in) + + ::targets(:) + +
+ + integer, + intent(in) + + ::scope + +
+ + type(string_t), + intent(out), + allocatable + ::list(:) + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
subroutine filter_executable_targets(targets, scope, list)
+    type(build_target_ptr), intent(in) :: targets(:)
+    integer, intent(in) :: scope
+    type(string_t), allocatable, intent(out) :: list(:)
+
+    integer :: i, n
+
+    n = 0
+    call resize(list)
+    do i = 1, size(targets)
+        if (is_executable_target(targets(i)%ptr, scope)) then
+            if (n >= size(list)) call resize(list)
+            n = n + 1
+            list(n)%s = targets(i)%ptr%output_file
+        end if
+    end do
+    call resize(list, n)
+end subroutine filter_executable_targets
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/filter_library_targets.html b/proc/filter_library_targets.html new file mode 100644 index 0000000000..3ac36b01e4 --- /dev/null +++ b/proc/filter_library_targets.html @@ -0,0 +1,280 @@ + + + + + + + + + + + + + filter_library_targets – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

filter_library_targets + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine filter_library_targets(targets, list) +

+ + +

Returns pointers to all library targets

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(build_target_ptr), + intent(in) + + ::targets(:) + +
+ + type(build_target_ptr), + intent(out), + allocatable + ::list(:) + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
subroutine filter_library_targets(targets, list)
+    type(build_target_ptr), intent(in) :: targets(:)
+    type(build_target_ptr), allocatable, intent(out) :: list(:)
+
+    integer :: i, n
+    
+    n = 0
+    do i = 1, size(targets)
+        if (any(targets(i)%ptr%target_type == [FPM_TARGET_ARCHIVE,FPM_TARGET_SHARED])) then
+            n = n + 1
+        end if
+    end do    
+    
+    allocate(list(n))
+
+    n = 0
+    do i = 1, size(targets)
+        if (any(targets(i)%ptr%target_type == [FPM_TARGET_ARCHIVE,FPM_TARGET_SHARED])) then
+            n = n + 1
+            list(n)%ptr => targets(i)%ptr
+        end if
+    end do
+end subroutine filter_library_targets
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/filter_modules.html b/proc/filter_modules.html new file mode 100644 index 0000000000..109aa2ee5b --- /dev/null +++ b/proc/filter_modules.html @@ -0,0 +1,278 @@ + + + + + + + + + + + + + filter_modules – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

filter_modules + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine filter_modules(targets, list) +

+ + + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(build_target_ptr), + intent(in) + + ::targets(:) + +
+ + type(string_t), + intent(out), + allocatable + ::list(:) + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
subroutine filter_modules(targets, list)
+    type(build_target_ptr), intent(in) :: targets(:)
+    type(string_t), allocatable, intent(out) :: list(:)
+
+    integer :: i, j, n
+
+    n = 0
+    call resize(list)
+    do i = 1, size(targets)
+        associate(target => targets(i)%ptr)
+            if (.not.allocated(target%source)) cycle
+            if (target%source%unit_type == FPM_UNIT_SUBMODULE) cycle
+            if (n + size(target%source%modules_provided) >= size(list)) call resize(list)
+            do j = 1, size(target%source%modules_provided)
+                n = n + 1
+                list(n)%s = join_path(target%output_dir, &
+                    target%source%modules_provided(j)%s)
+            end do
+        end associate
+    end do
+    call resize(list, n)
+end subroutine filter_modules
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/find_profile.html b/proc/find_profile.html new file mode 100644 index 0000000000..1e59897b76 --- /dev/null +++ b/proc/find_profile.html @@ -0,0 +1,510 @@ + + + + + + + + + + + + + find_profile – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

find_profile + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine find_profile(profiles, profile_name, compiler, os_type, found_matching, chosen_profile) +

+ + +

Look for profile with given configuration in array profiles

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(profile_config_t), + intent(in), + allocatable + ::profiles(:) +

Array of profiles

+
+ + character(len=:), + intent(in), + allocatable + ::profile_name +

Name of profile

+
+ + character(len=:), + intent(in), + allocatable + ::compiler +

Name of compiler

+
+ + integer, + intent(in) + + ::os_type +

Type of operating system (enum)

+
+ + logical, + intent(out) + + ::found_matching +

Boolean value containing true if matching profile was found

+
+ + type(profile_config_t), + intent(out) + + ::chosen_profile +

Last matching profile in the profiles array

+
+ +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=:), + public, + allocatable + ::curr_compiler + +
+ + integer, + public + + ::curr_os + +
+ + integer, + public + + ::curr_priority + +
+ + character(len=:), + public, + allocatable + ::curr_profile_name + +
+ + integer, + public + + ::i + +
+ + integer, + public + + ::priority + +
+ +
+
+ + + + + + + + + +
+

Source Code

+
      subroutine find_profile(profiles, profile_name, compiler, os_type, found_matching, chosen_profile)
+
+        !> Array of profiles
+        type(profile_config_t), allocatable, intent(in) :: profiles(:)
+
+        !> Name of profile
+        character(:), allocatable, intent(in) :: profile_name
+
+        !> Name of compiler
+        character(:), allocatable, intent(in) :: compiler
+
+        !> Type of operating system (enum)
+        integer, intent(in) :: os_type
+
+        !> Boolean value containing true if matching profile was found
+        logical, intent(out) :: found_matching
+
+        !> Last matching profile in the profiles array
+        type(profile_config_t), intent(out) :: chosen_profile
+
+        character(:), allocatable :: curr_profile_name
+        character(:), allocatable :: curr_compiler
+        integer :: curr_os
+        integer :: i, priority, curr_priority
+
+        found_matching = .false.
+        if (size(profiles) < 1) return
+        ! Try to find profile with matching OS type
+        do i=1,size(profiles)
+          curr_profile_name = profiles(i)%profile_name
+          curr_compiler = profiles(i)%compiler
+          curr_os = profiles(i)%os_type
+          if (curr_profile_name.eq.profile_name) then
+            if (curr_compiler.eq.compiler) then
+              if (curr_os.eq.os_type) then
+                chosen_profile = profiles(i)
+                found_matching = .true.
+              end if
+            end if
+          end if
+        end do
+        ! Try to find profile with OS type 'all'
+        if (.not. found_matching) then
+          do i=1,size(profiles)
+            curr_profile_name = profiles(i)%profile_name
+            curr_compiler = profiles(i)%compiler
+            curr_os = profiles(i)%os_type
+            if (curr_profile_name.eq.profile_name) then
+              if (curr_compiler.eq.compiler) then
+                if (curr_os.eq.OS_ALL) then
+                  chosen_profile = profiles(i)
+                  found_matching = .true.
+                end if
+              end if
+            end if
+          end do
+        end if
+      end subroutine find_profile
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/fpm_scope_name.html b/proc/fpm_scope_name.html new file mode 100644 index 0000000000..f4a19d48bb --- /dev/null +++ b/proc/fpm_scope_name.html @@ -0,0 +1,263 @@ + + + + + + + + + + + + + FPM_SCOPE_NAME – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

FPM_SCOPE_NAME + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function FPM_SCOPE_NAME(flag) result(name) +

+ + +

Return the character name of a scope flag

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + integer, + intent(in) + + ::flag + +
+ +

Return Value + + + character(len=:), allocatable + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
function FPM_SCOPE_NAME(flag) result(name)
+    integer, intent(in) :: flag
+    character(len=:), allocatable :: name
+
+    select case (flag)
+       case (FPM_SCOPE_UNKNOWN); name = "FPM_SCOPE_UNKNOWN"
+       case (FPM_SCOPE_LIB);     name = "FPM_SCOPE_LIB"
+       case (FPM_SCOPE_DEP);     name = "FPM_SCOPE_DEP"
+       case (FPM_SCOPE_APP);     name = "FPM_SCOPE_APP"
+       case (FPM_SCOPE_TEST);    name = "FPM_SCOPE_TEST"
+       case (FPM_SCOPE_EXAMPLE); name = "FPM_SCOPE_EXAMPLE"
+       case default;             name = "INVALID"
+    end select
+end function FPM_SCOPE_NAME
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/fpm_stop.html b/proc/fpm_stop.html new file mode 100644 index 0000000000..6f45879055 --- /dev/null +++ b/proc/fpm_stop.html @@ -0,0 +1,278 @@ + + + + + + + + + + + + + fpm_stop – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_stop + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine fpm_stop(value, message) +

+ + + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + integer, + intent(in) + + ::value +

value to use on STOP

+
+ + character(len=*), + intent(in) + + ::message +

Error message

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
    subroutine fpm_stop(value,message)
+    ! TODO: if verbose mode, call ERROR STOP instead of STOP
+    ! TODO: if M_escape is used, add color
+    ! to work with older compilers might need a case statement for values
+
+        !> value to use on STOP
+        integer, intent(in) :: value
+        !> Error message
+        character(len=*), intent(in) :: message
+        integer :: iostat
+        if(message/='')then
+           flush(unit=stderr,iostat=iostat)
+           flush(unit=stdout,iostat=iostat)
+           if(value>0)then
+              write(stderr,'("<ERROR> ",a)')trim(message)
+           else
+              write(stderr,'("<INFO> ",a)')trim(message)
+           endif
+           flush(unit=stderr,iostat=iostat)
+        endif
+        stop value
+    end subroutine fpm_stop
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/fpm_target_name.html b/proc/fpm_target_name.html new file mode 100644 index 0000000000..dda6bfceca --- /dev/null +++ b/proc/fpm_target_name.html @@ -0,0 +1,264 @@ + + + + + + + + + + + + + FPM_TARGET_NAME – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

FPM_TARGET_NAME + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public pure function FPM_TARGET_NAME(type) result(msg) +

+ + +

Target type name

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + integer, + intent(in) + + ::type + +
+ +

Return Value + + + character(len=:), allocatable + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
pure function FPM_TARGET_NAME(type) result(msg)
+   integer, intent(in) :: type
+   character(:), allocatable :: msg
+
+   select case (type)
+      case (FPM_TARGET_ARCHIVE);    msg = 'Archive'
+      case (FPM_TARGET_SHARED);     msg = 'Shared library'
+      case (FPM_TARGET_CPP_OBJECT); msg = 'C++ object'
+      case (FPM_TARGET_C_OBJECT);   msg = 'C Object'
+      case (FPM_TARGET_EXECUTABLE); msg = 'Executable'
+      case (FPM_TARGET_OBJECT);     msg = 'Object'      
+      case default;                 msg = 'Unknown'
+   end select
+
+end function FPM_TARGET_NAME
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/fpm_unit_name.html b/proc/fpm_unit_name.html new file mode 100644 index 0000000000..33a0663d16 --- /dev/null +++ b/proc/fpm_unit_name.html @@ -0,0 +1,265 @@ + + + + + + + + + + + + + FPM_UNIT_NAME – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

FPM_UNIT_NAME + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function FPM_UNIT_NAME(flag) result(name) +

+ + +

Return the character name of a unit flag

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + integer, + intent(in) + + ::flag + +
+ +

Return Value + + + character(len=:), allocatable + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
function FPM_UNIT_NAME(flag) result(name)
+    integer, intent(in) :: flag
+    character(len=:), allocatable :: name
+
+    select case (flag)
+       case (FPM_UNIT_UNKNOWN);    name = "FPM_UNIT_UNKNOWN"
+       case (FPM_UNIT_PROGRAM);    name = "FPM_UNIT_PROGRAM"
+       case (FPM_UNIT_MODULE);     name = "FPM_UNIT_MODULE"
+       case (FPM_UNIT_SUBMODULE);  name = "FPM_UNIT_SUBMODULE"
+       case (FPM_UNIT_SUBPROGRAM); name = "FPM_UNIT_SUBPROGRAM"
+       case (FPM_UNIT_CSOURCE);    name = "FPM_UNIT_CSOURCE"
+       case (FPM_UNIT_CPPSOURCE);  name = "FPM_UNIT_CPPSOURCE"
+       case (FPM_UNIT_CHEADER);    name = "FPM_UNIT_CHEADER"
+       case default;               name = "INVALID"
+    end select
+end function FPM_UNIT_NAME
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/fpm_version.html b/proc/fpm_version.html new file mode 100644 index 0000000000..6d1fd150e9 --- /dev/null +++ b/proc/fpm_version.html @@ -0,0 +1,253 @@ + + + + + + + + + + + + + fpm_version – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

fpm_version + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function fpm_version() +

+ + +

Return the current fpm version from fpm_version_ID as a version type

+ + +

Arguments

+ None +
+

Return Value + + + type(version_t) + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
    type(version_t) function fpm_version()
+
+        type(error_t), allocatable :: error
+
+! Fallback to last known version in case of undefined macro
+#ifndef FPM_RELEASE_VERSION
+#  define FPM_RELEASE_VERSION 0.12.0
+#endif
+
+! Accept solution from https://stackoverflow.com/questions/31649691/stringify-macro-with-gnu-gfortran
+! which provides the "easiest" way to pass a macro to a string in Fortran complying with both
+! gfortran's "traditional" cpp and the standard cpp syntaxes
+#ifdef __GFORTRAN__ /* traditional-cpp stringification */
+#  define STRINGIFY_START(X) "&
+#  define STRINGIFY_END(X) &X"
+#else               /* default stringification */
+#  define STRINGIFY_(X) #X
+#  define STRINGIFY_START(X) &
+#  define STRINGIFY_END(X) STRINGIFY_(X)
+#endif
+
+        character (len=:), allocatable :: ver_string
+        ver_string = STRINGIFY_START(FPM_RELEASE_VERSION)
+        STRINGIFY_END(FPM_RELEASE_VERSION)
+
+        call new_version(fpm_version,ver_string,error)
+
+        if (allocated(error)) call fpm_stop(1,'*fpm*:internal error: cannot get version - '//error%message)
+
+    end function fpm_version
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/get_absolute_path.html b/proc/get_absolute_path.html new file mode 100644 index 0000000000..c6a7a07e6f --- /dev/null +++ b/proc/get_absolute_path.html @@ -0,0 +1,261 @@ + + + + + + + + + + + + + get_absolute_path – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

get_absolute_path + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine get_absolute_path(path, absolute_path, error) +

+ + +

Determine the canonical, absolute path for the given path. +Expands home folder (~) on both Unix and Windows.

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::path + +
+ + character(len=:), + intent(out), + allocatable + ::absolute_path + +
+ + type(error_t), + intent(out), + allocatable + ::error + +
+ +
+ + + + + + + + + + + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/get_absolute_path_by_cd.html b/proc/get_absolute_path_by_cd.html new file mode 100644 index 0000000000..addc41d646 --- /dev/null +++ b/proc/get_absolute_path_by_cd.html @@ -0,0 +1,261 @@ + + + + + + + + + + + + + get_absolute_path_by_cd – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

get_absolute_path_by_cd + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine get_absolute_path_by_cd(path, absolute_path, error) +

+ + +

Alternative to get_absolute_path that uses chdir/_chdir to determine the absolute path.

+

get_absolute_path is preferred but get_absolute_path_by_cd can be used in bootstrap mode.

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::path + +
+ + character(len=:), + intent(out), + allocatable + ::absolute_path + +
+ + type(error_t), + intent(out), + allocatable + ::error + +
+ +
+ + + + + + + + + + + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/get_command_arguments_quoted.html b/proc/get_command_arguments_quoted.html new file mode 100644 index 0000000000..392defe224 --- /dev/null +++ b/proc/get_command_arguments_quoted.html @@ -0,0 +1,256 @@ + + + + + + + + + + + + + get_command_arguments_quoted – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

get_command_arguments_quoted + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function get_command_arguments_quoted() result(args) +

+ + + + +

Arguments

+ None +
+

Return Value + + + character(len=:), allocatable + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
    function get_command_arguments_quoted() result(args)
+    character(len=:),allocatable :: args
+    character(len=:),allocatable :: arg
+    character(len=1)             :: quote
+    integer                      :: ilength, istatus, i
+    ilength=0
+    args=''
+        quote=merge('"',"'",separator()=='\')
+        do i=2,command_argument_count() ! look at all arguments after subcommand
+            call get_command_argument(number=i,length=ilength,status=istatus)
+            if(istatus /= 0) then
+                write(stderr,'(*(g0,1x))')'<ERROR>*get_command_arguments_stack* error obtaining argument ',i
+                exit
+            else
+                if(allocated(arg))deallocate(arg)
+                allocate(character(len=ilength) :: arg)
+                call get_command_argument(number=i,value=arg,length=ilength,status=istatus)
+                if(istatus /= 0) then
+                    write(stderr,'(*(g0,1x))')'<ERROR>*get_command_arguments_stack* error obtaining argument ',i
+                    exit
+                elseif(ilength>0)then
+                    if(index(arg//' ','-')/=1)then
+                        args=args//quote//arg//quote//' '
+                    elseif(index(arg,' ')/=0)then
+                        args=args//quote//arg//quote//' '
+                    else
+                        args=args//arg//' '
+                    endif
+                else
+                    args=args//repeat(quote,2)//' '
+                endif
+             endif
+         enddo
+    end function get_command_arguments_quoted
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/get_command_line_settings.html b/proc/get_command_line_settings.html new file mode 100644 index 0000000000..1c2cca63c3 --- /dev/null +++ b/proc/get_command_line_settings.html @@ -0,0 +1,853 @@ + + + + + + + + + + + + + get_command_line_settings – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

get_command_line_settings + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine get_command_line_settings(cmd_settings) +

+ + +

! canon_path is not converting “.”, etc. +& ‘ unknown help topic “’//trim(unnamed(i)).’not found in:’,manual]

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(fpm_cmd_settings), + intent(out), + allocatable + ::cmd_settings + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
    subroutine get_command_line_settings(cmd_settings)
+        class(fpm_cmd_settings), allocatable, intent(out) :: cmd_settings
+
+        integer, parameter            :: widest = 256
+        character(len=4096)           :: cmdarg
+        integer                       :: i
+        integer                       :: os
+        type(fpm_install_settings), allocatable :: install_settings
+        type(fpm_publish_settings), allocatable :: publish_settings
+        type(fpm_export_settings) , allocatable :: export_settings
+        type(version_t) :: version
+        character(len=:), allocatable :: common_args, compiler_args, run_args, working_dir, &
+            & c_compiler, cxx_compiler, archiver, version_s, token_s, config_file
+
+        character(len=*), parameter :: fc_env = "FC", cc_env = "CC", ar_env = "AR", &
+            & fflags_env = "FFLAGS", cflags_env = "CFLAGS", cxxflags_env = "CXXFLAGS", ldflags_env = "LDFLAGS", &
+            & fc_default = "gfortran", cc_default = " ", ar_default = " ", flags_default = " ", &
+            & cxx_env = "CXX", cxx_default = " "
+        type(error_t), allocatable :: error
+
+        call set_help()
+        os = get_os_type()
+        ! text for --version switch,
+        select case (os)
+            case (OS_LINUX);   os_type =  "OS Type:     Linux"
+            case (OS_MACOS);   os_type =  "OS Type:     macOS"
+            case (OS_WINDOWS); os_type =  "OS Type:     Windows"
+            case (OS_CYGWIN);  os_type =  "OS Type:     Cygwin"
+            case (OS_SOLARIS); os_type =  "OS Type:     Solaris"
+            case (OS_FREEBSD); os_type =  "OS Type:     FreeBSD"
+            case (OS_OPENBSD); os_type =  "OS Type:     OpenBSD"
+            case (OS_UNKNOWN); os_type =  "OS Type:     Unknown"
+            case default     ; os_type =  "OS Type:     UNKNOWN"
+        end select
+
+        ! Get current release version
+        version = fpm_version()
+        version_s = version%s()
+
+        version_text = [character(len=80) :: &
+         &  'Version:     '//trim(version_s)//', alpha',               &
+         &  'Program:     fpm(1)',                                     &
+         &  'Description: A Fortran package manager and build system', &
+         &  'Home Page:   https://github.com/fortran-lang/fpm',        &
+         &  'License:     MIT',                                        &
+         &  os_type]
+        ! find the subcommand name by looking for first word on command
+        ! not starting with dash
+        CLI_RESPONSE_FILE=.true.
+        cmdarg = get_subcommand()
+
+        common_args = &
+          ' --directory:C " "' // &
+          ' --verbose F'
+
+        run_args = &
+          ' --target " "' // &
+          ' --list F' // &
+          ' --runner " "' // &
+          ' --runner-args " "'
+
+        compiler_args = &
+          ' --profile " "' // &
+          ' --no-prune F' // &
+          ' --compiler "'//get_fpm_env(fc_env, fc_default)//'"' // &
+          ' --c-compiler "'//get_fpm_env(cc_env, cc_default)//'"' // &
+          ' --cxx-compiler "'//get_fpm_env(cxx_env, cxx_default)//'"' // &
+          ' --archiver "'//get_fpm_env(ar_env, ar_default)//'"' // &
+          ' --flag:: "'//get_fpm_env(fflags_env, flags_default)//'"' // &
+          ' --c-flag:: "'//get_fpm_env(cflags_env, flags_default)//'"' // &
+          ' --cxx-flag:: "'//get_fpm_env(cxxflags_env, flags_default)//'"' // &
+          ' --link-flag:: "'//get_fpm_env(ldflags_env, flags_default)//'"'
+
+        ! now set subcommand-specific help text and process commandline
+        ! arguments. Then call subcommand routine
+        select case(trim(cmdarg))
+
+        case('run')
+            call set_args(common_args // compiler_args // run_args //'&
+            & --all F &
+            & --example F &
+            & --config-file " " &
+            & --',help_run,version_text)
+
+            call check_build_vals()
+
+            if( size(unnamed) > 1 )then
+                names=unnamed(2:)
+            else
+                names=[character(len=len(names)) :: ]
+            endif
+
+            if(specified('target') )then
+               call split(sget('target'),tnames,delimiters=' ,:')
+               names=[character(len=max(len(names),len(tnames))) :: names,tnames]
+            endif
+
+            ! convert --all to '*'
+            if(lget('all'))then
+               names=[character(len=max(len(names),1)) :: names,'*' ]
+            endif
+
+            ! convert special string '..' to equivalent (shorter) '*'
+            ! to allow for a string that does not require shift-key and quoting
+            do i=1,size(names)
+               if(names(i)=='..')names(i)='*'
+            enddo
+
+            ! If there are additional command-line arguments, remove the additional
+            ! double quotes which have been added by M_CLI2
+            val_runner_args=sget('runner-args')
+            call remove_characters_in_set(val_runner_args,set='"')
+
+            c_compiler = sget('c-compiler')
+            cxx_compiler = sget('cxx-compiler')
+            archiver = sget('archiver')
+            config_file = sget('config-file')
+            allocate(fpm_run_settings :: cmd_settings)
+            val_runner=sget('runner')
+            if(specified('runner') .and. val_runner=='')val_runner='echo'
+
+            cmd_settings=fpm_run_settings(&
+            & args=remaining,&
+            & profile=val_profile,&
+            & prune=.not.lget('no-prune'), &
+            & compiler=val_compiler, &
+            & c_compiler=c_compiler, &
+            & cxx_compiler=cxx_compiler, &
+            & archiver=archiver, &
+            & path_to_config=config_file, &
+            & flag=val_flag, &
+            & cflag=val_cflag, &
+            & cxxflag=val_cxxflag, &
+            & ldflag=val_ldflag, &
+            & example=lget('example'), &
+            & list=lget('list'),&
+            & build_tests=.false.,&
+            & name=names,&
+            & runner=val_runner,&
+            & runner_args=val_runner_args, &
+            & verbose=lget('verbose') )
+
+        case('build')
+            call set_args(common_args // compiler_args //'&
+            & --list F &
+            & --show-model F &
+            & --dump " " &
+            & --tests F &
+            & --config-file " " &
+            & --',help_build,version_text)
+
+            call check_build_vals()
+
+            c_compiler = sget('c-compiler')
+            cxx_compiler = sget('cxx-compiler')
+            archiver = sget('archiver')
+            config_file = sget('config-file')
+            val_dump = sget('dump')
+            if (specified('dump') .and. val_dump=='')val_dump='fpm_model.toml'
+
+            allocate( fpm_build_settings :: cmd_settings )
+            cmd_settings=fpm_build_settings(  &
+            & profile=val_profile,&
+            & dump=val_dump,&
+            & prune=.not.lget('no-prune'), &
+            & compiler=val_compiler, &
+            & c_compiler=c_compiler, &
+            & cxx_compiler=cxx_compiler, &
+            & archiver=archiver, &
+            & path_to_config=config_file, &
+            & flag=val_flag, &
+            & cflag=val_cflag, &
+            & cxxflag=val_cxxflag, &
+            & ldflag=val_ldflag, &
+            & list=lget('list'),&
+            & show_model=lget('show-model'),&
+            & build_tests=lget('tests'),&
+            & verbose=lget('verbose') )
+
+        case('new')
+            call set_args(common_args // '&
+            & --src F &
+            & --lib F &
+            & --app F &
+            & --test F &
+            & --example F &
+            & --backfill F &
+            & --full F &
+            & --bare F &
+            &', help_new, version_text)
+            select case(size(unnamed))
+            case(1)
+                if(lget('backfill'))then
+                   name='.'
+                else
+                   write(stderr,'(*(7x,g0,/))') &
+                   & '<USAGE> fpm new NAME [[--lib|--src] [--app] [--test] [--example]]|[--full|--bare] [--backfill]'
+                   call fpm_stop(1,'directory name required')
+                endif
+            case(2)
+                name=trim(unnamed(2))
+            case default
+                write(stderr,'(7x,g0)') &
+                & '<USAGE> fpm new NAME [[--lib|--src] [--app] [--test] [--example]]| [--full|--bare] [--backfill]'
+                call fpm_stop(2,'only one directory name allowed')
+            end select
+            !*! canon_path is not converting ".", etc.
+            if(name=='.')then
+               call get_current_directory(name, error)
+               if (allocated(error)) then
+                  write(stderr, '("[Error]", 1x, a)') error%message
+                  stop 1
+               endif
+            endif
+            name=canon_path(name)
+            if( .not.is_fortran_name(to_fortran_name(basename(name))) )then
+                write(stderr,'(g0)') [ character(len=72) :: &
+                & '<ERROR> the fpm project name must be made of up to 63 ASCII letters,', &
+                & '        numbers, underscores, or hyphens, and start with a letter.']
+                call fpm_stop(4,' ')
+            endif
+
+            allocate(fpm_new_settings :: cmd_settings)
+            if (any( specified([character(len=10) :: 'src','lib','app','test','example','bare'])) &
+            & .and.lget('full') )then
+                write(stderr,'(*(a))')&
+                &'<ERROR> --full and any of [--src|--lib,--app,--test,--example,--bare]', &
+                &'        are mutually exclusive.'
+                call fpm_stop(5,' ')
+            elseif (any( specified([character(len=10) :: 'src','lib','app','test','example','full'])) &
+            & .and.lget('bare') )then
+                write(stderr,'(*(a))')&
+                &'<ERROR> --bare and any of [--src|--lib,--app,--test,--example,--full]', &
+                &'        are mutually exclusive.'
+                call fpm_stop(3,' ')
+            elseif (any( specified([character(len=10) :: 'src','lib','app','test','example']) ) )then
+                cmd_settings=fpm_new_settings(&
+                 & backfill=lget('backfill'),               &
+                 & name=name,                               &
+                 & with_executable=lget('app'),             &
+                 & with_lib=any([lget('lib'),lget('src')]), &
+                 & with_test=lget('test'),                  &
+                 & with_example=lget('example'),            &
+                 & verbose=lget('verbose') )
+            else  ! default if no specific directories are requested
+                cmd_settings=fpm_new_settings(&
+                 & backfill=lget('backfill') ,           &
+                 & name=name,                            &
+                 & with_executable=.true.,               &
+                 & with_lib=.true.,                      &
+                 & with_test=.true.,                     &
+                 & with_example=lget('full'),            &
+                 & with_full=lget('full'),               &
+                 & with_bare=lget('bare'),               &
+                 & verbose=lget('verbose') )
+            endif
+
+        case('help', 'manual')
+            call set_args(common_args, help_help,version_text)
+            if(size(unnamed)<2)then
+                if(unnamed(1)=='help')then
+                   unnamed=['   ', 'fpm']
+                else
+                   unnamed=manual
+                endif
+            elseif(unnamed(2)=='manual')then
+                unnamed=manual
+            endif
+            allocate(character(len=widest) :: help_text(0))
+            do i=2,size(unnamed)
+                select case(unnamed(i))
+                case('       ' )
+                case('fpm    ' )
+                   help_text=[character(len=widest) :: help_text, help_fpm]
+                case('new    ' )
+                   help_text=[character(len=widest) :: help_text, help_new]
+                case('build  ' )
+                   help_text=[character(len=widest) :: help_text, help_build]
+                case('install' )
+                   help_text=[character(len=widest) :: help_text, help_install]
+                case('run    ' )
+                   help_text=[character(len=widest) :: help_text, help_run]
+                case('test   ' )
+                   help_text=[character(len=widest) :: help_text, help_test]
+                case('runner' )
+                   help_text=[character(len=widest) :: help_text, help_runner]
+                case('list   ' )
+                   help_text=[character(len=widest) :: help_text, help_list]
+                case('update ' )
+                   help_text=[character(len=widest) :: help_text, help_update]
+                case('help   ' )
+                   help_text=[character(len=widest) :: help_text, help_help]
+                case('version' )
+                   help_text=[character(len=widest) :: help_text, version_text]
+                case('clean' )
+                   help_text=[character(len=widest) :: help_text, help_clean]
+                case('publish')
+                   help_text=[character(len=widest) :: help_text, help_publish]
+                case default
+                   help_text=[character(len=widest) :: help_text, &
+                   & '<ERROR> unknown help topic "'//trim(unnamed(i))//'"']
+                   !!& '<ERROR> unknown help topic "'//trim(unnamed(i)).'not found in:',manual]
+                end select
+            enddo
+            call printhelp(help_text)
+
+        case('install')
+            call set_args(common_args // compiler_args // '&
+                & --no-rebuild F &
+                & --prefix " " &
+                & --list F &
+                & --test F &
+                & --libdir "lib" &
+                & --bindir "bin" &
+                & --testdir "test" &
+                & --includedir "include" &
+                & --config-file " " &
+                &', help_install, version_text)
+
+            call check_build_vals()
+
+            c_compiler = sget('c-compiler')
+            cxx_compiler = sget('cxx-compiler')
+            archiver = sget('archiver')
+            config_file = sget('config-file')
+            allocate(install_settings, source=fpm_install_settings(&
+                list=lget('list'), &
+                build_tests=lget('test'), &
+                profile=val_profile,&
+                prune=.not.lget('no-prune'), &
+                compiler=val_compiler, &
+                c_compiler=c_compiler, &
+                cxx_compiler=cxx_compiler, &
+                archiver=archiver, &
+                path_to_config=config_file, &
+                flag=val_flag, &
+                cflag=val_cflag, &
+                cxxflag=val_cxxflag, &
+                ldflag=val_ldflag, &
+                no_rebuild=lget('no-rebuild'), &
+                verbose=lget('verbose')))
+            call get_char_arg(install_settings%prefix, 'prefix')
+            call get_char_arg(install_settings%libdir, 'libdir')
+            call get_char_arg(install_settings%testdir, 'testdir')
+            call get_char_arg(install_settings%bindir, 'bindir')
+            call get_char_arg(install_settings%includedir, 'includedir')
+            call move_alloc(install_settings, cmd_settings)
+
+        case('list')
+            call set_args(common_args // '&
+            & --list F &
+            &', help_list, version_text)
+            if(lget('list'))then
+                help_text = [character(widest) :: help_list_nodash, help_list_dash]
+            else
+                help_text = help_list_nodash
+            endif
+            call printhelp(help_text)
+
+        case('test')
+            call set_args(common_args // compiler_args // run_args // '&
+            & --config-file " " &
+            & -- ', help_test,version_text)
+
+            call check_build_vals()
+
+            if( size(unnamed) > 1 )then
+                names=unnamed(2:)
+            else
+                names=[character(len=len(names)) :: ]
+            endif
+
+            if(specified('target') )then
+               call split(sget('target'),tnames,delimiters=' ,:')
+               names=[character(len=max(len(names),len(tnames))) :: names,tnames]
+            endif
+
+            ! convert special string '..' to equivalent (shorter) '*'
+            ! to allow for a string that does not require shift-key and quoting
+            do i=1,size(names)
+               if(names(i)=='..')names(i)='*'
+            enddo
+
+            ! If there are additional command-line arguments, remove the additional
+            ! double quotes which have been added by M_CLI2
+            val_runner_args=sget('runner-args')
+            call remove_characters_in_set(val_runner_args,set='"')
+
+            c_compiler = sget('c-compiler')
+            cxx_compiler = sget('cxx-compiler')
+            archiver = sget('archiver')
+            config_file = sget('config-file')
+
+            allocate(fpm_test_settings :: cmd_settings)
+            val_runner=sget('runner')
+            if(specified('runner') .and. val_runner=='')val_runner='echo'
+
+            cmd_settings=fpm_test_settings(&
+            & args=remaining, &
+            & profile=val_profile, &
+            & prune=.not.lget('no-prune'), &
+            & compiler=val_compiler, &
+            & c_compiler=c_compiler, &
+            & cxx_compiler=cxx_compiler, &
+            & archiver=archiver, &
+            & path_to_config=config_file, &
+            & flag=val_flag, &
+            & cflag=val_cflag, &
+            & cxxflag=val_cxxflag, &
+            & ldflag=val_ldflag, &
+            & example=.false., &
+            & list=lget('list'), &
+            & build_tests=.true., &
+            & name=names, &
+            & runner=val_runner, &
+            & runner_args=val_runner_args, &
+            & verbose=lget('verbose'))
+
+        case('update')
+            call set_args(common_args // '&
+            & --fetch-only F &
+            & --clean F &
+            & --dump " " &
+            & --config-file " " &
+            &', help_update, version_text)
+
+            if( size(unnamed) > 1 )then
+                names=unnamed(2:)
+            else
+                names=[character(len=len(names)) :: ]
+            endif
+
+
+            config_file = sget('config-file')
+            val_dump = sget('dump')
+            if (specified('dump') .and. val_dump=='')val_dump='fpm_dependencies.toml'
+
+
+            allocate(fpm_update_settings :: cmd_settings)
+            cmd_settings=fpm_update_settings(name=names, &
+            & fetch_only=lget('fetch-only'), &
+            & dump=val_dump, &
+            & verbose=lget('verbose'), &
+            & path_to_config=config_file, &
+            & clean=lget('clean'))
+
+        case('export')
+
+            call set_args(common_args // compiler_args // '&
+                & --manifest "filename"  &
+                & --model "filename" &
+                & --dependencies "filename" ', &
+                help_build, version_text)
+
+            call check_build_vals()
+
+            c_compiler = sget('c-compiler')
+            cxx_compiler = sget('cxx-compiler')
+            archiver = sget('archiver')
+            allocate(export_settings, source=fpm_export_settings(&
+                profile=val_profile,&
+                prune=.not.lget('no-prune'), &
+                compiler=val_compiler, &
+                c_compiler=c_compiler, &
+                cxx_compiler=cxx_compiler, &
+                archiver=archiver, &
+                flag=val_flag, &
+                cflag=val_cflag, &
+                show_model=.true., &
+                cxxflag=val_cxxflag, &
+                ldflag=val_ldflag, &
+                verbose=lget('verbose')))
+            call get_char_arg(export_settings%dump_model, 'model')
+            call get_char_arg(export_settings%dump_manifest, 'manifest')
+            call get_char_arg(export_settings%dump_dependencies, 'dependencies')
+            call move_alloc(export_settings, cmd_settings)
+
+
+        case('clean')
+            call set_args(common_args // &
+            &   ' --registry-cache'   // &
+            &   ' --skip'             // &
+            &   ' --all'              // &
+            &   ' --config-file ""', help_clean, version_text)
+
+            block
+                logical :: skip, clean_all
+
+                skip = lget('skip')
+                clean_all = lget('all')
+                config_file = sget('config-file')
+
+                if (all([skip, clean_all])) then
+                    call fpm_stop(6, 'Do not specify both --skip and --all options on the clean subcommand.')
+                end if
+
+                allocate(fpm_clean_settings :: cmd_settings)
+                call get_current_directory(working_dir, error)
+                cmd_settings = fpm_clean_settings( &
+                &   working_dir=working_dir, &
+                &   clean_skip=skip, &
+                &   registry_cache=lget('registry-cache'), &
+                &   clean_all=clean_all, &
+                &   path_to_config=config_file)
+            end block
+
+        case('publish')
+            call set_args(common_args // compiler_args //'&
+            & --show-package-version F &
+            & --show-upload-data F &
+            & --dry-run F &
+            & --token " " &
+            & --list F &
+            & --show-model F &
+            & --tests F &
+            & --config-file " " &
+            & --', help_publish, version_text)
+
+            call check_build_vals()
+
+            c_compiler = sget('c-compiler')
+            cxx_compiler = sget('cxx-compiler')
+            archiver = sget('archiver')
+            config_file = sget('config-file')
+            token_s = sget('token')
+
+            allocate(fpm_publish_settings :: cmd_settings)
+            cmd_settings = fpm_publish_settings( &
+            & show_package_version = lget('show-package-version'), &
+            & show_upload_data = lget('show-upload-data'), &
+            & is_dry_run = lget('dry-run'), &
+            & profile=val_profile,&
+            & prune=.not.lget('no-prune'), &
+            & compiler=val_compiler, &
+            & c_compiler=c_compiler, &
+            & cxx_compiler=cxx_compiler, &
+            & archiver=archiver, &
+            & flag=val_flag, &
+            & cflag=val_cflag, &
+            & cxxflag=val_cxxflag, &
+            & ldflag=val_ldflag, &
+            & list=lget('list'),&
+            & show_model=lget('show-model'),&
+            & build_tests=lget('tests'),&
+            & path_to_config=config_file, &
+            & verbose=lget('verbose'),&
+            & token=token_s)
+
+        case default
+
+            if(cmdarg.ne.''.and.which('fpm-'//cmdarg).ne.'')then
+                call run('fpm-'//trim(cmdarg)//' '// get_command_arguments_quoted(),.false.)
+                stop
+            else
+                call set_args('&
+                & --list F&
+                &', help_fpm, version_text)
+                ! Note: will not get here if --version or --usage or --help
+                ! is present on commandline
+                if(lget('list'))then
+                    help_text = help_list_dash
+                elseif(len_trim(cmdarg)==0)then
+                    write(stdout,'(*(a))')'Fortran Package Manager:'
+                    write(stdout,'(*(a))')' '
+                    help_text = [character(widest) :: help_list_nodash, help_usage]
+                else
+                    write(stderr,'(*(a))')'<ERROR> unknown subcommand [', &
+                     & trim(cmdarg), ']'
+                    help_text = [character(widest) :: help_list_dash, help_usage]
+                endif
+                call printhelp(help_text)
+            endif
+
+        end select
+
+        if (allocated(cmd_settings)) then
+            working_dir = sget("directory")
+            call move_alloc(working_dir, cmd_settings%working_dir)
+        end if
+
+    contains
+
+    subroutine check_build_vals()
+        val_compiler=sget('compiler')
+        if(val_compiler=='') val_compiler='gfortran'
+
+        val_flag = " " // sget('flag')
+        val_cflag = " " // sget('c-flag')
+        val_cxxflag = " " // sget('cxx-flag')
+        val_ldflag = " " // sget('link-flag')
+        val_profile = sget('profile')
+
+    end subroutine check_build_vals
+
+    !> Print help text and stop
+    subroutine printhelp(lines)
+    character(len=:),intent(in),allocatable :: lines(:)
+    integer :: iii,ii
+        if(allocated(lines))then
+           ii=size(lines)
+           if(ii > 0 .and. len(lines)> 0) then
+               write(stdout,'(g0)')(trim(lines(iii)), iii=1, ii)
+           else
+               write(stdout,'(a)')'<WARNING> *printhelp* output requested is empty'
+           endif
+        endif
+        stop
+    end subroutine printhelp
+
+    end subroutine get_command_line_settings
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/get_compiler_id.html b/proc/get_compiler_id.html new file mode 100644 index 0000000000..4ae1e4e2ac --- /dev/null +++ b/proc/get_compiler_id.html @@ -0,0 +1,417 @@ + + + + + + + + + + + + + get_compiler_id – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

get_compiler_id + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function get_compiler_id(compiler) result(id) +

+ + + + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::compiler + +
+ +

Return Value + + + integer(kind=compiler_enum) + +

+ +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=:), + public, + allocatable + ::command + +
+ + character(len=:), + public, + allocatable + ::full_command + +
+ + character(len=:), + public, + allocatable + ::full_command_parts(:) + +
+ + integer, + public + + ::io + +
+ + character(len=:), + public, + allocatable + ::output + +
+ + integer, + public + + ::stat + +
+ +
+
+ + + + + + + + + +
+

Source Code

+
function get_compiler_id(compiler) result(id)
+    character(len=*), intent(in) :: compiler
+    integer(kind=compiler_enum) :: id
+
+    character(len=:), allocatable :: full_command, full_command_parts(:), command, output
+    integer :: stat, io
+
+    ! Check whether we are dealing with an MPI compiler wrapper first
+    if (check_compiler(compiler, "mpifort") &
+        & .or. check_compiler(compiler, "mpif90") &
+        & .or. check_compiler(compiler, "mpif77")) then
+        output = get_temp_filename()
+        call run(compiler//" -show > "//output//" 2>&1", &
+            & echo=.false., exitstat=stat)
+        if (stat == 0) then
+            open(file=output, newunit=io, iostat=stat)
+            if (stat == 0) call getline(io, full_command, stat)
+            close(io, iostat=stat)
+
+            ! If we get a command from the wrapper, we will try to identify it
+            call split(full_command, full_command_parts, delimiters=' ')
+            if(size(full_command_parts) > 0)then
+               command = trim(full_command_parts(1))
+            endif
+            if (allocated(command)) then
+                id = get_id(command)
+                if (id /= id_unknown) return
+            end if
+        end if
+    end if
+
+    id = get_id(compiler)
+
+end function get_compiler_id
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/get_current_directory.html b/proc/get_current_directory.html new file mode 100644 index 0000000000..535a3acbba --- /dev/null +++ b/proc/get_current_directory.html @@ -0,0 +1,273 @@ + + + + + + + + + + + + + get_current_directory – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

get_current_directory + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine get_current_directory(path, error) +

+ + + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=:), + intent(out), + allocatable + ::path + +
+ + type(error_t), + intent(out), + allocatable + ::error + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
    subroutine get_current_directory(path, error)
+        character(len=:), allocatable, intent(out) :: path
+        type(error_t), allocatable, intent(out) :: error
+
+        character(kind=c_char, len=1), allocatable :: cpath(:)
+        type(c_ptr) :: tmp
+
+        allocate (cpath(buffersize))
+
+        tmp = getcwd_(cpath, buffersize)
+        if (c_associated(tmp)) then
+            call c_f_character(cpath, path)
+        else
+            call fatal_error(error, "Failed to retrieve current directory")
+        end if
+
+    end subroutine get_current_directory
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/get_debug_compile_flags.html b/proc/get_debug_compile_flags.html new file mode 100644 index 0000000000..74f1c6d564 --- /dev/null +++ b/proc/get_debug_compile_flags.html @@ -0,0 +1,350 @@ + + + + + + + + + + + + + get_debug_compile_flags – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

get_debug_compile_flags + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine get_debug_compile_flags(id, flags) +

+ + + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + integer(kind=compiler_enum), + intent(in) + + ::id + +
+ + character(len=:), + intent(out), + allocatable + ::flags + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
subroutine get_debug_compile_flags(id, flags)
+    integer(compiler_enum), intent(in) :: id
+    character(len=:), allocatable, intent(out) :: flags
+
+    select case(id)
+    case default
+        flags = ""
+    case(id_caf)
+        flags = &
+            flag_gnu_warn//&
+            flag_gnu_pic//&
+            flag_gnu_limit//&
+            flag_gnu_debug//&
+            flag_gnu_check//&
+            flag_gnu_backtrace
+    case(id_gcc)
+        flags = &
+            flag_gnu_warn//&
+            flag_gnu_pic//&
+            flag_gnu_limit//&
+            flag_gnu_debug//&
+            flag_gnu_check//&
+            flag_gnu_backtrace//&
+            flag_gnu_coarray
+    case(id_f95)
+        flags = &
+            flag_gnu_warn//&
+            flag_gnu_pic//&
+            flag_gnu_limit//&
+            flag_gnu_debug//&
+            flag_gnu_check//&
+            ' -Wno-maybe-uninitialized -Wno-uninitialized'//&
+            flag_gnu_backtrace
+    case(id_nvhpc)
+        flags = &
+            flag_pgi_warn//&
+            flag_pgi_backslash//&
+            flag_pgi_check//&
+            flag_pgi_traceback
+    case(id_ibmxl)
+        flags = &
+            flag_ibmxl_backslash
+    case(id_intel_classic_nix)
+        flags = &
+            flag_intel_warn//&
+            flag_intel_check//&
+            flag_intel_limit//&
+            flag_intel_debug//&
+            flag_intel_byterecl//&
+            flag_intel_backtrace
+
+    case(id_intel_classic_mac)
+        flags = &
+            flag_intel_warn//&
+            flag_intel_check//&
+            flag_intel_limit//&
+            flag_intel_debug//&
+            flag_intel_byterecl//&
+            flag_intel_backtrace
+    case(id_intel_classic_windows)
+        flags = &
+            flag_intel_warn_win//&
+            flag_intel_check_win//&
+            flag_intel_limit_win//&
+            flag_intel_debug_win//&
+            flag_intel_byterecl_win//&
+            flag_intel_backtrace_win
+    case(id_intel_llvm_nix)
+        flags = &
+            flag_intel_unknown_cmd_err//&
+            flag_intel_llvm_check//&
+            flag_intel_limit//&
+            flag_intel_debug//&
+            flag_intel_byterecl//&
+            flag_intel_backtrace
+    case(id_intel_llvm_windows)
+        flags = &
+            flag_intel_unknown_cmd_err_win//&
+            flag_intel_check_win//&
+            flag_intel_limit_win//&
+            flag_intel_debug_win//&
+            flag_intel_byterecl_win
+    case(id_nag)
+        flags = &
+            flag_nag_debug//&
+            flag_nag_check//&
+            flag_nag_backtrace//&
+            flag_nag_coarray//&
+            flag_nag_pic
+
+    case(id_lfortran)
+        flags = ""
+    end select
+end subroutine get_debug_compile_flags
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/get_default_c_compiler.html b/proc/get_default_c_compiler.html new file mode 100644 index 0000000000..b60e315b2c --- /dev/null +++ b/proc/get_default_c_compiler.html @@ -0,0 +1,334 @@ + + + + + + + + + + + + + get_default_c_compiler – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

get_default_c_compiler + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine get_default_c_compiler(f_compiler, c_compiler) +

+ + + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::f_compiler + +
+ + character(len=:), + intent(out), + allocatable + ::c_compiler + +
+ +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + integer(kind=compiler_enum), + public + + ::id + +
+ +
+
+ + + + + + + + + +
+

Source Code

+
subroutine get_default_c_compiler(f_compiler, c_compiler)
+    character(len=*), intent(in) :: f_compiler
+    character(len=:), allocatable, intent(out) :: c_compiler
+    integer(compiler_enum) :: id
+
+    id = get_compiler_id(f_compiler)
+
+    select case(id)
+
+    case(id_intel_classic_nix, id_intel_classic_mac, id_intel_classic_windows)
+        c_compiler = 'icc'
+
+    case(id_intel_llvm_nix,id_intel_llvm_windows)
+        c_compiler = 'icx'
+
+    case(id_flang, id_flang_new, id_f18)
+        c_compiler='clang'
+
+    case(id_ibmxl)
+        c_compiler='xlc'
+
+    case(id_lfortran)
+        c_compiler = 'cc'
+
+    case(id_gcc)
+        c_compiler = 'gcc'
+
+    case default
+        ! Fall-back to using Fortran compiler
+        c_compiler = f_compiler
+    end select
+
+end subroutine get_default_c_compiler
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/get_default_cxx_compiler.html b/proc/get_default_cxx_compiler.html new file mode 100644 index 0000000000..6401851b59 --- /dev/null +++ b/proc/get_default_cxx_compiler.html @@ -0,0 +1,335 @@ + + + + + + + + + + + + + get_default_cxx_compiler – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

get_default_cxx_compiler + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine get_default_cxx_compiler(f_compiler, cxx_compiler) +

+ + +

Get C++ Compiler.

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::f_compiler + +
+ + character(len=:), + intent(out), + allocatable + ::cxx_compiler + +
+ +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + integer(kind=compiler_enum), + public + + ::id + +
+ +
+
+ + + + + + + + + +
+

Source Code

+
subroutine get_default_cxx_compiler(f_compiler, cxx_compiler)
+    character(len=*), intent(in) :: f_compiler
+    character(len=:), allocatable, intent(out) :: cxx_compiler
+    integer(compiler_enum) :: id
+
+    id = get_compiler_id(f_compiler)
+
+    select case(id)
+
+    case(id_intel_classic_nix, id_intel_classic_mac, id_intel_classic_windows)
+        cxx_compiler = 'icpc'
+
+    case(id_intel_llvm_nix,id_intel_llvm_windows)
+        cxx_compiler = 'icpx'
+
+    case(id_flang, id_flang_new, id_f18)
+        cxx_compiler='clang++'
+
+    case(id_ibmxl)
+        cxx_compiler='xlc++'
+
+    case(id_lfortran)
+        cxx_compiler = 'cc'
+
+    case(id_gcc)
+        cxx_compiler = 'g++'
+
+    case default
+        ! Fall-back to using Fortran compiler
+        cxx_compiler = f_compiler
+    end select
+
+end subroutine get_default_cxx_compiler
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/get_default_flags.html b/proc/get_default_flags.html new file mode 100644 index 0000000000..cbaa6475f5 --- /dev/null +++ b/proc/get_default_flags.html @@ -0,0 +1,339 @@ + + + + + + + + + + + + + get_default_flags – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

get_default_flags + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function get_default_flags(self, release) result(flags) +

+ + + +

Type Bound

+

compiler_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::self + +
+ + logical, + intent(in) + + ::release + +
+ +

Return Value + + + character(len=:), allocatable + +

+ +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=:), + public, + allocatable + ::pic_flag + +
+ +
+
+ + + + + + + + + +
+

Source Code

+
function get_default_flags(self, release) result(flags)
+    class(compiler_t), intent(in) :: self
+    logical, intent(in) :: release
+    character(len=:), allocatable :: flags
+
+    character(len=:), allocatable :: pic_flag
+
+    if (release) then
+        call get_release_compile_flags(self%id, flags)
+    else
+        call get_debug_compile_flags(self%id, flags)
+    end if
+
+    ! Append position-independent code (PIC) flag, that is necessary 
+    ! building shared libraries
+    select case (self%id)
+    case (id_gcc, id_f95, id_caf, id_flang, id_flang_new, id_f18, id_lfortran, &
+          id_intel_classic_nix, id_intel_classic_mac, id_intel_llvm_nix, &
+          id_pgi, id_nvhpc, id_nag, id_cray, id_ibmxl)
+        pic_flag = " -fPIC"
+    case (id_intel_classic_windows, id_intel_llvm_windows)
+        pic_flag = ""  ! Windows does not use -fPIC
+    case default
+        pic_flag = " -fPIC"  ! Conservative fallback
+    end select
+
+    flags = flags // pic_flag
+
+end function get_default_flags
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/get_default_profiles.html b/proc/get_default_profiles.html new file mode 100644 index 0000000000..ecbb83460c --- /dev/null +++ b/proc/get_default_profiles.html @@ -0,0 +1,367 @@ + + + + + + + + + + + + + get_default_profiles – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

get_default_profiles + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function get_default_profiles(error) result(default_profiles) +

+ + +

Construct an array of built-in profiles

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ +

Return Value + + + type(profile_config_t), allocatable, (:) + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
      function get_default_profiles(error) result(default_profiles)
+
+        !> Error handling
+        type(error_t), allocatable, intent(out) :: error
+
+        type(profile_config_t), allocatable :: default_profiles(:)
+
+        default_profiles = [ &
+              & new_profile('release', &
+                & 'caf', &
+                & OS_ALL, &
+                & flags=' -O3 -Wimplicit-interface -fPIC -fmax-errors=1 -funroll-loops', &
+                & is_built_in=.true.), &
+              & new_profile('release', &
+                & 'gfortran', &
+                & OS_ALL, &
+                & flags=' -O3 -Wimplicit-interface -fPIC -fmax-errors=1 -funroll-loops -fcoarray=single', &
+                & is_built_in=.true.), &
+              & new_profile('release', &
+                & 'f95', &
+                & OS_ALL, &
+                & flags=' -O3 -Wimplicit-interface -fPIC -fmax-errors=1 -ffast-math -funroll-loops', &
+                & is_built_in=.true.), &
+              & new_profile('release', &
+                & 'nvfortran', &
+                & OS_ALL, &
+                & flags = ' -Mbackslash', &
+                & is_built_in=.true.), &
+              & new_profile('release', &
+                & 'ifort', &
+                & OS_ALL, &
+                & flags = ' -fp-model precise -pc64 -align all -error-limit 1 -reentrancy&
+                          & threaded -nogen-interfaces -assume byterecl', &
+                & is_built_in=.true.), &
+              & new_profile('release', &
+                & 'ifort', &
+                & OS_WINDOWS, &
+                & flags = ' /fp:precise /align:all /error-limit:1 /reentrancy:threaded&
+                          & /nogen-interfaces /assume:byterecl', &
+                & is_built_in=.true.), &
+              & new_profile('release', &
+                & 'ifx', &
+                & OS_ALL, &
+                & flags = ' -fp-model=precise -pc64 -align all -error-limit 1 -reentrancy&
+                          & threaded -nogen-interfaces -assume byterecl', &
+                & is_built_in=.true.), &
+              & new_profile('release', &
+                & 'ifx', &
+                & OS_WINDOWS, &
+                & flags = ' /fp:precise /align:all /error-limit:1 /reentrancy:threaded&
+                          & /nogen-interfaces /assume:byterecl', &
+                & is_built_in=.true.), &
+              & new_profile('release', &
+                &'nagfor', &
+                & OS_ALL, &
+                & flags = ' -O4 -coarray=single -PIC', &
+                & is_built_in=.true.), &
+              & new_profile('release', &
+                &'lfortran', &
+                & OS_ALL, &
+                & flags = ' flag_lfortran_opt', &
+                & is_built_in=.true.), &
+              & new_profile('debug', &
+                & 'caf', &
+                & OS_ALL, &
+                & flags = ' -Wall -Wextra -Wimplicit-interface -fPIC -fmax-errors=1 -g -fcheck=bounds&
+                          & -fcheck=array-temps -fbacktrace', &
+                & is_built_in=.true.), &
+              & new_profile('debug', &
+                & 'gfortran', &
+                & OS_ALL, &
+                & flags = ' -Wall -Wextra -Wimplicit-interface -fPIC -fmax-errors=1 -g -fcheck=bounds&
+                          & -fcheck=array-temps -fbacktrace -fcoarray=single', &
+                & is_built_in=.true.), &
+              & new_profile('debug', &
+                & 'f95', &
+                & OS_ALL, &
+                & flags = ' -Wall -Wextra -Wimplicit-interface -fPIC -fmax-errors=1 -g -fcheck=bounds&
+                          & -fcheck=array-temps -Wno-maybe-uninitialized -Wno-uninitialized -fbacktrace', &
+                & is_built_in=.true.), &
+              & new_profile('debug', &
+                & 'nvfortran', &
+                & OS_ALL, &
+                & flags = ' -Minform=inform -Mbackslash -g -Mbounds -Mchkptr -Mchkstk -traceback', &
+                & is_built_in=.true.), &
+              & new_profile('debug', &
+                & 'ifort', &
+                & OS_ALL, &
+                & flags = ' -warn all -check all -error-limit 1 -O0 -g -assume byterecl -traceback', &
+                & is_built_in=.true.), &
+              & new_profile('debug', &
+                & 'ifort', &
+                & OS_WINDOWS, &
+                & flags = ' /warn:all /check:all /error-limit:1&
+                          & /Od /Z7 /assume:byterecl /traceback', &
+                & is_built_in=.true.), &
+              & new_profile('debug', &
+                & 'ifx', &
+                & OS_ALL, &
+                & flags = ' -warn all -check all -error-limit 1 -O0 -g -assume byterecl -traceback', &
+                & is_built_in=.true.), &
+              & new_profile('debug', &
+                & 'ifx', &
+                & OS_WINDOWS, &
+                & flags = ' /warn:all /check:all /error-limit:1 /Od /Z7 /assume:byterecl', &
+                & is_built_in=.true.), &
+              & new_profile('debug', &
+                & 'ifx', &
+                & OS_WINDOWS, &
+                & flags = ' /warn:all /check:all /error-limit:1 /Od /Z7 /assume:byterecl', &
+                & is_built_in=.true.), &
+              & new_profile('debug', &
+                & 'lfortran', &
+                & OS_ALL, &
+                & flags = '', &
+                & is_built_in=.true.) &
+              &]
+      end function get_default_profiles
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/get_dos_path.html b/proc/get_dos_path.html new file mode 100644 index 0000000000..bf3600d53f --- /dev/null +++ b/proc/get_dos_path.html @@ -0,0 +1,328 @@ + + + + + + + + + + + + + get_dos_path – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

get_dos_path + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function get_dos_path(path, error) +

+ + +

Ensure a windows path is converted to an 8.3 DOS path if it contains spaces +No need to convert if there are no spaces

+

Read screen output

+

Ensure there are no trailing slashes

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::path + +
+ + type(error_t), + intent(out), + allocatable + ::error + +
+ +

Return Value + + + character(len=:), allocatable + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
    function get_dos_path(path,error)
+        character(len=*), intent(in) :: path
+        type(error_t), allocatable, intent(out) :: error
+        character(len=:), allocatable :: get_dos_path
+
+        character(:), allocatable :: redirect,screen_output,line
+        integer :: stat,cmdstat,iunit,last
+
+        ! Non-Windows OS
+        if (get_os_type()/=OS_WINDOWS) then
+            get_dos_path = path
+            return
+        end if
+
+        ! Trim path first
+        get_dos_path = trim(path)
+
+        !> No need to convert if there are no spaces
+        has_spaces: if (scan(get_dos_path,' ')>0) then
+
+            redirect = get_temp_filename()
+            call execute_command_line('cmd /c for %A in ("'//path//'") do @echo %~sA >'//redirect//' 2>&1',&
+                                      exitstat=stat,cmdstat=cmdstat)
+
+            !> Read screen output
+            command_OK: if (cmdstat==0 .and. stat==0) then
+
+                allocate(character(len=0) :: screen_output)
+                open(newunit=iunit,file=redirect,status='old',iostat=stat)
+                if (stat == 0)then
+
+                   do
+                       call getline(iunit, line, stat)
+                       if (stat /= 0) exit
+                       screen_output = screen_output//line//' '
+                   end do
+
+                   ! Close and delete file
+                   close(iunit,status='delete')
+
+                else
+                   call fatal_error(error,'cannot read temporary file from successful DOS path evaluation')
+                   return
+                endif
+
+            else command_OK
+
+                call fatal_error(error,'unsuccessful Windows->DOS path command')
+                return
+
+            end if command_OK
+
+            get_dos_path = trim(adjustl(screen_output))
+
+        endif has_spaces
+
+        !> Ensure there are no trailing slashes
+        last = len_trim(get_dos_path)
+        if (last>1 .and. get_dos_path(last:last)=='/' .or. get_dos_path(last:last)=='\') get_dos_path = get_dos_path(1:last-1)
+
+    end function get_dos_path
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/get_env.html b/proc/get_env.html new file mode 100644 index 0000000000..465165aa80 --- /dev/null +++ b/proc/get_env.html @@ -0,0 +1,301 @@ + + + + + + + + + + + + + get_env – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

get_env + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function get_env(NAME, DEFAULT) result(VALUE) +

+ + +

get named environment variable value. It it is blank or + not set return the optional default value +!print , NAME, ” is not defined in the environment. Strange…” +!print , “This processor doesn’t support environment variables. Boooh!”

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::NAME +

name of environment variable to get the value of

+
+ + character(len=*), + intent(in),optional + + ::DEFAULT +

default value to return if the requested value is undefined or blank

+
+ +

Return Value + + + character(len=:), allocatable + +

+

the returned value

+
+ + + + + + + + + + + +
+

Source Code

+
    function get_env(NAME,DEFAULT) result(VALUE)
+    implicit none
+    !> name of environment variable to get the value of
+    character(len=*),intent(in)          :: NAME
+    !> default value to return if the requested value is undefined or blank
+    character(len=*),intent(in),optional :: DEFAULT
+    !> the returned value
+    character(len=:),allocatable         :: VALUE
+    integer                              :: howbig
+    integer                              :: stat
+    integer                              :: length
+        ! get length required to hold value
+        length=0
+        if(NAME/='')then
+           call get_environment_variable(NAME, length=howbig,status=stat,trim_name=.true.)
+           select case (stat)
+           case (1)
+               !*!print *, NAME, " is not defined in the environment. Strange..."
+               VALUE=''
+           case (2)
+               !*!print *, "This processor doesn't support environment variables. Boooh!"
+               VALUE=''
+           case default
+               ! make string to hold value of sufficient size
+               allocate(character(len=max(howbig,1)) :: VALUE)
+               ! get value
+               call get_environment_variable(NAME,VALUE,status=stat,trim_name=.true.)
+               if(stat/=0)VALUE=''
+           end select
+        else
+           VALUE=''
+        endif
+        if(VALUE==''.and.present(DEFAULT))VALUE=DEFAULT
+     end function get_env
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/get_exe_name_with_suffix.html b/proc/get_exe_name_with_suffix.html new file mode 100644 index 0000000000..c0904b7cd8 --- /dev/null +++ b/proc/get_exe_name_with_suffix.html @@ -0,0 +1,264 @@ + + + + + + + + + + + + + get_exe_name_with_suffix – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

get_exe_name_with_suffix + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function get_exe_name_with_suffix(source) result(suffixed) +

+ + +

Build an executable name with suffix. Safe routine that always returns an allocated string

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(srcfile_t), + intent(in) + + ::source + +
+ +

Return Value + + + character(len=:), allocatable + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
function get_exe_name_with_suffix(source) result(suffixed)
+    type(srcfile_t), intent(in) :: source
+    character(len=:), allocatable :: suffixed
+
+    if (allocated(source%exe_name)) then
+       if (get_os_type() == OS_WINDOWS) then
+           suffixed = source%exe_name//'.exe'
+       else
+           suffixed = source%exe_name
+       end if
+    else
+       suffixed = ""
+    endif
+
+end function get_exe_name_with_suffix
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/get_export_flags.html b/proc/get_export_flags.html new file mode 100644 index 0000000000..de892372dd --- /dev/null +++ b/proc/get_export_flags.html @@ -0,0 +1,384 @@ + + + + + + + + + + + + + get_export_flags – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

get_export_flags + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function get_export_flags(self, target_dir, target_name) result(export_flags) +

+ + +

Generate library export flags for a shared library build

+ +

Type Bound

+

compiler_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::self +

Instance of the compiler

+
+ + character(len=*), + intent(in) + + ::target_dir +

Path and package name

+
+ + character(len=*), + intent(in) + + ::target_name +

Path and package name

+
+ +

Return Value + + + character(len=:), allocatable + +

+ +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=:), + public, + allocatable + ::def_path + +
+ + character(len=:), + public, + allocatable + ::implib_path + +
+ +
+
+ + + + + + + + + +
+

Source Code

+
function get_export_flags(self, target_dir, target_name) result(export_flags)
+    !> Instance of the compiler
+    class(compiler_t), intent(in) :: self
+    !> Path and package name
+    character(len=*), intent(in) :: target_dir, target_name
+    character(len=:), allocatable :: export_flags
+
+    character(len=:), allocatable :: implib_path, def_path
+
+    ! Only apply on Windows
+    if (get_os_type() /= OS_WINDOWS) then
+        export_flags = ""
+        return
+    end if
+
+    select case (self%id)
+
+    case (id_gcc, id_caf, id_f95)
+        ! GNU-based: emit both import library and def file
+        implib_path = quote(join_path(target_dir, target_name // ".dll.a") , for_cmd=.true.)
+        def_path    = quote(join_path(target_dir, target_name // ".def" ) , for_cmd=.true.)
+
+        export_flags = " -Wl,--out-implib," // implib_path // &
+                       " -Wl,--output-def," // def_path
+
+    case (id_intel_classic_windows, id_intel_llvm_windows)
+        ! Intel/MSVC-style
+        implib_path = quote(join_path(target_dir, target_name // ".lib") , for_cmd=.true.)
+        def_path    = quote(join_path(target_dir, target_name // ".def") , for_cmd=.true.)
+                
+        export_flags = " /IMPLIB:" // implib_path // &
+                       " /DEF:" // def_path
+
+    case default
+        
+        export_flags = ""  ! Do nothing elsewhere
+
+    end select
+
+end function get_export_flags
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/get_feature_flag.html b/proc/get_feature_flag.html new file mode 100644 index 0000000000..aa0597892a --- /dev/null +++ b/proc/get_feature_flag.html @@ -0,0 +1,365 @@ + + + + + + + + + + + + + get_feature_flag – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

get_feature_flag + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function get_feature_flag(self, feature) result(flags) +

+ + + +

Type Bound

+

compiler_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::self + +
+ + character(len=*), + intent(in) + + ::feature + +
+ +

Return Value + + + character(len=:), allocatable + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
function get_feature_flag(self, feature) result(flags)
+    class(compiler_t), intent(in) :: self
+    character(len=*), intent(in) :: feature
+    character(len=:), allocatable :: flags
+
+    flags = ""
+    select case(feature)
+    case("no-implicit-typing")
+       select case(self%id)
+       case(id_caf, id_gcc, id_f95)
+           flags = flag_gnu_no_implicit_typing
+
+       case(id_nag)
+           flags = flag_nag_no_implicit_typing
+
+       case(id_cray)
+           flags = flag_cray_no_implicit_typing
+
+       end select
+
+    case("implicit-typing")
+       select case(self%id)
+       case(id_cray)
+           flags = flag_cray_implicit_typing
+
+       case(id_lfortran)
+           flags = flag_lfortran_implicit_typing
+
+       end select
+
+    case("no-implicit-external")
+       select case(self%id)
+       case(id_caf, id_gcc, id_f95)
+           flags = flag_gnu_no_implicit_external
+
+       end select
+
+    case("implicit-external")
+       select case(self%id)
+       case(id_lfortran)
+           flags = flag_lfortran_implicit_external
+
+       end select
+
+    case("free-form")
+       select case(self%id)
+       case(id_caf, id_gcc, id_f95)
+           flags = flag_gnu_free_form
+
+       case(id_pgi, id_nvhpc, id_flang)
+           flags = flag_pgi_free_form
+
+       case(id_nag)
+           flags = flag_nag_free_form
+
+       case(id_intel_classic_nix, id_intel_classic_mac, id_intel_llvm_nix, &
+             & id_intel_llvm_unknown)
+           flags = flag_intel_free_form
+
+       case(id_intel_classic_windows, id_intel_llvm_windows)
+           flags = flag_intel_free_form_win
+
+       case(id_cray)
+           flags = flag_cray_free_form
+
+       end select
+
+    case("fixed-form")
+       select case(self%id)
+       case(id_caf, id_gcc, id_f95)
+           flags = flag_gnu_fixed_form
+
+       case(id_pgi, id_nvhpc, id_flang)
+           flags = flag_pgi_fixed_form
+
+       case(id_nag)
+           flags = flag_nag_fixed_form
+
+       case(id_intel_classic_nix, id_intel_classic_mac, id_intel_llvm_nix, &
+             & id_intel_llvm_unknown)
+           flags = flag_intel_fixed_form
+
+       case(id_intel_classic_windows, id_intel_llvm_windows)
+           flags = flag_intel_fixed_form_win
+
+       case(id_cray)
+           flags = flag_cray_fixed_form
+
+       case(id_lfortran)
+           flags = flag_lfortran_fixed_form
+
+       end select
+
+    case("default-form")
+        continue
+
+    case default
+        error stop "Unknown feature '"//feature//"'"
+    end select
+end function get_feature_flag
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/get_flags.html b/proc/get_flags.html new file mode 100644 index 0000000000..7238577944 --- /dev/null +++ b/proc/get_flags.html @@ -0,0 +1,701 @@ + + + + + + + + + + + + + get_flags – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

get_flags + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine get_flags(profile_name, compiler_name, os_type, key_list, table, profiles, profindex, os_valid) +

+ + +

Look for flags, c-flags, link-time-flags key-val pairs +and files table in a given table and create new profiles

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=:), + intent(in), + allocatable + ::profile_name +

Name of profile

+
+ + character(len=:), + intent(in), + allocatable + ::compiler_name +

Name of compiler

+
+ + integer, + intent(in) + + ::os_type +

OS type

+
+ + type(toml_key), + intent(in), + allocatable + ::key_list(:) +

List of keys in the table

+
+ + type(toml_table), + intent(in), + pointer + ::table +

Table containing OS tables

+
+ + type(profile_config_t), + intent(inout), + allocatable + ::profiles(:) +

List of profiles

+
+ + integer, + intent(inout) + + ::profindex +

Index in the list of profiles

+
+ + logical, + intent(in) + + ::os_valid +

Was called with valid operating system

+
+ +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=:), + public, + allocatable + ::c_flags + +
+ + character(len=:), + public, + allocatable + ::cxx_flags + +
+ + character(len=:), + public, + allocatable + ::err_message + +
+ + character(len=:), + public, + allocatable + ::file_flags + +
+ + type(toml_key), + public, + allocatable + ::file_list(:) + +
+ + character(len=:), + public, + allocatable + ::file_name + +
+ + type(file_scope_flag), + public, + allocatable + ::file_scope_flags(:) + +
+ + type(toml_table), + public, + pointer + ::files + +
+ + character(len=:), + public, + allocatable + ::flags + +
+ + integer, + public + + ::ifile + +
+ + integer, + public + + ::ikey + +
+ + logical, + public + + ::is_valid + +
+ + character(len=:), + public, + allocatable + ::key_name + +
+ + character(len=:), + public, + allocatable + ::link_time_flags + +
+ + integer, + public + + ::stat + +
+ +
+
+ + + + + + + + + +
+

Source Code

+
      subroutine get_flags(profile_name, compiler_name, os_type, key_list, table, profiles, profindex, os_valid)
+
+        !> Name of profile
+        character(len=:), allocatable, intent(in) :: profile_name
+
+        !> Name of compiler
+        character(len=:), allocatable, intent(in) :: compiler_name
+
+        !> OS type
+        integer, intent(in) :: os_type
+
+        !> List of keys in the table
+        type(toml_key), allocatable, intent(in) :: key_list(:)
+
+        !> Table containing OS tables
+        type(toml_table), pointer, intent(in) :: table
+
+        !> List of profiles
+        type(profile_config_t), allocatable, intent(inout) :: profiles(:)
+
+        !> Index in the list of profiles
+        integer, intent(inout) :: profindex
+
+        !> Was called with valid operating system
+        logical, intent(in) :: os_valid
+
+        character(len=:), allocatable :: flags, c_flags, cxx_flags, link_time_flags, key_name, file_name, file_flags, err_message
+        type(toml_table), pointer :: files
+        type(toml_key), allocatable :: file_list(:)
+        type(file_scope_flag), allocatable :: file_scope_flags(:)
+        integer :: ikey, ifile, stat
+        logical :: is_valid
+
+        call get_value(table, 'flags', flags)
+        call get_value(table, 'c-flags', c_flags)
+        call get_value(table, 'cxx-flags', cxx_flags)
+        call get_value(table, 'link-time-flags', link_time_flags)
+        call get_value(table, 'files', files)
+        if (associated(files)) then
+          call files%get_keys(file_list)
+          allocate(file_scope_flags(size(file_list)))
+          do ifile=1,size(file_list)
+            file_name = file_list(ifile)%key
+            call get_value(files, file_name, file_flags)
+            associate(cur_file=>file_scope_flags(ifile))
+              if (.not.(path.eq."")) file_name = join_path(path, file_name)
+              cur_file%file_name = file_name
+              cur_file%flags = file_flags
+            end associate
+          end do
+        end if
+
+        profiles(profindex) = new_profile(profile_name, compiler_name, os_type, &
+                 & flags, c_flags, cxx_flags, link_time_flags, file_scope_flags)
+        profindex = profindex + 1
+      end subroutine get_flags
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/get_fpm_env.html b/proc/get_fpm_env.html new file mode 100644 index 0000000000..0cd0819297 --- /dev/null +++ b/proc/get_fpm_env.html @@ -0,0 +1,274 @@ + + + + + + + + + + + + + get_fpm_env – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

get_fpm_env + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function get_fpm_env(env, default) result(val) +

+ + +

Get an environment variable for fpm, this routine ensures that every variable +used by fpm is prefixed with FPM_.

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::env + +
+ + character(len=*), + intent(in) + + ::default + +
+ +

Return Value + + + character(len=:), allocatable + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
    function get_fpm_env(env, default) result(val)
+      character(len=*), intent(in) :: env
+      character(len=*), intent(in) :: default
+      character(len=:), allocatable :: val
+
+      character(len=*), parameter :: fpm_prefix = "FPM_"
+
+      val = get_env(fpm_prefix//env, default)
+    end function get_fpm_env
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/get_global_settings.html b/proc/get_global_settings.html new file mode 100644 index 0000000000..af581caa58 --- /dev/null +++ b/proc/get_global_settings.html @@ -0,0 +1,245 @@ + + + + + + + + + + + + + get_global_settings – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

get_global_settings + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine get_global_settings(global_settings, error) +

+ + +

Obtain global settings from the global config file.

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(fpm_global_settings), + intent(inout) + + ::global_settings +

Global settings to be obtained.

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error reading config file.

+
+ +
+ + + + + + + + + + + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/get_headerpad_flags.html b/proc/get_headerpad_flags.html new file mode 100644 index 0000000000..c5fa4cbca3 --- /dev/null +++ b/proc/get_headerpad_flags.html @@ -0,0 +1,264 @@ + + + + + + + + + + + + + get_headerpad_flags – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

get_headerpad_flags + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function get_headerpad_flags(self) result(flags) +

+ + +

Generate header padding flags for install_name_tool compatibility on macOS

+ +

Type Bound

+

compiler_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::self + +
+ +

Return Value + + + character(len=:), allocatable + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
function get_headerpad_flags(self) result(flags)
+    class(compiler_t), intent(in) :: self
+    character(len=:), allocatable :: flags
+
+    if (get_os_type() /= OS_MACOS) then
+        flags = ""
+        return
+    end if
+
+    ! Reserve enough space in the Mach-O header to safely add two install_name or rpath later
+    flags = " -Wl,-headerpad,0x200"
+
+end function get_headerpad_flags
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/get_home.html b/proc/get_home.html new file mode 100644 index 0000000000..c94d4c1556 --- /dev/null +++ b/proc/get_home.html @@ -0,0 +1,275 @@ + + + + + + + + + + + + + get_home – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

get_home + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine get_home(home, error) +

+ + +

Get the HOME directory on Unix and the %USERPROFILE% directory on Windows.

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=:), + intent(out), + allocatable + ::home + +
+ + type(error_t), + intent(out), + allocatable + ::error + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
    subroutine get_home(home, error)
+        character(len=:), allocatable, intent(out) :: home
+        type(error_t), allocatable, intent(out) :: error
+
+        if (os_is_unix()) then
+            home=get_env('HOME','')
+            if ( home == '' ) then
+                call fatal_error(error, "Couldn't retrieve 'HOME' variable")
+                return
+            end if
+        else
+            home=get_env('USERPROFILE','')
+            if ( home == '' ) then
+                call fatal_error(error, "Couldn't retrieve '%USERPROFILE%' variable")
+                return
+            end if
+        end if
+    end subroutine get_home
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/get_id.html b/proc/get_id.html new file mode 100644 index 0000000000..78d303aa08 --- /dev/null +++ b/proc/get_id.html @@ -0,0 +1,344 @@ + + + + + + + + + + + + + get_id – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

get_id + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function get_id(compiler) result(id) +

+ + + + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::compiler + +
+ +

Return Value + + + integer(kind=compiler_enum) + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
function get_id(compiler) result(id)
+    character(len=*), intent(in) :: compiler
+    integer(kind=compiler_enum) :: id
+
+    if (check_compiler(compiler, "gfortran")) then
+        id = id_gcc
+        return
+    end if
+
+    if (check_compiler(compiler, "f95")) then
+        id = id_f95
+        return
+    end if
+
+    if (check_compiler(compiler, "caf")) then
+        id = id_caf
+        return
+    end if
+
+    if (check_compiler(compiler, "ifort")) then
+        select case (get_os_type())
+        case default
+            id = id_intel_classic_nix
+        case (OS_MACOS)
+            id = id_intel_classic_mac
+        case (OS_WINDOWS, OS_CYGWIN)
+            id = id_intel_classic_windows
+        end select
+        return
+    end if
+
+    if (check_compiler(compiler, "ifx")) then
+        select case (get_os_type())
+        case default
+            id = id_intel_llvm_nix
+        case (OS_WINDOWS, OS_CYGWIN)
+            id = id_intel_llvm_windows
+        end select
+        return
+    end if
+
+    if (check_compiler(compiler, "nvfortran")) then
+        id = id_nvhpc
+        return
+    end if
+
+    if (check_compiler(compiler, "pgfortran") &
+        & .or. check_compiler(compiler, "pgf90") &
+        & .or. check_compiler(compiler, "pgf95")) then
+        id = id_pgi
+        return
+    end if
+
+    if (check_compiler(compiler, "nagfor")) then
+        id = id_nag
+        return
+    end if
+
+    if (check_compiler(compiler, "flang-new")) then
+        id = id_flang_new
+        return
+    end if
+
+    if (check_compiler(compiler, "f18")) then
+        id = id_f18
+        return
+    end if
+
+    if (check_compiler(compiler, "flang")) then
+        id = id_flang
+        return
+    end if
+
+    if (check_compiler(compiler, "xlf90")) then
+        id = id_ibmxl
+        return
+    end if
+
+    if (check_compiler(compiler, "crayftn")) then
+        id = id_cray
+        return
+    end if
+
+    if (check_compiler(compiler, "lfc")) then
+        id = id_lahey
+        return
+    end if
+
+    if (check_compiler(compiler, "lfortran")) then
+        id = id_lfortran
+        return
+    end if
+
+    id = id_unknown
+
+end function get_id
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/get_include_flag.html b/proc/get_include_flag.html new file mode 100644 index 0000000000..481eaa86bf --- /dev/null +++ b/proc/get_include_flag.html @@ -0,0 +1,286 @@ + + + + + + + + + + + + + get_include_flag – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

get_include_flag + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function get_include_flag(self, path) result(flags) +

+ + + +

Type Bound

+

compiler_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::self + +
+ + character(len=*), + intent(in) + + ::path + +
+ +

Return Value + + + character(len=:), allocatable + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
function get_include_flag(self, path) result(flags)
+    class(compiler_t), intent(in) :: self
+    character(len=*), intent(in) :: path
+    character(len=:), allocatable :: flags
+
+    select case(self%id)
+    case default
+        flags = "-I "//path
+
+    case(id_caf, id_gcc, id_f95, id_cray, id_nvhpc, id_pgi, &
+        & id_flang, id_flang_new, id_f18, &
+        & id_intel_classic_nix, id_intel_classic_mac, &
+        & id_intel_llvm_nix, id_lahey, id_nag, id_ibmxl, &
+        & id_lfortran)
+        flags = "-I "//path
+
+    case(id_intel_classic_windows, id_intel_llvm_windows)
+        flags = "/I"//path
+
+    end select
+end function get_include_flag
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/get_install_name_flags.html b/proc/get_install_name_flags.html new file mode 100644 index 0000000000..b00526db01 --- /dev/null +++ b/proc/get_install_name_flags.html @@ -0,0 +1,347 @@ + + + + + + + + + + + + + get_install_name_flags – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

get_install_name_flags + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function get_install_name_flags(self, target_dir, target_name) result(flags) +

+ + +

Generate install_name flag for a shared library build on macOS

+ +

Type Bound

+

compiler_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::self + +
+ + character(len=*), + intent(in) + + ::target_dir + +
+ + character(len=*), + intent(in) + + ::target_name + +
+ +

Return Value + + + character(len=:), allocatable + +

+ +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=:), + public, + allocatable + ::library_file + +
+ +
+
+ + + + + + + + + +
+

Source Code

+
function get_install_name_flags(self, target_dir, target_name) result(flags)
+    class(compiler_t), intent(in) :: self
+    character(len=*), intent(in) :: target_dir, target_name
+    character(len=:), allocatable :: flags
+    character(len=:), allocatable :: library_file
+
+    if (get_os_type() /= OS_MACOS) then
+        flags = ""
+        return
+    end if
+
+    ! Shared library basename (e.g., libfoo.dylib)
+    if (str_ends_with(target_name, ".dylib")) then
+        library_file = target_name        
+    else
+        library_file = library_filename(target_name,.true.,.false.,OS_MACOS)
+    end if
+    
+    flags = " -Wl,-install_name,@rpath/" // library_file
+
+end function get_install_name_flags
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/get_library_dirs.html b/proc/get_library_dirs.html new file mode 100644 index 0000000000..678dde52fd --- /dev/null +++ b/proc/get_library_dirs.html @@ -0,0 +1,292 @@ + + + + + + + + + + + + + get_library_dirs – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

get_library_dirs + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine get_library_dirs(model, targets, shared_lib_dirs) +

+ + +

Add link directories for all shared libraries in the dependency graph

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(fpm_model_t), + intent(in) + + ::model + +
+ + type(build_target_ptr), + intent(inout), + target + ::targets(:) + +
+ + type(string_t), + intent(out), + allocatable + ::shared_lib_dirs(:) + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
subroutine get_library_dirs(model, targets, shared_lib_dirs)
+    type(fpm_model_t), intent(in) :: model
+    type(build_target_ptr), intent(inout), target :: targets(:)
+    type(string_t), allocatable, intent(out) :: shared_lib_dirs(:)
+
+    integer :: i
+    type(string_t) :: temp
+    
+    allocate(shared_lib_dirs(0))
+
+    do i = 1, size(targets)
+        associate(target => targets(i)%ptr)
+            if (all(target%target_type /= [FPM_TARGET_SHARED,FPM_TARGET_ARCHIVE])) cycle
+            if (target%output_dir .in. shared_lib_dirs) cycle
+            temp = string_t(target%output_dir)
+            shared_lib_dirs = [shared_lib_dirs, temp]
+        end associate
+    end do
+    
+end subroutine get_library_dirs
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/get_list.html b/proc/get_list.html new file mode 100644 index 0000000000..6b9afbcee3 --- /dev/null +++ b/proc/get_list.html @@ -0,0 +1,332 @@ + + + + + + + + + + + + + get_list – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

get_list + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine get_list(table, key, list, error) +

+ + + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(toml_table), + intent(inout) + + ::table +

Instance of the TOML data structure

+
+ + character(len=*), + intent(in) + + ::key +

Key to read from

+
+ + type(string_t), + intent(out), + allocatable + ::list(:) +

List of strings to read

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
    subroutine get_list(table, key, list, error)
+
+        !> Instance of the TOML data structure
+        type(toml_table), intent(inout) :: table
+
+        !> Key to read from
+        character(len=*), intent(in) :: key
+
+        !> List of strings to read
+        type(string_t), allocatable, intent(out) :: list(:)
+
+        !> Error handling
+        type(error_t), allocatable, intent(out) :: error
+
+        integer :: stat, ilist, nlist
+        type(toml_array), pointer :: children
+        character(len=:), allocatable :: str
+
+        if (.not.table%has_key(key)) return
+
+        call get_value(table, key, children, requested=.false.)
+        if (associated(children)) then
+            nlist = len(children)
+            allocate (list(nlist))
+            do ilist = 1, nlist
+                call get_value(children, ilist, str, stat=stat)
+                if (stat /= toml_stat%success) then
+                    call fatal_error(error, "Entry in "//key//" field cannot be read")
+                    exit
+                end if
+                call move_alloc(str, list(ilist)%s)
+            end do
+            if (allocated(error)) return
+        else
+            call get_value(table, key, str, stat=stat)
+            if (stat /= toml_stat%success) then
+                call fatal_error(error, "Entry in "//key//" field cannot be read")
+                return
+            end if
+            if (allocated(str)) then
+                allocate (list(1))
+                call move_alloc(str, list(1)%s)
+            end if
+        end if
+
+    end subroutine get_list
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/get_local_prefix.html b/proc/get_local_prefix.html new file mode 100644 index 0000000000..bc8e53a8aa --- /dev/null +++ b/proc/get_local_prefix.html @@ -0,0 +1,279 @@ + + + + + + + + + + + + + get_local_prefix – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

get_local_prefix + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function get_local_prefix(os) result(prefix) +

+ + +

Determine the path prefix to the local folder. Used for installation, registry etc.

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + integer, + intent(in),optional + + ::os +

Platform identifier

+
+ +

Return Value + + + character(len=:), allocatable + +

+

Installation prefix

+
+ + + + + + + + + + + +
+

Source Code

+
    function get_local_prefix(os) result(prefix)
+        !> Installation prefix
+        character(len=:), allocatable :: prefix
+        !> Platform identifier
+        integer, intent(in), optional :: os
+
+        !> Default installation prefix on Unix platforms
+        character(len=*), parameter :: default_prefix_unix = "/usr/local"
+        !> Default installation prefix on Windows platforms
+        character(len=*), parameter :: default_prefix_win = "C:\"
+
+        character(len=:), allocatable :: home
+
+        if (os_is_unix(os)) then
+            home=get_env('HOME','')
+            if (home /= '' ) then
+                prefix = join_path(home, ".local")
+            else
+                prefix = default_prefix_unix
+            end if
+        else
+            home=get_env('APPDATA','')
+            if (home /= '' ) then
+                prefix = join_path(home, "local")
+            else
+                prefix = default_prefix_win
+            end if
+        end if
+
+    end function get_local_prefix
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/get_macros.html b/proc/get_macros.html new file mode 100644 index 0000000000..c994cfe653 --- /dev/null +++ b/proc/get_macros.html @@ -0,0 +1,426 @@ + + + + + + + + + + + + + get_macros – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

get_macros + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function get_macros(id, macros_list, version) result(macros) +

+ + +

This function will parse and read the macros list and +return them as defined flags. +Set macro defintion symbol on the basis of compiler used +Check if macros are not allocated. +Split the macro name and value.

+

Check if the value of macro starts with ‘{’ character.

+

Check if the value of macro ends with ‘}’ character.

+

Check if the string contains “version” as substring.

+

These conditions are placed in order to ensure proper spacing between the macros.

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + integer(kind=compiler_enum), + intent(in) + + ::id + +
+ + type(string_t), + intent(in), + allocatable + ::macros_list(:) + +
+ + character(len=:), + intent(in), + allocatable + ::version + +
+ +

Return Value + + + character(len=:), allocatable + +

+ +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + integer, + public + + ::i + +
+ + character(len=:), + public, + allocatable + ::macro_definition_symbol + +
+ + character(len=:), + public, + allocatable + ::valued_macros(:) + +
+ +
+
+ + + + + + + + + +
+

Source Code

+
function get_macros(id, macros_list, version) result(macros)
+    integer(compiler_enum), intent(in) :: id
+    character(len=:), allocatable, intent(in) :: version
+    type(string_t), allocatable, intent(in) :: macros_list(:)
+
+    character(len=:), allocatable :: macros
+    character(len=:), allocatable :: macro_definition_symbol
+    character(:), allocatable :: valued_macros(:)
+
+
+    integer :: i
+
+    if (.not.allocated(macros_list)) then
+        macros = ""
+        return
+    end if
+
+    !> Set macro defintion symbol on the basis of compiler used
+    select case(id)
+    case default
+        macro_definition_symbol = " -D"
+    case (id_intel_classic_windows, id_intel_llvm_windows)
+        macro_definition_symbol = " /D"
+    end select
+
+    !> Check if macros are not allocated.
+    if (.not.allocated(macros)) then
+        macros=""
+    end if
+
+    do i = 1, size(macros_list)
+
+        !> Split the macro name and value.
+        call split(macros_list(i)%s, valued_macros, delimiters="=")
+
+        if (size(valued_macros) > 1) then
+            !> Check if the value of macro starts with '{' character.
+            if (str_begins_with_str(trim(valued_macros(size(valued_macros))), "{")) then
+
+                !> Check if the value of macro ends with '}' character.
+                if (str_ends_with(trim(valued_macros(size(valued_macros))), "}")) then
+
+                    !> Check if the string contains "version" as substring.
+                    if (index(valued_macros(size(valued_macros)), "version") /= 0) then
+
+                        !> These conditions are placed in order to ensure proper spacing between the macros.
+                        macros = macros//macro_definition_symbol//trim(valued_macros(1))//'='//version
+                        cycle
+                    end if
+                end if
+            end if
+        end if
+
+        macros = macros//macro_definition_symbol//macros_list(i)%s
+
+    end do
+
+end function get_macros
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/get_main_flags.html b/proc/get_main_flags.html new file mode 100644 index 0000000000..eefd82b8ff --- /dev/null +++ b/proc/get_main_flags.html @@ -0,0 +1,315 @@ + + + + + + + + + + + + + get_main_flags – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

get_main_flags + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine get_main_flags(self, language, flags) +

+ + +

Get special flags for the main linker

+ +

Type Bound

+

compiler_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::self + +
+ + character(len=*), + intent(in) + + ::language + +
+ + character(len=:), + intent(out), + allocatable + ::flags + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
subroutine get_main_flags(self, language, flags)
+    class(compiler_t), intent(in) :: self
+    character(len=*), intent(in) :: language
+    character(len=:), allocatable, intent(out) :: flags
+
+    flags = ""
+    select case(language)
+
+    case("fortran")
+        flags = ""
+
+    case("c")
+
+        ! If the main program is on a C/C++ source, the Intel Fortran compiler requires option
+        ! -nofor-main to avoid "duplicate main" errors.
+        ! https://stackoverflow.com/questions/36221612/p3dfft-compilation-ifort-compiler-error-multiple-definiton-of-main
+        select case(self%id)
+           case(id_intel_classic_nix, id_intel_classic_mac, id_intel_llvm_nix)
+               flags = '-nofor-main'
+           case(id_intel_classic_windows,id_intel_llvm_windows)
+               flags = '/nofor-main'
+           case (id_pgi,id_nvhpc)
+               flags = '-Mnomain'
+        end select
+
+    case("c++","cpp","cxx")
+
+        select case(self%id)
+           case(id_intel_classic_nix, id_intel_classic_mac, id_intel_llvm_nix)
+               flags = '-nofor-main'
+           case(id_intel_classic_windows,id_intel_llvm_windows)
+               flags = '/nofor-main'
+           case (id_pgi,id_nvhpc)
+               flags = '-Mnomain'
+        end select
+
+    case default
+        error stop "Unknown language '"//language//'", try "fortran", "c", "c++"'
+    end select
+
+end subroutine get_main_flags
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/get_module_flag.html b/proc/get_module_flag.html new file mode 100644 index 0000000000..7ae714ae68 --- /dev/null +++ b/proc/get_module_flag.html @@ -0,0 +1,302 @@ + + + + + + + + + + + + + get_module_flag – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

get_module_flag + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function get_module_flag(self, path) result(flags) +

+ + + +

Type Bound

+

compiler_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::self + +
+ + character(len=*), + intent(in) + + ::path + +
+ +

Return Value + + + character(len=:), allocatable + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
function get_module_flag(self, path) result(flags)
+    class(compiler_t), intent(in) :: self
+    character(len=*), intent(in) :: path
+    character(len=:), allocatable :: flags
+
+    select case(self%id)
+    case default
+        flags = "-module "//path
+
+    case(id_caf, id_gcc, id_f95, id_cray, id_lfortran)
+        flags = "-J "//path
+
+    case(id_nvhpc, id_pgi, id_flang)
+        flags = "-module "//path
+
+    case(id_flang_new, id_f18)
+        flags = "-module-dir "//path
+
+    case(id_intel_classic_nix, id_intel_classic_mac, &
+        & id_intel_llvm_nix)
+        flags = "-module "//path
+
+    case(id_intel_classic_windows, id_intel_llvm_windows)
+        flags = "/module:"//path
+
+    case(id_lahey)
+        flags = "-M "//path
+
+    case(id_nag)
+        flags = "-mdir "//path
+
+    case(id_ibmxl)
+        flags = "-qmoddir "//path
+
+    end select
+
+end function get_module_flag
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/get_os_type.html b/proc/get_os_type.html new file mode 100644 index 0000000000..c048a2fa1e --- /dev/null +++ b/proc/get_os_type.html @@ -0,0 +1,346 @@ + + + + + + + + + + + + + get_os_type – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

get_os_type + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function get_os_type() result(r) +

+ + +

Determine the OS type

+

Returns one of OS_UNKNOWN, OS_LINUX, OS_MACOS, OS_WINDOWS, OS_CYGWIN, +OS_SOLARIS, OS_FREEBSD, OS_OPENBSD.

+

At first, the environment variable OS is checked, which is usually +found on Windows. Then, OSTYPE is read in and compared with common +names. If this fails too, check the existence of files that can be +found on specific system types only.

+

Returns OS_UNKNOWN if the operating system cannot be determined.

+ + +

Arguments

+ None +
+

Return Value + + + integer + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
    integer function get_os_type() result(r)
+        !!
+        !! Returns one of OS_UNKNOWN, OS_LINUX, OS_MACOS, OS_WINDOWS, OS_CYGWIN,
+        !! OS_SOLARIS, OS_FREEBSD, OS_OPENBSD.
+        !!
+        !! At first, the environment variable `OS` is checked, which is usually
+        !! found on Windows. Then, `OSTYPE` is read in and compared with common
+        !! names. If this fails too, check the existence of files that can be
+        !! found on specific system types only.
+        !!
+        !! Returns OS_UNKNOWN if the operating system cannot be determined.
+        character(len=255) :: val
+        integer            :: length, rc
+        logical            :: file_exists
+        logical, save      :: first_run = .true.
+        integer, save      :: ret = OS_UNKNOWN
+        !$omp threadprivate(ret, first_run)
+
+        if (.not. first_run) then
+            r = ret
+            return
+        end if
+
+        first_run = .false.
+        r = OS_UNKNOWN
+
+        ! Check environment variable `OSTYPE`.
+        call get_environment_variable('OSTYPE', val, length, rc)
+
+        if (rc == 0 .and. length > 0) then
+            ! Linux
+            if (index(val, 'linux') > 0) then
+                r = OS_LINUX
+                ret = r
+                return
+            end if
+
+            ! macOS
+            if (index(val, 'darwin') > 0) then
+                r = OS_MACOS
+                ret = r
+                return
+            end if
+
+            ! Windows, MSYS, MinGW, Git Bash
+            if (index(val, 'win') > 0 .or. index(val, 'msys') > 0) then
+                r = OS_WINDOWS
+                ret = r
+                return
+            end if
+
+            ! Cygwin
+            if (index(val, 'cygwin') > 0) then
+                r = OS_CYGWIN
+                ret = r
+                return
+            end if
+
+            ! Solaris, OpenIndiana, ...
+            if (index(val, 'SunOS') > 0 .or. index(val, 'solaris') > 0) then
+                r = OS_SOLARIS
+                ret = r
+                return
+            end if
+
+            ! FreeBSD
+            if (index(val, 'FreeBSD') > 0 .or. index(val, 'freebsd') > 0) then
+                r = OS_FREEBSD
+                ret = r
+                return
+            end if
+
+            ! OpenBSD
+            if (index(val, 'OpenBSD') > 0 .or. index(val, 'openbsd') > 0) then
+                r = OS_OPENBSD
+                ret = r
+                return
+            end if
+        end if
+
+        ! Check environment variable `OS`.
+        call get_environment_variable('OS', val, length, rc)
+
+        if (rc == 0 .and. length > 0 .and. index(val, 'Windows_NT') > 0) then
+            r = OS_WINDOWS
+            ret = r
+            return
+        end if
+
+        ! Linux
+        inquire (file='/etc/os-release', exist=file_exists)
+
+        if (file_exists) then
+            r = OS_LINUX
+            ret = r
+            return
+        end if
+
+        ! macOS
+        inquire (file='/usr/bin/sw_vers', exist=file_exists)
+
+        if (file_exists) then
+            r = OS_MACOS
+            ret = r
+            return
+        end if
+
+        ! FreeBSD
+        inquire (file='/bin/freebsd-version', exist=file_exists)
+
+        if (file_exists) then
+            r = OS_FREEBSD
+            ret = r
+            return
+        end if
+    end function get_os_type
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/get_package_data.html b/proc/get_package_data.html new file mode 100644 index 0000000000..a064695213 --- /dev/null +++ b/proc/get_package_data.html @@ -0,0 +1,325 @@ + + + + + + + + + + + + + get_package_data – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

get_package_data + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine get_package_data(package, file, error, apply_defaults) +

+ + +

Obtain package meta data from a configuation file

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(package_config_t), + intent(out) + + ::package +

Parsed package meta data

+
+ + character(len=*), + intent(in) + + ::file +

Name of the package configuration file

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error status of the operation

+
+ + logical, + intent(in),optional + + ::apply_defaults +

Apply package defaults (uses file system operations)

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
    subroutine get_package_data(package, file, error, apply_defaults)
+
+        !> Parsed package meta data
+        type(package_config_t), intent(out) :: package
+
+        !> Name of the package configuration file
+        character(len=*), intent(in) :: file
+
+        !> Error status of the operation
+        type(error_t), allocatable, intent(out) :: error
+
+        !> Apply package defaults (uses file system operations)
+        logical, intent(in), optional :: apply_defaults
+
+        type(toml_table), allocatable :: table
+        character(len=:), allocatable :: root
+
+        call read_package_file(table, file, error)
+        if (allocated(error)) return
+
+        if (.not. allocated(table)) then
+            call fatal_error(error, "Unclassified error while reading: '"//file//"'")
+            return
+        end if
+
+        call new_package(package, table, dirname(file), error)
+        if (allocated(error)) return
+
+        if (present(apply_defaults)) then
+            if (apply_defaults) then
+                root = dirname(file)
+                if (len_trim(root) == 0) root = "."
+                call package_defaults(package, root, error)
+                if (allocated(error)) return
+            end if
+        end if
+
+    end subroutine get_package_data
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/get_package_dependencies.html b/proc/get_package_dependencies.html new file mode 100644 index 0000000000..2a49367eb0 --- /dev/null +++ b/proc/get_package_dependencies.html @@ -0,0 +1,369 @@ + + + + + + + + + + + + + get_package_dependencies – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

get_package_dependencies + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine get_package_dependencies(package, main, deps) +

+ + + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(package_config_t), + intent(in) + + ::package +

Parsed package meta data

+
+ + logical, + intent(in) + + ::main +

Is the main project

+
+ + type(dependency_config_t), + intent(out), + allocatable + ::deps(:) +

Unprocessed list of all dependencies listed in this manifest

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
    subroutine get_package_dependencies(package, main, deps)
+
+        !> Parsed package meta data
+        type(package_config_t), intent(in) :: package
+        
+        !> Is the main project
+        logical, intent(in) :: main        
+        
+        !> Unprocessed list of all dependencies listed in this manifest
+        type(dependency_config_t), allocatable, intent(out) :: deps(:)
+        
+        integer :: ndeps,k
+        
+        ndeps = 0
+        if (allocated(package%dependency)) &
+        ndeps = ndeps + size(package%dependency)
+        
+        if (main) then 
+        
+            if (allocated(package%dev_dependency)) &
+            ndeps = ndeps + size(package%dev_dependency)
+                    
+            if (allocated(package%example)) then
+               do k = 1, size(package%example)
+                  if (allocated(package%example(k)%dependency)) &
+                  ndeps = ndeps + size(package%example(k)%dependency)
+               end do
+            end if
+
+            if (allocated(package%executable)) then
+               do k = 1, size(package%executable)
+                  if (allocated(package%executable(k)%dependency)) &
+                  ndeps = ndeps + size(package%executable(k)%dependency)
+               end do
+            end if
+            
+            if (allocated(package%test)) then
+               do k = 1, size(package%test)
+                  if (allocated(package%test(k)%dependency)) &
+                  ndeps = ndeps + size(package%test(k)%dependency)
+               end do
+            end if     
+        
+        endif   
+        
+        allocate(deps(ndeps))
+        
+        if (ndeps > 0) then
+           
+           ndeps = 0
+           
+           if (allocated(package%dependency)) &
+           call collect(deps,ndeps,package%dependency)
+           
+           if (main) then 
+           
+               if (allocated(package%dev_dependency)) &
+               call collect(deps,ndeps,package%dev_dependency)
+               
+               if (allocated(package%example)) then
+                  do k = 1, size(package%example)
+                     if (allocated(package%example(k)%dependency)) &
+                     call collect(deps,ndeps,package%example(k)%dependency)
+                  end do
+               end if
+               if (allocated(package%executable)) then
+                  do k = 1, size(package%executable)
+                     if (allocated(package%executable(k)%dependency)) &
+                     call collect(deps,ndeps,package%executable(k)%dependency)
+                  end do
+               end if
+               if (allocated(package%test)) then
+                  do k = 1, size(package%test)
+                     if (allocated(package%test(k)%dependency)) &
+                     call collect(deps,ndeps,package%test(k)%dependency)
+                  end do
+               end if    
+           
+           endif
+         
+         endif
+
+      contains
+      
+         ! Add dependencies to the list      
+         pure subroutine collect(list, nreq, new_deps)
+            type(dependency_config_t), intent(inout) :: list(:)
+            integer,                   intent(inout) :: nreq
+            type(dependency_config_t), intent(in)    :: new_deps(:)
+            
+            integer :: i
+            do i = 1, size(new_deps)
+               nreq = nreq + 1
+               list(nreq) = new_deps(i)
+            end do
+         end subroutine collect
+        
+    end subroutine get_package_dependencies
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/get_registry_settings.html b/proc/get_registry_settings.html new file mode 100644 index 0000000000..e2c53e467a --- /dev/null +++ b/proc/get_registry_settings.html @@ -0,0 +1,260 @@ + + + + + + + + + + + + + get_registry_settings – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

get_registry_settings + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine get_registry_settings(table, global_settings, error) +

+ + +

Read registry settings from the global config file.

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(toml_table), + intent(inout), + target + ::table +

The [registry] subtable from the global config file.

+
+ + type(fpm_global_settings), + intent(inout) + + ::global_settings +

The global settings which can be filled with the registry settings.

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling.

+
+ +
+ + + + + + + + + + + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/get_release_compile_flags.html b/proc/get_release_compile_flags.html new file mode 100644 index 0000000000..13ff0c228a --- /dev/null +++ b/proc/get_release_compile_flags.html @@ -0,0 +1,355 @@ + + + + + + + + + + + + + get_release_compile_flags – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

get_release_compile_flags + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine get_release_compile_flags(id, flags) +

+ + + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + integer(kind=compiler_enum), + intent(in) + + ::id + +
+ + character(len=:), + intent(out), + allocatable + ::flags + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
subroutine get_release_compile_flags(id, flags)
+    integer(compiler_enum), intent(in) :: id
+    character(len=:), allocatable, intent(out) :: flags
+
+    select case(id)
+    case default
+        flags = ""
+    case(id_caf)
+        flags = &
+            flag_gnu_opt//&
+            flag_gnu_external//&
+            flag_gnu_pic//&
+            flag_gnu_limit
+
+    case(id_gcc)
+        flags = &
+            flag_gnu_opt//&
+            flag_gnu_external//&
+            flag_gnu_pic//&
+            flag_gnu_limit//&
+            flag_gnu_coarray
+
+    case(id_f95)
+        flags = &
+            flag_gnu_opt//&
+            flag_gnu_external//&
+            flag_gnu_pic//&
+            flag_gnu_limit
+
+    case(id_nvhpc)
+        flags = &
+            flag_pgi_backslash
+
+    case(id_ibmxl)
+        flags = &
+            flag_ibmxl_backslash
+
+    case(id_intel_classic_nix)
+        flags = &
+            flag_intel_opt//&
+            flag_intel_fp//&
+            flag_intel_align//&
+            flag_intel_limit//&
+            flag_intel_pthread//&
+            flag_intel_nogen//&
+            flag_intel_byterecl
+
+    case(id_intel_classic_mac)
+        flags = &
+            flag_intel_opt//&
+            flag_intel_fp//&
+            flag_intel_align//&
+            flag_intel_limit//&
+            flag_intel_pthread//&
+            flag_intel_nogen//&
+            flag_intel_byterecl
+
+    case(id_intel_classic_windows)
+        flags = &
+            flag_intel_opt_win//&
+            flag_intel_fp_win//&
+            flag_intel_align_win//&
+            flag_intel_limit_win//&
+            flag_intel_pthread_win//&
+            flag_intel_nogen_win//&
+            flag_intel_byterecl_win
+
+    case(id_intel_llvm_nix)
+        flags = &
+            flag_intel_opt//&
+            flag_intel_fp//&
+            flag_intel_align//&
+            flag_intel_limit//&
+            flag_intel_pthread//&
+            flag_intel_nogen//&
+            flag_intel_byterecl
+
+    case(id_intel_llvm_windows)
+        flags = &
+            flag_intel_opt_win//&
+            flag_intel_fp_win//&
+            flag_intel_align_win//&
+            flag_intel_limit_win//&
+            flag_intel_pthread_win//&
+            flag_intel_nogen_win//&
+            flag_intel_byterecl_win
+
+    case(id_nag)
+        flags = &
+            flag_nag_opt//&
+            flag_nag_coarray//&
+            flag_nag_pic
+
+    case(id_lfortran)
+        flags = &
+            flag_lfortran_opt
+
+    end select
+end subroutine get_release_compile_flags
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/get_shared_flag.html b/proc/get_shared_flag.html new file mode 100644 index 0000000000..38535062ef --- /dev/null +++ b/proc/get_shared_flag.html @@ -0,0 +1,270 @@ + + + + + + + + + + + + + get_shared_flag – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

get_shared_flag + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function get_shared_flag(self) result(shared_flag) +

+ + + + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::self + +
+ +

Return Value + + + character(len=:), allocatable + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
function get_shared_flag(self) result(shared_flag)
+    class(compiler_t), intent(in) :: self
+    character(len=:), allocatable :: shared_flag
+
+    select case (self%id)
+    case default
+        shared_flag = "-shared"
+    case (id_gcc, id_f95, id_flang, id_flang_new, id_lfortran)
+        shared_flag = "-shared"
+    case (id_intel_classic_nix, id_intel_llvm_nix, id_pgi, id_nvhpc)
+        shared_flag = "-shared"
+    case (id_intel_classic_windows, id_intel_llvm_windows)
+        shared_flag = "/DLL"
+    case (id_nag)
+        shared_flag = "-Wl,-shared"
+    case (id_ibmxl)
+        shared_flag = "-qmkshrobj"
+    case (id_cray, id_lahey)
+        shared_flag = ""  ! Needs special handling
+    end select
+
+end function get_shared_flag
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/get_temp_filename.html b/proc/get_temp_filename.html new file mode 100644 index 0000000000..62e36a686f --- /dev/null +++ b/proc/get_temp_filename.html @@ -0,0 +1,272 @@ + + + + + + + + + + + + + get_temp_filename – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

get_temp_filename + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function get_temp_filename() result(tempfile) +

+
+

Uses

+
+ +
+
+ + +

Get a unused temporary filename + Calls posix ‘tempnam’ - not recommended, but + we have no security concerns for this application + and use here is temporary. +Works with MinGW

+ + +

Arguments

+ None +
+

Return Value + + + character(len=:), allocatable + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
function get_temp_filename() result(tempfile)
+    !
+    use iso_c_binding, only: c_ptr, C_NULL_PTR, c_f_pointer
+    integer, parameter :: MAX_FILENAME_LENGTH = 32768
+    character(:), allocatable :: tempfile
+
+    type(c_ptr) :: c_tempfile_ptr
+    character(len=1), pointer :: c_tempfile(:)
+
+    interface
+
+        function c_tempnam(dir,pfx) result(tmp) bind(c,name="tempnam")
+            import
+            type(c_ptr), intent(in), value :: dir
+            type(c_ptr), intent(in), value :: pfx
+            type(c_ptr) :: tmp
+        end function c_tempnam
+
+        subroutine c_free(ptr) BIND(C,name="free")
+            import
+            type(c_ptr), value :: ptr
+        end subroutine c_free
+
+    end interface
+
+    c_tempfile_ptr = c_tempnam(C_NULL_PTR, C_NULL_PTR)
+    call c_f_pointer(c_tempfile_ptr,c_tempfile,[MAX_FILENAME_LENGTH])
+
+    tempfile = f_string(c_tempfile)
+
+    call c_free(c_tempfile_ptr)
+
+end function get_temp_filename
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/get_working_dir.html b/proc/get_working_dir.html new file mode 100644 index 0000000000..410e722179 --- /dev/null +++ b/proc/get_working_dir.html @@ -0,0 +1,264 @@ + + + + + + + + + + + + + get_working_dir – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

get_working_dir + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

subroutine get_working_dir(settings, working_dir_) +

+ + +

Save access to working directory in settings, in case setting have not been allocated

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(fpm_cmd_settings), + intent(in),optional + + ::settings + +
+ + character(len=:), + intent(out), + allocatable + ::working_dir_ + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
    subroutine get_working_dir(settings, working_dir_)
+        class(fpm_cmd_settings), optional, intent(in) :: settings
+        character(len=:), allocatable, intent(out) :: working_dir_
+        if (present(settings)) then
+            working_dir_ = settings%working_dir
+        end if
+    end subroutine get_working_dir
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/getline.html b/proc/getline.html new file mode 100644 index 0000000000..058ee93c15 --- /dev/null +++ b/proc/getline.html @@ -0,0 +1,388 @@ + + + + + + + + + + + + + getline – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

getline + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine getline(unit, line, iostat, iomsg) +

+ + +

NAME

+
 getline(3f) - [M_io:READ] read a line of arbintrary length from specified
+ LUN into allocatable string (up to system line length limit)
+(LICENSE:PD)
+
+ +

SYNTAX

+

subroutine getline(unit,line,iostat,iomsg)

+
integer,intent(in)                       :: unit
+character(len=:),allocatable,intent(out) :: line
+integer,intent(out)                      :: iostat
+character(len=:), allocatable, optional  :: iomsg
+
+ +

DESCRIPTION

+
Read a line of any length up to programming environment maximum
+line length. Requires Fortran 2003+.
+
+It is primarily expected to be used when reading input which will
+then be parsed or echoed.
+
+The input file must have a PAD attribute of YES for the function
+to work properly, which is typically true.
+
+The simple use of a loop that repeatedly re-allocates a character
+variable in addition to reading the input file one buffer at a
+time could (depending on the programming environment used) be
+inefficient, as it could reallocate and allocate memory used for
+the output string with each buffer read.
+
+ +

OPTIONS

+
LINE    The line read when IOSTAT returns as zero.
+LUN     LUN (Fortran logical I/O unit) number of file open and ready
+        to read.
+IOSTAT  status returned by READ(IOSTAT=IOS). If not zero, an error
+        occurred or an end-of-file or end-of-record was encountered.
+IOMSG   error message returned by system when IOSTAT is not zero.
+
+ +

EXAMPLE

+

Sample program:

+
program demo_getline
+use,intrinsic :: iso_fortran_env, only : stdin=>input_unit
+use,intrinsic :: iso_fortran_env, only : iostat_end
+use FPM_filesystem, only : getline
+implicit none
+integer :: iostat
+character(len=:),allocatable :: line, iomsg
+   open(unit=stdin,pad='yes')
+   INFINITE: do
+      call getline(stdin,line,iostat,iomsg)
+      if(iostat /= 0) exit INFINITE
+      write(*,'(a)')'['//line//']'
+   enddo INFINITE
+   if(iostat /= iostat_end)then
+      write(*,*)'error reading input:',iomsg
+   endif
+end program demo_getline
+
+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + integer, + intent(in) + + ::unit +

Formatted IO unit

+
+ + character(len=:), + intent(out), + allocatable + ::line +

Line to read

+
+ + integer, + intent(out) + + ::iostat +

Status of operation

+
+ + character(len=:), + optional, + allocatable + ::iomsg +

Error message

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
subroutine getline(unit, line, iostat, iomsg)
+
+    !> Formatted IO unit
+    integer, intent(in) :: unit
+
+    !> Line to read
+    character(len=:), allocatable, intent(out) :: line
+
+    !> Status of operation
+    integer, intent(out) :: iostat
+
+    !> Error message
+    character(len=:), allocatable, optional :: iomsg
+
+    integer, parameter :: BUFFER_SIZE = 1024
+    character(len=BUFFER_SIZE)       :: buffer
+    character(len=256)               :: msg
+    integer :: size
+    integer :: stat
+
+    allocate(character(len=0) :: line)
+    do
+        read(unit, '(a)', advance='no', iostat=stat, iomsg=msg, size=size) &
+            & buffer
+        if (stat > 0) exit
+        line = line // buffer(:size)
+        if (stat < 0) then
+            if (is_iostat_eor(stat)) then
+                stat = 0
+            end if
+            exit
+        end if
+    end do
+
+    if (stat /= 0) then
+        if (present(iomsg)) iomsg = trim(msg)
+    end if
+    iostat = stat
+
+end subroutine getline
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/git_archive.html b/proc/git_archive.html new file mode 100644 index 0000000000..fa2c0166e7 --- /dev/null +++ b/proc/git_archive.html @@ -0,0 +1,422 @@ + + + + + + + + + + + + + git_archive – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

git_archive + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine git_archive(source, destination, ref, additional_files, verbose, error) +

+ + +

Archive a folder using git archive.

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::source +

Directory to archive.

+
+ + character(len=*), + intent(in) + + ::destination +

Destination of the archive.

+
+ + character(len=*), + intent(in) + + ::ref +

(Symbolic) Reference to be archived.

+
+ + character(len=*), + intent(in),optional + + ::additional_files(:) +

(Optional) list of additional untracked files to be added to the archive.

+
+ + logical, + intent(in) + + ::verbose +

Print additional information if true.

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling.

+
+ +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=:), + public, + allocatable + ::add_files + +
+ + character(len=:), + public, + allocatable + ::archive_format + +
+ + character(len=:), + public, + allocatable + ::cmd_output + +
+ + integer, + public + + ::i + +
+ + integer, + public + + ::stat + +
+ +
+
+ + + + + + + + + + +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/git_is_same.html b/proc/git_is_same.html new file mode 100644 index 0000000000..ce436ebff5 --- /dev/null +++ b/proc/git_is_same.html @@ -0,0 +1,293 @@ + + + + + + + + + + + + + git_is_same – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

git_is_same + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function git_is_same(this, that) +

+ + +

Check that two git targets are equal +All checks passed!

+ +

Type Bound

+

git_target_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(git_target_t), + intent(in) + + ::this + +
+ + class(serializable_t), + intent(in) + + ::that + +
+ +

Return Value + + + logical + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
    logical function git_is_same(this,that)
+        class(git_target_t), intent(in) :: this
+        class(serializable_t), intent(in) :: that
+
+        git_is_same = .false.
+
+        select type (other=>that)
+           type is (git_target_t)
+              if (.not.(this%descriptor==other%descriptor)) return
+              if (allocated(this%url) .neqv. allocated(other%url)) return
+              if (allocated(this%url)) then
+                if (.not.(this%url==other%url)) return
+              end if
+              if (allocated(this%object) .neqv. allocated(other%object)) return
+              if (allocated(this%object)) then
+                if (.not.(this%object==other%object)) return
+              end if
+           class default
+              ! Not the same type
+              return
+        end select
+
+        !> All checks passed!
+        git_is_same = .true.
+
+    end function git_is_same
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/git_matches_manifest.html b/proc/git_matches_manifest.html new file mode 100644 index 0000000000..d3608521f5 --- /dev/null +++ b/proc/git_matches_manifest.html @@ -0,0 +1,323 @@ + + + + + + + + + + + + + git_matches_manifest – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

git_matches_manifest + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function git_matches_manifest(cached, manifest, verbosity, iunit) +

+ + +

Check that a cached dependency matches a manifest request

+

The manifest dependency only contains partial information (what’s requested), +while the cached dependency always stores a commit hash because it’s built +after the repo is available (saved as git_descriptor%revision==revision). +So, comparing against the descriptor is not reliable

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(git_target_t), + intent(in) + + ::cached +

Two input git targets

+
+ + type(git_target_t), + intent(in) + + ::manifest +

Two input git targets

+
+ + integer, + intent(in) + + ::verbosity + +
+ + integer, + intent(in) + + ::iunit + +
+ +

Return Value + + + logical + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
    logical function git_matches_manifest(cached,manifest,verbosity,iunit)
+
+        !> Two input git targets
+        type(git_target_t), intent(in) :: cached,manifest
+
+        integer, intent(in) :: verbosity,iunit
+
+        git_matches_manifest = cached%url == manifest%url
+        if (.not.git_matches_manifest) then
+            if (verbosity>1) write(iunit,out_fmt) "GIT URL has changed: ",cached%url," vs. ", manifest%url
+            return
+        endif
+
+        !> The manifest dependency only contains partial information (what's requested),
+        !> while the cached dependency always stores a commit hash because it's built
+        !> after the repo is available (saved as git_descriptor%revision==revision).
+        !> So, comparing against the descriptor is not reliable
+        git_matches_manifest = allocated(cached%object) .eqv. allocated(manifest%object)
+        if (git_matches_manifest .and. allocated(cached%object)) &
+        git_matches_manifest = cached%object == manifest%object
+        if (.not.git_matches_manifest) then
+            if (verbosity>1) write(iunit,out_fmt) "GIT OBJECT has changed: ",cached%object," vs. ", manifest%object
+        end if
+
+    end function git_matches_manifest
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/git_revision.html b/proc/git_revision.html new file mode 100644 index 0000000000..920c56925a --- /dev/null +++ b/proc/git_revision.html @@ -0,0 +1,502 @@ + + + + + + + + + + + + + git_revision – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

git_revision + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine git_revision(local_path, object, error) +

+ + + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::local_path +

Local path to checkout in

+
+ + character(len=:), + intent(out), + allocatable + ::object +

Git object reference

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error

+
+ +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=*), + public, +parameter + ::hexdigits ='0123456789abcdef' + +
+ + integer, + public + + ::iend + +
+ + character(len=:), + public, + allocatable + ::iomsg + +
+ + integer, + public + + ::istart + +
+ + character(len=:), + public, + allocatable + ::line + +
+ + integer, + public + + ::stat + +
+ + character(len=:), + public, + allocatable + ::temp_file + +
+ + integer, + public + + ::unit + +
+ + character(len=:), + public, + allocatable + ::workdir + +
+ +
+
+ + + + + + + + + +
+

Source Code

+
    subroutine git_revision(local_path, object, error)
+
+        !> Local path to checkout in
+        character(*), intent(in) :: local_path
+
+        !> Git object reference
+        character(len=:), allocatable, intent(out) :: object
+
+        !> Error
+        type(error_t), allocatable, intent(out) :: error
+
+        integer :: stat, unit, istart, iend
+        character(len=:), allocatable :: temp_file, line, iomsg, workdir
+        character(len=*), parameter :: hexdigits = '0123456789abcdef'
+
+        workdir = "--work-tree="//local_path//" --git-dir="//join_path(local_path, ".git")
+        allocate(temp_file, source=get_temp_filename())
+        line = "git "//workdir//" log -n 1 > "//temp_file
+        call execute_command_line(line, exitstat=stat)
+
+        if (stat /= 0) then
+            call fatal_error(error, "Error while retrieving commit information")
+            return
+        end if
+
+        open(file=temp_file, newunit=unit)
+        call getline(unit, line, stat, iomsg)
+
+        if (stat /= 0) then
+            call fatal_error(error, iomsg)
+            return
+        end if
+        close(unit, status="delete")
+
+        ! Tokenize:
+        ! commit 0123456789abcdef (HEAD, ...)
+        istart = scan(line, ' ') + 1
+        iend = verify(line(istart:), hexdigits) + istart - 1
+        if (iend < istart) iend = len(line)
+        object = line(istart:iend)
+
+    end subroutine git_revision
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/git_target_branch.html b/proc/git_target_branch.html new file mode 100644 index 0000000000..15ebb9b251 --- /dev/null +++ b/proc/git_target_branch.html @@ -0,0 +1,280 @@ + + + + + + + + + + + + + git_target_branch – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

git_target_branch + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function git_target_branch(url, branch) result(self) +

+ + +

Target a branch in the git repository

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::url +

Target URL of the git repository

+
+ + character(len=*), + intent(in) + + ::branch +

Name of the branch of interest

+
+ +

Return Value + + + type(git_target_t) + +

+

New git target

+
+ + + + + + + + + + + +
+

Source Code

+
    function git_target_branch(url, branch) result(self)
+
+        !> Target URL of the git repository
+        character(len=*), intent(in) :: url
+
+        !> Name of the branch of interest
+        character(len=*), intent(in) :: branch
+
+        !> New git target
+        type(git_target_t) :: self
+
+        self%descriptor = git_descriptor%branch
+        self%url = url
+        self%object = branch
+
+    end function git_target_branch
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/git_target_default.html b/proc/git_target_default.html new file mode 100644 index 0000000000..1de99eccaf --- /dev/null +++ b/proc/git_target_default.html @@ -0,0 +1,261 @@ + + + + + + + + + + + + + git_target_default – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

git_target_default + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function git_target_default(url) result(self) +

+ + +

Default target

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::url +

Target URL of the git repository

+
+ +

Return Value + + + type(git_target_t) + +

+

New git target

+
+ + + + + + + + + + + +
+

Source Code

+
    function git_target_default(url) result(self)
+
+        !> Target URL of the git repository
+        character(len=*), intent(in) :: url
+
+        !> New git target
+        type(git_target_t) :: self
+
+        self%descriptor = git_descriptor%default
+        self%url = url
+
+    end function git_target_default
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/git_target_revision.html b/proc/git_target_revision.html new file mode 100644 index 0000000000..d9f077f02a --- /dev/null +++ b/proc/git_target_revision.html @@ -0,0 +1,280 @@ + + + + + + + + + + + + + git_target_revision – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

git_target_revision + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function git_target_revision(url, sha1) result(self) +

+ + +

Target a specific git revision

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::url +

Target URL of the git repository

+
+ + character(len=*), + intent(in) + + ::sha1 +

Commit hash of interest

+
+ +

Return Value + + + type(git_target_t) + +

+

New git target

+
+ + + + + + + + + + + +
+

Source Code

+
    function git_target_revision(url, sha1) result(self)
+
+        !> Target URL of the git repository
+        character(len=*), intent(in) :: url
+
+        !> Commit hash of interest
+        character(len=*), intent(in) :: sha1
+
+        !> New git target
+        type(git_target_t) :: self
+
+        self%descriptor = git_descriptor%revision
+        self%url = url
+        self%object = sha1
+
+    end function git_target_revision
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/git_target_tag.html b/proc/git_target_tag.html new file mode 100644 index 0000000000..f4cc812ffb --- /dev/null +++ b/proc/git_target_tag.html @@ -0,0 +1,280 @@ + + + + + + + + + + + + + git_target_tag – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

git_target_tag + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function git_target_tag(url, tag) result(self) +

+ + +

Target a git tag

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::url +

Target URL of the git repository

+
+ + character(len=*), + intent(in) + + ::tag +

Tag name of interest

+
+ +

Return Value + + + type(git_target_t) + +

+

New git target

+
+ + + + + + + + + + + +
+

Source Code

+
    function git_target_tag(url, tag) result(self)
+
+        !> Target URL of the git repository
+        character(len=*), intent(in) :: url
+
+        !> Tag name of interest
+        character(len=*), intent(in) :: tag
+
+        !> New git target
+        type(git_target_t) :: self
+
+        self%descriptor = git_descriptor%tag
+        self%url = url
+        self%object = tag
+
+    end function git_target_tag
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/glob.html b/proc/glob.html new file mode 100644 index 0000000000..6f16a43d3d --- /dev/null +++ b/proc/glob.html @@ -0,0 +1,581 @@ + + + + + + + + + + + + + glob – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

glob + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function glob(tame, wild) +

+ + +

NAME

+
glob(3f) - [fpm_strings:COMPARE] compare given string for match to
+pattern which may contain wildcard characters
+(LICENSE:PD)
+
+ +

SYNOPSIS

+
logical function glob(string, pattern )
+
+ character(len=*),intent(in) :: string
+ character(len=*),intent(in) :: pattern
+
+ +

DESCRIPTION

+

glob(3f) compares given STRING for match to PATTERN which may + contain wildcard characters.

+

In this version to get a match the entire string must be described + by PATTERN. Trailing whitespace is significant, so trim the input + string to have trailing whitespace ignored.

+

OPTIONS

+
string   the input string to test to see if it contains the pattern.
+pattern  the following simple globbing options are available
+
+         o "?" matching any one character
+         o "*" matching zero or more characters.
+           Do NOT use adjacent asterisks.
+         o Both strings may have trailing spaces which
+           are ignored.
+         o There is no escape character, so matching strings with
+           literal question mark and asterisk is problematic.
+
+ +

EXAMPLES

+

Example program

+
program demo_glob
+implicit none
+! This main() routine passes a bunch of test strings
+! into the above code.  In performance comparison mode,
+! it does that over and over. Otherwise, it does it just
+! once. Either way, it outputs a passed/failed result.
+!
+integer :: nReps
+logical :: allpassed
+integer :: i
+ allpassed = .true.
+
+ nReps = 10000
+ ! Can choose as many repetitions as you're expecting
+ ! in the real world.
+ nReps = 1
+
+ do i=1,nReps
+  ! Cases with repeating character sequences.
+  allpassed=allpassed .and. test("a*abab", "a*b", .true.)
+  !!cycle
+  allpassed=allpassed .and. test("ab", "*?", .true.)
+  allpassed=allpassed .and. test("abc", "*?", .true.)
+  allpassed=allpassed .and. test("abcccd", "*ccd", .true.)
+  allpassed=allpassed .and. test("bLah", "bLaH", .false.)
+  allpassed=allpassed .and. test("mississippi", "*sip*", .true.)
+  allpassed=allpassed .and. &
+   & test("xxxx*zzzzzzzzy*f", "xxx*zzy*f", .true.)
+  allpassed=allpassed .and. &
+   & test("xxxx*zzzzzzzzy*f", "xxxx*zzy*fffff", .false.)
+  allpassed=allpassed .and. &
+   & test("mississipissippi", "*issip*ss*", .true.)
+  allpassed=allpassed .and. &
+   & test("xxxxzzzzzzzzyf", "xxxx*zzy*fffff", .false.)
+  allpassed=allpassed .and. &
+   & test("xxxxzzzzzzzzyf", "xxxx*zzy*f", .true.)
+  allpassed=allpassed .and. test("xyxyxyzyxyz", "xy*z*xyz", .true.)
+  allpassed=allpassed .and. test("xyxyxyxyz", "xy*xyz", .true.)
+  allpassed=allpassed .and. test("mississippi", "mi*sip*", .true.)
+  allpassed=allpassed .and. test("ababac", "*abac*", .true.)
+  allpassed=allpassed .and. test("aaazz", "a*zz*", .true.)
+  allpassed=allpassed .and. test("a12b12", "*12*23", .false.)
+  allpassed=allpassed .and. test("a12b12", "a12b", .false.)
+  allpassed=allpassed .and. test("a12b12", "*12*12*", .true.)
+
+  ! Additional cases where the '*' char appears in the tame string.
+  allpassed=allpassed .and. test("*", "*", .true.)
+  allpassed=allpassed .and. test("a*r", "a*", .true.)
+  allpassed=allpassed .and. test("a*ar", "a*aar", .false.)
+
+  ! More double wildcard scenarios.
+  allpassed=allpassed .and. test("XYXYXYZYXYz", "XY*Z*XYz", .true.)
+  allpassed=allpassed .and. test("missisSIPpi", "*SIP*", .true.)
+  allpassed=allpassed .and. test("mississipPI", "*issip*PI", .true.)
+  allpassed=allpassed .and. test("xyxyxyxyz", "xy*xyz", .true.)
+  allpassed=allpassed .and. test("miSsissippi", "mi*sip*", .true.)
+  allpassed=allpassed .and. test("miSsissippi", "mi*Sip*", .false.)
+  allpassed=allpassed .and. test("abAbac", "*Abac*", .true.)
+  allpassed=allpassed .and. test("aAazz", "a*zz*", .true.)
+  allpassed=allpassed .and. test("A12b12", "*12*23", .false.)
+  allpassed=allpassed .and. test("a12B12", "*12*12*", .true.)
+  allpassed=allpassed .and. test("oWn", "*oWn*", .true.)
+
+  ! Completely tame (no wildcards) cases.
+  allpassed=allpassed .and. test("bLah", "bLah", .true.)
+
+  ! Simple mixed wildcard tests suggested by IBMer Marlin Deckert.
+  allpassed=allpassed .and. test("a", "*?", .true.)
+
+  ! More mixed wildcard tests including coverage for false positives.
+  allpassed=allpassed .and. test("a", "??", .false.)
+  allpassed=allpassed .and. test("ab", "?*?", .true.)
+  allpassed=allpassed .and. test("ab", "*?*?*", .true.)
+  allpassed=allpassed .and. test("abc", "?**?*?", .true.)
+  allpassed=allpassed .and. test("abc", "?**?*&?", .false.)
+  allpassed=allpassed .and. test("abcd", "?b*??", .true.)
+  allpassed=allpassed .and. test("abcd", "?a*??", .false.)
+  allpassed=allpassed .and. test("abcd", "?**?c?", .true.)
+  allpassed=allpassed .and. test("abcd", "?**?d?", .false.)
+  allpassed=allpassed .and. test("abcde", "?*b*?*d*?", .true.)
+
+  ! Single-character-match cases.
+  allpassed=allpassed .and. test("bLah", "bL?h", .true.)
+  allpassed=allpassed .and. test("bLaaa", "bLa?", .false.)
+  allpassed=allpassed .and. test("bLah", "bLa?", .true.)
+  allpassed=allpassed .and. test("bLaH", "?Lah", .false.)
+  allpassed=allpassed .and. test("bLaH", "?LaH", .true.)
+
+  ! Many-wildcard scenarios.
+  allpassed=allpassed .and. test(&
+  &"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa&
+  &aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab",&
+  &"a*a*a*a*a*a*aa*aaa*a*a*b",&
+  &.true.)
+  allpassed=allpassed .and. test(&
+  &"abababababababababababababababababababaacacacacacacac&
+  &adaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab",&
+  &"*a*b*ba*ca*a*aa*aaa*fa*ga*b*",&
+  &.true.)
+  allpassed=allpassed .and. test(&
+  &"abababababababababababababababababababaacacacacacaca&
+  &cadaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab",&
+  &"*a*b*ba*ca*a*x*aaa*fa*ga*b*",&
+  &.false.)
+  allpassed=allpassed .and. test(&
+  &"abababababababababababababababababababaacacacacacacacad&
+  &aeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab",&
+  &"*a*b*ba*ca*aaaa*fa*ga*gggg*b*",&
+  &.false.)
+  allpassed=allpassed .and. test(&
+  &"abababababababababababababababababababaacacacacacacacad&
+  &aeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab",&
+  &"*a*b*ba*ca*aaaa*fa*ga*ggg*b*",&
+  &.true.)
+  allpassed=allpassed .and. test("aaabbaabbaab", "*aabbaa*a*", .true.)
+  allpassed=allpassed .and. &
+  test("a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*",&
+  &"a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*", .true.)
+  allpassed=allpassed .and. test("aaaaaaaaaaaaaaaaa",&
+  &"*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*", .true.)
+  allpassed=allpassed .and. test("aaaaaaaaaaaaaaaa",&
+  &"*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*", .false.)
+  allpassed=allpassed .and. test(&
+  &"abc*abcd*abcde*abcdef*abcdefg*abcdefgh*abcdefghi*abcdefghij&
+  &*abcdefghijk*abcdefghijkl*abcdefghijklm*abcdefghijklmn",&
+  & "abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc&
+  &*abc*abc*abc*",&
+  &.false.)
+  allpassed=allpassed .and. test(&
+  &"abc*abcd*abcde*abcdef*abcdefg*abcdefgh*abcdefghi*abcdefghij&
+  &*abcdefghijk*abcdefghijkl*abcdefghijklm*abcdefghijklmn",&
+  &"abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*",&
+  &.true.)
+  allpassed=allpassed .and. test("abc*abcd*abcd*abc*abcd",&
+  &"abc*abc*abc*abc*abc", .false.)
+  allpassed=allpassed .and. test( "abc*abcd*abcd*abc*abcd*abcd&
+  &*abc*abcd*abc*abc*abcd", &
+  &"abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abcd",&
+  &.true.)
+  allpassed=allpassed .and. test("abc",&
+  &"********a********b********c********", .true.)
+  allpassed=allpassed .and.&
+  &test("********a********b********c********", "abc", .false.)
+  allpassed=allpassed .and. &
+  &test("abc", "********a********b********b********", .false.)
+  allpassed=allpassed .and. test("*abc*", "***a*b*c***", .true.)
+
+  ! A case-insensitive algorithm test.
+  ! allpassed=allpassed .and. test("mississippi", "*issip*PI", .true.)
+ enddo
+
+ if (allpassed)then
+    write(*,'(a)')"Passed",nReps
+ else
+    write(*,'(a)')"Failed"
+ endif
+contains
+! This is a test program for wildcard matching routines.
+! It can be used either to test a single routine for correctness,
+! or to compare the timings of two (or more) different wildcard
+! matching routines.
+!
+function test(tame, wild, bExpectedResult) result(bpassed)
+use fpm_strings, only : glob
+   character(len=*) :: tame
+   character(len=*) :: wild
+   logical          :: bExpectedResult
+   logical          :: bResult
+   logical          :: bPassed
+   bResult = .true.    ! We'll do "&=" cumulative checking.
+   bPassed = .false.   ! Assume the worst.
+   write(*,*)repeat('=',79)
+   bResult = glob(tame, wild) ! Call a wildcard matching routine.
+
+   ! To assist correctness checking, output the two strings in any
+   ! failing scenarios.
+   if (bExpectedResult .eqv. bResult) then
+      bPassed = .true.
+      if(nReps == 1) write(*,*)"Passed match on ",tame," vs. ", wild
+   else
+      if(nReps == 1) write(*,*)"Failed match on ",tame," vs. ", wild
+   endif
+
+end function test
+end program demo_glob
+
+ +

Expected output

+

REFERENCE

+

The article “Matching Wildcards: An Empirical Way to Tame an Algorithm” + in Dr Dobb’s Journal, By Kirk J. Krauss, October 07, 2014

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*) + + + ::tame +

A string without wildcards to compare to the globbing expression

+
+ + character(len=*) + + + ::wild +

A (potentially) corresponding string with wildcards

+
+ +

Return Value + + + logical + +

+

result of test

+
+ + + + + + + + + + + +
+

Source Code

+
function glob(tame,wild)
+
+! @(#)fpm_strings::glob(3f): function compares text strings, one of which can have wildcards ('*' or '?').
+
+logical                    :: glob       !! result of test
+character(len=*)           :: tame       !! A string without wildcards to compare to the globbing expression
+character(len=*)           :: wild       !! A (potentially) corresponding string with wildcards
+character(len=len(tame)+1) :: tametext
+character(len=len(wild)+1) :: wildtext
+character(len=1),parameter :: NULL=char(0)
+integer                    :: wlen
+integer                    :: ti, wi
+integer                    :: i
+character(len=:),allocatable :: tbookmark, wbookmark
+! These two values are set when we observe a wildcard character. They
+! represent the locations, in the two strings, from which we start once we've observed it.
+   tametext=tame//NULL
+   wildtext=wild//NULL
+   tbookmark = NULL
+   wbookmark = NULL
+   wlen=len(wild)
+   wi=1
+   ti=1
+   do                                            ! Walk the text strings one character at a time.
+      if(wildtext(wi:wi) == '*')then             ! How do you match a unique text string?
+         do i=wi,wlen                            ! Easy: unique up on it!
+            if(wildtext(wi:wi)=='*')then
+               wi=wi+1
+            else
+               exit
+            endif
+         enddo
+         if(wildtext(wi:wi)==NULL) then        ! "x" matches "*"
+            glob=.true.
+            return
+         endif
+         if(wildtext(wi:wi) /= '?') then
+            ! Fast-forward to next possible match.
+            do while (tametext(ti:ti) /= wildtext(wi:wi))
+               ti=ti+1
+               if (tametext(ti:ti)==NULL)then
+                  glob=.false.
+                  return                         ! "x" doesn't match "*y*"
+               endif
+            enddo
+         endif
+         wbookmark = wildtext(wi:)
+         tbookmark = tametext(ti:)
+      elseif(tametext(ti:ti) /= wildtext(wi:wi) .and. wildtext(wi:wi) /= '?') then
+         ! Got a non-match. If we've set our bookmarks, back up to one or both of them and retry.
+         if(wbookmark/=NULL) then
+            if(wildtext(wi:)/= wbookmark) then
+               wildtext = wbookmark;
+               wlen=len_trim(wbookmark)
+               wi=1
+               ! Don't go this far back again.
+               if (tametext(ti:ti) /= wildtext(wi:wi)) then
+                  tbookmark=tbookmark(2:)
+                  tametext = tbookmark
+                  ti=1
+                  cycle                          ! "xy" matches "*y"
+               else
+                  wi=wi+1
+               endif
+            endif
+            if (tametext(ti:ti)/=NULL) then
+               ti=ti+1
+               cycle                             ! "mississippi" matches "*sip*"
+            endif
+         endif
+         glob=.false.
+         return                                  ! "xy" doesn't match "x"
+      endif
+      ti=ti+1
+      wi=wi+1
+      if (tametext(ti:ti)==NULL) then          ! How do you match a tame text string?
+         if(wildtext(wi:wi)/=NULL)then
+            do while (wildtext(wi:wi) == '*')    ! The tame way: unique up on it!
+               wi=wi+1                           ! "x" matches "x*"
+               if(wildtext(wi:wi)==NULL)exit
+            enddo
+         endif
+         if (wildtext(wi:wi)==NULL)then
+            glob=.true.
+            return                               ! "x" matches "x"
+         endif
+         glob=.false.
+         return                                  ! "x" doesn't match "xy"
+      endif
+   enddo
+end function glob
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/handle_error~4.html b/proc/handle_error~4.html new file mode 100644 index 0000000000..3ea13f6e37 --- /dev/null +++ b/proc/handle_error~4.html @@ -0,0 +1,248 @@ + + + + + + + + + + + + + handle_error – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

handle_error + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

subroutine handle_error(error_) +

+ + + + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(error_t), + intent(in),optional + + ::error_ + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
    subroutine handle_error(error_)
+        type(error_t), optional, intent(in) :: error_
+        if (present(error_)) then
+            write (error_unit, '("[Error]", 1x, a)') error_%message
+            stop 1
+        end if
+    end subroutine handle_error
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/has_list.html b/proc/has_list.html new file mode 100644 index 0000000000..c5f7039bae --- /dev/null +++ b/proc/has_list.html @@ -0,0 +1,284 @@ + + + + + + + + + + + + + has_list – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

has_list + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function has_list(table, key) +

+ + +

Check if an instance of the TOML data structure contains a list

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(toml_table), + intent(inout) + + ::table +

Instance of the TOML data structure

+
+ + character(len=*), + intent(in) + + ::key +

Key to read from

+
+ +

Return Value + + + logical + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
    logical function has_list(table, key)
+
+        !> Instance of the TOML data structure
+        type(toml_table), intent(inout) :: table
+
+        !> Key to read from
+        character(len=*), intent(in) :: key
+
+        type(toml_array), pointer :: children
+
+        has_list = .false.
+
+        if (.not.table%has_key(key)) return
+
+        call get_value(table, key, children, requested=.false.)
+
+        ! There is an allocated list
+        has_list = associated(children)
+
+    end function has_list
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/has_manifest.html b/proc/has_manifest.html new file mode 100644 index 0000000000..5deb8be574 --- /dev/null +++ b/proc/has_manifest.html @@ -0,0 +1,254 @@ + + + + + + + + + + + + + has_manifest – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

has_manifest + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

function has_manifest(dir) +

+ + + + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::dir + +
+ +

Return Value + + + logical + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
    function has_manifest(dir)
+        character(len=*), intent(in) :: dir
+        logical :: has_manifest
+
+        has_manifest = exists(join_path(dir, "fpm.toml"))
+    end function has_manifest
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/has_valid_custom_prefix.html b/proc/has_valid_custom_prefix.html new file mode 100644 index 0000000000..cdbbceef80 --- /dev/null +++ b/proc/has_valid_custom_prefix.html @@ -0,0 +1,315 @@ + + + + + + + + + + + + + has_valid_custom_prefix – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

has_valid_custom_prefix + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function has_valid_custom_prefix(module_name, custom_prefix) result(valid) +

+ + +

Check that a module name is prefixed with a custom prefix: +1) It must be a valid FORTRAN name subset (<=63 chars, begin with letter, only alphanumeric allowed) +2) It must begin with the prefix +3) If longer, package name must be followed by default separator (“_”) plus at least one char

+

Basic check: check that both names are individually valid

+

FPM package enforcing: check that the module name begins with the custom prefix

+

Query string lengths +2) It must begin with the package name. +3) It can be equal to the package name, or, if longer, must be followed by the +4) Package name must not end with an underscore

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(string_t), + intent(in) + + ::module_name + +
+ + type(string_t), + intent(in) + + ::custom_prefix + +
+ +

Return Value + + + logical + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
logical function has_valid_custom_prefix(module_name,custom_prefix) result(valid)
+
+    type(string_t), intent(in) :: module_name
+    type(string_t), intent(in) :: custom_prefix
+
+    !> custom_module separator: single underscore
+    character(*), parameter :: SEP = "_"
+
+    logical :: is_same,has_separator,same_beginning
+    integer :: lpkg,lmod,lsep
+
+    !> Basic check: check that both names are individually valid
+    valid = is_fortran_name(module_name%s) .and. &
+            is_valid_module_prefix(custom_prefix)
+
+    !> FPM package enforcing: check that the module name begins with the custom prefix
+    if (valid) then
+
+        !> Query string lengths
+        lpkg  = len_trim(custom_prefix)
+        lmod  = len_trim(module_name)
+        lsep  = len_trim(SEP)
+
+        same_beginning = str_begins_with_str(module_name%s,custom_prefix%s,case_sensitive=.false.)
+
+        is_same = lpkg==lmod .and. same_beginning
+
+        if (lmod>=lpkg+lsep) then
+           has_separator = str_begins_with_str(module_name%s(lpkg+1:lpkg+lsep),SEP)
+        else
+           has_separator = .false.
+        endif
+
+        !> 2) It must begin with the package name.
+        !> 3) It can be equal to the package name, or, if longer, must be followed by the
+        !     default separator plus at least one character
+        !> 4) Package name must not end with an underscore
+        valid = same_beginning .and. (is_same .or. (lmod>lpkg+lsep .and. has_separator))
+
+    end if
+
+end function has_valid_custom_prefix
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/has_valid_standard_prefix.html b/proc/has_valid_standard_prefix.html new file mode 100644 index 0000000000..be900ee02a --- /dev/null +++ b/proc/has_valid_standard_prefix.html @@ -0,0 +1,319 @@ + + + + + + + + + + + + + has_valid_standard_prefix – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

has_valid_standard_prefix + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function has_valid_standard_prefix(module_name, package_name) result(valid) +

+ + +

Check that a module name is prefixed with the default package prefix: +1) It must be a valid FORTRAN name (<=63 chars, begin with letter, “_” is only allowed non-alphanumeric) +2) It must begin with the package name +3) If longer, package name must be followed by default separator plus at least one char

+

Basic check: check the name is Fortran-compliant

+

FPM package enforcing: check that the module name begins with the package name

+

Query string lengths +2) It must begin with the package name. +3) It can be equal to the package name, or, if longer, must be followed by the +4) Package name must not end with an underscore

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(string_t), + intent(in) + + ::module_name + +
+ + type(string_t), + intent(in) + + ::package_name + +
+ +

Return Value + + + logical + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
logical function has_valid_standard_prefix(module_name,package_name) result(valid)
+
+    type(string_t), intent(in) :: module_name
+    type(string_t), intent(in) :: package_name
+
+    !> Default package__module separator: two underscores
+    character(*), parameter :: SEP = "__"
+
+    character(len=:), allocatable :: fortranized_pkg
+    logical :: is_same,has_separator,same_beginning
+    integer :: lpkg,lmod,lsep
+
+    !> Basic check: check the name is Fortran-compliant
+    valid = is_fortran_name(module_name%s)
+
+    !> FPM package enforcing: check that the module name begins with the package name
+    if (valid) then
+
+        fortranized_pkg = to_fortran_name(package_name%s)
+
+        !> Query string lengths
+        lpkg  = len_trim(fortranized_pkg)
+        lmod  = len_trim(module_name)
+        lsep  = len_trim(SEP)
+
+        same_beginning = str_begins_with_str(module_name%s,fortranized_pkg,case_sensitive=.false.)
+
+        is_same = lpkg==lmod .and. same_beginning
+
+        if (lmod>=lpkg+lsep) then
+           has_separator = str_begins_with_str(module_name%s(lpkg+1:lpkg+lsep),SEP)
+        else
+           has_separator = .false.
+        endif
+
+        !> 2) It must begin with the package name.
+        !> 3) It can be equal to the package name, or, if longer, must be followed by the
+        !     default separator plus at least one character
+        !> 4) Package name must not end with an underscore
+        valid = is_fortran_name(fortranized_pkg) .and. &
+                fortranized_pkg(lpkg:lpkg)/='_' .and. &
+                (same_beginning .and. (is_same .or. (lmod>lpkg+lsep .and. has_separator)))
+
+    end if
+
+end function has_valid_standard_prefix
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/info_profile.html b/proc/info_profile.html new file mode 100644 index 0000000000..8ee2339210 --- /dev/null +++ b/proc/info_profile.html @@ -0,0 +1,343 @@ + + + + + + + + + + + + + info_profile – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

info_profile + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function info_profile(profile) result(s) +

+ + +

Print a representation of profile_config_t

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(profile_config_t), + intent(in) + + ::profile +

Profile to be represented

+
+ +

Return Value + + + character(len=:), allocatable + +

+

String representation of given profile

+
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + integer, + public + + ::i + +
+ +
+
+ + + + + + + + + +
+

Source Code

+
      function info_profile(profile) result(s)
+
+        !> Profile to be represented
+        type(profile_config_t), intent(in) :: profile
+
+        !> String representation of given profile
+        character(:), allocatable :: s
+
+        integer :: i
+
+        s = "profile_config_t("
+        s = s // 'profile_name="' // profile%profile_name // '"'
+        s = s // ', compiler="' // profile%compiler // '"'
+        s = s // ", os_type="
+        select case(profile%os_type)
+        case (OS_UNKNOWN)
+          s = s // "OS_UNKNOWN"
+        case (OS_LINUX)
+          s = s // "OS_LINUX"
+        case (OS_MACOS)
+          s = s // "OS_MACOS"
+        case (OS_WINDOWS)
+          s = s // "OS_WINDOWS"
+        case (OS_CYGWIN)
+          s = s // "OS_CYGWIN"
+        case (OS_SOLARIS)
+          s = s // "OS_SOLARIS"
+        case (OS_FREEBSD)
+          s = s // "OS_FREEBSD"
+        case (OS_OPENBSD)
+          s = s // "OS_OPENBSD"
+        case (OS_ALL)
+          s = s // "OS_ALL"
+        case default
+          s = s // "INVALID"
+        end select
+        if (allocated(profile%flags)) s = s // ', flags="' // profile%flags // '"'
+        if (allocated(profile%c_flags)) s = s // ', c_flags="' // profile%c_flags // '"'
+        if (allocated(profile%cxx_flags)) s = s // ', cxx_flags="' // profile%cxx_flags // '"'
+        if (allocated(profile%link_time_flags)) s = s // ', link_time_flags="' // profile%link_time_flags // '"'
+        if (allocated(profile%file_scope_flags)) then
+          do i=1,size(profile%file_scope_flags)
+            s = s // ', flags for '//profile%file_scope_flags(i)%file_name// &
+                    & ' ="' // profile%file_scope_flags(i)%flags // '"'
+          end do
+        end if
+        s = s // ")"
+
+      end function info_profile
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/info~4.html b/proc/info~4.html new file mode 100644 index 0000000000..fd2e1bcbea --- /dev/null +++ b/proc/info~4.html @@ -0,0 +1,377 @@ + + + + + + + + + + + + + info – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

info + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine info(self, unit, verbosity) +

+ + +

Show information on git target

+ +

Type Bound

+

git_target_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(git_target_t), + intent(in) + + ::self +

Instance of the git target

+
+ + integer, + intent(in) + + ::unit +

Unit for IO

+
+ + integer, + intent(in),optional + + ::verbosity +

Verbosity of the printout

+
+ +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=*), + public, +parameter + ::fmt ='("#", 1x, a, t30, a)' + +
+ + integer, + public + + ::pr + +
+ +
+
+ + + + + + + + + +
+

Source Code

+
    subroutine info(self, unit, verbosity)
+
+        !> Instance of the git target
+        class(git_target_t), intent(in) :: self
+
+        !> Unit for IO
+        integer, intent(in) :: unit
+
+        !> Verbosity of the printout
+        integer, intent(in), optional :: verbosity
+
+        integer :: pr
+        character(len=*), parameter :: fmt = '("#", 1x, a, t30, a)'
+
+        if (present(verbosity)) then
+            pr = verbosity
+        else
+            pr = 1
+        end if
+
+        if (pr < 1) return
+
+        write(unit, fmt) "Git target"
+        if (allocated(self%url)) then
+            write(unit, fmt) "- URL", self%url
+        end if
+        if (allocated(self%object)) then
+            select case(self%descriptor)
+            case default
+                write(unit, fmt) "- object", self%object
+            case(git_descriptor%tag)
+                write(unit, fmt) "- tag", self%object
+            case(git_descriptor%branch)
+                write(unit, fmt) "- branch", self%object
+            case(git_descriptor%revision)
+                write(unit, fmt) "- sha1", self%object
+            end select
+        end if
+
+    end subroutine info
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/info~8.html b/proc/info~8.html new file mode 100644 index 0000000000..fd7426d4dd --- /dev/null +++ b/proc/info~8.html @@ -0,0 +1,373 @@ + + + + + + + + + + + + + info – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

info + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine info(self, unit, verbosity) +

+ + +

Write information on instance

+ +

Type Bound

+

profile_config_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(profile_config_t), + intent(in) + + ::self +

Instance of the profile configuration

+
+ + integer, + intent(in) + + ::unit +

Unit for IO

+
+ + integer, + intent(in),optional + + ::verbosity +

Verbosity of the printout

+
+ +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=*), + public, +parameter + ::fmt ='("#", 1x, a, t30, a)' + +
+ + integer, + public + + ::pr + +
+ +
+
+ + + + + + + + + +
+

Source Code

+
      subroutine info(self, unit, verbosity)
+
+        !> Instance of the profile configuration
+        class(profile_config_t), intent(in) :: self
+
+        !> Unit for IO
+        integer, intent(in) :: unit
+
+        !> Verbosity of the printout
+        integer, intent(in), optional :: verbosity
+
+        integer :: pr
+        character(len=*), parameter :: fmt = '("#", 1x, a, t30, a)'
+
+        if (present(verbosity)) then
+            pr = verbosity
+        else
+            pr = 1
+        end if
+
+        write(unit, fmt) "Profile"
+        if (allocated(self%profile_name)) then
+            write(unit, fmt) "- profile name", self%profile_name
+        end if
+
+        if (allocated(self%compiler)) then
+            write(unit, fmt) "- compiler", self%compiler
+        end if
+
+        write(unit, fmt) "- os", os_type_name(self%os_type)
+
+        if (allocated(self%flags)) then
+            write(unit, fmt) "- compiler flags", self%flags
+        end if
+
+      end subroutine info
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/init_blas.html b/proc/init_blas.html new file mode 100644 index 0000000000..30c864d730 --- /dev/null +++ b/proc/init_blas.html @@ -0,0 +1,349 @@ + + + + + + + + + + + + + init_blas – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

init_blas + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine init_blas(this, compiler, all_meta, error) +

+ + +

Initialize blas metapackage for the current system +Cleanup +Set name

+

Assert pkg-config is installed

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(metapackage_t), + intent(inout) + + ::this + +
+ + type(compiler_t), + intent(in) + + ::compiler + +
+ + type(metapackage_request_t), + intent(in) + + ::all_meta(:) + +
+ + type(error_t), + intent(out), + allocatable + ::error + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
    subroutine init_blas(this, compiler, all_meta, error)
+        class(metapackage_t), intent(inout) :: this
+        type(compiler_t), intent(in) :: compiler
+        type(metapackage_request_t), intent(in) :: all_meta(:)
+        type(error_t), allocatable, intent(out) :: error
+
+        integer :: i
+        character(len=:), allocatable :: include_flag, libdir
+        character(*), parameter :: candidates(*) = &
+                                   [character(20) :: 'mkl-dynamic-lp64-tbb', 'openblas', 'blas']
+
+        include_flag = get_include_flag(compiler, "")
+
+        !> Cleanup
+        call destroy(this)
+        allocate (this%link_libs(0), this%incl_dirs(0), this%external_modules(0))
+        this%link_flags = string_t("")
+        this%flags = string_t("")
+        this%has_external_modules = .false.
+        
+        !> Set name
+        this%name = ""
+
+        if (get_os_type() == OS_MACOS) then
+            if (compile_and_link_flags_supported(compiler, "-framework Accelerate")) then
+                call set_compile_and_link_flags(this, compiler, "-framework Accelerate")
+                return
+            end if
+        end if
+
+        if (compiler%is_intel()) then
+            if (get_os_type() == OS_WINDOWS) then
+                if (compile_and_link_flags_supported(compiler, "/Qmkl")) then
+                    call set_compile_and_link_flags(this, compiler, "/Qmkl")
+                    return
+                end if
+            else if (compile_and_link_flags_supported(compiler, "-qmkl")) then
+                call set_compile_and_link_flags(this, compiler, "-qmkl")
+                return
+            endif
+        end if
+
+        !> Assert pkg-config is installed
+        if (.not. assert_pkg_config()) then
+            call fatal_error(error, 'blas metapackage requires pkg-config to continue lookup')
+            return
+        end if
+
+        do i = 1, size(candidates)
+            if (pkgcfg_has_package(trim(candidates(i)))) then
+                call add_pkg_config_compile_options( &
+                    this, trim(candidates(i)), include_flag, libdir, error)
+                print *, 'found blas package: ', trim(candidates(i))
+                return
+            end if
+        end do
+
+        call fatal_error(error, 'pkg-config could not find a suitable blas package.')
+    end subroutine init_blas
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/init_hdf5.html b/proc/init_hdf5.html new file mode 100644 index 0000000000..ff82061b54 --- /dev/null +++ b/proc/init_hdf5.html @@ -0,0 +1,423 @@ + + + + + + + + + + + + + init_hdf5 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

init_hdf5 + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine init_hdf5(this, compiler, all_meta, error) +

+ + +

Initialize HDF5 metapackage for the current system +Cleanup +Set name

+

Assert pkg-config is installed +Find pkg-config package file by priority +some distros put hdf5-1.2.3.pc with version number in .pc filename. +Add HDF5 modules as external

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(metapackage_t), + intent(inout) + + ::this + +
+ + type(compiler_t), + intent(in) + + ::compiler + +
+ + type(metapackage_request_t), + intent(in) + + ::all_meta(:) + +
+ + type(error_t), + intent(out), + allocatable + ::error + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
    subroutine init_hdf5(this,compiler,all_meta,error)
+        class(metapackage_t), intent(inout) :: this
+        type(compiler_t), intent(in) :: compiler
+        type(metapackage_request_t), intent(in) :: all_meta(:)
+        type(error_t), allocatable, intent(out) :: error
+
+        character(*), parameter :: find_hl(*) = &
+                     [character(11) :: '_hl_fortran','hl_fortran','_fortran','_hl']
+        character(*), parameter :: candidates(*) = &
+                     [character(15) :: 'hdf5_hl_fortran','hdf5-hl-fortran','hdf5_fortran','hdf5-fortran',&
+                                       'hdf5_hl','hdf5','hdf5-serial']
+
+        integer :: i,j,k,l
+        logical :: s,found_hl(size(find_hl)),found
+        type(string_t) :: log,this_lib
+        type(string_t), allocatable :: libs(:),flags(:),modules(:),non_fortran(:)
+        character(len=:), allocatable :: name, include_flag, libdir, ext, pref
+
+        include_flag = get_include_flag(compiler,"")
+
+        !> Cleanup
+        call destroy(this)
+        allocate(this%link_libs(0),this%incl_dirs(0),this%external_modules(0),non_fortran(0))
+        this%link_flags = string_t("")
+        this%flags = string_t("")
+        
+        !> Set name
+        this%name = "hdf5"
+
+        !> Assert pkg-config is installed
+        if (.not.assert_pkg_config()) then
+            call fatal_error(error,'hdf5 metapackage requires pkg-config')
+            return
+        end if
+
+        !> Find pkg-config package file by priority
+        name = 'NOT_FOUND'
+        find_package: do i=1,size(candidates)
+            if (pkgcfg_has_package(trim(candidates(i)))) then
+                name = trim(candidates(i))
+                exit find_package
+            end if
+        end do find_package
+
+        !> some distros put hdf5-1.2.3.pc with version number in .pc filename.
+        if (name=='NOT_FOUND') then
+            modules = pkgcfg_list_all(error)
+            find_global_package: do i=1,size(modules)
+                if (str_begins_with_str(modules(i)%s,'hdf5')) then
+                    name = modules(i)%s
+                    exit find_global_package
+                end if
+            end do find_global_package
+        end if
+
+        if (name=='NOT_FOUND') then
+            call fatal_error(error,'pkg-config could not find a suitable hdf5 package.')
+            return
+        end if
+
+        call add_pkg_config_compile_options(this, name, include_flag, libdir, error)
+        if (allocated(error)) return
+
+        ! Some pkg-config hdf5.pc (e.g. Ubuntu) don't include the commonly-used HL HDF5 libraries,
+        ! so let's add them if they exist
+        if (len_trim(libdir)>0) then
+            do i=1,size(this%link_libs)
+
+                found_hl = .false.
+
+                if (.not.str_ends_with(this%link_libs(i)%s, find_hl)) then
+
+                   ! Extract name with no extension
+                   call lib_get_trailing(this%link_libs(i)%s, libdir, pref, ext, found)
+
+                   ! Search how many versions with the Fortran endings there are
+                   finals: do k=1,size(find_hl)
+                      do j=1,size(this%link_libs)
+                       if (str_begins_with_str(this%link_libs(j)%s,this%link_libs(i)%s) .and. &
+                           str_ends_with(this%link_libs(j)%s,trim(find_hl(k)))) then
+                           found_hl(k) = .true.
+                           cycle finals
+                       end if
+                      end do
+                   end do finals
+
+                   ! For each of the missing ones, if there is a file, add it
+                   add_missing: do k=1,size(find_hl)
+                      if (found_hl(k)) cycle add_missing
+
+                      ! Build file name
+                      this_lib%s = join_path(libdir,pref//this%link_libs(i)%s//trim(find_hl(k))//ext)
+                      inquire(file=this_lib%s,exist=found)
+
+                      ! File exists, but it is not linked against
+                      if (found) this%link_libs = [this%link_libs, &
+                                                   string_t(this%link_libs(i)%s//trim(find_hl(k)))]
+
+                   end do add_missing
+
+                end if
+
+            end do
+        endif
+
+        !> Add HDF5 modules as external
+        this%has_external_modules = .true.
+        this%external_modules = [string_t('h5a'), &
+                                 string_t('h5d'), &
+                                 string_t('h5es'), &
+                                 string_t('h5e'), &
+                                 string_t('h5f'), &
+                                 string_t('h5g'), &
+                                 string_t('h5i'), &
+                                 string_t('h5l'), &
+                                 string_t('h5o'), &
+                                 string_t('h5p'), &
+                                 string_t('h5r'), &
+                                 string_t('h5s'), &
+                                 string_t('h5t'), &
+                                 string_t('h5vl'), &
+                                 string_t('h5z'), &
+                                 string_t('h5lt'), &
+                                 string_t('h5lib'), &
+                                 string_t('h5global'), &
+                                 string_t('h5_gen'), &
+                                 string_t('h5fortkit'), &
+                                 string_t('hdf5')]
+
+    end subroutine init_hdf5
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/init_minpack.html b/proc/init_minpack.html new file mode 100644 index 0000000000..671d01301b --- /dev/null +++ b/proc/init_minpack.html @@ -0,0 +1,317 @@ + + + + + + + + + + + + + init_minpack – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

init_minpack + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine init_minpack(this, compiler, all_meta, error) +

+ + +

Initialize minpack metapackage for the current system +Cleanup

+

Set name

+

minpack is queried as a dependency from the official repository

+

1) minpack. There are no true releases currently. Fetch HEAD

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(metapackage_t), + intent(inout) + + ::this + +
+ + type(compiler_t), + intent(in) + + ::compiler + +
+ + type(metapackage_request_t), + intent(in) + + ::all_meta(:) + +
+ + type(error_t), + intent(out), + allocatable + ::error + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
    subroutine init_minpack(this,compiler,all_meta,error)
+        class(metapackage_t), intent(inout) :: this
+        type(compiler_t), intent(in) :: compiler
+        type(metapackage_request_t), intent(in) :: all_meta(:)
+        type(error_t), allocatable, intent(out) :: error
+
+        !> Cleanup
+        call destroy(this)
+        
+        !> Set name
+        this%name = "minpack"
+
+        !> minpack is queried as a dependency from the official repository
+        this%has_dependencies = .true.
+
+        allocate(this%dependency(1))
+
+        !> 1) minpack. There are no true releases currently. Fetch HEAD
+        this%dependency(1)%name = "minpack"
+        this%dependency(1)%git = git_target_tag("https://github.com/fortran-lang/minpack", "v2.0.0-rc.1")
+        if (.not.allocated(this%dependency(1)%git)) then
+            call fatal_error(error,'cannot initialize git repo dependency for minpack metapackage')
+            return
+        end if
+
+    end subroutine init_minpack
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/init_mpi.html b/proc/init_mpi.html new file mode 100644 index 0000000000..d371fce8fe --- /dev/null +++ b/proc/init_mpi.html @@ -0,0 +1,378 @@ + + + + + + + + + + + + + init_mpi – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

init_mpi + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine init_mpi(this, compiler, all_meta, error) +

+ + +

Initialize MPI metapackage for the current system +Cleanup

+

Set name

+

Get all candidate MPI wrappers +No wrapper compiler fit. Are we on Windows? use MSMPI-specific search +All attempts failed +If there’s only an available Fortran wrapper, and the compiler’s different than fpm’s baseline +fortran compiler suite, we still want to enable C language flags as that is most likely being +ABI-compatible anyways. However, issues may arise. +see e.g. Homebrew with clabng C/C++ and GNU fortran at https://gitlab.kitware.com/cmake/cmake/-/issues/18139 +Initialize MPI package from wrapper command +Request Fortran implicit typing +Not all MPI implementations offer modules mpi and mpi_f08: hence, include them +to the list of external modules, so they won’t be requested as standard source files

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(metapackage_t), + intent(inout) + + ::this + +
+ + type(compiler_t), + intent(in) + + ::compiler + +
+ + type(metapackage_request_t), + intent(in) + + ::all_meta(:) + +
+ + type(error_t), + intent(out), + allocatable + ::error + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
    subroutine init_mpi(this,compiler,all_meta,error)
+        class(metapackage_t), intent(inout) :: this
+        type(compiler_t), intent(in) :: compiler
+        type(metapackage_request_t), intent(in) :: all_meta(:)
+        type(error_t), allocatable, intent(out) :: error
+
+
+        type(string_t), allocatable :: c_wrappers(:),cpp_wrappers(:),fort_wrappers(:)
+        type(string_t) :: output,fwrap,cwrap,cxxwrap
+        character(256) :: msg_out
+        character(len=:), allocatable :: tokens(:)
+        integer :: wcfit(3),mpilib(3),ic,icpp,i
+        logical :: found
+
+        !> Cleanup
+        call destroy(this)
+        
+        !> Set name
+        this%name = "mpi"
+
+        !> Get all candidate MPI wrappers
+        call mpi_wrappers(compiler,fort_wrappers,c_wrappers,cpp_wrappers)
+        if (verbose) print 1, size(fort_wrappers),size(c_wrappers),size(cpp_wrappers)
+
+        call wrapper_compiler_fit(fort_wrappers,c_wrappers,cpp_wrappers,compiler,wcfit,mpilib,error)
+
+        if (allocated(error) .or. all(wcfit==0)) then
+
+            !> No wrapper compiler fit. Are we on Windows? use MSMPI-specific search
+            found = msmpi_init(this,compiler,error)
+            if (allocated(error)) return
+
+            !> All attempts failed
+            if (.not.found) then
+                call fatal_error(error,"cannot find MPI wrappers or libraries for "//compiler%name()//" compiler")
+                return
+            endif
+
+        else
+
+            if (wcfit(LANG_FORTRAN)>0) fwrap   = fort_wrappers(wcfit(LANG_FORTRAN))
+            if (wcfit(LANG_C)>0)       cwrap   = c_wrappers   (wcfit(LANG_C))
+            if (wcfit(LANG_CXX)>0)     cxxwrap = cpp_wrappers (wcfit(LANG_CXX))
+
+            !> If there's only an available Fortran wrapper, and the compiler's different than fpm's baseline
+            !> fortran compiler suite, we still want to enable C language flags as that is most likely being
+            !> ABI-compatible anyways. However, issues may arise.
+            !> see e.g. Homebrew with clabng C/C++ and GNU fortran at https://gitlab.kitware.com/cmake/cmake/-/issues/18139
+            if (wcfit(LANG_FORTRAN)>0 .and. all(wcfit([LANG_C,LANG_CXX])==0)) then
+                cwrap   = fort_wrappers(wcfit(LANG_FORTRAN))
+                cxxwrap = fort_wrappers(wcfit(LANG_FORTRAN))
+            end if
+
+            if (verbose) print *, '+ MPI fortran wrapper: ',fwrap%s
+            if (verbose) print *, '+ MPI c       wrapper: ',cwrap%s
+            if (verbose) print *, '+ MPI c++     wrapper: ',cxxwrap%s
+
+            !> Initialize MPI package from wrapper command
+            call init_mpi_from_wrappers(this,compiler,mpilib(LANG_FORTRAN),fwrap,cwrap,cxxwrap,error)
+            if (allocated(error)) return
+
+            !> Request Fortran implicit typing
+            if (mpilib(LANG_FORTRAN)/=MPI_TYPE_INTEL) then
+                allocate(this%fortran)
+                this%fortran%implicit_typing   = .true.
+                this%fortran%implicit_external = .true.
+            endif
+
+        end if
+
+        !> Not all MPI implementations offer modules mpi and mpi_f08: hence, include them
+        !> to the list of external modules, so they won't be requested as standard source files
+        this%has_external_modules = .true.
+        this%external_modules = [string_t("mpi"),string_t("mpi_f08")]
+
+        1 format('MPI wrappers found: fortran=',i0,' c=',i0,' c++=',i0)
+
+    end subroutine init_mpi
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/init_netcdf.html b/proc/init_netcdf.html new file mode 100644 index 0000000000..500ced5133 --- /dev/null +++ b/proc/init_netcdf.html @@ -0,0 +1,345 @@ + + + + + + + + + + + + + init_netcdf – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

init_netcdf + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine init_netcdf(this, compiler, all_meta, error) +

+ + +

Initialize NetCDF metapackage for the current system +Cleanup +Set name

+

Assert pkg-config is installed +Add NetCDF modules as external

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(metapackage_t), + intent(inout) + + ::this + +
+ + type(compiler_t), + intent(in) + + ::compiler + +
+ + type(metapackage_request_t), + intent(in) + + ::all_meta(:) + +
+ + type(error_t), + intent(out), + allocatable + ::error + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
    subroutine init_netcdf(this, compiler, all_meta, error)
+        class(metapackage_t), intent(inout) :: this
+        type(compiler_t), intent(in) :: compiler
+        type(metapackage_request_t), intent(in) :: all_meta(:)
+        type(error_t), allocatable, intent(out) :: error
+
+        logical :: s
+        character(len=:), allocatable :: include_flag, libdir
+
+        include_flag = get_include_flag(compiler, "")
+
+        !> Cleanup
+        call destroy(this)
+        allocate (this % link_libs(0), this % incl_dirs(0), this % external_modules(0))
+        this % link_flags = string_t("")
+        this % flags = string_t("")
+        
+        !> Set name
+        this%name = "netcdf"
+
+        !> Assert pkg-config is installed
+        if (.not. assert_pkg_config()) then
+            call fatal_error(error, 'netcdf metapackage requires pkg-config')
+            return
+        end if
+
+        if (.not. pkgcfg_has_package('netcdf')) then
+            call fatal_error(error, 'pkg-config could not find a suitable netcdf package.')
+            return
+        end if
+        call add_pkg_config_compile_options(this, 'netcdf', include_flag, libdir, error)
+        if (allocated(error)) return
+
+        if (.not. pkgcfg_has_package('netcdf-fortran')) then
+            call fatal_error(error, &
+                             'pkg-config could not find a suitable netcdf-fortran package.')
+            return
+        end if
+        call add_pkg_config_compile_options(this, 'netcdf-fortran', include_flag, libdir, error)
+        if (allocated(error)) return
+
+        !> Add NetCDF modules as external
+        this % has_external_modules = .true.
+        this % external_modules = [string_t('netcdf'), &
+                                   string_t('netcdf4_f03'), &
+                                   string_t('netcdf4_nc_interfaces'), &
+                                   string_t('netcdf4_nf_interfaces'), &
+                                   string_t('netcdf_f03'), &
+                                   string_t('netcdf_fortv2_c_interfaces'), &
+                                   string_t('netcdf_nc_data'), &
+                                   string_t('netcdf_nc_interfaces'), &
+                                   string_t('netcdf_nf_data'), &
+                                   string_t('netcdf_nf_interfaces')]
+    end subroutine init_netcdf
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/init_openmp.html b/proc/init_openmp.html new file mode 100644 index 0000000000..aaadca565e --- /dev/null +++ b/proc/init_openmp.html @@ -0,0 +1,350 @@ + + + + + + + + + + + + + init_openmp – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

init_openmp + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine init_openmp(this, compiler, all_meta, error) +

+ + +

Initialize OpenMP metapackage for the current system +Cleanup

+

Set name

+

OpenMP has compiler flags +OpenMP flags should be added to

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(metapackage_t), + intent(inout) + + ::this + +
+ + type(compiler_t), + intent(in) + + ::compiler + +
+ + type(metapackage_request_t), + intent(in) + + ::all_meta(:) + +
+ + type(error_t), + intent(out), + allocatable + ::error + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
    subroutine init_openmp(this,compiler,all_meta,error)
+        class(metapackage_t), intent(inout) :: this
+        type(compiler_t), intent(in) :: compiler
+        type(metapackage_request_t), intent(in) :: all_meta(:)
+        type(error_t), allocatable, intent(out) :: error
+
+        !> Cleanup
+        call destroy(this)
+        
+        !> Set name
+        this%name = "openmp"
+
+        !> OpenMP has compiler flags
+        this%has_build_flags = .true.
+        this%has_link_flags  = .true.
+
+        !> OpenMP flags should be added to
+        which_compiler: select case (compiler%id)
+           case (id_gcc,id_f95)
+                this%flags      = string_t(flag_gnu_openmp)
+                this%link_flags = string_t(flag_gnu_openmp)
+
+           case (id_intel_classic_windows,id_intel_llvm_windows)
+                this%flags      = string_t(flag_intel_openmp_win)
+                this%link_flags = string_t(flag_intel_openmp_win)
+
+           case (id_intel_classic_nix,id_intel_classic_mac,&
+                 id_intel_llvm_nix)
+                this%flags      = string_t(flag_intel_openmp)
+                this%link_flags = string_t(flag_intel_openmp)
+
+           case (id_pgi,id_nvhpc)
+                this%flags      = string_t(flag_pgi_openmp)
+                this%link_flags = string_t(flag_pgi_openmp)
+
+           case (id_ibmxl)
+                this%flags      = string_t(" -qsmp=omp")
+                this%link_flags = string_t(" -qsmp=omp")
+
+           case (id_nag)
+                this%flags      = string_t(flag_nag_openmp)
+                this%link_flags = string_t(flag_nag_openmp)
+
+           case (id_lfortran)
+                this%flags      = string_t(flag_lfortran_openmp)
+                this%link_flags = string_t(flag_lfortran_openmp)
+
+           case (id_flang, id_flang_new)
+                this%flags      = string_t(flag_flang_new_openmp)
+                this%link_flags = string_t(flag_flang_new_openmp)
+
+           case default
+
+              call fatal_error(error,'openmp not supported on compiler '//compiler%name()//' yet')
+
+        end select which_compiler
+
+
+    end subroutine init_openmp
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/init_stdlib.html b/proc/init_stdlib.html new file mode 100644 index 0000000000..c1a90ad21f --- /dev/null +++ b/proc/init_stdlib.html @@ -0,0 +1,345 @@ + + + + + + + + + + + + + init_stdlib – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

init_stdlib + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine init_stdlib(this, compiler, all_meta, error) +

+ + +

Initialize stdlib metapackage for the current system +Cleanup

+

Set name

+

Stdlib is queried as a dependency from the official repository

+

1) Test-drive +2) stdlib +If an external BLAS is available, deploy appropriate macros

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(metapackage_t), + intent(inout) + + ::this + +
+ + type(compiler_t), + intent(in) + + ::compiler + +
+ + type(metapackage_request_t), + intent(in) + + ::all_meta(:) + +
+ + type(error_t), + intent(out), + allocatable + ::error + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
    subroutine init_stdlib(this,compiler,all_meta,error)
+        class(metapackage_t), intent(inout) :: this
+        type(compiler_t), intent(in) :: compiler
+        type(metapackage_request_t), intent(in) :: all_meta(:)
+        type(error_t), allocatable, intent(out) :: error
+        
+        integer :: i
+        logical :: with_blas
+
+        !> Cleanup
+        call destroy(this)
+        
+        !> Set name
+        this%name = "stdlib"
+        
+        !> Stdlib is queried as a dependency from the official repository
+        this%has_dependencies = .true.
+
+        allocate(this%dependency(2))
+
+        !> 1) Test-drive
+        this%dependency(1)%name = "test-drive"
+        this%dependency(1)%git = git_target_branch("https://github.com/fortran-lang/test-drive","v0.4.0")
+        if (.not.allocated(this%dependency(1)%git)) then
+            call fatal_error(error,'cannot initialize test-drive git dependency for stdlib metapackage')
+            return
+        end if
+
+        !> 2) stdlib
+        this%dependency(2)%name = "stdlib"
+        this%dependency(2)%git = git_target_branch("https://github.com/fortran-lang/stdlib","stdlib-fpm")
+        if (.not.allocated(this%dependency(2)%git)) then
+            call fatal_error(error,'cannot initialize git repo dependency for stdlib metapackage')
+            return
+        end if
+        
+        !> If an external BLAS is available, deploy appropriate macros    
+        with_blas = external_blas(all_meta)
+        if (with_blas) then 
+            allocate(this%preprocess)
+            call this%preprocess%new([string_t('STDLIB_EXTERNAL_BLAS'),string_t('STDLIB_EXTERNAL_LAPACK')])
+            call this%dependency(2)%add_preprocess(this%preprocess)
+        end if
+
+        ! Stdlib is not 100% thread safe. print a warning to the user
+        do i=1,size(all_meta)
+            if (all_meta(i)%name=="openmp") then 
+                write(stdout,'(a)')'<WARNING> both openmp and stdlib requested: some functions may not be thread-safe!'
+            end if                
+        end do
+
+    end subroutine init_stdlib
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/is_absolute_path.html b/proc/is_absolute_path.html new file mode 100644 index 0000000000..9010bcdbb8 --- /dev/null +++ b/proc/is_absolute_path.html @@ -0,0 +1,289 @@ + + + + + + + + + + + + + is_absolute_path – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

is_absolute_path + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function is_absolute_path(path, is_unix) +

+ + +

Returns .true. if provided path is absolute.

+

~ not treated as absolute.

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::path + +
+ + logical, + intent(in),optional + + ::is_unix + +
+ +

Return Value + + + logical + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
    logical function is_absolute_path(path, is_unix)
+        character(len=*), intent(in) :: path
+        logical, optional, intent(in):: is_unix
+        character(len=*), parameter :: letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
+        logical :: is_unix_os
+
+        if (present(is_unix)) then
+            is_unix_os = is_unix
+        else
+            is_unix_os = os_is_unix()
+        end if
+
+        if (is_unix_os) then
+            is_absolute_path = path(1:1) == '/'
+        else
+            if (len(path) < 2) then
+                is_absolute_path = .false.
+                return
+            end if
+
+            is_absolute_path = index(letters, path(1:1)) /= 0 .and. path(2:2) == ':'
+        end if
+
+    end function is_absolute_path
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/is_dir.html b/proc/is_dir.html new file mode 100644 index 0000000000..105f3170f6 --- /dev/null +++ b/proc/is_dir.html @@ -0,0 +1,268 @@ + + + + + + + + + + + + + is_dir – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

is_dir + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function is_dir(dir) +

+ + +

test if a name matches an existing directory path

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::dir + +
+ +

Return Value + + + logical + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
logical function is_dir(dir)
+    character(*), intent(in) :: dir
+    integer :: stat
+
+    select case (get_os_type())
+
+    case (OS_UNKNOWN, OS_LINUX, OS_MACOS, OS_CYGWIN, OS_SOLARIS, OS_FREEBSD, OS_OPENBSD)
+        call run( "test -d " // dir , &
+                & exitstat=stat,echo=.false.,verbose=.false.)
+
+    case (OS_WINDOWS)
+        call run('cmd /c "if not exist ' // windows_path(dir) // '\ exit /B 1"', &
+                & exitstat=stat,echo=.false.,verbose=.false.)
+
+    end select
+
+    is_dir = (stat == 0)
+
+end function is_dir
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/is_fortran_name.html b/proc/is_fortran_name.html new file mode 100644 index 0000000000..c144d54690 --- /dev/null +++ b/proc/is_fortran_name.html @@ -0,0 +1,268 @@ + + + + + + + + + + + + + is_fortran_name – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

is_fortran_name + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public elemental function is_fortran_name(line) result(lout) +

+ + + + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::line + +
+ +

Return Value + + + logical + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
elemental function is_fortran_name(line) result (lout)
+! determine if a string is a valid Fortran name ignoring trailing spaces
+! (but not leading spaces)
+    character(len=*),parameter   :: int='0123456789'
+    character(len=*),parameter   :: lower='abcdefghijklmnopqrstuvwxyz'
+    character(len=*),parameter   :: upper='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+    character(len=*),parameter   :: allowed=upper//lower//int//'_'
+    character(len=*),intent(in)  :: line
+    character(len=:),allocatable :: name
+    logical                      :: lout
+        name=trim(line)
+        if(len(name)/=0)then
+            lout = .true.                                  &
+             & .and. verify(name(1:1), lower//upper) == 0  &
+             & .and. verify(name,allowed) == 0             &
+             & .and. len(name) <= 63
+        else
+            lout = .false.
+        endif
+end function is_fortran_name
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/is_gnu.html b/proc/is_gnu.html new file mode 100644 index 0000000000..ca578457ca --- /dev/null +++ b/proc/is_gnu.html @@ -0,0 +1,254 @@ + + + + + + + + + + + + + is_gnu – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

is_gnu + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public pure function is_gnu(self) +

+ + + +

Type Bound

+

compiler_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::self + +
+ +

Return Value + + + logical + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
pure logical function is_gnu(self)
+    class(compiler_t), intent(in) :: self
+    is_gnu = any(self%id == [id_f95,id_gcc,id_caf])
+end function is_gnu
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/is_hidden_file.html b/proc/is_hidden_file.html new file mode 100644 index 0000000000..ee4173430e --- /dev/null +++ b/proc/is_hidden_file.html @@ -0,0 +1,257 @@ + + + + + + + + + + + + + is_hidden_file – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

is_hidden_file + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function is_hidden_file(file_basename) result(r) +

+ + +

test if a file is hidden

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::file_basename + +
+ +

Return Value + + + logical + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
logical function is_hidden_file(file_basename) result(r)
+    character(*), intent(in) :: file_basename
+    if (len(file_basename) <= 2) then
+        r = .false.
+    else
+        r = str_begins_with_str(file_basename, '.')
+    end if
+end function is_hidden_file
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/is_intel.html b/proc/is_intel.html new file mode 100644 index 0000000000..68faa926d2 --- /dev/null +++ b/proc/is_intel.html @@ -0,0 +1,255 @@ + + + + + + + + + + + + + is_intel – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

is_intel + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public pure function is_intel(self) +

+ + + +

Type Bound

+

compiler_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::self + +
+ +

Return Value + + + logical + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
pure logical function is_intel(self)
+    class(compiler_t), intent(in) :: self
+    is_intel = any(self%id == [id_intel_classic_nix,id_intel_classic_mac,id_intel_classic_windows, &
+                               id_intel_llvm_nix,id_intel_llvm_windows,id_intel_llvm_unknown])
+end function is_intel
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/is_meta_package.html b/proc/is_meta_package.html new file mode 100644 index 0000000000..055c6ddc16 --- /dev/null +++ b/proc/is_meta_package.html @@ -0,0 +1,267 @@ + + + + + + + + + + + + + is_meta_package – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

is_meta_package + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function is_meta_package(key) +

+ + +

Check local schema for allowed entries

+

Supported metapackages

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::key +

Instance of the TOML data structure

+
+ +

Return Value + + + logical + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
    logical function is_meta_package(key)
+
+        !> Instance of the TOML data structure
+        character(*), intent(in) :: key
+
+        select case (key)
+
+            !> Supported metapackages
+            case ("openmp","stdlib","mpi","minpack","hdf5","netcdf","blas")
+                is_meta_package = .true.
+
+            case default
+                is_meta_package = .false.
+
+        end select
+
+    end function is_meta_package
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/is_unknown.html b/proc/is_unknown.html new file mode 100644 index 0000000000..8def57cfcb --- /dev/null +++ b/proc/is_unknown.html @@ -0,0 +1,255 @@ + + + + + + + + + + + + + is_unknown – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

is_unknown + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public pure function is_unknown(self) +

+ + + +

Type Bound

+

compiler_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::self + +
+ +

Return Value + + + logical + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
pure function is_unknown(self)
+    class(compiler_t), intent(in) :: self
+    logical :: is_unknown
+    is_unknown = self%id == id_unknown
+end function is_unknown
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/is_valid_module_name.html b/proc/is_valid_module_name.html new file mode 100644 index 0000000000..0a433145d0 --- /dev/null +++ b/proc/is_valid_module_name.html @@ -0,0 +1,324 @@ + + + + + + + + + + + + + is_valid_module_name – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

is_valid_module_name + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function is_valid_module_name(module_name, package_name, custom_prefix, enforce_module_names) result(valid) +

+ + +

Check that a module name fits the current naming rules: +1) It must be a valid FORTRAN name (<=63 chars, begin with letter, “_” is only allowed non-alphanumeric) +2) It must begin with the package name +3) If longer, package name must be followed by default separator plus at least one char

+

Basic check: check the name is Fortran-compliant

+

FPM package enforcing: check that the module name begins with the package name

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(string_t), + intent(in) + + ::module_name + +
+ + type(string_t), + intent(in) + + ::package_name + +
+ + type(string_t), + intent(in) + + ::custom_prefix + +
+ + logical, + intent(in) + + ::enforce_module_names + +
+ +

Return Value + + + logical + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
logical function is_valid_module_name(module_name,package_name,custom_prefix,enforce_module_names) result(valid)
+
+    type(string_t), intent(in) :: module_name
+    type(string_t), intent(in) :: package_name
+    type(string_t), intent(in) :: custom_prefix
+    logical       , intent(in) :: enforce_module_names
+
+
+    !> Basic check: check the name is Fortran-compliant
+    valid = is_fortran_name(module_name%s); if (.not.valid) return
+
+    !> FPM package enforcing: check that the module name begins with the package name
+    if (enforce_module_names) then
+
+        ! Default prefixing is always valid
+        valid = has_valid_standard_prefix(module_name,package_name)
+
+        ! If a custom prefix was validated, it provides additional naming options
+        ! Because they never overlap with the default prefix, the former is always an option
+        if (len_trim(custom_prefix)>0 .and. .not.valid) &
+            valid = has_valid_custom_prefix(module_name,custom_prefix)
+
+    end if
+
+end function is_valid_module_name
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/is_valid_module_prefix.html b/proc/is_valid_module_prefix.html new file mode 100644 index 0000000000..de2ad9001e --- /dev/null +++ b/proc/is_valid_module_prefix.html @@ -0,0 +1,273 @@ + + + + + + + + + + + + + is_valid_module_prefix – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

is_valid_module_prefix + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function is_valid_module_prefix(module_prefix) result(valid) +

+ + +

Check that a custom module prefix fits the current naming rules: +1) Only alphanumeric characters (no spaces, dashes, underscores or other characters) +2) Does not begin with a number (Fortran-compatible syntax)

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(string_t), + intent(in) + + ::module_prefix + +
+ +

Return Value + + + logical + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
logical function is_valid_module_prefix(module_prefix) result(valid)
+
+    type(string_t), intent(in) :: module_prefix
+
+    character(len=*),parameter :: num='0123456789'
+    character(len=*),parameter :: lower='abcdefghijklmnopqrstuvwxyz'
+    character(len=*),parameter :: upper='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+    character(len=*),parameter :: alpha  =upper//lower
+    character(len=*),parameter :: allowed=alpha//num
+
+    character(len=:),allocatable :: name
+
+    name = trim(module_prefix%s)
+
+    if (len(name)>0 .and. len(name)<=63) then
+        valid = verify(name(1:1), alpha) == 0 .and. &
+                verify(name,allowed)     == 0
+    else
+        valid = .false.
+    endif
+
+end function is_valid_module_prefix
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/join.html b/proc/join.html new file mode 100644 index 0000000000..c86e134f27 --- /dev/null +++ b/proc/join.html @@ -0,0 +1,450 @@ + + + + + + + + + + + + + join – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

join + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public pure function join(str, sep, trm, left, right, start, end) result(string) +

+ + +

NAME

+
join(3f) - [M_strings:EDITING] append CHARACTER variable array into
+a single CHARACTER variable with specified separator
+(LICENSE:PD)
+
+ +

SYNOPSIS

+
pure function join(str,sep,trm,left,right,start,end) result (string)
+
+ character(len=*),intent(in)          :: str(:)
+ character(len=*),intent(in),optional :: sep
+ logical,intent(in),optional          :: trm
+ character(len=*),intent(in),optional :: right
+ character(len=*),intent(in),optional :: left
+ character(len=*),intent(in),optional :: start
+ character(len=*),intent(in),optional :: end
+ character(len=:),allocatable         :: string
+
+ +

DESCRIPTION

+

JOIN(3f) appends the elements of a CHARACTER array into a single + CHARACTER variable, with elements 1 to N joined from left to right. + By default each element is trimmed of trailing spaces and the + default separator is a null string.

+

OPTIONS

+
  STR(:)  array of CHARACTER variables to be joined
+  SEP     separator string to place between each variable. defaults
+          to a null string.
+  LEFT    string to place at left of each element
+  RIGHT   string to place at right of each element
+  START   prefix string
+  END     suffix string
+  TRM     option to trim each element of STR of trailing
+          spaces. Defaults to .TRUE.
+
+ +

RESULT

+
  STRING  CHARACTER variable composed of all of the elements of STR()
+          appended together with the optional separator SEP placed
+          between the elements.
+
+ +

EXAMPLE

+

Sample program:

+

program demo_join + use M_strings, only: join + implicit none + character(len=:),allocatable :: s(:) + character(len=:),allocatable :: out + integer :: i + s=[character(len=10) :: ‘United’,’ we’,’ stand,’, & + & ’ divided’,’ we fall.’] + out=join(s) + write(,’(a)’) out + write(,’(a)’) join(s,trm=.false.) + write(,’(a)’) (join(s,trm=.false.,sep=’|’),i=1,3) + write(,’(a)’) join(s,sep=’<>’) + write(,’(a)’) join(s,sep=’;’,left=’[‘,right=’]’) + write(,’(a)’) join(s,left=’[‘,right=’]’) + write(*,’(a)’) join(s,left=’>>’) + end program demo_join

+

Expected output:

+

United we stand, divided we fall. + United we stand, divided we fall. + United | we | stand, | divided | we fall. + United | we | stand, | divided | we fall. + United | we | stand, | divided | we fall. + United<> we<> stand,<> divided<> we fall. + [United];[ we];[ stand,];[ divided];[ we fall.] + [United][ we][ stand,][ divided][ we fall.]

+
+
+

United>> we>> stand,>> divided>> we fall.

+
+
+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::str(:) + +
+ + character(len=*), + intent(in),optional + + ::sep + +
+ + logical, + intent(in),optional + + ::trm + +
+ + character(len=*), + intent(in),optional + + ::left + +
+ + character(len=*), + intent(in),optional + + ::right + +
+ + character(len=*), + intent(in),optional + + ::start + +
+ + character(len=*), + intent(in),optional + + ::end + +
+ +

Return Value + + + character(len=:), allocatable + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
pure function join(str,sep,trm,left,right,start,end) result (string)
+
+! @(#)M_strings::join(3f): merge string array into a single CHARACTER value adding specified separators, caps, prefix and suffix
+
+character(len=*),intent(in)          :: str(:)
+character(len=*),intent(in),optional :: sep, right, left, start, end
+logical,intent(in),optional          :: trm
+character(len=:),allocatable         :: sep_local, left_local, right_local
+character(len=:),allocatable         :: string
+logical                              :: trm_local
+integer                              :: i
+   if(present(sep))then   ; sep_local=sep     ; else ; sep_local=''     ; endif
+   if(present(trm))then   ; trm_local=trm     ; else ; trm_local=.true. ; endif
+   if(present(left))then  ; left_local=left   ; else ; left_local=''    ; endif
+   if(present(right))then ; right_local=right ; else ; right_local=''   ; endif
+   string=''
+   if(size(str)==0)then
+      string=string//left_local//right_local
+   else
+      do i = 1,size(str)-1
+         if(trm_local)then
+            string=string//left_local//trim(str(i))//right_local//sep_local
+         else
+            string=string//left_local//str(i)//right_local//sep_local
+         endif
+      enddo
+      if(trm_local)then
+         string=string//left_local//trim(str(i))//right_local
+      else
+         string=string//left_local//str(i)//right_local
+      endif
+   endif
+   if(present(start))string=start//string
+   if(present(end))string=string//end
+end function join
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/join_path.html b/proc/join_path.html new file mode 100644 index 0000000000..0f272ae3f7 --- /dev/null +++ b/proc/join_path.html @@ -0,0 +1,358 @@ + + + + + + + + + + + + + join_path – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

join_path + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function join_path(a1, a2, a3, a4, a5) result(path) +

+ + +

Construct path by joining strings with os file separator

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::a1 + +
+ + character(len=*), + intent(in) + + ::a2 + +
+ + character(len=*), + intent(in),optional + + ::a3 + +
+ + character(len=*), + intent(in),optional + + ::a4 + +
+ + character(len=*), + intent(in),optional + + ::a5 + +
+ +

Return Value + + + character(len=:), allocatable + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
function join_path(a1,a2,a3,a4,a5) result(path)
+
+    character(len=*), intent(in)           :: a1, a2
+    character(len=*), intent(in), optional :: a3, a4, a5
+    character(len=:), allocatable          :: path
+    character(len=1)                       :: filesep
+    logical, save                          :: has_cache = .false.
+    character(len=1), save                 :: cache = '/'
+    !$omp threadprivate(has_cache, cache)
+
+    if (has_cache) then
+        filesep = cache
+    else
+        select case (get_os_type())
+            case default
+                filesep = '/'
+            case (OS_WINDOWS)
+                filesep = '\'
+        end select
+
+        cache = filesep
+        has_cache = .true.
+    end if
+
+    if (a1 == "") then
+        path = a2
+    else
+        path = a1 // filesep // a2
+    end if
+
+    if (present(a3)) then
+        path = path // filesep // a3
+    else
+        return
+    end if
+
+    if (present(a4)) then
+        path = path // filesep // a4
+    else
+        return
+    end if
+
+    if (present(a5)) then
+        path = path // filesep // a5
+    else
+        return
+    end if
+
+end function join_path
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/lib_get_trailing.html b/proc/lib_get_trailing.html new file mode 100644 index 0000000000..86e4f83bfe --- /dev/null +++ b/proc/lib_get_trailing.html @@ -0,0 +1,344 @@ + + + + + + + + + + + + + lib_get_trailing – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

lib_get_trailing + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine lib_get_trailing(lib_name, lib_dir, prefix, suffix, found) +

+ + +

Given a library name and folder, find extension and prefix

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::lib_name + +
+ + character(len=*), + intent(in) + + ::lib_dir + +
+ + character(len=:), + intent(out), + allocatable + ::prefix + +
+ + character(len=:), + intent(out), + allocatable + ::suffix + +
+ + logical, + intent(out) + + ::found + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
    subroutine lib_get_trailing(lib_name,lib_dir,prefix,suffix,found)
+        character(*), intent(in) :: lib_name,lib_dir
+        character(:), allocatable, intent(out) :: prefix,suffix
+        logical, intent(out) :: found
+
+        character(*), parameter :: extensions(*) = [character(11) :: '.dll.a','.a','.dylib','.dll']
+        logical :: is_file
+        character(:), allocatable :: noext,tokens(:),path
+        integer :: l,k
+
+        ! Extract name with no extension
+        call split(lib_name,tokens,'.')
+        noext = trim(tokens(1))
+
+        ! Get library extension: find file name: NAME.a, NAME.dll.a, NAME.dylib, libNAME.a, etc.
+        found = .false.
+        suffix = ""
+        prefix = ""
+        with_pref: do l=1,2
+            if (l==2) then
+               prefix = "lib"
+            else
+               prefix = ""
+            end if
+            find_ext: do k=1,size(extensions)
+                path = join_path(lib_dir,prefix//noext//trim(extensions(k)))
+                inquire(file=path,exist=is_file)
+
+                if (is_file) then
+                   suffix = trim(extensions(k))
+                   found = .true.
+                   exit with_pref
+                end if
+            end do find_ext
+        end do with_pref
+
+        if (.not.found) then
+             prefix = ""
+             suffix = ""
+        end if
+
+    end subroutine lib_get_trailing
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/library_filename.html b/proc/library_filename.html new file mode 100644 index 0000000000..6cef27e6cd --- /dev/null +++ b/proc/library_filename.html @@ -0,0 +1,326 @@ + + + + + + + + + + + + + library_filename – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

library_filename + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public pure function library_filename(package_name, shared, import, target_os) result(name) +

+ + +

Utility function: return library filename

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::package_name + +
+ + logical, + intent(in) + + ::shared +

Whether it’s a shared library

+
+ + logical, + intent(in) + + ::import +

Whether it’s for linking (import library) or actual library

+
+ + integer, + intent(in) + + ::target_os +

Build target OS: one of OS_WINDOWS, OS_MACOS, …

+
+ +

Return Value + + + character(len=:), allocatable + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
    pure function library_filename(package_name, shared, import, target_os) result(name)
+        character(*), intent(in) :: package_name    
+        !> Whether it's a shared library
+        logical, intent(in) :: shared       
+        !> Whether it's for linking (import library) or actual library
+        logical, intent(in) :: import       
+        !> Build target OS: one of OS_WINDOWS, OS_MACOS, ...
+        integer, intent(in) :: target_os        
+
+        character(len=:), allocatable :: name
+
+        if (shared) then
+            select case (target_os)
+            case (OS_WINDOWS)
+                if (import) then
+                    ! Linking requires the import library
+                    name = 'lib' // package_name // '.lib'
+                else
+                    ! The actual shared object is a DLL
+                    name = 'lib' // package_name // '.dll'
+                end if
+            case (OS_MACOS)
+                name = 'lib' // package_name // '.dylib'
+            case default
+                name = 'lib' // package_name // '.so'
+            end select
+        else
+            ! Static library (same for all platforms)
+            name = 'lib' // package_name // '.a'
+        end if
+
+    end function library_filename
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/link_executable.html b/proc/link_executable.html new file mode 100644 index 0000000000..a59ea748cf --- /dev/null +++ b/proc/link_executable.html @@ -0,0 +1,411 @@ + + + + + + + + + + + + + link_executable – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

link_executable + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine link_executable(self, output, args, log_file, stat, dry_run) +

+ + +

Link an executable

+ +

Type Bound

+

compiler_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::self +

Instance of the compiler object

+
+ + character(len=*), + intent(in) + + ::output +

Output file of object

+
+ + character(len=*), + intent(in) + + ::args +

Arguments for compiler

+
+ + character(len=*), + intent(in) + + ::log_file +

Compiler output log file

+
+ + integer, + intent(out) + + ::stat +

Status flag

+
+ + logical, + intent(in),optional + + ::dry_run +

Optional mocking

+
+ +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=:), + public, + allocatable + ::command + +
+ + logical, + public + + ::mock + +
+ +
+
+ + + + + + + + + +
+

Source Code

+
subroutine link_executable(self, output, args, log_file, stat, dry_run)
+    !> Instance of the compiler object
+    class(compiler_t), intent(in) :: self
+    !> Output file of object
+    character(len=*), intent(in) :: output
+    !> Arguments for compiler
+    character(len=*), intent(in) :: args
+    !> Compiler output log file
+    character(len=*), intent(in) :: log_file
+    !> Status flag
+    integer, intent(out) :: stat
+    !> Optional mocking
+    logical, optional, intent(in) :: dry_run    
+    
+    character(len=:), allocatable :: command 
+    logical :: mock
+        
+    ! Check if we're actually linking
+    mock = .false.
+    if (present(dry_run)) mock = dry_run                
+        
+    ! Set command
+    command = self%fc // " " // args // " -o " // output    
+    
+    ! Execute command
+    if (.not.mock) &
+    call run(command, echo=self%echo, verbose=self%verbose, redirect=log_file, exitstat=stat)
+    
+end subroutine link_executable
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/link_shared.html b/proc/link_shared.html new file mode 100644 index 0000000000..635926a770 --- /dev/null +++ b/proc/link_shared.html @@ -0,0 +1,429 @@ + + + + + + + + + + + + + link_shared – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

link_shared + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine link_shared(self, output, args, log_file, stat, dry_run) +

+ + +

Link a shared library

+ +

Type Bound

+

compiler_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::self +

Instance of the compiler object

+
+ + character(len=*), + intent(in) + + ::output +

Output file of shared library object

+
+ + character(len=*), + intent(in) + + ::args +

Arguments for the compiler

+
+ + character(len=*), + intent(in) + + ::log_file +

Compiler output log file

+
+ + integer, + intent(out) + + ::stat +

Status flag

+
+ + logical, + intent(in),optional + + ::dry_run +

Optional mocking

+
+ +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=:), + public, + allocatable + ::command + +
+ + logical, + public + + ::mock + +
+ + character(len=:), + public, + allocatable + ::shared_flag + +
+ +
+
+ + + + + + + + + +
+

Source Code

+
subroutine link_shared(self, output, args, log_file, stat, dry_run)
+    !> Instance of the compiler object
+    class(compiler_t), intent(in) :: self
+    !> Output file of shared library object
+    character(len=*), intent(in) :: output
+    !> Arguments for the compiler
+    character(len=*), intent(in) :: args
+    !> Compiler output log file
+    character(len=*), intent(in) :: log_file
+    !> Status flag
+    integer, intent(out) :: stat
+    !> Optional mocking
+    logical, optional, intent(in) :: dry_run
+
+    character(len=:), allocatable :: command
+    logical :: mock
+    character(len=:), allocatable :: shared_flag
+
+    mock = .false.
+    if (present(dry_run)) mock = dry_run
+
+    shared_flag = get_shared_flag(self)
+
+    command = self%fc // " " // shared_flag // " " // args // " -o " // output
+
+    if (.not.mock) &
+        call run(command, echo=self%echo, verbose=self%verbose, redirect=log_file, exitstat=stat)
+
+end subroutine link_shared
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/list_files.html b/proc/list_files.html new file mode 100644 index 0000000000..0958801f17 --- /dev/null +++ b/proc/list_files.html @@ -0,0 +1,356 @@ + + + + + + + + + + + + + list_files – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

list_files + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public recursive subroutine list_files(dir, files, recurse) +

+ + +

Get file & directory names in directory dir using iso_c_binding.

+
    +
  • File/directory names return are relative to cwd, ie. preprended with dir
  • +
  • Includes files starting with . except current directory and parent directory
  • +
+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::dir + +
+ + type(string_t), + intent(out), + allocatable + ::files(:) + +
+ + logical, + intent(in),optional + + ::recurse + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
recursive subroutine list_files(dir, files, recurse)
+    character(len=*), intent(in) :: dir
+    type(string_t), allocatable, intent(out) :: files(:)
+    logical, intent(in), optional :: recurse
+
+    integer :: i
+    type(string_t), allocatable :: dir_files(:)
+    type(string_t), allocatable :: sub_dir_files(:)
+
+    type(c_ptr) :: dir_handle
+    type(c_ptr) :: dir_entry_c
+    character(len=:,kind=c_char), allocatable :: fortran_name
+    character(len=:), allocatable :: string_fortran
+    integer, parameter :: N_MAX = 256
+    type(string_t) :: files_tmp(N_MAX)
+    integer(kind=c_int) :: r
+
+    if (c_is_dir(dir(1:len_trim(dir))//c_null_char) == 0) then
+        allocate (files(0))
+        return
+    end if
+
+    dir_handle = c_opendir(dir(1:len_trim(dir))//c_null_char)
+    if (.not. c_associated(dir_handle)) then
+        print *, 'c_opendir() failed'
+        error stop
+    end if
+
+    i = 0
+    allocate(files(0))
+
+    do
+        dir_entry_c = c_readdir(dir_handle)
+        if (.not. c_associated(dir_entry_c)) then
+            exit
+        else
+            string_fortran = f_string(c_get_d_name(dir_entry_c))
+
+            if ((string_fortran == '.' .or. string_fortran == '..')) then
+                cycle
+            end if
+
+            i = i + 1
+
+            if (i > N_MAX) then
+                files = [files, files_tmp]
+                i = 1
+            end if
+
+            files_tmp(i)%s = join_path(dir, string_fortran)
+        end if
+    end do
+
+    r = c_closedir(dir_handle)
+
+    if (r /= 0) then
+        print *, 'c_closedir() failed'
+        error stop
+    end if
+
+    if (i > 0) then
+        files = [files, files_tmp(1:i)]
+    end if
+
+    if (present(recurse)) then
+        if (recurse) then
+
+            allocate(sub_dir_files(0))
+
+            do i=1,size(files)
+                if (c_is_dir(files(i)%s//c_null_char) /= 0) then
+                    call list_files(files(i)%s, dir_files, recurse=.true.)
+                    sub_dir_files = [sub_dir_files, dir_files]
+                end if
+            end do
+
+            files = [files, sub_dir_files]
+        end if
+    end if
+end subroutine list_files
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/load_from_toml~3.html b/proc/load_from_toml~3.html new file mode 100644 index 0000000000..a9c81a15d0 --- /dev/null +++ b/proc/load_from_toml~3.html @@ -0,0 +1,350 @@ + + + + + + + + + + + + + load_from_toml – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

load_from_toml + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine load_from_toml(self, table, error) +

+ + +

Read dependency from toml table (no checks made at this stage)

+

Target URL of the git repository

+

Additional descriptor of the git object

+ +

Type Bound

+

git_target_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(git_target_t), + intent(inout) + + ::self +

Instance of the serializable object

+
+ + type(toml_table), + intent(inout) + + ::table +

Data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=:), + public, + allocatable + ::descriptor_name +

Local variables

+
+ +
+
+ + + + + + + + + +
+

Source Code

+
    subroutine load_from_toml(self, table, error)
+
+        !> Instance of the serializable object
+        class(git_target_t), intent(inout) :: self
+
+        !> Data structure
+        type(toml_table), intent(inout) :: table
+
+        !> Error handling
+        type(error_t), allocatable, intent(out) :: error
+
+        !> Local variables
+        character(len=:), allocatable :: descriptor_name
+
+        call get_value(table, "descriptor", descriptor_name)
+        self%descriptor = parse_descriptor(descriptor_name)
+
+        if (self%descriptor==git_descriptor%error) then
+            call fatal_error(error,"invalid descriptor ID <"//descriptor_name//"> in TOML entry")
+            return
+        end if
+
+        !> Target URL of the git repository
+        call get_value(table, "url", self%url)
+
+        !> Additional descriptor of the git object
+        call get_value(table,"object", self%object)
+
+    end subroutine load_from_toml
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/load_from_toml~8.html b/proc/load_from_toml~8.html new file mode 100644 index 0000000000..609854c88b --- /dev/null +++ b/proc/load_from_toml~8.html @@ -0,0 +1,295 @@ + + + + + + + + + + + + + load_from_toml – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

load_from_toml + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine load_from_toml(self, table, error) +

+ + +

Read dependency from toml table (no checks made at this stage)

+ +

Type Bound

+

archiver_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(archiver_t), + intent(inout) + + ::self +

Instance of the serializable object

+
+ + type(toml_table), + intent(inout) + + ::table +

Data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
subroutine load_from_toml(self, table, error)
+
+    !> Instance of the serializable object
+    class(archiver_t), intent(inout) :: self
+
+    !> Data structure
+    type(toml_table), intent(inout) :: table
+
+    !> Error handling
+    type(error_t), allocatable, intent(out) :: error
+
+    call get_value(table, "ar", self%ar)
+
+    call get_value(table, "use-response-file", self%use_response_file, error, 'archiver_t')
+    if (allocated(error)) return
+    call get_value(table, "echo", self%echo, error, 'archiver_t')
+    if (allocated(error)) return
+    call get_value(table, "verbose", self%verbose, error, 'archiver_t')
+    if (allocated(error)) return
+
+end subroutine load_from_toml
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/lower.html b/proc/lower.html new file mode 100644 index 0000000000..7f2c84e59b --- /dev/null +++ b/proc/lower.html @@ -0,0 +1,309 @@ + + + + + + + + + + + + + lower – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

lower + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public pure elemental function lower(str, begin, end) result(string) +

+ + +

Changes a string to lowercase over optional specified column range

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::str + +
+ + integer, + intent(in),optional + + ::begin + +
+ + integer, + intent(in),optional + + ::end + +
+ +

Return Value + + + character(len=len(str)) + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
elemental pure function lower(str,begin,end) result (string)
+
+    character(*), intent(In)     :: str
+    character(len(str))          :: string
+    integer,intent(in),optional  :: begin, end
+    integer                      :: i
+    integer                      :: ibegin, iend
+    string = str
+
+    ibegin = 1
+    if (present(begin))then
+        ibegin = max(ibegin,begin)
+    endif
+
+    iend = len_trim(str)
+    if (present(end))then
+        iend= min(iend,end)
+    endif
+
+    do i = ibegin, iend                               ! step thru each letter in the string in specified range
+        select case (str(i:i))
+        case ('A':'Z')
+            string(i:i) = char(iachar(str(i:i))+32)     ! change letter to miniscule
+        case default
+        end select
+    end do
+
+end function lower
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/make_archive.html b/proc/make_archive.html new file mode 100644 index 0000000000..161c65e451 --- /dev/null +++ b/proc/make_archive.html @@ -0,0 +1,469 @@ + + + + + + + + + + + + + make_archive – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

make_archive + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine make_archive(self, output, args, log_file, stat, dry_run) +

+ + +

Create an archive

+
+

Todo

+

For Windows OS, use the local delete_file_win32 in stead of delete_file. +This may be related to a bug in Mingw64-openmp and is expected to be resolved in the future, +see issue #707, #708 and #808.

+
+ +

Type Bound

+

archiver_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(archiver_t), + intent(in) + + ::self +

Instance of the archiver object

+
+ + character(len=*), + intent(in) + + ::output +

Name of the archive to generate

+
+ + type(string_t), + intent(in) + + ::args(:) +

Object files to include into the archive

+
+ + character(len=*), + intent(in) + + ::log_file +

Compiler output log file

+
+ + integer, + intent(out) + + ::stat +

Status flag

+
+ + logical, + intent(in),optional + + ::dry_run +

Optional mocking

+
+ +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + logical, + public + + ::mock + +
+ +
+
+ + + + + + + +
+

Subroutines

+
+

subroutine delete_file_win32(file) +

+
+ + + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::file + +
+ + +
+
+ +
+ + +
+

Source Code

+
subroutine make_archive(self, output, args, log_file, stat, dry_run)
+    !> Instance of the archiver object
+    class(archiver_t), intent(in) :: self
+    !> Name of the archive to generate
+    character(len=*), intent(in) :: output
+    !> Object files to include into the archive
+    type(string_t), intent(in) :: args(:)
+    !> Compiler output log file
+    character(len=*), intent(in) :: log_file
+    !> Status flag
+    integer, intent(out) :: stat
+    !> Optional mocking
+    logical, optional, intent(in) :: dry_run    
+    
+    logical :: mock
+        
+    ! Check if we're actually linking
+    mock = .false.
+    if (present(dry_run)) mock = dry_run            
+    
+    if (mock) return
+
+    if (self%use_response_file) then
+        call write_response_file(output//".resp" , args)
+        call run(self%ar // output // " @" // output//".resp", echo=self%echo, &
+            &  verbose=self%verbose, redirect=log_file, exitstat=stat)
+        call delete_file_win32(output//".resp")
+
+    else
+        call run(self%ar // output // " " // string_cat(args, " "), &
+            & echo=self%echo, verbose=self%verbose, redirect=log_file, exitstat=stat)
+    end if
+
+    contains
+        subroutine delete_file_win32(file)
+            character(len=*), intent(in) :: file
+            logical :: exist
+            integer :: unit, iostat
+            inquire(file=file, exist=exist)
+            if (exist) then
+                open(file=file, newunit=unit)
+                close(unit, status='delete', iostat=iostat)
+            end if
+        end subroutine delete_file_win32
+end subroutine make_archive
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/manifest_has_changed.html b/proc/manifest_has_changed.html new file mode 100644 index 0000000000..e78556435c --- /dev/null +++ b/proc/manifest_has_changed.html @@ -0,0 +1,319 @@ + + + + + + + + + + + + + manifest_has_changed – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

manifest_has_changed + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function manifest_has_changed(cached, manifest, verbosity, iunit) result(has_changed) +

+ + +

Check if two dependency configurations are different

+

Perform all checks +All checks passed! The two instances are equal

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(dependency_config_t), + intent(in) + + ::cached +

Two instances of the dependency configuration

+
+ + class(dependency_config_t), + intent(in) + + ::manifest +

Two instances of the dependency configuration

+
+ + integer, + intent(in) + + ::verbosity +

Log verbosity

+
+ + integer, + intent(in) + + ::iunit +

Log verbosity

+
+ +

Return Value + + + logical + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
    logical function manifest_has_changed(cached, manifest, verbosity, iunit) result(has_changed)
+
+        !> Two instances of the dependency configuration
+        class(dependency_config_t), intent(in) :: cached, manifest
+
+        !> Log verbosity
+        integer, intent(in) :: verbosity, iunit
+
+        has_changed = .true.
+
+        !> Perform all checks
+        if (allocated(cached%git).neqv.allocated(manifest%git)) then
+            if (verbosity>1) write(iunit,out_fmt) "GIT presence has changed. "
+            return
+        endif
+        if (allocated(cached%git)) then
+            if (.not.git_matches_manifest(cached%git,manifest%git,verbosity,iunit)) return
+        end if
+
+        !> All checks passed! The two instances are equal
+        has_changed = .false.
+
+    end function manifest_has_changed
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/match_os_type.html b/proc/match_os_type.html new file mode 100644 index 0000000000..07ae64dc24 --- /dev/null +++ b/proc/match_os_type.html @@ -0,0 +1,278 @@ + + + + + + + + + + + + + match_os_type – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

match_os_type + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine match_os_type(os_name, os_type) +

+ + +

Match os_type enum to a lowercase string with name of OS

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=:), + intent(in), + allocatable + ::os_name +

Name of operating system

+
+ + integer, + intent(out) + + ::os_type +

Enum representing type of OS

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
      subroutine match_os_type(os_name, os_type)
+
+        !> Name of operating system
+        character(len=:), allocatable, intent(in) :: os_name
+
+        !> Enum representing type of OS
+        integer, intent(out) :: os_type
+
+        select case (os_name)
+          case ("linux");   os_type = OS_LINUX
+          case ("macos");   os_type = OS_MACOS
+          case ("windows"); os_type = OS_WINDOWS
+          case ("cygwin");  os_type = OS_CYGWIN
+          case ("solaris"); os_type = OS_SOLARIS
+          case ("freebsd"); os_type = OS_FREEBSD
+          case ("openbsd"); os_type = OS_OPENBSD
+          case ("all");     os_type = OS_ALL
+          case default;     os_type = OS_UNKNOWN
+        end select
+
+      end subroutine match_os_type
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/mkdir.html b/proc/mkdir.html new file mode 100644 index 0000000000..8cbdfbb43b --- /dev/null +++ b/proc/mkdir.html @@ -0,0 +1,279 @@ + + + + + + + + + + + + + mkdir – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

mkdir + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine mkdir(dir, echo) +

+ + +

Create a directory. Create subdirectories as needed

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::dir + +
+ + logical, + intent(in),optional + + ::echo + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
subroutine mkdir(dir, echo)
+    character(len=*), intent(in) :: dir
+    logical, intent(in), optional :: echo
+
+    integer :: stat
+
+    if (is_dir(dir)) return
+
+    select case (get_os_type())
+        case (OS_UNKNOWN, OS_LINUX, OS_MACOS, OS_CYGWIN, OS_SOLARIS, OS_FREEBSD, OS_OPENBSD)
+            call run('mkdir -p ' // dir, exitstat=stat,echo=echo,verbose=.false.)
+
+        case (OS_WINDOWS)
+            call run("mkdir " // windows_path(dir), &
+                    & echo=echo, exitstat=stat,verbose=.false.)
+
+    end select
+
+    if (stat /= 0) then
+        call fpm_stop(1, '*mkdir*:directory creation failed')
+    end if
+end subroutine mkdir
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/module_prefix_template.html b/proc/module_prefix_template.html new file mode 100644 index 0000000000..8c58341300 --- /dev/null +++ b/proc/module_prefix_template.html @@ -0,0 +1,278 @@ + + + + + + + + + + + + + module_prefix_template – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

module_prefix_template + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function module_prefix_template(project_name, custom_prefix) result(prefix) +

+ + + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(string_t), + intent(in) + + ::project_name + +
+ + type(string_t), + intent(in) + + ::custom_prefix + +
+ +

Return Value + + + type(string_t) + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
type(string_t) function module_prefix_template(project_name,custom_prefix) result(prefix)
+    type(string_t), intent(in) :: project_name
+    type(string_t), intent(in) :: custom_prefix
+
+    if (is_valid_module_prefix(custom_prefix)) then
+
+        prefix = string_t(trim(custom_prefix%s)//"_")
+
+    else
+
+        prefix = string_t(to_fortran_name(project_name%s)//"__")
+
+    end if
+
+end function module_prefix_template
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/module_prefix_type.html b/proc/module_prefix_type.html new file mode 100644 index 0000000000..142d1122c8 --- /dev/null +++ b/proc/module_prefix_type.html @@ -0,0 +1,274 @@ + + + + + + + + + + + + + module_prefix_type – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

module_prefix_type + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function module_prefix_type(project_name, custom_prefix) result(ptype) +

+ + + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(string_t), + intent(in) + + ::project_name + +
+ + type(string_t), + intent(in) + + ::custom_prefix + +
+ +

Return Value + + + type(string_t) + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
type(string_t) function module_prefix_type(project_name,custom_prefix) result(ptype)
+    type(string_t), intent(in) :: project_name
+    type(string_t), intent(in) :: custom_prefix
+
+    if (is_valid_module_prefix(custom_prefix)) then
+        ptype = string_t("custom")
+    else
+        ptype = string_t("default")
+    end if
+
+end function module_prefix_type
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/mpi_type_name.html b/proc/mpi_type_name.html new file mode 100644 index 0000000000..9b43fa0144 --- /dev/null +++ b/proc/mpi_type_name.html @@ -0,0 +1,261 @@ + + + + + + + + + + + + + MPI_TYPE_NAME – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

MPI_TYPE_NAME + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public pure function MPI_TYPE_NAME(mpilib) result(name) +

+ + +

Return a name for the MPI library

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + integer, + intent(in) + + ::mpilib + +
+ +

Return Value + + + character(len=:), allocatable + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
    pure function MPI_TYPE_NAME(mpilib) result(name)
+       integer, intent(in) :: mpilib
+       character(len=:), allocatable :: name
+       select case (mpilib)
+          case (MPI_TYPE_NONE);    name = "none"
+          case (MPI_TYPE_OPENMPI); name = "OpenMPI"
+          case (MPI_TYPE_MPICH);   name = "MPICH"
+          case (MPI_TYPE_INTEL);   name = "INTELMPI"
+          case (MPI_TYPE_MSMPI);   name = "MS-MPI"
+          case default;            name = "UNKNOWN"
+       end select
+    end function MPI_TYPE_NAME
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/name_is_json.html b/proc/name_is_json.html new file mode 100644 index 0000000000..2593522203 --- /dev/null +++ b/proc/name_is_json.html @@ -0,0 +1,261 @@ + + + + + + + + + + + + + name_is_json – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

name_is_json + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function name_is_json(filename) +

+ + +

Choose between JSON or TOML based on a file name

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::filename + +
+ +

Return Value + + + logical + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
    logical function name_is_json(filename)
+        character(*), intent(in) :: filename
+
+        character(*), parameter :: json_identifier = ".json"
+
+        name_is_json = .false.
+
+        if (len_trim(filename)<len(json_identifier)) return
+
+        name_is_json = str_ends_with(lower(filename),json_identifier)
+
+    end function name_is_json
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/new_archiver.html b/proc/new_archiver.html new file mode 100644 index 0000000000..04692f395f --- /dev/null +++ b/proc/new_archiver.html @@ -0,0 +1,444 @@ + + + + + + + + + + + + + new_archiver – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

new_archiver + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine new_archiver(self, ar, echo, verbose) +

+ + +

Create new archiver instance

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(archiver_t), + intent(out) + + ::self +

New instance of the archiver

+
+ + character(len=*), + intent(in) + + ::ar +

User provided archiver command

+
+ + logical, + intent(in) + + ::echo +

Echo compiler command

+
+ + logical, + intent(in) + + ::verbose +

Verbose mode: dump compiler output

+
+ +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=*), + public, +parameter + ::arflags =" -rs " + +
+ + integer, + public + + ::estat + +
+ + character(len=*), + public, +parameter + ::libflags =" /OUT:" + +
+ + integer, + public + + ::os_type + +
+ +
+
+ + + + + + + + + +
+

Source Code

+
subroutine new_archiver(self, ar, echo, verbose)
+    !> New instance of the archiver
+    type(archiver_t), intent(out) :: self
+    !> User provided archiver command
+    character(len=*), intent(in) :: ar
+    !> Echo compiler command
+    logical, intent(in) :: echo
+    !> Verbose mode: dump compiler output
+    logical, intent(in) :: verbose
+
+    integer :: estat, os_type
+
+    character(len=*), parameter :: arflags = " -rs ", libflags = " /OUT:"
+
+    if (len_trim(ar) > 0) then
+      ! Check first for ar-like commands
+      if (check_compiler(ar, "ar")) then
+        self%ar = ar//arflags
+      end if
+
+      ! Check for lib-like commands
+      if (check_compiler(ar, "lib")) then
+        self%ar = ar//libflags
+      end if
+
+      ! Fallback and assume ar-like behaviour
+      self%ar = ar//arflags
+    else
+      os_type = get_os_type()
+      if (os_type /= OS_WINDOWS .and. os_type /= OS_UNKNOWN) then
+        self%ar = "ar"//arflags
+      else
+        ! Attempt "ar"
+        call execute_command_line("ar --version > "//get_temp_filename()//" 2>&1", &
+          & exitstat=estat)
+
+        if (estat == 0) then
+
+            self%ar = "ar"//arflags
+
+        else
+
+            ! Then "gcc-ar"
+            call execute_command_line("gcc-ar --version > "//get_temp_filename()//" 2>&1", &
+               & exitstat=estat)
+
+            if (estat /= 0) then
+              self%ar = "lib"//libflags
+            else
+              self%ar = "gcc-ar"//arflags
+            end if
+        endif
+      end if
+    end if
+    self%use_response_file = os_type == OS_WINDOWS
+    self%echo = echo
+    self%verbose = verbose
+end subroutine new_archiver
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/new_build_config.html b/proc/new_build_config.html new file mode 100644 index 0000000000..9285353f78 --- /dev/null +++ b/proc/new_build_config.html @@ -0,0 +1,365 @@ + + + + + + + + + + + + + new_build_config – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

new_build_config + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine new_build_config(self, table, package_name, error) +

+ + +

Construct a new build configuration from a TOML data structure

+

Module naming: fist, attempt boolean value first

+

Value found, but not a boolean. Attempt to read a prefix string

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(build_config_t), + intent(out) + + ::self +

Instance of the build configuration

+
+ + type(toml_table), + intent(inout) + + ::table +

Instance of the TOML data structure

+
+ + character(len=*), + intent(in) + + ::package_name +

Package name

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
    subroutine new_build_config(self, table, package_name, error)
+
+        !> Instance of the build configuration
+        type(build_config_t), intent(out) :: self
+
+        !> Instance of the TOML data structure
+        type(toml_table), intent(inout) :: table
+
+        !> Package name
+        character(len=*), intent(in) :: package_name
+
+        !> Error handling
+        type(error_t), allocatable, intent(out) :: error
+
+        integer :: stat
+
+        call check(table, package_name, error)
+        if (allocated(error)) return
+
+        call get_value(table, "auto-executables", self%auto_executables, .true., stat=stat)
+
+        if (stat /= toml_stat%success) then
+            call fatal_error(error,"Error while reading value for 'auto-executables' in fpm.toml, expecting logical")
+            return
+        end if
+
+        call get_value(table, "auto-tests", self%auto_tests, .true., stat=stat)
+
+        if (stat /= toml_stat%success) then
+            call fatal_error(error,"Error while reading value for 'auto-tests' in fpm.toml, expecting logical")
+            return
+        end if
+
+        call get_value(table, "auto-examples", self%auto_examples, .true., stat=stat)
+
+        if (stat /= toml_stat%success) then
+            call fatal_error(error,"Error while reading value for 'auto-examples' in fpm.toml, expecting logical")
+            return
+        end if
+
+        !> Module naming: fist, attempt boolean value first
+        call get_value(table, "module-naming", self%module_naming, .false., stat=stat)
+
+        if (stat == toml_stat%success) then
+
+            ! Boolean value found. Set no custom prefix. This also falls back to key not provided
+            if (allocated(self%module_prefix%s)) deallocate(self%module_prefix%s)
+
+        else
+
+            !> Value found, but not a boolean. Attempt to read a prefix string
+            call get_value(table, "module-naming", self%module_prefix%s)
+
+            if (.not.allocated(self%module_prefix%s)) then
+               call syntax_error(error,"Could not read value for 'module-naming' in fpm.toml, expecting logical or a string")
+               return
+            end if
+
+            if (.not.is_valid_module_prefix(self%module_prefix)) then
+               call syntax_error(error,"Invalid custom module name prefix for in fpm.toml: <"//self%module_prefix%s// &
+                            ">, expecting a valid alphanumeric string")
+               return
+            end if
+
+            ! Set module naming to ON
+            self%module_naming = .true.
+
+        end if
+
+        call get_list(table, "link", self%link, error)
+        if (allocated(error)) return
+
+        call get_list(table, "external-modules", self%external_modules, error)
+        if (allocated(error)) return
+
+    end subroutine new_build_config
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/new_compiler.html b/proc/new_compiler.html new file mode 100644 index 0000000000..5a99056122 --- /dev/null +++ b/proc/new_compiler.html @@ -0,0 +1,349 @@ + + + + + + + + + + + + + new_compiler – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

new_compiler + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine new_compiler(self, fc, cc, cxx, echo, verbose) +

+ + +

Create new compiler instance

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(compiler_t), + intent(out) + + ::self +

New instance of the compiler

+
+ + character(len=*), + intent(in) + + ::fc +

Fortran compiler name or path

+
+ + character(len=*), + intent(in) + + ::cc +

C compiler name or path

+
+ + character(len=*), + intent(in) + + ::cxx +

C++ Compiler name or path

+
+ + logical, + intent(in) + + ::echo +

Echo compiler command

+
+ + logical, + intent(in) + + ::verbose +

Verbose mode: dump compiler output

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
subroutine new_compiler(self, fc, cc, cxx, echo, verbose)
+    !> New instance of the compiler
+    type(compiler_t), intent(out) :: self
+    !> Fortran compiler name or path
+    character(len=*), intent(in) :: fc
+    !> C compiler name or path
+    character(len=*), intent(in) :: cc
+    !> C++ Compiler name or path
+    character(len=*), intent(in) :: cxx
+    !> Echo compiler command
+    logical, intent(in) :: echo
+    !> Verbose mode: dump compiler output
+    logical, intent(in) :: verbose
+
+    self%id = get_compiler_id(fc)
+
+    self%echo = echo
+    self%verbose = verbose
+    self%fc = fc
+    if (len_trim(cc) > 0) then
+      self%cc = cc
+    else
+      call get_default_c_compiler(self%fc, self%cc)
+    end if
+
+    if (len_trim(cxx) > 0) then
+      self%cxx = cxx
+    else
+      call get_default_cxx_compiler(self%fc, self%cxx)
+    end if
+
+end subroutine new_compiler
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/new_dependencies.html b/proc/new_dependencies.html new file mode 100644 index 0000000000..dd9a59f604 --- /dev/null +++ b/proc/new_dependencies.html @@ -0,0 +1,387 @@ + + + + + + + + + + + + + new_dependencies – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

new_dependencies + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine new_dependencies(deps, table, root, meta, error) +

+ + +

Construct new dependency array from a TOML data structure

+

Flag dependencies that should be treated as metapackages +Parse all meta- and non-metapackage dependencies

+

Neither a standard dep nor a metapackage +Valid meta dependency

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(dependency_config_t), + intent(out), + allocatable + ::deps(:) +

Instance of the dependency configuration

+
+ + type(toml_table), + intent(inout) + + ::table +

Instance of the TOML data structure

+
+ + character(len=*), + intent(in),optional + + ::root +

Root directory of the manifest

+
+ + type(metapackage_config_t), + intent(out),optional + + ::meta +

(optional) metapackages

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
    subroutine new_dependencies(deps, table, root, meta, error)
+
+        !> Instance of the dependency configuration
+        type(dependency_config_t), allocatable, intent(out) :: deps(:)
+
+        !> (optional) metapackages
+        type(metapackage_config_t), optional, intent(out) :: meta
+
+        !> Instance of the TOML data structure
+        type(toml_table), intent(inout) :: table
+
+        !> Root directory of the manifest
+        character(*), intent(in), optional :: root
+
+        !> Error handling
+        type(error_t), allocatable, intent(out) :: error
+
+        type(toml_table), pointer :: node
+        type(toml_key), allocatable :: list(:)
+        type(dependency_config_t), allocatable :: all_deps(:)
+        type(metapackage_request_t) :: meta_request
+        logical, allocatable :: is_meta(:)
+        logical :: metapackages_allowed
+        integer :: idep, stat, ndep
+
+        call table%get_keys(list)
+        ! An empty table is okay
+        if (size(list) < 1) return
+
+        !> Flag dependencies that should be treated as metapackages
+        metapackages_allowed = present(meta)
+        allocate(is_meta(size(list)),source=.false.)
+        allocate(all_deps(size(list)))
+
+        !> Parse all meta- and non-metapackage dependencies
+        do idep = 1, size(list)
+
+            ! Check if this is a standard dependency node
+            call get_value(table, list(idep)%key, node, stat=stat)
+            is_standard_dependency: if (stat /= toml_stat%success) then
+
+                ! See if it can be a valid metapackage name
+                call new_meta_request(meta_request, list(idep)%key, table, error=error)
+
+                !> Neither a standard dep nor a metapackage
+                if (allocated(error)) then
+                   call syntax_error(error, "Dependency "//list(idep)%key//" is not a valid metapackage or a table entry")
+                   return
+                endif
+
+                !> Valid meta dependency
+                is_meta(idep) = .true.
+
+            else
+
+                ! Parse as a standard dependency
+                is_meta(idep) = .false.
+
+                call new_dependency(all_deps(idep), node, root, error)
+                if (allocated(error)) return
+
+            end if is_standard_dependency
+
+        end do
+
+        ! Non-meta dependencies
+        ndep = count(.not.is_meta)
+
+        ! Finalize standard dependencies
+        allocate(deps(ndep))
+        ndep = 0
+        do idep = 1, size(list)
+            if (is_meta(idep)) cycle
+            ndep = ndep+1
+            deps(ndep) = all_deps(idep)
+        end do
+
+        ! Finalize meta dependencies
+        if (metapackages_allowed) call new_meta_config(meta,table,is_meta,error)
+
+    end subroutine new_dependencies
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/new_dependency.html b/proc/new_dependency.html new file mode 100644 index 0000000000..0bad6f239f --- /dev/null +++ b/proc/new_dependency.html @@ -0,0 +1,362 @@ + + + + + + + + + + + + + new_dependency – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

new_dependency + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine new_dependency(self, table, root, error) +

+ + +

Construct a new dependency configuration from a TOML data structure

+

Get optional preprocessor directives

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(dependency_config_t), + intent(out) + + ::self +

Instance of the dependency configuration

+
+ + type(toml_table), + intent(inout) + + ::table +

Instance of the TOML data structure

+
+ + character(len=*), + intent(in),optional + + ::root +

Root directory of the manifest

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
    subroutine new_dependency(self, table, root, error)
+
+        !> Instance of the dependency configuration
+        type(dependency_config_t), intent(out) :: self
+
+        !> Instance of the TOML data structure
+        type(toml_table), intent(inout) :: table
+
+        !> Root directory of the manifest
+        character(*), intent(in), optional :: root
+
+        !> Error handling
+        type(error_t), allocatable, intent(out) :: error
+
+        character(len=:), allocatable :: uri, value, requested_version
+
+        type(toml_table), pointer :: child
+
+        call check(table, error)
+        if (allocated(error)) return
+
+        call table%get_key(self%name)
+        call get_value(table, "namespace", self%namespace)
+
+        call get_value(table, "v", requested_version)
+        if (allocated(requested_version)) then
+            if (.not. allocated(self%requested_version)) allocate (self%requested_version)
+            call new_version(self%requested_version, requested_version, error)
+            if (allocated(error)) return
+        end if
+
+        !> Get optional preprocessor directives
+        call get_value(table, "preprocess", child, requested=.false.)
+        if (associated(child)) then
+            call new_preprocessors(self%preprocess, child, error)
+            if (allocated(error)) return
+        endif
+
+        call get_value(table, "path", uri)
+        if (allocated(uri)) then
+            if (get_os_type() == OS_WINDOWS) uri = windows_path(uri)
+            if (present(root)) uri = join_path(root,uri)  ! Relative to the fpm.toml it’s written in
+            call move_alloc(uri, self%path)
+            return
+        end if
+
+        call get_value(table, "git", uri)
+        if (allocated(uri)) then
+            call get_value(table, "tag", value)
+            if (allocated(value)) then
+                self%git = git_target_tag(uri, value)
+            end if
+
+            if (.not. allocated(self%git)) then
+                call get_value(table, "branch", value)
+                if (allocated(value)) then
+                    self%git = git_target_branch(uri, value)
+                end if
+            end if
+
+            if (.not. allocated(self%git)) then
+                call get_value(table, "rev", value)
+                if (allocated(value)) then
+                    self%git = git_target_revision(uri, value)
+                end if
+            end if
+
+            if (.not. allocated(self%git)) then
+                self%git = git_target_default(uri)
+            end if
+            return
+        end if
+
+    end subroutine new_dependency
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/new_dependency_node.html b/proc/new_dependency_node.html new file mode 100644 index 0000000000..8d6af3b4f2 --- /dev/null +++ b/proc/new_dependency_node.html @@ -0,0 +1,329 @@ + + + + + + + + + + + + + new_dependency_node – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

new_dependency_node + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine new_dependency_node(self, dependency, version, proj_dir, update) +

+ + +

Create a new dependency node from a configuration

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(dependency_node_t), + intent(out) + + ::self +

Instance of the dependency node

+
+ + type(dependency_config_t), + intent(in) + + ::dependency +

Dependency configuration data

+
+ + type(version_t), + intent(in),optional + + ::version +

Version of the dependency

+
+ + character(len=*), + intent(in),optional + + ::proj_dir +

Installation prefix of the dependency

+
+ + logical, + intent(in),optional + + ::update +

Dependency should be updated

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
  subroutine new_dependency_node(self, dependency, version, proj_dir, update)
+    !> Instance of the dependency node
+    type(dependency_node_t), intent(out) :: self
+    !> Dependency configuration data
+    type(dependency_config_t), intent(in) :: dependency
+    !> Version of the dependency
+    type(version_t), intent(in), optional :: version
+    !> Installation prefix of the dependency
+    character(len=*), intent(in), optional :: proj_dir
+    !> Dependency should be updated
+    logical, intent(in), optional :: update
+
+    self%dependency_config_t = dependency
+
+    if (present(version)) then
+      self%version = version
+    end if
+
+    if (present(proj_dir)) then
+      self%proj_dir = proj_dir
+    end if
+
+    if (present(update)) then
+      self%update = update
+    end if
+
+  end subroutine new_dependency_node
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/new_dependency_tree.html b/proc/new_dependency_tree.html new file mode 100644 index 0000000000..99a052b421 --- /dev/null +++ b/proc/new_dependency_tree.html @@ -0,0 +1,307 @@ + + + + + + + + + + + + + new_dependency_tree – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

new_dependency_tree + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine new_dependency_tree(self, verbosity, cache, path_to_config) +

+ + +

Create a new dependency tree

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(dependency_tree_t), + intent(out) + + ::self +

Instance of the dependency tree

+
+ + integer, + intent(in),optional + + ::verbosity +

Verbosity of printout

+
+ + character(len=*), + intent(in),optional + + ::cache +

Name of the cache file

+
+ + character(len=*), + intent(in),optional + + ::path_to_config +

Path to the global config file.

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
  subroutine new_dependency_tree(self, verbosity, cache, path_to_config)
+    !> Instance of the dependency tree
+    type(dependency_tree_t), intent(out) :: self
+    !> Verbosity of printout
+    integer, intent(in), optional :: verbosity
+    !> Name of the cache file
+    character(len=*), intent(in), optional :: cache
+    !> Path to the global config file.
+    character(len=*), intent(in), optional :: path_to_config
+
+    call resize(self%dep)
+    self%dep_dir = join_path("build", "dependencies")
+
+    if (present(verbosity)) self%verbosity = verbosity
+
+    if (present(cache)) self%cache = cache
+
+    if (present(path_to_config)) self%path_to_config = path_to_config
+
+  end subroutine new_dependency_tree
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/new_example.html b/proc/new_example.html new file mode 100644 index 0000000000..c7a1b64929 --- /dev/null +++ b/proc/new_example.html @@ -0,0 +1,309 @@ + + + + + + + + + + + + + new_example – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

new_example + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine new_example(self, table, error) +

+ + +

Construct a new example configuration from a TOML data structure

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(example_config_t), + intent(out) + + ::self +

Instance of the example configuration

+
+ + type(toml_table), + intent(inout) + + ::table +

Instance of the TOML data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
    subroutine new_example(self, table, error)
+
+        !> Instance of the example configuration
+        type(example_config_t), intent(out) :: self
+
+        !> Instance of the TOML data structure
+        type(toml_table), intent(inout) :: table
+
+        !> Error handling
+        type(error_t), allocatable, intent(out) :: error
+
+        type(toml_table), pointer :: child
+
+        call check(table, error)
+        if (allocated(error)) return
+
+        call get_value(table, "name", self%name)
+        if (.not.allocated(self%name)) then
+           call syntax_error(error, "Could not retrieve example name")
+           return
+        end if
+        if (bad_name_error(error,'example',self%name))then
+           return
+        endif
+        call get_value(table, "source-dir", self%source_dir, "example")
+        call get_value(table, "main", self%main, "main.f90")
+
+        call get_value(table, "dependencies", child, requested=.false.)
+        if (associated(child)) then
+            call new_dependencies(self%dependency, child, error=error)
+            if (allocated(error)) return
+        end if
+
+        call get_list(table, "link", self%link, error)
+        if (allocated(error)) return
+
+    end subroutine new_example
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/new_executable.html b/proc/new_executable.html new file mode 100644 index 0000000000..df0e8cfa62 --- /dev/null +++ b/proc/new_executable.html @@ -0,0 +1,309 @@ + + + + + + + + + + + + + new_executable – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

new_executable + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine new_executable(self, table, error) +

+ + +

Construct a new executable configuration from a TOML data structure

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(executable_config_t), + intent(out) + + ::self +

Instance of the executable configuration

+
+ + type(toml_table), + intent(inout) + + ::table +

Instance of the TOML data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
    subroutine new_executable(self, table, error)
+
+        !> Instance of the executable configuration
+        type(executable_config_t), intent(out) :: self
+
+        !> Instance of the TOML data structure
+        type(toml_table), intent(inout) :: table
+
+        !> Error handling
+        type(error_t), allocatable, intent(out) :: error
+
+        type(toml_table), pointer :: child
+
+        call check(table, error)
+        if (allocated(error)) return
+
+        call get_value(table, "name", self%name)
+        if (.not.allocated(self%name)) then
+           call syntax_error(error, "Could not retrieve executable name")
+           return
+        end if
+        if (bad_name_error(error,'executable',self%name))then
+           return
+        endif
+        call get_value(table, "source-dir", self%source_dir, "app")
+        call get_value(table, "main", self%main, "main.f90")
+
+        call get_value(table, "dependencies", child, requested=.false.)
+        if (associated(child)) then
+            call new_dependencies(self%dependency, child, error=error)
+            if (allocated(error)) return
+        end if
+
+        call get_list(table, "link", self%link, error)
+        if (allocated(error)) return
+
+    end subroutine new_executable
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/new_fortran_config.html b/proc/new_fortran_config.html new file mode 100644 index 0000000000..ecc0287895 --- /dev/null +++ b/proc/new_fortran_config.html @@ -0,0 +1,318 @@ + + + + + + + + + + + + + new_fortran_config – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

new_fortran_config + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine new_fortran_config(self, table, error) +

+ + +

Construct a new build configuration from a TOML data structure

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(fortran_config_t), + intent(out) + + ::self +

Instance of the fortran configuration

+
+ + type(toml_table), + intent(inout) + + ::table +

Instance of the TOML data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
    subroutine new_fortran_config(self, table, error)
+
+        !> Instance of the fortran configuration
+        type(fortran_config_t), intent(out) :: self
+
+        !> Instance of the TOML data structure
+        type(toml_table), intent(inout) :: table
+
+        !> Error handling
+        type(error_t), allocatable, intent(out) :: error
+
+        integer :: stat
+        character(:), allocatable :: source_form
+
+        call check(table, error)
+        if (allocated(error)) return
+
+        call get_value(table, "implicit-typing", self%implicit_typing, .false., stat=stat)
+
+        if (stat /= toml_stat%success) then
+            call fatal_error(error,"Error while reading value for 'implicit-typing' in fpm.toml, expecting logical")
+            return
+        end if
+
+        call get_value(table, "implicit-external", self%implicit_external, .false., stat=stat)
+
+        if (stat /= toml_stat%success) then
+            call fatal_error(error,"Error while reading value for 'implicit-external' in fpm.toml, expecting logical")
+            return
+        end if
+
+        call get_value(table, "source-form", source_form, "free", stat=stat)
+
+        if (stat /= toml_stat%success) then
+            call fatal_error(error,"Error while reading value for 'source-form' in fpm.toml, expecting logical")
+            return
+        end if
+        select case(source_form)
+        case default
+            call fatal_error(error,"Value of source-form cannot be '"//source_form//"'")
+            return
+        case("free", "fixed", "default")
+            self%source_form = source_form
+        end select
+
+    end subroutine new_fortran_config
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/new_install_config.html b/proc/new_install_config.html new file mode 100644 index 0000000000..12ef00cc9a --- /dev/null +++ b/proc/new_install_config.html @@ -0,0 +1,290 @@ + + + + + + + + + + + + + new_install_config – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

new_install_config + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine new_install_config(self, table, error) +

+ + +

Create a new installation configuration from a TOML data structure

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(install_config_t), + intent(out) + + ::self +

Instance of the install configuration

+
+ + type(toml_table), + intent(inout) + + ::table +

Instance of the TOML data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
  subroutine new_install_config(self, table, error)
+
+    !> Instance of the install configuration
+    type(install_config_t), intent(out) :: self
+
+    !> Instance of the TOML data structure
+    type(toml_table), intent(inout) :: table
+
+    !> Error handling
+    type(error_t), allocatable, intent(out) :: error
+
+    call check(table, error)
+    if (allocated(error)) return
+
+    call get_value(table, "library", self%library, .false.)
+    call get_value(table, "test", self%test, .false.)
+
+  end subroutine new_install_config
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/new_installer.html b/proc/new_installer.html new file mode 100644 index 0000000000..259a55b62e --- /dev/null +++ b/proc/new_installer.html @@ -0,0 +1,443 @@ + + + + + + + + + + + + + new_installer – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

new_installer + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine new_installer(self, prefix, bindir, libdir, includedir, testdir, verbosity, copy, move) +

+ + +

Create a new instance of an installer

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(installer_t), + intent(out) + + ::self +

Instance of the installer

+
+ + character(len=*), + intent(in),optional + + ::prefix +

Path to installation directory

+
+ + character(len=*), + intent(in),optional + + ::bindir +

Binary dir relative to the installation prefix

+
+ + character(len=*), + intent(in),optional + + ::libdir +

Library directory relative to the installation prefix

+
+ + character(len=*), + intent(in),optional + + ::includedir +

Include directory relative to the installation prefix

+
+ + character(len=*), + intent(in),optional + + ::testdir +

Test directory relative to the installation prefix

+
+ + integer, + intent(in),optional + + ::verbosity +

Verbosity of the installer

+
+ + character(len=*), + intent(in),optional + + ::copy +

Copy command

+
+ + character(len=*), + intent(in),optional + + ::move +

Move command

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
  subroutine new_installer(self, prefix, bindir, libdir, includedir, testdir, verbosity, &
+          copy, move)
+    !> Instance of the installer
+    type(installer_t), intent(out) :: self
+    !> Path to installation directory
+    character(len=*), intent(in), optional :: prefix
+    !> Binary dir relative to the installation prefix
+    character(len=*), intent(in), optional :: bindir
+    !> Library directory relative to the installation prefix
+    character(len=*), intent(in), optional :: libdir
+    !> Include directory relative to the installation prefix
+    character(len=*), intent(in), optional :: includedir
+    !> Test directory relative to the installation prefix
+    character(len=*), intent(in), optional :: testdir    
+    !> Verbosity of the installer
+    integer, intent(in), optional :: verbosity
+    !> Copy command
+    character(len=*), intent(in), optional :: copy
+    !> Move command
+    character(len=*), intent(in), optional :: move
+
+    self%os = get_os_type()
+
+    ! By default, never prompt the user for overwrites
+    if (present(copy)) then
+      self%copy = copy
+    else
+      if (os_is_unix(self%os)) then
+        self%copy = default_force_copy_unix
+      else
+        self%copy = default_force_copy_win
+      end if
+    end if
+
+    if (present(move)) then
+      self%move = move
+    else
+      if (os_is_unix(self%os)) then
+        self%move = default_move_unix
+      else
+        self%move = default_move_win
+      end if
+    end if
+
+    if (present(includedir)) then
+      self%includedir = includedir
+    else
+      self%includedir = default_includedir
+    end if
+    
+    if (present(testdir)) then 
+      self%testdir = testdir
+    else
+      self%testdir = default_testdir  
+    end if
+
+    if (present(prefix)) then
+      self%prefix = prefix
+    else
+      self%prefix = get_local_prefix(self%os)
+    end if
+
+    if (present(bindir)) then
+      self%bindir = bindir
+    else
+      self%bindir = default_bindir
+    end if
+
+    if (present(libdir)) then
+      self%libdir = libdir
+    else
+      self%libdir = default_libdir
+    end if
+
+    if (present(verbosity)) then
+      self%verbosity = verbosity
+    else
+      self%verbosity = 1
+    end if
+
+  end subroutine new_installer
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/new_library.html b/proc/new_library.html new file mode 100644 index 0000000000..33a3a6a066 --- /dev/null +++ b/proc/new_library.html @@ -0,0 +1,325 @@ + + + + + + + + + + + + + new_library – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

new_library + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine new_library(self, table, error) +

+ + +

Construct a new library configuration from a TOML data structure

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(library_config_t), + intent(out) + + ::self +

Instance of the library configuration

+
+ + type(toml_table), + intent(inout) + + ::table +

Instance of the TOML data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
    subroutine new_library(self, table, error)
+
+        !> Instance of the library configuration
+        type(library_config_t), intent(out) :: self
+
+        !> Instance of the TOML data structure
+        type(toml_table), intent(inout) :: table
+
+        !> Error handling
+        type(error_t), allocatable, intent(out) :: error
+        
+        integer :: stat
+
+        call check(table, error)
+        if (allocated(error)) return
+
+        if (has_list(table, "source-dir")) then
+            call syntax_error(error, "Manifest key [library.source-dir] does not allow list input")
+            return
+        end if
+
+        if (has_list(table, "type")) then
+            call syntax_error(error, "Manifest key [library.type] does not allow list input")
+            return
+        end if
+
+        call get_value(table, "source-dir", self%source_dir, "src")
+        call get_value(table, "build-script", self%build_script)
+
+        call get_list(table, "include-dir", self%include_dir, error)
+        if (allocated(error)) return
+        
+        call get_value(table, "type", self%lib_type, "monolithic")
+        
+        select case(self%lib_type)
+        case("shared","static","monolithic")
+            ! OK
+        case default
+            call fatal_error(error,"Value of library.type cannot be '"//self%lib_type &
+                                 //"', choose shared/static/monolithic (default)")
+            return
+        end select        
+        
+        ! Set default value of include-dir if not found in manifest
+        if (.not.allocated(self%include_dir)) then
+            self%include_dir = [string_t("include")]
+        end if
+        
+        if (.not.allocated(self%lib_type)) then 
+            self%lib_type = "monolithic"
+        end if
+
+    end subroutine new_library
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/new_meta_config.html b/proc/new_meta_config.html new file mode 100644 index 0000000000..238f1f3868 --- /dev/null +++ b/proc/new_meta_config.html @@ -0,0 +1,329 @@ + + + + + + + + + + + + + new_meta_config – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

new_meta_config + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine new_meta_config(self, table, meta_allowed, error) +

+ + +

Construct a new build configuration from a TOML data structure

+

The toml table is not checked here because it already passed +the “new_dependencies” check

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(metapackage_config_t), + intent(out) + + ::self +

Instance of the build configuration

+
+ + type(toml_table), + intent(inout) + + ::table +

Instance of the TOML data structure

+
+ + logical, + intent(in) + + ::meta_allowed(:) +

List of keys allowed to be metapackages

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
    subroutine new_meta_config(self, table, meta_allowed, error)
+
+        !> Instance of the build configuration
+        type(metapackage_config_t), intent(out) :: self
+
+        !> Instance of the TOML data structure
+        type(toml_table), intent(inout) :: table
+
+        !> List of keys allowed to be metapackages
+        logical, intent(in) :: meta_allowed(:)
+
+        !> Error handling
+        type(error_t), allocatable, intent(out) :: error
+
+        integer :: stat
+
+        !> The toml table is not checked here because it already passed
+        !> the "new_dependencies" check
+        call new_meta_request(self%openmp, "openmp", table, meta_allowed, error)
+        if (allocated(error)) return
+
+        call new_meta_request(self%stdlib, "stdlib", table, meta_allowed, error)
+        if (allocated(error)) return
+
+        call new_meta_request(self%minpack, "minpack", table, meta_allowed, error)
+        if (allocated(error)) return
+
+        call new_meta_request(self%mpi, "mpi", table, meta_allowed, error)
+        if (allocated(error)) return
+
+        call new_meta_request(self%hdf5, "hdf5", table, meta_allowed, error)
+        if (allocated(error)) return
+
+        call new_meta_request(self%netcdf, "netcdf", table, meta_allowed, error)
+        if (allocated(error)) return
+
+        call new_meta_request(self%blas, "blas", table, meta_allowed, error)
+        if (allocated(error)) return
+
+    end subroutine new_meta_config
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/new_meta_request.html b/proc/new_meta_request.html new file mode 100644 index 0000000000..e305ff3ed2 --- /dev/null +++ b/proc/new_meta_request.html @@ -0,0 +1,375 @@ + + + + + + + + + + + + + new_meta_request – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

new_meta_request + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine new_meta_request(self, key, table, meta_allowed, error) +

+ + +

Construct a new metapackage request from the dependencies table

+

Set name +The toml table is not checked here because it already passed +the “new_dependencies” check

+

Set list of entries that are allowed to be metapackages

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(metapackage_request_t), + intent(out) + + ::self + +
+ + character(len=*), + intent(in) + + ::key +

The package name

+
+ + type(toml_table), + intent(inout) + + ::table +

Instance of the TOML data structure

+
+ + logical, + intent(in),optional + + ::meta_allowed(:) +

List of keys allowed to be metapackages

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
    subroutine new_meta_request(self, key, table, meta_allowed, error)
+
+        type(metapackage_request_t), intent(out) :: self
+
+        !> The package name
+        character(len=*), intent(in) :: key
+
+        !> Instance of the TOML data structure
+        type(toml_table), intent(inout) :: table
+
+        !> List of keys allowed to be metapackages
+        logical, intent(in), optional :: meta_allowed(:)
+
+        !> Error handling
+        type(error_t), allocatable, intent(out) :: error
+
+
+        integer :: stat,i
+        character(len=:), allocatable :: value
+        logical, allocatable :: allow_meta(:)
+        type(toml_key), allocatable :: keys(:)
+
+        call request_destroy(self)
+
+        !> Set name
+        self%name = key
+        if (.not.is_meta_package(key)) then
+            call fatal_error(error,"Error reading fpm.toml: <"//key//"> is not a valid metapackage name")
+            return
+        end if
+
+        !> The toml table is not checked here because it already passed
+        !> the "new_dependencies" check
+
+        call table%get_keys(keys)
+
+        !> Set list of entries that are allowed to be metapackages
+        if (present(meta_allowed)) then
+            if (size(meta_allowed)/=size(keys)) then
+                 call fatal_error(error,"Internal error: list of metapackage-enable entries does not match table size")
+                 return
+            end if
+            allow_meta = meta_allowed
+        else
+            allocate(allow_meta(size(keys)),source=.true.)
+        endif
+
+
+        do i=1,size(keys)
+
+            ! Skip standard dependencies
+            if (.not.allow_meta(i)) cycle
+
+            if (keys(i)%key==key) then
+                call get_value(table, key, value)
+                if (.not. allocated(value)) then
+                    call syntax_error(error, "Could not retrieve version string for metapackage key <"//key//">. Check syntax")
+                    return
+                else
+                    call request_parse(self, value, error)
+                    return
+                endif
+            end if
+        end do
+
+        ! Key is not present, metapackage not requested
+        return
+
+    end subroutine new_meta_request
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/new_package.html b/proc/new_package.html new file mode 100644 index 0000000000..fa51a470c3 --- /dev/null +++ b/proc/new_package.html @@ -0,0 +1,481 @@ + + + + + + + + + + + + + new_package – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

new_package + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine new_package(self, table, root, error) +

+ + +

Construct a new package configuration from a TOML data structure

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(package_config_t), + intent(out) + + ::self +

Instance of the package configuration

+
+ + type(toml_table), + intent(inout) + + ::table +

Instance of the TOML data structure

+
+ + character(len=*), + intent(in),optional + + ::root +

Root directory of the manifest

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
    subroutine new_package(self, table, root, error)
+
+        !> Instance of the package configuration
+        type(package_config_t), intent(out) :: self
+
+        !> Instance of the TOML data structure
+        type(toml_table), intent(inout) :: table
+
+        !> Root directory of the manifest
+        character(len=*), intent(in), optional :: root
+
+        !> Error handling
+        type(error_t), allocatable, intent(out) :: error
+
+        ! Backspace (8), tabulator (9), newline (10), formfeed (12) and carriage
+        ! return (13) are invalid in package names
+        character(len=*), parameter :: invalid_chars = &
+           achar(8) // achar(9) // achar(10) // achar(12) // achar(13)
+        type(toml_table), pointer :: child, node
+        type(toml_array), pointer :: children
+        character(len=:), allocatable :: version, version_file
+        integer :: ii, nn, stat, io
+
+        call check(table, error)
+        if (allocated(error)) return
+
+        call get_value(table, "name", self%name)
+        if (.not.allocated(self%name)) then
+           call syntax_error(error, "Could not retrieve package name")
+           return
+        end if
+        if (bad_name_error(error,'package',self%name))then
+           return
+        endif
+
+        call get_value(table, "license", self%license)
+        call get_value(table, "author", self%author)
+        call get_value(table, "maintainer", self%maintainer)
+        call get_value(table, "copyright", self%copyright)
+
+        if (len(self%name) <= 0) then
+            call syntax_error(error, "Package name must be a non-empty string")
+            return
+        end if
+
+        ii = scan(self%name, invalid_chars)
+        if (ii > 0) then
+            call syntax_error(error, "Package name contains invalid characters")
+            return
+        end if
+
+        call get_value(table, "build", child, requested=.true., stat=stat)
+        if (stat /= toml_stat%success) then
+            call fatal_error(error, "Type mismatch for build entry, must be a table")
+            return
+        end if
+        call new_build_config(self%build, child, self%name, error)
+        if (allocated(error)) return
+
+        call get_value(table, "install", child, requested=.true., stat=stat)
+        if (stat /= toml_stat%success) then
+            call fatal_error(error, "Type mismatch for install entry, must be a table")
+            return
+        end if
+        call new_install_config(self%install, child, error)
+        if (allocated(error)) return
+
+        call get_value(table, "fortran", child, requested=.true., stat=stat)
+        if (stat /= toml_stat%success) then
+            call fatal_error(error, "Type mismatch for fortran entry, must be a table")
+            return
+        end if
+        call new_fortran_config(self%fortran, child, error)
+        if (allocated(error)) return
+
+        call get_value(table, "version", version, "0")
+        call new_version(self%version, version, error)
+        if (allocated(error) .and. present(root)) then
+            version_file = join_path(root, version)
+            if (exists(version_file)) then
+                deallocate(error)
+                open(file=version_file, newunit=io, iostat=stat)
+                if (stat == 0) then
+                    call getline(io, version, iostat=stat)
+                end if
+                if (stat == 0) then
+                    close(io, iostat=stat)
+                end if
+                if (stat == 0) then
+                    call new_version(self%version, version, error)
+                else
+                    call fatal_error(error, "Reading version number from file '" &
+                        & //version_file//"' failed")
+                end if
+            end if
+        end if
+        if (allocated(error)) return
+
+        call get_value(table, "dependencies", child, requested=.false.)
+        if (associated(child)) then
+            call new_dependencies(self%dependency, child, root, self%meta, error)
+            if (allocated(error)) return
+        end if
+
+        call get_value(table, "dev-dependencies", child, requested=.false.)
+        if (associated(child)) then
+            call new_dependencies(self%dev_dependency, child, root, error=error)
+            if (allocated(error)) return
+        end if
+
+        call get_value(table, "library", child, requested=.false.)
+        if (associated(child)) then
+            allocate(self%library)
+            call new_library(self%library, child, error)
+            if (allocated(error)) return
+        end if
+
+        call get_value(table, "profiles", child, requested=.false.)
+        if (associated(child)) then
+            call new_profiles(self%profiles, child, error)
+            if (allocated(error)) return
+        else
+            self%profiles = get_default_profiles(error)
+            if (allocated(error)) return
+        end if
+
+        call get_value(table, "executable", children, requested=.false.)
+        if (associated(children)) then
+            nn = len(children)
+            allocate(self%executable(nn))
+            do ii = 1, nn
+                call get_value(children, ii, node, stat=stat)
+                if (stat /= toml_stat%success) then
+                    call fatal_error(error, "Could not retrieve executable from array entry")
+                    exit
+                end if
+                call new_executable(self%executable(ii), node, error)
+                if (allocated(error)) exit
+            end do
+            if (allocated(error)) return
+
+            call unique_programs(self%executable, error)
+            if (allocated(error)) return
+        end if
+
+        call get_value(table, "example", children, requested=.false.)
+        if (associated(children)) then
+            nn = len(children)
+            allocate(self%example(nn))
+            do ii = 1, nn
+                call get_value(children, ii, node, stat=stat)
+                if (stat /= toml_stat%success) then
+                    call fatal_error(error, "Could not retrieve example from array entry")
+                    exit
+                end if
+                call new_example(self%example(ii), node, error)
+                if (allocated(error)) exit
+            end do
+            if (allocated(error)) return
+
+            call unique_programs(self%example, error)
+            if (allocated(error)) return
+
+            if (allocated(self%executable)) then
+                call unique_programs(self%executable, self%example, error)
+                if (allocated(error)) return
+            end if
+        end if
+
+        call get_value(table, "test", children, requested=.false.)
+        if (associated(children)) then
+            nn = len(children)
+            allocate(self%test(nn))
+            do ii = 1, nn
+                call get_value(children, ii, node, stat=stat)
+                if (stat /= toml_stat%success) then
+                    call fatal_error(error, "Could not retrieve test from array entry")
+                    exit
+                end if
+                call new_test(self%test(ii), node, error)
+                if (allocated(error)) exit
+            end do
+            if (allocated(error)) return
+
+            call unique_programs(self%test, error)
+            if (allocated(error)) return
+        end if
+
+        call get_value(table, "preprocess", child, requested=.false.)
+        if (associated(child)) then
+            call new_preprocessors(self%preprocess, child, error)
+            if (allocated(error)) return
+        end if
+    end subroutine new_package
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/new_preprocessors.html b/proc/new_preprocessors.html new file mode 100644 index 0000000000..198e30bb2f --- /dev/null +++ b/proc/new_preprocessors.html @@ -0,0 +1,306 @@ + + + + + + + + + + + + + new_preprocessors – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

new_preprocessors + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine new_preprocessors(preprocessors, table, error) +

+ + +

Construct new preprocess array from a TOML data structure.

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(preprocess_config_t), + intent(out), + allocatable + ::preprocessors(:) +

Instance of the preprocess configuration

+
+ + type(toml_table), + intent(inout) + + ::table +

Instance of the TOML data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
   subroutine new_preprocessors(preprocessors, table, error)
+
+      !> Instance of the preprocess configuration
+      type(preprocess_config_t), allocatable, intent(out) :: preprocessors(:)
+
+      !> Instance of the TOML data structure
+      type(toml_table), intent(inout) :: table
+
+      !> Error handling
+      type(error_t), allocatable, intent(out) :: error
+
+      type(toml_table), pointer :: node
+      type(toml_key), allocatable :: list(:)
+      integer :: iprep, stat
+
+      call table%get_keys(list)
+
+      ! An empty table is not allowed
+      if (size(list) == 0) then
+         call syntax_error(error, "No preprocessors defined")
+      end if
+
+      allocate(preprocessors(size(list)))
+      do iprep = 1, size(list)
+         call get_value(table, list(iprep)%key, node, stat=stat)
+         if (stat /= toml_stat%success) then
+            call syntax_error(error, "Preprocessor "//list(iprep)%key//" must be a table entry")
+            exit
+         end if
+         call preprocessors(iprep)%new(node, error)
+         if (allocated(error)) exit
+      end do
+
+   end subroutine new_preprocessors
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/new_profile.html b/proc/new_profile.html new file mode 100644 index 0000000000..c07c352418 --- /dev/null +++ b/proc/new_profile.html @@ -0,0 +1,435 @@ + + + + + + + + + + + + + new_profile – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

new_profile + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function new_profile(profile_name, compiler, os_type, flags, c_flags, cxx_flags, link_time_flags, file_scope_flags, is_built_in) result(profile) +

+ + +

Construct a new profile configuration from a TOML data structure

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::profile_name +

Name of the profile

+
+ + character(len=*), + intent(in) + + ::compiler +

Name of the compiler

+
+ + integer, + intent(in) + + ::os_type +

Type of the OS

+
+ + character(len=*), + intent(in),optional + + ::flags +

Fortran compiler flags

+
+ + character(len=*), + intent(in),optional + + ::c_flags +

C compiler flags

+
+ + character(len=*), + intent(in),optional + + ::cxx_flags +

C++ compiler flags

+
+ + character(len=*), + intent(in),optional + + ::link_time_flags +

Link time compiler flags

+
+ + type(file_scope_flag), + intent(in),optional + + ::file_scope_flags(:) +

File scope flags

+
+ + logical, + intent(in),optional + + ::is_built_in +

Is this profile one of the built-in ones?

+
+ +

Return Value + + + type(profile_config_t) + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
      function new_profile(profile_name, compiler, os_type, flags, c_flags, cxx_flags, &
+                           link_time_flags, file_scope_flags, is_built_in) &
+                      & result(profile)
+
+        !> Name of the profile
+        character(len=*), intent(in) :: profile_name
+
+        !> Name of the compiler
+        character(len=*), intent(in) :: compiler
+
+        !> Type of the OS
+        integer, intent(in) :: os_type
+
+        !> Fortran compiler flags
+        character(len=*), optional, intent(in) :: flags
+
+        !> C compiler flags
+        character(len=*), optional, intent(in) :: c_flags
+
+        !> C++ compiler flags
+        character(len=*), optional, intent(in) :: cxx_flags
+
+        !> Link time compiler flags
+        character(len=*), optional, intent(in) :: link_time_flags
+
+        !> File scope flags
+        type(file_scope_flag), optional, intent(in) :: file_scope_flags(:)
+
+        !> Is this profile one of the built-in ones?
+        logical, optional, intent(in) :: is_built_in
+
+        type(profile_config_t) :: profile
+
+        profile%profile_name = profile_name
+        profile%compiler = compiler
+        profile%os_type = os_type
+        if (present(flags)) then
+          profile%flags = flags
+        else
+          profile%flags = ""
+        end if
+        if (present(c_flags)) then
+          profile%c_flags = c_flags
+        else
+          profile%c_flags = ""
+        end if
+        if (present(cxx_flags)) then
+          profile%cxx_flags = cxx_flags
+        else
+          profile%cxx_flags = ""
+        end if
+        if (present(link_time_flags)) then
+          profile%link_time_flags = link_time_flags
+        else
+          profile%link_time_flags = ""
+        end if
+        if (present(file_scope_flags)) then
+           profile%file_scope_flags = file_scope_flags
+        end if
+        if (present(is_built_in)) then
+           profile%is_built_in = is_built_in
+        else
+           profile%is_built_in = .false.
+        end if
+
+      end function new_profile
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/new_profiles.html b/proc/new_profiles.html new file mode 100644 index 0000000000..c17750b677 --- /dev/null +++ b/proc/new_profiles.html @@ -0,0 +1,629 @@ + + + + + + + + + + + + + new_profiles – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

new_profiles + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine new_profiles(profiles, table, error) +

+ + +

Construct new profiles array from a TOML data structure

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(profile_config_t), + intent(out), + allocatable + ::profiles(:) +

Instance of the dependency configuration

+
+ + type(toml_table), + intent(inout), + target + ::table +

Instance of the TOML data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + type(toml_key), + public, + allocatable + ::comp_list(:) + +
+ + character(len=:), + public, + allocatable + ::compiler_name + +
+ + type(profile_config_t), + public, + allocatable + ::default_profiles(:) + +
+ + integer, + public + + ::iprof + +
+ + logical, + public + + ::is_valid + +
+ + type(toml_key), + public, + allocatable + ::os_list(:) + +
+ + type(toml_key), + public, + allocatable + ::prof_list(:) + +
+ + type(toml_table), + public, + pointer + ::prof_node + +
+ + character(len=:), + public, + allocatable + ::profile_name + +
+ + integer, + public + + ::profiles_size + +
+ + integer, + public + + ::profindex + +
+ + integer, + public + + ::stat + +
+ +
+
+ + + + + + + + + +
+

Source Code

+
      subroutine new_profiles(profiles, table, error)
+
+        !> Instance of the dependency configuration
+        type(profile_config_t), allocatable, intent(out) :: profiles(:)
+
+        !> Instance of the TOML data structure
+        type(toml_table), target, intent(inout) :: table
+
+        !> Error handling
+        type(error_t), allocatable, intent(out) :: error
+
+        type(toml_table), pointer :: prof_node
+        type(toml_key), allocatable :: prof_list(:)
+        type(toml_key), allocatable :: comp_list(:)
+        type(toml_key), allocatable :: os_list(:)
+        character(len=:), allocatable :: profile_name, compiler_name
+        integer :: profiles_size, iprof, stat, profindex
+        logical :: is_valid
+        type(profile_config_t), allocatable :: default_profiles(:)
+
+        path = ''
+
+        default_profiles = get_default_profiles(error)
+        if (allocated(error)) return
+        call table%get_keys(prof_list)
+
+        if (size(prof_list) < 1) return
+
+        profiles_size = 0
+
+        do iprof = 1, size(prof_list)
+          profile_name = prof_list(iprof)%key
+          call validate_compiler_name(profile_name, is_valid)
+          if (is_valid) then
+            profile_name = "all"
+            comp_list = prof_list(iprof:iprof)
+            prof_node=>table
+            call traverse_compilers(profile_name, comp_list, prof_node, error, profiles_size=profiles_size)
+            if (allocated(error)) return
+          else
+            call validate_os_name(profile_name, is_valid)
+            if (is_valid) then
+              os_list = prof_list(iprof:iprof)
+              profile_name = 'all'
+              compiler_name = DEFAULT_COMPILER
+              call traverse_oss_for_size(profile_name, compiler_name, os_list, table, profiles_size, error)
+              if (allocated(error)) return
+            else
+              call get_value(table, profile_name, prof_node, stat=stat)
+              if (stat /= toml_stat%success) then
+                call syntax_error(error, "Profile "//prof_list(iprof)%key//" must be a table entry")
+                exit
+              end if
+              call prof_node%get_keys(comp_list)
+              call traverse_compilers(profile_name, comp_list, prof_node, error, profiles_size=profiles_size)
+              if (allocated(error)) return
+            end if
+          end if
+        end do
+
+        profiles_size = profiles_size + size(default_profiles)
+        allocate(profiles(profiles_size))
+
+        do profindex=1, size(default_profiles)
+          profiles(profindex) = default_profiles(profindex)
+        end do
+
+        do iprof = 1, size(prof_list)
+          profile_name = prof_list(iprof)%key
+          call validate_compiler_name(profile_name, is_valid)
+          if (is_valid) then
+            profile_name = "all"
+            comp_list = prof_list(iprof:iprof)
+            prof_node=>table
+            call traverse_compilers(profile_name, comp_list, prof_node, error, profiles=profiles, profindex=profindex)
+            if (allocated(error)) return
+          else
+            call validate_os_name(profile_name, is_valid)
+            if (is_valid) then
+              os_list = prof_list(iprof:iprof)
+              profile_name = 'all'
+              compiler_name = DEFAULT_COMPILER
+              prof_node=>table
+              call traverse_oss(profile_name, compiler_name, os_list, prof_node, profiles, profindex, error)
+              if (allocated(error)) return
+            else
+              call get_value(table, profile_name, prof_node, stat=stat)
+              call prof_node%get_keys(comp_list)
+              call traverse_compilers(profile_name, comp_list, prof_node, error, profiles=profiles, profindex=profindex)
+              if (allocated(error)) return
+            end if
+          end if
+        end do
+
+        ! Apply profiles with profile name 'all' to matching profiles
+        do iprof = 1,size(profiles)
+          if (profiles(iprof)%profile_name.eq.'all') then
+            do profindex = 1,size(profiles)
+              if (.not.(profiles(profindex)%profile_name.eq.'all') &
+                      & .and.(profiles(profindex)%compiler.eq.profiles(iprof)%compiler) &
+                      & .and.(profiles(profindex)%os_type.eq.profiles(iprof)%os_type)) then
+                profiles(profindex)%flags=profiles(profindex)%flags// &
+                        & " "//profiles(iprof)%flags
+                profiles(profindex)%c_flags=profiles(profindex)%c_flags// &
+                        & " "//profiles(iprof)%c_flags
+                profiles(profindex)%cxx_flags=profiles(profindex)%cxx_flags// &
+                        & " "//profiles(iprof)%cxx_flags
+                profiles(profindex)%link_time_flags=profiles(profindex)%link_time_flags// &
+                        & " "//profiles(iprof)%link_time_flags
+              end if
+            end do
+          end if
+        end do
+      end subroutine new_profiles
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/new_target.html b/proc/new_target.html new file mode 100644 index 0000000000..e96a7be450 --- /dev/null +++ b/proc/new_target.html @@ -0,0 +1,402 @@ + + + + + + + + + + + + + new_target – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

new_target + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function new_target(package, type, output_name, source, link_libraries, features, preprocess, version, output_dir) +

+ + +

Allocate a new target

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::package + +
+ + integer, + intent(in) + + ::type + +
+ + character(len=*), + intent(in) + + ::output_name + +
+ + type(srcfile_t), + intent(in),optional + + ::source + +
+ + type(string_t), + intent(in),optional + + ::link_libraries(:) + +
+ + type(fortran_features_t), + intent(in),optional + + ::features + +
+ + type(preprocess_config_t), + intent(in),optional + + ::preprocess + +
+ + character(len=*), + intent(in),optional + + ::version + +
+ + character(len=*), + intent(in),optional + + ::output_dir + +
+ +

Return Value + + + type(build_target_ptr) + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
type(build_target_ptr) function new_target(package, type, output_name, source, link_libraries, &
+        & features, preprocess, version, output_dir)
+    character(*), intent(in) :: package
+    integer, intent(in) :: type
+    character(*), intent(in) :: output_name
+    type(srcfile_t), intent(in), optional :: source
+    type(string_t), intent(in), optional :: link_libraries(:)
+    type(fortran_features_t), intent(in), optional :: features
+    type(preprocess_config_t), intent(in), optional :: preprocess
+    character(*), intent(in), optional :: version
+    character(*), intent(in), optional :: output_dir
+
+    allocate(new_target%ptr)
+    
+    associate(target=>new_target%ptr)
+    
+        target%target_type = type
+        target%output_name = output_name
+        target%package_name = package
+        if (present(source)) target%source = source
+        if (present(link_libraries)) target%link_libraries = link_libraries
+        if (present(features)) target%features = features
+        if (present(preprocess)) then
+            if (allocated(preprocess%macros)) target%macros = preprocess%macros
+        endif
+        if (present(version)) target%version = version
+        allocate(target%dependencies(0))
+        
+        call target%set_output_dir(output_dir)
+    
+    endassociate
+    
+end function new_target
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/new_test.html b/proc/new_test.html new file mode 100644 index 0000000000..41f2080962 --- /dev/null +++ b/proc/new_test.html @@ -0,0 +1,309 @@ + + + + + + + + + + + + + new_test – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

new_test + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine new_test(self, table, error) +

+ + +

Construct a new test configuration from a TOML data structure

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(test_config_t), + intent(out) + + ::self +

Instance of the test configuration

+
+ + type(toml_table), + intent(inout) + + ::table +

Instance of the TOML data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
    subroutine new_test(self, table, error)
+
+        !> Instance of the test configuration
+        type(test_config_t), intent(out) :: self
+
+        !> Instance of the TOML data structure
+        type(toml_table), intent(inout) :: table
+
+        !> Error handling
+        type(error_t), allocatable, intent(out) :: error
+
+        type(toml_table), pointer :: child
+
+        call check(table, error)
+        if (allocated(error)) return
+
+        call get_value(table, "name", self%name)
+        if (.not.allocated(self%name)) then
+           call syntax_error(error, "Could not retrieve test name")
+           return
+        end if
+        if (bad_name_error(error,'test',self%name))then
+           return
+        endif
+        call get_value(table, "source-dir", self%source_dir, "test")
+        call get_value(table, "main", self%main, "main.f90")
+
+        call get_value(table, "dependencies", child, requested=.false.)
+        if (associated(child)) then
+            call new_dependencies(self%dependency, child, error=error)
+            if (allocated(error)) return
+        end if
+
+        call get_list(table, "link", self%link, error)
+        if (allocated(error)) return
+
+    end subroutine new_test
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/notabs.html b/proc/notabs.html new file mode 100644 index 0000000000..501161e6ec --- /dev/null +++ b/proc/notabs.html @@ -0,0 +1,370 @@ + + + + + + + + + + + + + notabs – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

notabs + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public impure elemental subroutine notabs(instr, outstr, ilen) +

+ + +

NAME

+

notabs(3f) - [fpm_strings:NONALPHA] expand tab characters + (LICENSE:PD)

+

SYNOPSIS

+
subroutine notabs(INSTR,OUTSTR,ILEN)
+
+ character(len=*),intent=(in)  :: INSTR
+ character(len=*),intent=(out) :: OUTSTR
+ integer,intent=(out)          :: ILEN
+
+ +

DESCRIPTION

+

NOTABS() converts tabs in INSTR to spaces in OUTSTR while maintaining + columns. It assumes a tab is set every 8 characters. Trailing spaces + are removed.

+

In addition, trailing carriage returns and line feeds are removed + (they are usually a problem created by going to and from MSWindows).

+

What are some reasons for removing tab characters from an input line? + Some Fortran compilers have problems with tabs, as tabs are not + part of the Fortran character set. Some editors and printers will + have problems with tabs. It is often useful to expand tabs in input + files to simplify further processing such as tokenizing an input line.

+

OPTIONS

+
 instr     Input line to remove tabs from
+
+ +

RESULTS

+
 outstr    Output string with tabs expanded. Assumed to be of sufficient
+           length
+ ilen      Significant length of returned string
+
+ +

EXAMPLES

+

Sample program:

+
program demo_notabs
+
+!  test filter to remove tabs and trailing white space from input
+!  on files up to 1024 characters wide
+use fpm_strings, only : notabs
+character(len=1024) :: in,out
+integer             :: ios,iout
+   do
+      read(*,'(A)',iostat=ios)in
+      if(ios /= 0) exit
+      call notabs(in,out,iout)
+      write(*,'(a)')out(:iout)
+   enddo
+end program demo_notabs
+
+ +

SEE ALSO

+

GNU/Unix commands expand(1) and unexpand(1)

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::instr + +
+ + character(len=*), + intent(out) + + ::outstr + +
+ + integer, + intent(out) + + ::ilen + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
elemental impure subroutine notabs(instr,outstr,ilen)
+
+! ident_31="@(#)fpm_strings::notabs(3f): convert tabs to spaces while maintaining columns, remove CRLF chars"
+
+character(len=*),intent(in)   :: instr        ! input line to scan for tab characters
+character(len=*),intent(out)  :: outstr       ! tab-expanded version of INSTR produced
+integer,intent(out)           :: ilen         ! column position of last character put into output string
+                                              ! that is, ILEN holds the position of the last non-blank character in OUTSTR
+
+integer,parameter             :: tabsize=8    ! assume a tab stop is set every 8th column
+integer                       :: ipos         ! position in OUTSTR to put next character of INSTR
+integer                       :: lenin        ! length of input string trimmed of trailing spaces
+integer                       :: lenout       ! number of characters output string can hold
+integer                       :: istep        ! counter that advances thru input string INSTR one character at a time
+character(len=1)              :: c            ! character in input line being processed
+integer                       :: iade         ! ADE (ASCII Decimal Equivalent) of character being tested
+
+   ipos=1                                     ! where to put next character in output string OUTSTR
+   lenin=len_trim(instr( 1:len(instr) ))      ! length of INSTR trimmed of trailing spaces
+   lenout=len(outstr)                         ! number of characters output string OUTSTR can hold
+   outstr=" "                                 ! this SHOULD blank-fill string, a buggy machine required a loop to set all characters
+
+      SCAN_LINE: do istep=1,lenin             ! look through input string one character at a time
+         c=instr(istep:istep)                 ! get next character
+         iade=ichar(c)                        ! get ADE of the character
+         EXPAND_TABS : select case (iade)     ! take different actions depending on which character was found
+         case(9)                              ! test if character is a tab and move pointer out to appropriate column
+            ipos = ipos + (tabsize - (mod(ipos-1,tabsize)))
+         case(10,13)                          ! convert carriage-return and new-line to space ,typically to handle DOS-format files
+            ipos=ipos+1
+         case default                         ! c is anything else other than a tab,newline,or return  insert it in output string
+            if(ipos > lenout)then
+               write(stderr,*)"*notabs* output string overflow"
+               exit
+            else
+               outstr(ipos:ipos)=c
+               ipos=ipos+1
+            endif
+         end select EXPAND_TABS
+      enddo SCAN_LINE
+
+      ipos=min(ipos,lenout)                   ! tabs or newline or return characters or last character might have gone too far
+      ilen=len_trim(outstr(:ipos))            ! trim trailing spaces
+
+end subroutine notabs
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/number_of_rows.html b/proc/number_of_rows.html new file mode 100644 index 0000000000..141dbc3b11 --- /dev/null +++ b/proc/number_of_rows.html @@ -0,0 +1,261 @@ + + + + + + + + + + + + + number_of_rows – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

number_of_rows + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function number_of_rows(s) result(nrows) +

+ + +

Determine number or rows in a file given a LUN

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + integer, + intent(in) + + ::s + +
+ +

Return Value + + + integer + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
integer function number_of_rows(s) result(nrows)
+    integer,intent(in)::s
+    integer :: ios
+    rewind(s)
+    nrows = 0
+    do
+        read(s, *, iostat=ios)
+        if (ios /= 0) exit
+        nrows = nrows + 1
+    end do
+    rewind(s)
+end function number_of_rows
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/os_delete_dir.html b/proc/os_delete_dir.html new file mode 100644 index 0000000000..732bcc3f25 --- /dev/null +++ b/proc/os_delete_dir.html @@ -0,0 +1,284 @@ + + + + + + + + + + + + + os_delete_dir – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

os_delete_dir + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine os_delete_dir(is_unix, dir, echo) +

+ + +

Delete directory using system OS remove directory commands

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + logical, + intent(in) + + ::is_unix + +
+ + character(len=*), + intent(in) + + ::dir + +
+ + logical, + intent(in),optional + + ::echo + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
subroutine os_delete_dir(is_unix, dir, echo)
+    logical, intent(in) :: is_unix
+    character(len=*), intent(in) :: dir
+    logical, intent(in), optional :: echo
+
+    if (is_unix) then
+        call run('rm -rf ' // dir, echo=echo,verbose=.false.)
+    else
+        call run('rmdir /s/q ' // dir, echo=echo,verbose=.false.)
+    end if
+
+end subroutine os_delete_dir
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/os_is_unix.html b/proc/os_is_unix.html new file mode 100644 index 0000000000..bc91ac0c0b --- /dev/null +++ b/proc/os_is_unix.html @@ -0,0 +1,261 @@ + + + + + + + + + + + + + os_is_unix – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

os_is_unix + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function os_is_unix(os) +

+ + +

Compare the output of get_os_type or the optional +passed INTEGER value to the value for OS_WINDOWS +and return .TRUE. if they match and .FALSE. otherwise

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + integer, + intent(in),optional + + ::os + +
+ +

Return Value + + + logical + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
    logical function os_is_unix(os)
+        integer, intent(in), optional :: os
+        integer :: build_os
+        if (present(os)) then
+            build_os = os
+        else
+            build_os = get_os_type()
+        end if
+        os_is_unix = build_os /= OS_WINDOWS
+    end function os_is_unix
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/os_name.html b/proc/os_name.html new file mode 100644 index 0000000000..8e90578842 --- /dev/null +++ b/proc/os_name.html @@ -0,0 +1,265 @@ + + + + + + + + + + + + + OS_NAME – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

OS_NAME + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public pure function OS_NAME(os) +

+ + +

Return string describing the OS type flag

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + integer, + intent(in) + + ::os + +
+ +

Return Value + + + character(len=:), allocatable + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
    pure function OS_NAME(os)
+        integer, intent(in) :: os
+        character(len=:), allocatable :: OS_NAME
+
+        select case (os)
+            case (OS_LINUX);   OS_NAME =  "Linux"
+            case (OS_MACOS);   OS_NAME =  "macOS"
+            case (OS_WINDOWS); OS_NAME =  "Windows"
+            case (OS_CYGWIN);  OS_NAME =  "Cygwin"
+            case (OS_SOLARIS); OS_NAME =  "Solaris"
+            case (OS_FREEBSD); OS_NAME =  "FreeBSD"
+            case (OS_OPENBSD); OS_NAME =  "OpenBSD"
+            case (OS_UNKNOWN); OS_NAME =  "Unknown"
+            case default     ; OS_NAME =  "UNKNOWN"
+        end select
+    end function OS_NAME
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/os_type_name.html b/proc/os_type_name.html new file mode 100644 index 0000000000..7f02d5088a --- /dev/null +++ b/proc/os_type_name.html @@ -0,0 +1,263 @@ + + + + + + + + + + + + + os_type_name – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

os_type_name + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function os_type_name(os_type) +

+ + +

Match lowercase string with name of OS to os_type enum

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + integer, + intent(in) + + ::os_type +

Enum representing type of OS

+
+ +

Return Value + + + character(len=:), allocatable + +

+

Name of operating system

+
+ + + + + + + + + + + +
+

Source Code

+
      function os_type_name(os_type)
+
+        !> Name of operating system
+        character(len=:), allocatable :: os_type_name
+
+        !> Enum representing type of OS
+        integer, intent(in) :: os_type
+
+        select case (os_type)
+          case (OS_ALL); os_type_name = "all"
+          case default; os_type_name = lower(OS_NAME(os_type))
+        end select
+
+      end function os_type_name
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/parent_dir.html b/proc/parent_dir.html new file mode 100644 index 0000000000..fd69845d47 --- /dev/null +++ b/proc/parent_dir.html @@ -0,0 +1,256 @@ + + + + + + + + + + + + + parent_dir – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

parent_dir + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function parent_dir(path) result(dir) +

+ + +

Extract dirname from path

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::path + +
+ +

Return Value + + + character(len=:), allocatable + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
function parent_dir(path) result (dir)
+    character(*), intent(in) :: path
+    character(:), allocatable :: dir
+
+    dir = path(1:scan(path,'/\',back=.true.)-1)
+
+end function parent_dir
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/parse_c_source.html b/proc/parse_c_source.html new file mode 100644 index 0000000000..7c66ca9607 --- /dev/null +++ b/proc/parse_c_source.html @@ -0,0 +1,340 @@ + + + + + + + + + + + + + parse_c_source – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

parse_c_source + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function parse_c_source(c_filename, error) result(c_source) +

+ + +

Parsing of c, cpp source files

+

The following statements are recognised and parsed:

+
    +
  • #include preprocessor statement
  • +
+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::c_filename + +
+ + type(error_t), + intent(out), + allocatable + ::error + +
+ +

Return Value + + + type(srcfile_t) + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
function parse_c_source(c_filename,error) result(c_source)
+    character(*), intent(in) :: c_filename
+    type(srcfile_t) :: c_source
+    type(error_t), allocatable, intent(out) :: error
+
+    integer :: fh, n_include, i, pass, stat
+    type(string_t), allocatable :: file_lines(:)
+
+    c_source%file_name = c_filename
+
+    if (str_ends_with(lower(c_filename), ".c")) then
+
+        c_source%unit_type = FPM_UNIT_CSOURCE
+
+    else if (str_ends_with(lower(c_filename), ".h")) then
+
+        c_source%unit_type = FPM_UNIT_CHEADER
+
+    else if (str_ends_with(lower(c_filename), ".cpp")) then
+
+        c_source%unit_type = FPM_UNIT_CPPSOURCE
+
+    end if
+
+    allocate(c_source%modules_used(0))
+    allocate(c_source%modules_provided(0))
+    allocate(c_source%parent_modules(0))
+
+    file_lines = read_lines(c_filename)
+
+    ! Ignore empty files, returned as FPM_UNIT_UNKNOWN
+    if (len_trim(file_lines) < 1) then
+        c_source%unit_type = FPM_UNIT_UNKNOWN
+        return
+    end if
+
+    c_source%digest = fnv_1a(file_lines)
+
+    do pass = 1,2
+        n_include = 0
+        file_loop: do i=1,size(file_lines)
+
+            ! Process 'INCLUDE' statements
+            if (index(adjustl(lower(file_lines(i)%s)),'#include') == 1 .and. &
+                index(file_lines(i)%s,'"') > 0) then
+
+                n_include = n_include + 1
+
+                if (pass == 2) then
+
+                    c_source%include_dependencies(n_include)%s = &
+                     &   split_n(file_lines(i)%s,n=2,delims='"',stat=stat)
+                    if (stat /= 0) then
+                        call file_parse_error(error,c_filename, &
+                            'unable to get c include file',i, &
+                            file_lines(i)%s,index(file_lines(i)%s,'"'))
+                        return
+                    end if
+
+                end if
+
+            end if
+
+        end do file_loop
+
+        if (pass == 1) then
+            allocate(c_source%include_dependencies(n_include))
+        end if
+
+    end do
+
+end function parse_c_source
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/parse_descriptor.html b/proc/parse_descriptor.html new file mode 100644 index 0000000000..f2ee95e425 --- /dev/null +++ b/proc/parse_descriptor.html @@ -0,0 +1,261 @@ + + + + + + + + + + + + + parse_descriptor – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

parse_descriptor + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public pure function parse_descriptor(name) +

+ + +

Parse git descriptor identifier from a string

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::name + +
+ +

Return Value + + + integer + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
    pure integer function parse_descriptor(name)
+        character(len=*), intent(in) :: name
+
+        select case (name)
+           case ("default");  parse_descriptor = git_descriptor%default
+           case ("branch");   parse_descriptor = git_descriptor%branch
+           case ("tag");      parse_descriptor = git_descriptor%tag
+           case ("revision"); parse_descriptor = git_descriptor%revision
+           case default;      parse_descriptor = git_descriptor%error
+        end select
+
+    end function parse_descriptor
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/parse_f_source.html b/proc/parse_f_source.html new file mode 100644 index 0000000000..6113439090 --- /dev/null +++ b/proc/parse_f_source.html @@ -0,0 +1,617 @@ + + + + + + + + + + + + + parse_f_source – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

parse_f_source + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function parse_f_source(f_filename, error) result(f_source) +

+ + +

Parsing of free-form fortran source files

+

The following statements are recognised and parsed:

+
    +
  • Module/submodule/program declaration
  • +
  • Module use statement
  • +
  • include statement
  • +
+

@note Note + Intrinsic modules used by sources are not listed in + the modules_used field of source objects.

+

@note Note + Submodules are treated as normal modules which use their + corresponding parent modules.

+

Parsing limitations

+

Statements must not continued onto another line + except for an only: list in the use statement.

+

This is supported:

+
 use my_module, only: &
+      my_var, my_function, my_subroutine
+
+ +

This is NOT supported:

+
 use &
+    my_module
+
+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::f_filename + +
+ + type(error_t), + intent(out), + allocatable + ::error + +
+ +

Return Value + + + type(srcfile_t) + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
function parse_f_source(f_filename,error) result(f_source)
+    character(*), intent(in) :: f_filename
+    type(srcfile_t) :: f_source
+    type(error_t), allocatable, intent(out) :: error
+
+    logical :: inside_module, inside_interface, using, intrinsic_module
+    integer :: stat
+    integer :: fh, n_use, n_include, n_mod, n_parent, i, j, ic, pass
+    type(string_t), allocatable :: file_lines(:), file_lines_lower(:)
+    character(:), allocatable :: temp_string, mod_name, string_parts(:)
+
+    if (.not. exists(f_filename)) then
+        call file_not_found_error(error, f_filename)
+        return
+    end if
+
+    f_source%file_name = f_filename
+
+    file_lines = read_lines_expanded(f_filename)
+
+    ! for efficiency in parsing make a lowercase left-adjusted copy of the file
+    ! Need a copy because INCLUDE (and #include) file arguments are case-sensitive
+    file_lines_lower=file_lines
+    do i=1,size(file_lines_lower)
+       file_lines_lower(i)%s=adjustl(lower(file_lines_lower(i)%s))
+    enddo
+
+    ! fnv_1a can only be applied to non-zero-length arrays
+    if (len_trim(file_lines_lower) > 0) f_source%digest = fnv_1a(file_lines)
+
+    do pass = 1,2
+        n_use = 0
+        n_include = 0
+        n_mod = 0
+        n_parent = 0
+        inside_module = .false.
+        inside_interface = .false.
+        file_loop: do i=1,size(file_lines_lower)
+
+            ! Skip comment lines and preprocessor directives
+            if (index(file_lines_lower(i)%s,'!') == 1 .or. &
+                index(file_lines_lower(i)%s,'#') == 1 .or. &
+                len_trim(file_lines_lower(i)%s) < 1) then
+                cycle
+            end if
+
+            ! Detect exported C-API via bind(C)
+            if (.not.inside_interface .and. &
+                parse_subsequence(file_lines_lower(i)%s,'bind','(','c')) then
+
+                do j=i,1,-1
+
+                    if (index(file_lines_lower(j)%s,'function') > 0 .or. &
+                        index(file_lines_lower(j)%s,'subroutine') > 0) then
+                        f_source%unit_type = FPM_UNIT_SUBPROGRAM
+                        exit
+                    end if
+
+                    if (j>1) then
+
+                        ic = index(file_lines_lower(j-1)%s,'!')
+                        if (ic < 1) then
+                            ic = len(file_lines_lower(j-1)%s)
+                        end if
+
+                        temp_string = trim(file_lines_lower(j-1)%s(1:ic))
+                        if (index(temp_string,'&') /= len(temp_string)) then
+                            exit
+                        end if
+
+                    end if
+
+                end do
+
+            end if
+
+            ! Skip lines that are continued: not statements
+            if (i > 1) then
+                ic = index(file_lines_lower(i-1)%s,'!')
+                if (ic < 1) then
+                    ic = len(file_lines_lower(i-1)%s)
+                end if
+                temp_string = trim(file_lines_lower(i-1)%s(1:ic))
+                if (len(temp_string) > 0 .and. index(temp_string,'&') == len(temp_string)) then
+                    cycle
+                end if
+            end if
+
+            ! Detect beginning of interface block
+            if (index(file_lines_lower(i)%s,'interface') == 1 &
+                .or. parse_sequence(file_lines_lower(i)%s,'abstract','interface')) then
+
+                inside_interface = .true.
+                cycle
+
+            end if
+
+            ! Detect end of interface block
+            if (parse_sequence(file_lines_lower(i)%s,'end','interface')) then
+
+                inside_interface = .false.
+                cycle
+
+            end if
+
+            ! Process 'USE' statements
+            call parse_use_statement(f_filename,i,file_lines_lower(i)%s,using,intrinsic_module,mod_name,error)
+            if (allocated(error)) return
+
+            if (using) then
+
+                ! Not a valid module name?
+                if (.not.is_fortran_name(mod_name)) cycle
+
+                ! Valid intrinsic module: not a dependency
+                if (intrinsic_module) cycle
+
+                n_use = n_use + 1
+
+                if (pass == 2) f_source%modules_used(n_use)%s = mod_name
+
+                cycle
+
+            endif
+
+            ! Process 'INCLUDE' statements
+            ic = index(file_lines_lower(i)%s,'include')
+            if ( ic == 1 ) then
+                ic = index(lower(file_lines(i)%s),'include')
+                if (index(adjustl(file_lines(i)%s(ic+7:)),'"') == 1 .or. &
+                    index(adjustl(file_lines(i)%s(ic+7:)),"'") == 1 ) then
+
+                    n_include = n_include + 1
+
+                    if (pass == 2) then
+                        f_source%include_dependencies(n_include)%s = &
+                         & split_n(file_lines(i)%s,n=2,delims="'"//'"',stat=stat)
+                        if (stat /= 0) then
+                            call file_parse_error(error,f_filename, &
+                                  'unable to find include file name',i, &
+                                  file_lines(i)%s)
+                            return
+                        end if
+                    end if
+
+                    cycle
+
+                end if
+            end if
+
+            ! Extract name of module if is module
+            if (index(file_lines_lower(i)%s,'module ') == 1) then
+
+                ! Remove any trailing comments
+                ic = index(file_lines_lower(i)%s,'!')-1
+                if (ic < 1) then
+                    ic = len(file_lines_lower(i)%s)
+                end if
+                temp_string = trim(file_lines_lower(i)%s(1:ic))
+
+                ! R1405 module-stmt := "MODULE" module-name
+                ! module-stmt has two space-delimited parts only
+                ! (no line continuations)
+                call split(temp_string,string_parts,' ')
+                if (size(string_parts) /= 2) then
+                    cycle
+                end if
+
+                mod_name = trim(adjustl(string_parts(2)))
+                if (scan(mod_name,'=(&')>0 ) then
+                    ! Ignore these cases:
+                    ! module <something>&
+                    ! module =*
+                    ! module (i)
+                    cycle
+                end if
+
+                if (.not.is_fortran_name(mod_name)) then
+                    call file_parse_error(error,f_filename, &
+                          'empty or invalid name for module',i, &
+                          file_lines_lower(i)%s, index(file_lines_lower(i)%s,mod_name))
+                    return
+                end if
+
+                n_mod = n_mod + 1
+
+                if (pass == 2) then
+                    f_source%modules_provided(n_mod) = string_t(mod_name)
+                end if
+
+                if (f_source%unit_type == FPM_UNIT_UNKNOWN) then
+                    f_source%unit_type = FPM_UNIT_MODULE
+                end if
+
+                if (.not.inside_module) then
+                    inside_module = .true.
+                else
+                    ! Must have missed an end module statement (can't assume a pure module)
+                    if (f_source%unit_type /= FPM_UNIT_PROGRAM) then
+                        f_source%unit_type = FPM_UNIT_SUBPROGRAM
+                    end if
+                end if
+
+                cycle
+
+            end if
+
+            ! Extract name of submodule if is submodule
+            if (index(file_lines_lower(i)%s,'submodule') == 1) then
+
+                mod_name = split_n(file_lines_lower(i)%s,n=3,delims='()',stat=stat)
+                if (stat /= 0) then
+                    call file_parse_error(error,f_filename, &
+                          'unable to get submodule name',i, &
+                          file_lines_lower(i)%s)
+                    return
+                end if
+                if (.not.is_fortran_name(mod_name)) then
+                    call file_parse_error(error,f_filename, &
+                          'empty or invalid name for submodule',i, &
+                          file_lines_lower(i)%s, index(file_lines_lower(i)%s,mod_name))
+                    return
+                end if
+
+                n_mod = n_mod + 1
+
+                temp_string = split_n(file_lines_lower(i)%s,n=2,delims='()',stat=stat)
+                if (stat /= 0) then
+                    call file_parse_error(error,f_filename, &
+                          'unable to get submodule ancestry',i, &
+                          file_lines_lower(i)%s)
+                    return
+                end if
+
+                if (f_source%unit_type /= FPM_UNIT_PROGRAM) then
+                    f_source%unit_type = FPM_UNIT_SUBMODULE
+                end if
+
+                n_use = n_use + 1
+
+                inside_module = .true.
+
+                n_parent = n_parent + 1
+
+                if (pass == 2) then
+
+                    if (index(temp_string,':') > 0) then
+
+                        temp_string = temp_string(index(temp_string,':')+1:)
+
+                    end if
+
+                    if (.not.is_fortran_name(temp_string)) then
+                        call file_parse_error(error,f_filename, &
+                          'empty or invalid name for submodule parent',i, &
+                          file_lines_lower(i)%s, index(file_lines_lower(i)%s,temp_string))
+                        return
+                    end if
+
+                    f_source%modules_used(n_use)%s = temp_string
+                    f_source%parent_modules(n_parent)%s = temp_string
+                    f_source%modules_provided(n_mod)%s = mod_name
+
+                end if
+
+                cycle
+
+            end if
+
+            ! Detect if contains a program
+            ! - no modules allowed after program def
+            ! - program header may be missing (only "end program" statement present)
+            if (index(file_lines_lower(i)%s,'program ')==1 .or. &
+                parse_sequence(file_lines_lower(i)%s,'end','program')) then
+
+                temp_string = split_n(file_lines_lower(i)%s,n=2,delims=' ',stat=stat)
+                if (stat == 0) then
+
+                    if (scan(temp_string,'=(')>0 ) then
+                        ! Ignore:
+                        ! program =*
+                        ! program (i) =*
+                        cycle
+                    end if
+
+                end if
+
+                f_source%unit_type = FPM_UNIT_PROGRAM
+
+                cycle
+                
+
+            end if
+
+            ! Parse end module statement
+            !  (to check for code outside of modules)
+            if (parse_sequence(file_lines_lower(i)%s,'end','module') .or. &
+                parse_sequence(file_lines_lower(i)%s,'end','submodule')) then
+
+                inside_module = .false.
+                cycle
+
+            end if
+
+            ! Any statements not yet parsed are assumed to be other code statements
+            if (.not.inside_module .and. f_source%unit_type /= FPM_UNIT_PROGRAM) then
+
+                f_source%unit_type = FPM_UNIT_SUBPROGRAM
+
+            end if
+
+        end do file_loop
+
+        ! If unable to parse end of module statement, then can't assume pure module
+        !  (there could be non-module subprograms present)
+        if (inside_module .and. f_source%unit_type == FPM_UNIT_MODULE) then
+            f_source%unit_type = FPM_UNIT_SUBPROGRAM
+        end if
+
+        if (pass == 1) then
+            allocate(f_source%modules_used(n_use))
+            allocate(f_source%include_dependencies(n_include))
+            allocate(f_source%modules_provided(n_mod))
+            allocate(f_source%parent_modules(n_parent))
+        end if
+
+    end do
+
+end function parse_f_source
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/parse_use_statement.html b/proc/parse_use_statement.html new file mode 100644 index 0000000000..d382d7b8df --- /dev/null +++ b/proc/parse_use_statement.html @@ -0,0 +1,438 @@ + + + + + + + + + + + + + parse_use_statement – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

parse_use_statement + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine parse_use_statement(f_filename, i, line, use_stmt, is_intrinsic, module_name, error) +

+ + + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::f_filename +

Current file name and line number (for error messaging)

+
+ + integer, + intent(in) + + ::i + +
+ + character(len=*), + intent(in) + + ::line +

The line being parsed. MUST BE preprocessed with trim(adjustl()

+
+ + logical, + intent(out) + + ::use_stmt +

Does this line contain a use statement?

+
+ + logical, + intent(out) + + ::is_intrinsic +

Is the module in this statement intrinsic?

+
+ + character(len=:), + intent(out), + allocatable + ::module_name +

used module name

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
subroutine parse_use_statement(f_filename,i,line,use_stmt,is_intrinsic,module_name,error)
+
+    !> Current file name and line number (for error messaging)
+    character(*), intent(in) :: f_filename
+    integer, intent(in) :: i
+
+    !> The line being parsed. MUST BE preprocessed with trim(adjustl()
+    character(*), intent(in) :: line
+
+    !> Does this line contain a `use` statement?
+    logical, intent(out) :: use_stmt
+
+    !> Is the module in this statement intrinsic?
+    logical, intent(out) :: is_intrinsic
+
+    !> used module name
+    character(:), allocatable, intent(out) :: module_name
+
+    !> Error handling
+    type(error_t), allocatable, intent(out) :: error
+
+    character(15), parameter :: INTRINSIC_NAMES(*) =  &
+                                 ['iso_c_binding  ', &
+                                  'iso_fortran_env', &
+                                  'ieee_arithmetic', &
+                                  'ieee_exceptions', &
+                                  'ieee_features  ', &
+                                  'omp_lib        ']
+
+    character(len=:), allocatable :: temp_string
+    integer :: colons,intr,nonintr,j,stat
+    logical :: has_intrinsic_name
+
+    use_stmt      = .false.
+    is_intrinsic  = .false.
+    if (len_trim(line)<=0) return
+
+    ! Quick check that the line is preprocessed
+    if (line(1:1)==' ') then
+        call fatal_error(error,'internal_error: source file line is not trim(adjustl()) on input to parse_use_statement')
+        return
+    end if
+
+    ! 'use' should be the first string in the adjustl line
+    use_stmt = index(line,'use ')==1 .or. index(line,'use::')==1 .or. index(line,'use,')==1
+    if (.not.use_stmt) return
+    colons   = index(line,'::')
+    nonintr  = 0
+    intr     = 0
+
+    have_colons: if (colons>3) then
+
+        ! there may be an intrinsic/non-intrinsic spec
+        nonintr = index(line(1:colons-1),'non_intrinsic')
+        if (nonintr==0) intr = index(line(1:colons-1),'intrinsic')
+
+
+        temp_string = split_n(line,delims=':',n=2,stat=stat)
+        if (stat /= 0) then
+            call file_parse_error(error,f_filename, &
+                    'unable to find used module name',i, &
+                    line,colons)
+            return
+        end if
+
+        module_name = split_n(temp_string,delims=' ,',n=1,stat=stat)
+        if (stat /= 0) then
+            call file_parse_error(error,f_filename, &
+                     'unable to find used module name',i, &
+                     line)
+            return
+        end if
+
+    else
+
+        module_name = split_n(line,n=2,delims=' ,',stat=stat)
+        if (stat /= 0) then
+            call file_parse_error(error,f_filename, &
+                    'unable to find used module name',i, &
+                    line)
+            return
+        end if
+
+    end if have_colons
+
+    ! If declared intrinsic, check that it is true
+    has_intrinsic_name = any([(index(module_name,trim(INTRINSIC_NAMES(j)))>0, &
+                             j=1,size(INTRINSIC_NAMES))])
+    if (intr>0 .and. .not.has_intrinsic_name) then
+
+        ! An intrinsic module was not found. Its name could be in the next line,
+        ! in which case, we just skip this check. The compiler will do the job if the name is invalid.
+
+        ! Module name was not read: it's in the next line
+        if (index(module_name,'&')<=0) then
+            call file_parse_error(error,f_filename, &
+                                  'module '//module_name//' is declared intrinsic but it is not ',i, &
+                                  line)
+            return
+        endif
+    endif
+
+    ! Should we treat this as an intrinsic module
+    is_intrinsic = nonintr==0 .and. & ! not declared non-intrinsic
+                   (intr>0 .or. has_intrinsic_name)
+
+end subroutine parse_use_statement
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/pkgcfg_get_build_flags.html b/proc/pkgcfg_get_build_flags.html new file mode 100644 index 0000000000..f69e232a00 --- /dev/null +++ b/proc/pkgcfg_get_build_flags.html @@ -0,0 +1,351 @@ + + + + + + + + + + + + + pkgcfg_get_build_flags – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

pkgcfg_get_build_flags + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function pkgcfg_get_build_flags(name, allow_system, error) result(flags) +

+ + +

Get build flags (option to include flags from system directories, that +gfortran does not look into by default)

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::name +

Package name

+
+ + logical, + intent(in) + + ::allow_system +

Should pkg-config look in system paths? This is necessary for gfortran +that doesn’t otherwise look into them

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error flag

+
+ +

Return Value + + + type(string_t), allocatable, (:) + +

+

List of compile flags

+
+ + + + + + + + + + + +
+

Source Code

+
function pkgcfg_get_build_flags(name,allow_system,error) result(flags)
+    
+    !> Package name
+    character(*), intent(in) :: name
+    
+    !> Should pkg-config look in system paths? This is necessary for gfortran 
+    !> that doesn't otherwise look into them
+    logical, intent(in) :: allow_system 
+    
+    !> Error flag 
+    type(error_t), allocatable, intent(out) :: error
+    
+    !> List of compile flags
+    type(string_t), allocatable :: flags(:)
+    
+    integer :: exitcode,i,nlib
+    logical :: old_had,success,old_allow
+    character(:), allocatable :: old,tokens(:)
+    type(string_t) :: log    
+    
+    ! Check if the current environment includes system flags
+    old = get_env('PKG_CONFIG_ALLOW_SYSTEM_CFLAGS',default='ERROR')
+    old_had = old/='ERROR'
+    old_allow = merge(old=='1',.false.,old_had)
+    
+    ! Set system flags
+    success = set_env('PKG_CONFIG_ALLOW_SYSTEM_CFLAGS',value=merge('1','0',allow_system))
+    if (.not.success) then 
+        call fatal_error(error,'Cannot get pkg-config build flags: environment variable error.')
+        return
+    end if
+    
+    ! Now run wrapper
+    call run_wrapper(wrapper=string_t('pkg-config'), &
+                     args=[string_t(name),string_t('--cflags')], &
+                     exitcode=exitcode,cmd_success=success,screen_output=log) 
+                     
+    if (success .and. exitcode==0) then 
+        
+        call remove_newline_characters(log)
+        
+        ! Split all arguments
+        tokens = shlex_split(log%s)
+        
+        nlib = size(tokens)
+        allocate(flags(nlib))
+        do i=1,nlib
+            flags(i) = string_t(trim(adjustl(tokens(i))))
+        end do
+        
+    else
+        
+        allocate(flags(0))
+        call fatal_error(error,'cannot get <'//name//'> build flags from pkg-config')
+        
+    end if   
+
+    ! Restore environment variable
+    if (old_had) then 
+        success = set_env('PKG_CONFIG_ALLOW_SYSTEM_CFLAGS',value=old)
+    else
+        success = delete_env('PKG_CONFIG_ALLOW_SYSTEM_CFLAGS')
+    end if
+    if (.not.success) then 
+        call fatal_error(error,'Cannot get pkg-config build flags: environment variable error.')
+        return
+    end if    
+    
+    
+end function pkgcfg_get_build_flags
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/pkgcfg_get_libs.html b/proc/pkgcfg_get_libs.html new file mode 100644 index 0000000000..6abfa09fcf --- /dev/null +++ b/proc/pkgcfg_get_libs.html @@ -0,0 +1,305 @@ + + + + + + + + + + + + + pkgcfg_get_libs – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

pkgcfg_get_libs + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function pkgcfg_get_libs(package, error) result(libraries) +

+ + +

Get package libraries from pkg-config

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::package +

Package name

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handler

+
+ +

Return Value + + + type(string_t), allocatable, (:) + +

+

A list of libraries

+
+ + + + + + + + + + + +
+

Source Code

+
function pkgcfg_get_libs(package,error) result(libraries)
+
+    !> Package name
+    character(*), intent(in) :: package
+    
+    !> Error handler
+    type(error_t), allocatable, intent(out) :: error
+    
+    !> A list of libraries
+    type(string_t), allocatable :: libraries(:)
+
+    integer :: exitcode,nlib,i
+    logical :: success
+    character(len=:), allocatable :: tokens(:)
+    type(string_t) :: log    
+        
+    call run_wrapper(wrapper=string_t('pkg-config'), &
+                     args=[string_t(package),string_t('--libs')], &
+                     exitcode=exitcode,cmd_success=success,screen_output=log)         
+
+    if (success .and. exitcode==0) then 
+        
+        call remove_newline_characters(log)
+        
+        ! Split all arguments
+        tokens = shlex_split(log%s)
+        
+        nlib = size(tokens)
+        allocate(libraries(nlib))
+        do i=1,nlib
+            libraries(i) = string_t(trim(adjustl(tokens(i))))
+        end do
+        
+    else
+        
+        allocate(libraries(0))
+        call fatal_error(error,'cannot get <'//package//'> libraries from pkg-config')
+        
+    end if   
+
+end function pkgcfg_get_libs
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/pkgcfg_get_version.html b/proc/pkgcfg_get_version.html new file mode 100644 index 0000000000..a46537e0f7 --- /dev/null +++ b/proc/pkgcfg_get_version.html @@ -0,0 +1,288 @@ + + + + + + + + + + + + + pkgcfg_get_version – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

pkgcfg_get_version + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function pkgcfg_get_version(package, error) result(screen) +

+ + +

Get package version from pkg-config

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::package +

Package name

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handler

+
+ +

Return Value + + + type(string_t) + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
type(string_t) function pkgcfg_get_version(package,error) result(screen)
+
+    !> Package name
+    character(*), intent(in) :: package
+    
+    !> Error handler
+    type(error_t), allocatable, intent(out) :: error
+
+    integer :: exitcode
+    logical :: success
+    type(string_t) :: log    
+        
+    call run_wrapper(wrapper=string_t('pkg-config'), &
+                     args=[string_t(package),string_t('--modversion')], &
+                     exitcode=exitcode,cmd_success=success,screen_output=log)    
+    
+    if (success .and. exitcode==0) then 
+        call remove_newline_characters(log)
+        screen = log
+    else
+        screen = string_t("")
+    end if      
+
+end function pkgcfg_get_version
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/pkgcfg_has_package.html b/proc/pkgcfg_has_package.html new file mode 100644 index 0000000000..1eb96f4c60 --- /dev/null +++ b/proc/pkgcfg_has_package.html @@ -0,0 +1,267 @@ + + + + + + + + + + + + + pkgcfg_has_package – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

pkgcfg_has_package + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function pkgcfg_has_package(name) result(success) +

+ + +

Check if pkgcfg has package

+

pkg-config –exists returns 0 only if the package exists

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::name +

Package name

+
+ +

Return Value + + + logical + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
logical function pkgcfg_has_package(name) result(success)
+
+    !> Package name
+    character(*), intent(in) :: name
+    
+    integer :: exitcode
+    logical :: cmdok
+    type(string_t) :: log    
+        
+    call run_wrapper(wrapper=string_t('pkg-config'), &
+                     args=[string_t(name),string_t('--exists')], &
+                     exitcode=exitcode,cmd_success=cmdok,screen_output=log)    
+    
+    !> pkg-config --exists returns 0 only if the package exists
+    success = cmdok .and. exitcode==0
+            
+end function pkgcfg_has_package
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/pkgcfg_list_all.html b/proc/pkgcfg_list_all.html new file mode 100644 index 0000000000..4dabecf2fa --- /dev/null +++ b/proc/pkgcfg_list_all.html @@ -0,0 +1,320 @@ + + + + + + + + + + + + + pkgcfg_list_all – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

pkgcfg_list_all + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function pkgcfg_list_all(error, descriptions) result(modules) +

+ + +

Return whole list of available pkg-cfg packages

+

Extract list

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handler

+
+ + type(string_t), + intent(out),optional, + allocatable + ::descriptions(:) +

An optional list of package descriptions

+
+ +

Return Value + + + type(string_t), allocatable, (:) + +

+

A list of all available packages

+
+ + + + + + + + + + + +
+

Source Code

+
function pkgcfg_list_all(error,descriptions) result(modules)
+    
+    !> Error handler
+    type(error_t), allocatable, intent(out) :: error
+    
+    !> A list of all available packages 
+    type(string_t), allocatable :: modules(:)    
+    
+    !> An optional list of package descriptions
+    type(string_t), optional, allocatable, intent(out) :: descriptions(:)
+    
+    integer :: exitcode,i,spc
+    logical :: success
+    character(len=:), allocatable :: lines(:)
+    type(string_t) :: log    
+    type(string_t), allocatable :: mods(:),descr(:)
+    character(*), parameter :: CRLF = achar(13)//new_line('a')
+        
+    call run_wrapper(wrapper=string_t('pkg-config'), &
+                     args=[string_t('--list-all')], &
+                     exitcode=exitcode,cmd_success=success,screen_output=log) 
+                     
+    if (.not.(success .and. exitcode==0)) then 
+        call fatal_error(error,'cannot get pkg-config modules')
+        allocate(modules(0))
+        return
+    end if
+                    
+    !> Extract list 
+    call split(log%s,lines,CRLF)
+    allocate(mods(size(lines)),descr(size(lines)))
+    
+    do i=1,size(lines)
+        
+        ! Module names have no spaces
+        spc = index(lines(i),' ')
+        
+        if (spc>0) then 
+            
+            mods(i)  = string_t(trim(adjustl(lines(i)(1:spc))))
+            descr(i) = string_t(trim(adjustl(lines(i)(spc+1:))))
+            
+        else
+            
+            mods(i)  = string_t(trim(adjustl(lines(i))))
+            descr(i) = string_t("")
+            
+        end if
+        
+    end do
+    
+    call move_alloc(from=mods,to=modules)
+    if (present(descriptions)) call move_alloc(from=descr,to=descriptions)
+    
+end function pkgcfg_list_all
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/profile_dump.html b/proc/profile_dump.html new file mode 100644 index 0000000000..280da13505 --- /dev/null +++ b/proc/profile_dump.html @@ -0,0 +1,459 @@ + + + + + + + + + + + + + profile_dump – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

profile_dump + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine profile_dump(self, table, error) +

+ + +

Dump to toml table

+

Because files need a name, fallback if this has no name

+ +

Type Bound

+

profile_config_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(profile_config_t), + intent(inout) + + ::self +

Instance of the serializable object

+
+ + type(toml_table), + intent(inout) + + ::table +

Data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + integer, + public + + ::ierr +

Local variables

+
+ + integer, + public + + ::ii +

Local variables

+
+ + type(toml_table), + public, + pointer + ::ptr + +
+ + type(toml_table), + public, + pointer + ::ptr_deps + +
+ + character(len=30), + public + + ::unnamed + +
+ +
+
+ + + + + + + + + +
+

Source Code

+
    subroutine profile_dump(self, table, error)
+
+       !> Instance of the serializable object
+       class(profile_config_t), intent(inout) :: self
+
+       !> Data structure
+       type(toml_table), intent(inout) :: table
+
+       !> Error handling
+       type(error_t), allocatable, intent(out) :: error
+
+       !> Local variables
+       integer :: ierr, ii
+       type(toml_table), pointer :: ptr_deps, ptr
+       character(len=30) :: unnamed
+
+       call set_string(table, "profile-name", self%profile_name, error)
+       if (allocated(error)) return
+       call set_string(table, "compiler", self%compiler, error)
+       if (allocated(error)) return
+       call set_string(table,"os-type",os_type_name(self%os_type), error, 'profile_config_t')
+       if (allocated(error)) return
+       call set_string(table, "flags", self%flags, error)
+       if (allocated(error)) return
+       call set_string(table, "c-flags", self%c_flags, error)
+       if (allocated(error)) return
+       call set_string(table, "cxx-flags", self%cxx_flags, error)
+       if (allocated(error)) return
+       call set_string(table, "link-time-flags", self%link_time_flags, error)
+       if (allocated(error)) return
+
+       if (allocated(self%file_scope_flags)) then
+
+           ! Create dependency table
+           call add_table(table, "file-scope-flags", ptr_deps)
+           if (.not. associated(ptr_deps)) then
+              call fatal_error(error, "profile_config_t cannot create file scope table ")
+              return
+           end if
+
+           do ii = 1, size(self%file_scope_flags)
+              associate (dep => self%file_scope_flags(ii))
+
+                 !> Because files need a name, fallback if this has no name
+                 if (len_trim(dep%file_name)==0) then
+                    write(unnamed,1) ii
+                    call add_table(ptr_deps, trim(unnamed), ptr)
+                 else
+                    call add_table(ptr_deps, dep%file_name, ptr)
+                 end if
+                 if (.not. associated(ptr)) then
+                    call fatal_error(error, "profile_config_t cannot create entry for file "//dep%file_name)
+                    return
+                 end if
+                 call dep%dump_to_toml(ptr, error)
+                 if (allocated(error)) return
+              end associate
+           end do
+
+       endif
+
+       call set_value(table, "is-built-in", self%is_built_in, error, 'profile_config_t')
+       if (allocated(error)) return
+
+       1 format('UNNAMED_FILE_',i0)
+
+     end subroutine profile_dump
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/profile_load.html b/proc/profile_load.html new file mode 100644 index 0000000000..c7fad31753 --- /dev/null +++ b/proc/profile_load.html @@ -0,0 +1,486 @@ + + + + + + + + + + + + + profile_load – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

profile_load + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine profile_load(self, table, error) +

+ + +

Read from toml table (no checks made at this stage)

+

Read all packages

+ +

Type Bound

+

profile_config_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(profile_config_t), + intent(inout) + + ::self +

Instance of the serializable object

+
+ + type(toml_table), + intent(inout) + + ::table +

Data structure

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + type(toml_key), + public, + allocatable + ::dep_keys(:) + +
+ + character(len=:), + public, + allocatable + ::flag +

Local variables

+
+ + integer, + public + + ::ii + +
+ + integer, + public + + ::jj + +
+ + type(toml_key), + public, + allocatable + ::keys(:) + +
+ + type(toml_table), + public, + pointer + ::ptr + +
+ + type(toml_table), + public, + pointer + ::ptr_dep + +
+ +
+
+ + + + + + + + + +
+

Source Code

+
     subroutine profile_load(self, table, error)
+
+        !> Instance of the serializable object
+        class(profile_config_t), intent(inout) :: self
+
+        !> Data structure
+        type(toml_table), intent(inout) :: table
+
+        !> Error handling
+        type(error_t), allocatable, intent(out) :: error
+
+        !> Local variables
+        character(len=:), allocatable :: flag
+        integer :: ii, jj
+        type(toml_table), pointer :: ptr_dep, ptr
+        type(toml_key), allocatable :: keys(:),dep_keys(:)
+
+        call table%get_keys(keys)
+
+        call get_value(table, "profile-name", self%profile_name)
+        call get_value(table, "compiler", self%compiler)
+        call get_value(table,"os-type",flag)
+        call match_os_type(flag, self%os_type)
+        call get_value(table, "flags", self%flags)
+        call get_value(table, "c-flags", self%c_flags)
+        call get_value(table, "cxx-flags", self%cxx_flags)
+        call get_value(table, "link-time-flags", self%link_time_flags)
+        call get_value(table, "is-built-in", self%is_built_in, error, 'profile_config_t')
+        if (allocated(error)) return
+
+        if (allocated(self%file_scope_flags)) deallocate(self%file_scope_flags)
+        sub_deps: do ii = 1, size(keys)
+
+           select case (keys(ii)%key)
+              case ("file-scope-flags")
+
+               call get_value(table, keys(ii), ptr)
+               if (.not.associated(ptr)) then
+                  call fatal_error(error,'profile_config_t: error retrieving file_scope_flags table')
+                  return
+               end if
+
+               !> Read all packages
+               call ptr%get_keys(dep_keys)
+               allocate(self%file_scope_flags(size(dep_keys)))
+
+               do jj = 1, size(dep_keys)
+
+                   call get_value(ptr, dep_keys(jj), ptr_dep)
+                   call self%file_scope_flags(jj)%load_from_toml(ptr_dep, error)
+                   if (allocated(error)) return
+
+               end do
+
+           end select
+        end do sub_deps
+
+     end subroutine profile_load
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/profile_same.html b/proc/profile_same.html new file mode 100644 index 0000000000..83266f1e70 --- /dev/null +++ b/proc/profile_same.html @@ -0,0 +1,367 @@ + + + + + + + + + + + + + profile_same – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

profile_same + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function profile_same(this, that) +

+ + +

All checks passed!

+ +

Type Bound

+

profile_config_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(profile_config_t), + intent(in) + + ::this + +
+ + class(serializable_t), + intent(in) + + ::that + +
+ +

Return Value + + + logical + +

+ +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + integer, + public + + ::ii + +
+ +
+
+ + + + + + + + + +
+

Source Code

+
      logical function profile_same(this,that)
+          class(profile_config_t), intent(in) :: this
+          class(serializable_t), intent(in) :: that
+
+          integer :: ii
+
+          profile_same = .false.
+
+          select type (other=>that)
+             type is (profile_config_t)
+                if (allocated(this%profile_name).neqv.allocated(other%profile_name)) return
+                if (allocated(this%profile_name)) then
+                    if (.not.(this%profile_name==other%profile_name)) return
+                endif
+                if (allocated(this%compiler).neqv.allocated(other%compiler)) return
+                if (allocated(this%compiler)) then
+                    if (.not.(this%compiler==other%compiler)) return
+                endif
+                if (this%os_type/=other%os_type) return
+                if (allocated(this%flags).neqv.allocated(other%flags)) return
+                if (allocated(this%flags)) then
+                    if (.not.(this%flags==other%flags)) return
+                endif
+                if (allocated(this%c_flags).neqv.allocated(other%c_flags)) return
+                if (allocated(this%c_flags)) then
+                    if (.not.(this%c_flags==other%c_flags)) return
+                endif
+                if (allocated(this%cxx_flags).neqv.allocated(other%cxx_flags)) return
+                if (allocated(this%cxx_flags)) then
+                    if (.not.(this%cxx_flags==other%cxx_flags)) return
+                endif
+                if (allocated(this%link_time_flags).neqv.allocated(other%link_time_flags)) return
+                if (allocated(this%link_time_flags)) then
+                    if (.not.(this%link_time_flags==other%link_time_flags)) return
+                endif
+
+                if (allocated(this%file_scope_flags).neqv.allocated(other%file_scope_flags)) return
+                if (allocated(this%file_scope_flags)) then
+                    if (.not.size(this%file_scope_flags)==size(other%file_scope_flags)) return
+                    do ii=1,size(this%file_scope_flags)
+                        print *, 'check ii-th file scope: ',ii
+                       if (.not.this%file_scope_flags(ii)==other%file_scope_flags(ii)) return
+                    end do
+                endif
+
+                if (this%is_built_in.neqv.other%is_built_in) return
+
+             class default
+                ! Not the same type
+                return
+          end select
+
+          !> All checks passed!
+          profile_same = .true.
+
+    end function profile_same
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/read_lines.html b/proc/read_lines.html new file mode 100644 index 0000000000..b7b84d7f49 --- /dev/null +++ b/proc/read_lines.html @@ -0,0 +1,272 @@ + + + + + + + + + + + + + read_lines – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

read_lines + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function read_lines(filename) result(lines) +

+ + +

read lines into an array of TYPE(STRING_T) variables

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::filename + +
+ +

Return Value + + + type(string_t), allocatable, (:) + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
function read_lines(filename) result(lines)
+    character(len=*), intent(in) :: filename
+    type(string_t), allocatable :: lines(:)
+
+    integer :: i
+    character(len=:), allocatable :: content
+    integer, allocatable :: first(:), last(:)
+
+    content = read_text_file(filename)
+    if (len(content) == 0) then
+        allocate (lines(0))
+        return
+    end if
+
+    call split_lines_first_last(content, first, last) 
+
+    ! allocate lines from file content string
+    allocate (lines(size(first)))
+    do i = 1, size(first)
+        allocate(lines(i)%s, source=content(first(i):last(i)))
+    end do
+
+end function read_lines
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/read_lines_expanded.html b/proc/read_lines_expanded.html new file mode 100644 index 0000000000..92489f657c --- /dev/null +++ b/proc/read_lines_expanded.html @@ -0,0 +1,272 @@ + + + + + + + + + + + + + read_lines_expanded – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

read_lines_expanded + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function read_lines_expanded(filename) result(lines) +

+ + +

read lines into an array of TYPE(STRING_T) variables expanding tabs

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::filename + +
+ +

Return Value + + + type(string_t), allocatable, (:) + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
function read_lines_expanded(filename) result(lines)
+    character(len=*), intent(in) :: filename
+    type(string_t), allocatable :: lines(:)
+
+    integer :: i
+    character(len=:), allocatable :: content
+    integer, allocatable :: first(:), last(:)
+
+    content = read_text_file(filename)
+    if (len(content) == 0) then
+        allocate (lines(0))
+        return
+    end if
+
+    call split_lines_first_last(content, first, last)  
+
+    ! allocate lines from file content string
+    allocate (lines(size(first)))
+    do i = 1, size(first)
+        allocate(lines(i)%s, source=dilate(content(first(i):last(i))))
+    end do
+
+end function read_lines_expanded
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/read_package_file.html b/proc/read_package_file.html new file mode 100644 index 0000000000..2217a45f4b --- /dev/null +++ b/proc/read_package_file.html @@ -0,0 +1,305 @@ + + + + + + + + + + + + + read_package_file – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

read_package_file + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine read_package_file(table, manifest, error) +

+ + +

Process the configuration file to a TOML data structure

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(toml_table), + intent(out), + allocatable + ::table +

TOML data structure

+
+ + character(len=*), + intent(in) + + ::manifest +

Name of the package configuration file

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error status of the operation

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
    subroutine read_package_file(table, manifest, error)
+
+        !> TOML data structure
+        type(toml_table), allocatable, intent(out) :: table
+
+        !> Name of the package configuration file
+        character(len=*), intent(in) :: manifest
+
+        !> Error status of the operation
+        type(error_t), allocatable, intent(out) :: error
+
+        type(toml_error), allocatable :: parse_error
+        integer :: unit
+        logical :: exist
+
+        inquire (file=manifest, exist=exist)
+
+        if (.not. exist) then
+            call file_not_found_error(error, manifest)
+            return
+        end if
+
+        open(file=manifest, newunit=unit)
+        call toml_load(table, unit, error=parse_error)
+        close(unit)
+
+        if (allocated(parse_error)) then
+            allocate (error)
+            call move_alloc(parse_error%message, error%message)
+            return
+        end if
+
+    end subroutine read_package_file
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/regex_version_from_text.html b/proc/regex_version_from_text.html new file mode 100644 index 0000000000..76ce822d19 --- /dev/null +++ b/proc/regex_version_from_text.html @@ -0,0 +1,309 @@ + + + + + + + + + + + + + regex_version_from_text – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

regex_version_from_text + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function regex_version_from_text(text, what, error) result(ver) +

+ + + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::text + +
+ + character(len=*), + intent(in) + + ::what + +
+ + type(error_t), + intent(out), + allocatable + ::error + +
+ +

Return Value + + + type(string_t) + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
    type(string_t) function regex_version_from_text(text,what,error) result(ver)
+        character(*), intent(in) :: text
+        character(*), intent(in) :: what
+        type(error_t), allocatable, intent(out) :: error
+
+        integer :: ire, length
+
+        if (len_trim(text)<=0) then
+            call syntax_error(error,'cannot retrieve '//what//' version: empty input string')
+            return
+        end if
+
+        ! Extract 3-sized version "1.0.4"
+        ire = regex(text,'\d+\.\d+\.\d+',length=length)
+        if (ire>0 .and. length>0) then
+            ! Parse version into the object (this should always work)
+            ver = string_t(text(ire:ire+length-1))
+        else
+
+            ! Try 2-sized version "1.0"
+            ire = regex(text,'\d+\.\d+',length=length)
+
+            if (ire>0 .and. length>0) then
+                ver = string_t(text(ire:ire+length-1))
+            else
+                call syntax_error(error,'cannot retrieve '//what//' version.')
+            end if
+
+        end if
+
+    end function regex_version_from_text
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/remove_characters_in_set.html b/proc/remove_characters_in_set.html new file mode 100644 index 0000000000..e5ce4f3bf8 --- /dev/null +++ b/proc/remove_characters_in_set.html @@ -0,0 +1,311 @@ + + + + + + + + + + + + + remove_characters_in_set – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

remove_characters_in_set + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine remove_characters_in_set(string, set, replace_with) +

+ + + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=:), + intent(inout), + allocatable + ::string + +
+ + character(len=*), + intent(in) + + ::set + +
+ + character(len=1), + intent(in),optional + + ::replace_with + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
subroutine remove_characters_in_set(string,set,replace_with)
+    character(len=:), allocatable, intent(inout) :: string
+    character(*), intent(in) :: set
+    character, optional, intent(in) :: replace_with ! Replace with this character instead of removing
+
+    integer :: feed,length
+
+    if (.not.allocated(string)) return
+    if (len(set)<=0) return
+
+    length = len(string)
+    feed   = scan(string,set)
+
+    do while (length>0 .and. feed>0)
+
+        ! Remove heading
+        if (length==1) then
+            string = ""
+
+        elseif (feed==1) then
+            string = string(2:length)
+
+        ! Remove trailing
+        elseif (feed==length) then
+            string = string(1:length-1)
+
+        ! In between: replace with given character
+        elseif (present(replace_with)) then
+            string(feed:feed) = replace_with
+        ! Or just remove
+        else
+            string = string(1:feed-1)//string(feed+1:length)
+        end if
+
+        length = len(string)
+        feed   = scan(string,set)
+
+    end do
+
+end subroutine remove_characters_in_set
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/remove_newline_characters.html b/proc/remove_newline_characters.html new file mode 100644 index 0000000000..c0d283b16d --- /dev/null +++ b/proc/remove_newline_characters.html @@ -0,0 +1,252 @@ + + + + + + + + + + + + + remove_newline_characters – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

remove_newline_characters + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine remove_newline_characters(string) +

+ + + + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(string_t), + intent(inout) + + ::string + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
subroutine remove_newline_characters(string)
+    type(string_t), intent(inout) :: string
+
+    integer :: feed,length
+
+    character(*), parameter :: CRLF  = achar(13)//new_line('a')
+    character(*), parameter :: SPACE = ' '
+
+    call remove_characters_in_set(string%s,set=CRLF,replace_with=SPACE)
+
+end subroutine remove_newline_characters
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/replace.html b/proc/replace.html new file mode 100644 index 0000000000..bbc1a3f58e --- /dev/null +++ b/proc/replace.html @@ -0,0 +1,291 @@ + + + + + + + + + + + + + replace – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

replace + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public pure function replace(string, charset, target_char) result(res) +

+ + +

Returns string with characters in charset replaced with target_char.

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::string + +
+ + character(len=1), + intent(in) + + ::charset(:) + +
+ + character(len=1), + intent(in) + + ::target_char + +
+ +

Return Value + + + character(len=len(string)) + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
pure function replace(string, charset, target_char) result(res)
+    character(*), intent(in) :: string
+    character, intent(in) :: charset(:), target_char
+    character(len(string)) :: res
+    integer :: n
+    res = string
+    do n = 1, len(string)
+        if (any(string(n:n) == charset)) then
+            res(n:n) = target_char
+        end if
+    end do
+end function replace
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/resolve_module_dependencies.html b/proc/resolve_module_dependencies.html new file mode 100644 index 0000000000..9b82e5310b --- /dev/null +++ b/proc/resolve_module_dependencies.html @@ -0,0 +1,344 @@ + + + + + + + + + + + + + resolve_module_dependencies – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

resolve_module_dependencies + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine resolve_module_dependencies(targets, external_modules, error) +

+ + +

Add dependencies to source-based targets (FPM_TARGET_OBJECT) + based on any modules used by the corresponding source file.

+

Source file scoping

+

Source files are assigned a scope of either FPM_SCOPE_LIB, + FPM_SCOPE_APP or FPM_SCOPE_TEST. The scope controls which + modules may be used by the source file:

+
    +
  • +

    Library sources (FPM_SCOPE_LIB) may only use modules + also with library scope. This includes library modules + from dependencies.

    +
  • +
  • +

    Executable sources (FPM_SCOPE_APP,FPM_SCOPE_TEST) may use + library modules (including dependencies) as well as any modules + corresponding to source files in the same directory or a + subdirectory of the executable source file.

    +
  • +
+

@note Warning + If a module used by a source file cannot be resolved to + a source file in the package of the correct scope, then a fatal error + is returned by the procedure and model construction fails.

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(build_target_ptr), + intent(inout), + target + ::targets(:) + +
+ + type(string_t), + intent(in) + + ::external_modules(:) + +
+ + type(error_t), + intent(out), + allocatable + ::error + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
subroutine resolve_module_dependencies(targets,external_modules,error)
+    type(build_target_ptr), intent(inout), target :: targets(:)
+    type(string_t), intent(in) :: external_modules(:)
+    type(error_t), allocatable, intent(out) :: error
+
+    type(build_target_ptr) :: dep
+
+    integer :: i, j
+
+    do i=1,size(targets)
+
+        if (.not.allocated(targets(i)%ptr%source)) cycle
+
+            do j=1,size(targets(i)%ptr%source%modules_used)
+
+                if (targets(i)%ptr%source%modules_used(j)%s .in. targets(i)%ptr%source%modules_provided) then
+                    ! Dependency satisfied in same file, skip
+                    cycle
+                end if
+
+                if (targets(i)%ptr%source%modules_used(j)%s .in. external_modules) then
+                    ! Dependency satisfied in system-installed module
+                    cycle
+                end if
+
+                if (any(targets(i)%ptr%source%unit_scope == &
+                    [FPM_SCOPE_APP, FPM_SCOPE_EXAMPLE, FPM_SCOPE_TEST])) then
+                    dep%ptr => &
+                        find_module_dependency(targets,targets(i)%ptr%source%modules_used(j)%s, &
+                                            include_dir = dirname(targets(i)%ptr%source%file_name))
+                else
+                    dep%ptr => &
+                        find_module_dependency(targets,targets(i)%ptr%source%modules_used(j)%s)
+                end if
+
+                if (.not.associated(dep%ptr)) then
+                    call fatal_error(error, &
+                            'Unable to find source for module dependency: "' // &
+                            targets(i)%ptr%source%modules_used(j)%s // &
+                            '" used by "'//targets(i)%ptr%source%file_name//'"')
+                    return
+                end if
+
+                call add_dependency(targets(i)%ptr, dep%ptr)
+
+            end do
+
+    end do
+
+end subroutine resolve_module_dependencies
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/run_wrapper.html b/proc/run_wrapper.html new file mode 100644 index 0000000000..586bd9dc62 --- /dev/null +++ b/proc/run_wrapper.html @@ -0,0 +1,404 @@ + + + + + + + + + + + + + run_wrapper – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

run_wrapper + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine run_wrapper(wrapper, args, verbose, exitcode, cmd_success, screen_output) +

+ + +

Simple call to execute_command_line involving one mpi* wrapper

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(string_t), + intent(in) + + ::wrapper + +
+ + type(string_t), + intent(in),optional + + ::args(:) + +
+ + logical, + intent(in),optional + + ::verbose + +
+ + integer, + intent(out),optional + + ::exitcode + +
+ + logical, + intent(out),optional + + ::cmd_success + +
+ + type(string_t), + intent(out),optional + + ::screen_output + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
subroutine run_wrapper(wrapper,args,verbose,exitcode,cmd_success,screen_output)
+    type(string_t), intent(in) :: wrapper
+    type(string_t), intent(in), optional :: args(:)
+    logical, intent(in), optional :: verbose
+    integer, intent(out), optional :: exitcode
+    logical, intent(out), optional :: cmd_success
+    type(string_t), intent(out), optional :: screen_output
+
+    logical :: echo_local
+    character(:), allocatable :: redirect_str,command,redirect,line
+    integer :: iunit,iarg,stat,cmdstat
+
+
+    if(present(verbose))then
+       echo_local=verbose
+    else
+       echo_local=.false.
+    end if
+
+    ! No redirection and non-verbose output
+    if (present(screen_output)) then
+        redirect = get_temp_filename()
+        redirect_str =  ">"//redirect//" 2>&1"
+    else
+        if (os_is_unix()) then
+            redirect_str = " >/dev/null 2>&1"
+        else
+            redirect_str = " >NUL 2>&1"
+        end if
+    end if
+
+    ! Empty command
+    if (len_trim(wrapper)<=0) then
+        if (echo_local) print *, '+ <EMPTY COMMAND>'
+        if (present(exitcode)) exitcode = 0
+        if (present(cmd_success)) cmd_success = .true.
+        if (present(screen_output)) screen_output = string_t("")
+        return
+    end if
+
+    ! Init command
+    command = trim(wrapper%s)
+
+    add_arguments: if (present(args)) then
+        do iarg=1,size(args)
+            if (len_trim(args(iarg))<=0) cycle
+            command = trim(command)//' '//args(iarg)%s
+        end do
+    endif add_arguments
+
+    if (echo_local) print *, '+ ', command
+
+    ! Test command
+    call execute_command_line(command//redirect_str,exitstat=stat,cmdstat=cmdstat)
+
+    ! Command successful?
+    if (present(cmd_success)) cmd_success = cmdstat==0
+
+    ! Program exit code?
+    if (present(exitcode)) exitcode = stat
+
+    ! Want screen output?
+    if (present(screen_output) .and. cmdstat==0) then
+
+        allocate(character(len=0) :: screen_output%s)
+
+        open(newunit=iunit,file=redirect,status='old',iostat=stat)
+        if (stat == 0)then
+           do
+               call getline(iunit, line, stat)
+               if (stat /= 0) exit
+
+               screen_output%s = screen_output%s//new_line('a')//line
+
+               if (echo_local) write(*,'(A)') trim(line)
+           end do
+
+           ! Close and delete file
+           close(iunit,status='delete')
+
+        else
+           call fpm_stop(1,'cannot read temporary file from successful MPI wrapper')
+        endif
+
+    end if
+
+end subroutine run_wrapper
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/run~2.html b/proc/run~2.html new file mode 100644 index 0000000000..b799caa938 --- /dev/null +++ b/proc/run~2.html @@ -0,0 +1,437 @@ + + + + + + + + + + + + + run – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

run + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine run(cmd, echo, exitstat, verbose, redirect) +

+ + +

Name

+
run(3f) -  execute specified system command and selectively echo
+command and output to a file and/or stdout.
+(LICENSE:MIT)
+
+ +

Syntax

+
subroutine run(cmd,echo,exitstat,verbose,redirect)
+
+ character(len=*), intent(in)       :: cmd
+ logical,intent(in),optional        :: echo
+ integer, intent(out),optional      :: exitstat
+ logical, intent(in), optional      :: verbose
+ character(*), intent(in), optional :: redirect
+
+ +

Description

+

Execute the specified system command. Optionally

+
    +
  • echo the command before execution
  • +
  • return the system exit status of the command.
  • +
  • redirect the output of the command to a file.
  • +
  • echo command output to stdout
  • +
+

Calling run(3f) is preferred to direct calls to + execute_command_line(3f) in the fpm(1) source to provide a standard + interface where output modes can be specified.

+

Options

+
CMD       System command to execute
+ECHO      Whether to echo the command being executed or not
+          Defaults to .TRUE. .
+VERBOSE   Whether to redirect the command output to a null device or not
+          Defaults to .TRUE. .
+REDIRECT  Filename to redirect stdout and stderr of the command into.
+          If generated it is closed before run(3f) returns.
+EXITSTAT  The system exit status of the command when supported by
+          the system. If not present and a non-zero status is
+          generated program termination occurs.
+
+ +

Example

+

Sample program:

+

Checking the error message and counting lines:

+
 program demo_run
+ use fpm_filesystem, only : run
+ implicit none
+ logical,parameter :: T=.true., F=.false.
+ integer :: exitstat
+ character(len=:),allocatable :: cmd
+    cmd='ls -ltrasd *.md'
+    call run(cmd)
+    call run(cmd,exitstat=exitstat)
+    call run(cmd,echo=F)
+    call run(cmd,verbose=F)
+ end program demo_run
+
+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::cmd + +
+ + logical, + intent(in),optional + + ::echo + +
+ + integer, + intent(out),optional + + ::exitstat + +
+ + logical, + intent(in),optional + + ::verbose + +
+ + character(len=*), + intent(in),optional + + ::redirect + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
subroutine run(cmd,echo,exitstat,verbose,redirect)
+    character(len=*), intent(in) :: cmd
+    logical,intent(in),optional  :: echo
+    integer, intent(out),optional :: exitstat
+    logical, intent(in), optional :: verbose
+    character(*), intent(in), optional :: redirect
+
+    integer            :: cmdstat
+    character(len=256) :: cmdmsg, iomsg
+    logical :: echo_local, verbose_local
+    character(:), allocatable :: redirect_str
+    character(:), allocatable :: line
+    integer :: stat, fh, iostat
+
+    if(present(echo))then
+       echo_local=echo
+    else
+       echo_local=.true.
+    end if
+
+    if(present(verbose))then
+        verbose_local=verbose
+    else
+        verbose_local=.true.
+    end if
+
+    if (present(redirect)) then
+        if(redirect /= '')then
+           redirect_str =  ">"//redirect//" 2>&1"
+        else
+           redirect_str = "" 
+        endif
+    else
+        if(verbose_local)then
+            ! No redirection but verbose output
+            redirect_str = ""
+        else
+            ! No redirection and non-verbose output
+            if (os_is_unix()) then
+                redirect_str = " >/dev/null 2>&1"
+            else
+                redirect_str = " >NUL 2>&1"
+            end if
+        end if
+    end if
+
+    if(echo_local) print *, '+ ', cmd !//redirect_str
+
+    call execute_command_line(cmd//redirect_str, exitstat=stat,cmdstat=cmdstat,cmdmsg=cmdmsg)
+    if(cmdstat /= 0)then
+        write(*,'(a)')'<ERROR>:failed command '//cmd//redirect_str
+        call fpm_stop(1,'*run*:'//trim(cmdmsg))
+    endif
+
+    if (verbose_local.and.present(redirect)) then
+
+        open(newunit=fh,file=redirect,status='old',iostat=iostat,iomsg=iomsg)
+        if(iostat == 0)then
+           do
+               call getline(fh, line, iostat)
+               if (iostat /= 0) exit
+               write(*,'(A)') trim(line)
+           end do
+        else
+           write(*,'(A)') trim(iomsg)
+        endif
+
+        close(fh)
+
+    end if
+
+    if (present(exitstat)) then
+        exitstat = stat
+    elseif (stat /= 0) then
+        call fpm_stop(stat,'*run*: Command '//cmd//redirect_str//' returned a non-zero status code')
+    end if
+
+end subroutine run
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/schedule_targets.html b/proc/schedule_targets.html new file mode 100644 index 0000000000..1ae8efee80 --- /dev/null +++ b/proc/schedule_targets.html @@ -0,0 +1,318 @@ + + + + + + + + + + + + + schedule_targets – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

schedule_targets + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine schedule_targets(queue, schedule_ptr, targets) +

+ + +

Construct a build schedule from the sorted targets.

+

The schedule is broken into regions, described by schedule_ptr, + where targets in each region can be compiled in parallel.

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(build_target_ptr), + intent(out), + allocatable + ::queue(:) + +
+ + integer, + + allocatable + ::schedule_ptr(:) + +
+ + type(build_target_ptr), + intent(in) + + ::targets(:) + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
subroutine schedule_targets(queue, schedule_ptr, targets)
+    type(build_target_ptr), allocatable, intent(out) :: queue(:)
+    integer, allocatable :: schedule_ptr(:)
+    type(build_target_ptr), intent(in) :: targets(:)
+
+    integer :: i, j
+    integer :: n_schedule, n_sorted
+
+    n_schedule = 0   ! Number of schedule regions
+    n_sorted = 0     ! Total number of targets to build
+    do i=1,size(targets)
+
+        if (targets(i)%ptr%sorted) then
+            n_sorted = n_sorted + 1
+        end if
+        n_schedule = max(n_schedule, targets(i)%ptr%schedule)
+
+    end do
+
+    allocate(queue(n_sorted))
+    allocate(schedule_ptr(n_schedule+1))
+
+    ! Construct the target queue and schedule region pointer
+    n_sorted = 1
+    schedule_ptr(n_sorted) = 1
+    do i=1,n_schedule
+
+        do j=1,size(targets)
+
+            if (targets(j)%ptr%sorted) then
+                if (targets(j)%ptr%schedule == i) then
+
+                    queue(n_sorted)%ptr => targets(j)%ptr
+                    n_sorted = n_sorted + 1
+                end if
+            end if
+
+        end do
+
+        schedule_ptr(i+1) = n_sorted
+
+    end do
+
+end subroutine schedule_targets
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/separator.html b/proc/separator.html new file mode 100644 index 0000000000..6424e9f7e5 --- /dev/null +++ b/proc/separator.html @@ -0,0 +1,347 @@ + + + + + + + + + + + + + separator – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

separator + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function separator() result(sep) +

+ + +

NAME

+
separator(3f) - [M_io:ENVIRONMENT] try to determine pathname directory separator character
+(LICENSE:PD)
+
+ +

SYNOPSIS

+
function separator() result(sep)
+
+ character(len=1) :: sep
+
+ +

DESCRIPTION

+
First using the name the program was invoked with, then the name
+returned by an INQUIRE(3f) of that name, then ".\NAME" and "./NAME"
+try to determine the separator character used to separate directory
+names from file basenames.
+
+If a slash or backslash is not found in the name, the environment
+variable PATH is examined first for a backslash, then a slash.
+
+Can be very system dependent. If the queries fail the default returned
+is "/".
+
+ +

EXAMPLE

+

sample usage

+
program demo_separator
+use M_io, only : separator
+implicit none
+   write(*,*)'separator=',separator()
+end program demo_separator
+
+ +

!write(,)’unknown system directory path separator’ +ifort_bug*!sep_cache=sep

+ + +

Arguments

+ None +
+

Return Value + + + character(len=1) + +

+

ifort_bug*!character(len=1),save :: sep_cache=’ ‘

+
+ + + + + + + + + + + +
+

Source Code

+
function separator() result(sep)
+!>
+!!##NAME
+!!    separator(3f) - [M_io:ENVIRONMENT] try to determine pathname directory separator character
+!!    (LICENSE:PD)
+!!
+!!##SYNOPSIS
+!!
+!!    function separator() result(sep)
+!!
+!!     character(len=1) :: sep
+!!
+!!##DESCRIPTION
+!!    First using the name the program was invoked with, then the name
+!!    returned by an INQUIRE(3f) of that name, then ".\NAME" and "./NAME"
+!!    try to determine the separator character used to separate directory
+!!    names from file basenames.
+!!
+!!    If a slash or backslash is not found in the name, the environment
+!!    variable PATH is examined first for a backslash, then a slash.
+!!
+!!    Can be very system dependent. If the queries fail the default returned
+!!    is "/".
+!!
+!!##EXAMPLE
+!!
+!!   sample usage
+!!
+!!    program demo_separator
+!!    use M_io, only : separator
+!!    implicit none
+!!       write(*,*)'separator=',separator()
+!!    end program demo_separator
+
+! use the pathname returned as arg0 to determine pathname separator
+implicit none
+character(len=:),allocatable :: arg0
+integer                      :: arg0_length
+integer                      :: istat
+logical                      :: existing
+character(len=1)             :: sep
+!*ifort_bug*!character(len=1),save        :: sep_cache=' '
+character(len=4096)          :: name
+character(len=:),allocatable :: fname
+
+   !*ifort_bug*!   if(sep_cache/=' ')then  ! use cached value. NOTE:  A parallel code might theoretically use multiple OS
+   !*ifort_bug*!      sep=sep_cache
+   !*ifort_bug*!      return
+   !*ifort_bug*!   endif
+
+   arg0_length=0
+   name=' '
+   call get_command_argument(0,length=arg0_length,status=istat)
+   if(allocated(arg0))deallocate(arg0)
+   allocate(character(len=arg0_length) :: arg0)
+   call get_command_argument(0,arg0,status=istat)
+   ! check argument name
+   if(index(arg0,'\')/=0)then
+      sep='\'
+   elseif(index(arg0,'/')/=0)then
+      sep='/'
+   else
+      ! try name returned by INQUIRE(3f)
+      existing=.false.
+      name=' '
+      inquire(file=arg0,iostat=istat,exist=existing,name=name)
+      if(index(name,'\')/=0)then
+         sep='\'
+      elseif(index(name,'/')/=0)then
+         sep='/'
+      else
+         ! well, try some common syntax and assume in current directory
+         fname='.\'//arg0
+         inquire(file=fname,iostat=istat,exist=existing)
+         if(existing)then
+            sep='\'
+         else
+            fname='./'//arg0
+            inquire(file=fname,iostat=istat,exist=existing)
+            if(existing)then
+               sep='/'
+            else ! check environment variable PATH
+               sep=merge('\','/',index(get_env('PATH'),'\')/=0)
+               !*!write(*,*)'<WARNING>unknown system directory path separator'
+            endif
+         endif
+      endif
+   endif
+   !*ifort_bug*!sep_cache=sep
+end function separator
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/set_cpp_preprocessor_flags.html b/proc/set_cpp_preprocessor_flags.html new file mode 100644 index 0000000000..03e311b0b2 --- /dev/null +++ b/proc/set_cpp_preprocessor_flags.html @@ -0,0 +1,324 @@ + + + + + + + + + + + + + set_cpp_preprocessor_flags – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

set_cpp_preprocessor_flags + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public pure subroutine set_cpp_preprocessor_flags(id, flags) +

+ + +

Modify the flag_cpp_preprocessor on the basis of the compiler.

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + integer(kind=compiler_enum), + intent(in) + + ::id + +
+ + character(len=:), + intent(inout), + allocatable + ::flags + +
+ +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=:), + public, + allocatable + ::flag_cpp_preprocessor + +
+ +
+
+ + + + + + + + + +
+

Source Code

+
pure subroutine set_cpp_preprocessor_flags(id, flags)
+    integer(compiler_enum), intent(in) :: id
+    character(len=:), allocatable, intent(inout) :: flags
+    character(len=:), allocatable :: flag_cpp_preprocessor
+
+    !> Modify the flag_cpp_preprocessor on the basis of the compiler.
+    select case(id)
+    case default
+        flag_cpp_preprocessor = ""
+    case(id_caf, id_gcc, id_f95, id_nvhpc)
+        flag_cpp_preprocessor = "-cpp"
+    case(id_intel_classic_windows, id_intel_llvm_windows)
+        flag_cpp_preprocessor = "/fpp"
+    case(id_intel_classic_nix, id_intel_classic_mac, id_intel_llvm_nix, id_nag)
+        flag_cpp_preprocessor = "-fpp"
+    case(id_lfortran)
+        flag_cpp_preprocessor = "--cpp"
+    end select
+
+    flags = flag_cpp_preprocessor// flags
+
+end subroutine set_cpp_preprocessor_flags
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/set_env.html b/proc/set_env.html new file mode 100644 index 0000000000..bb95e0a4aa --- /dev/null +++ b/proc/set_env.html @@ -0,0 +1,329 @@ + + + + + + + + + + + + + set_env – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

set_env + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function set_env(name, value, overwrite) +

+ + +

Set an environment variable for the current environment using the C standard library

+

Overwrite setting +C strings +Call setenv

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::name +

Variable name

+
+ + character(len=*), + intent(in) + + ::value +

Variable value

+
+ + logical, + intent(in),optional + + ::overwrite +

Should a former value be overwritten? default = .true.

+
+ +

Return Value + + + logical + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
logical function set_env(name,value,overwrite)
+
+   !> Variable name
+   character(*), intent(in) :: name
+   
+   !> Variable value
+   character(*), intent(in) :: value
+   
+   !> Should a former value be overwritten? default = .true.
+   logical, optional, intent(in) :: overwrite
+   
+   ! Local variables
+   logical :: can_overwrite
+   integer(c_int) :: cover,cerr
+   character(kind=c_char,len=1), allocatable :: c_value(:),c_name(:)
+   
+   interface
+      integer(c_int) function c_setenv(envname, envval, overwrite) &
+                     bind(C,name="c_setenv")
+         import c_int, c_char
+         implicit none
+         !> Pointer to the name string
+         character(kind=c_char,len=1), intent(in) :: envname(*)
+         !> Pointer to the value string 
+         character(kind=c_char,len=1), intent(in) :: envval(*)
+         !> Overwrite option
+         integer(c_int), intent(in), value :: overwrite
+      end function c_setenv 
+   end interface
+   
+   !> Overwrite setting
+   cerr = 0_c_int
+   can_overwrite = .true.
+   if (present(overwrite)) can_overwrite = overwrite
+   cover = merge(1_c_int,0_c_int,can_overwrite)
+   
+   !> C strings
+   call f2cs(name,c_name)
+   call f2cs(value,c_value)
+   
+   !> Call setenv
+#ifndef FPM_BOOTSTRAP   
+   cerr = c_setenv(c_name,c_value,cover)
+#endif
+   set_env = cerr==0_c_int
+   
+end function set_env
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/set_list.html b/proc/set_list.html new file mode 100644 index 0000000000..2dbd273e2f --- /dev/null +++ b/proc/set_list.html @@ -0,0 +1,346 @@ + + + + + + + + + + + + + set_list – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

set_list + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine set_list(table, key, list, error) +

+ + +

Set no key if array is not present

+

Check the key is not empty +String array

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(toml_table), + intent(inout) + + ::table +

Instance of the toml table

+
+ + character(len=*), + intent(in) + + ::key +

Key to save to

+
+ + type(string_t), + intent(in), + allocatable + ::list(:) +

Instance of the string array

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
    subroutine set_list(table, key, list, error)
+
+        !> Instance of the string array
+        type(string_t), allocatable, intent(in) :: list(:)
+
+        !> Key to save to
+        character(len=*), intent(in) :: key
+
+        !> Instance of the toml table
+        type(toml_table), intent(inout) :: table
+
+        !> Error handling
+        type(error_t), allocatable, intent(out) :: error
+
+        !> Local variables
+        integer :: stat, ilist
+        type(toml_array), pointer :: children
+        character(len=:), allocatable :: str
+
+        !> Set no key if array is not present
+        if (.not.allocated(list)) return
+
+        !> Check the key is not empty
+        if (len_trim(key)<=0) then
+            call fatal_error(error, 'key is empty dumping string array to TOML table')
+            return
+        end if
+
+        if (size(list)/=1) then ! includes empty list case
+
+            !> String array
+            call add_array(table, key, children, stat)
+            if (stat /= toml_stat%success) then
+                call fatal_error(error, "Cannot set array table in "//key//" field")
+                return
+            end if
+
+            do ilist = 1, size(list)
+                  call set_value(children, ilist, list(ilist)%s, stat=stat)
+                  if (stat /= toml_stat%success) then
+                      call fatal_error(error, "Cannot store array entry in "//key//" field")
+                      return
+                  end if
+            end do
+
+        else
+
+            ! Single value: set string
+            call set_value(table, key, list(1)%s, stat=stat)
+
+            if (stat /= toml_stat%success) &
+            call fatal_error(error, "Cannot store entry in "//key//" field")
+
+            return
+        end if
+
+    end subroutine set_list
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/show_model.html b/proc/show_model.html new file mode 100644 index 0000000000..1b9b88e08c --- /dev/null +++ b/proc/show_model.html @@ -0,0 +1,246 @@ + + + + + + + + + + + + + show_model – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

show_model + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine show_model(model) +

+ + + + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(fpm_model_t), + intent(in) + + ::model + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
subroutine show_model(model)
+    ! Prints a human readable representation of the Model
+    type(fpm_model_t), intent(in) :: model
+    print *, info_model(model)
+end subroutine show_model
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/sort_target.html b/proc/sort_target.html new file mode 100644 index 0000000000..fca668d2f6 --- /dev/null +++ b/proc/sort_target.html @@ -0,0 +1,343 @@ + + + + + + + + + + + + + sort_target – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

sort_target + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public recursive subroutine sort_target(target, mock) +

+ + +

Topologically sort a target for scheduling by + recursing over its dependencies.

+

Checks disk-cached source hashes to determine if objects are + up-to-date. Up-to-date sources are tagged as skipped.

+

On completion, target should either be marked as +sorted (target%sorted=.true.) or skipped (target%skip=.true.)

+

If target is marked as sorted, target%schedule should be an +integer greater than zero indicating the region for scheduling

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(build_target_t), + intent(inout), + target + ::target + +
+ + logical, + intent(in),optional + + ::mock +

Optionally sort ALL targets if this is a dry run

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
recursive subroutine sort_target(target, mock)
+    type(build_target_t), intent(inout), target :: target
+    !> Optionally sort ALL targets if this is a dry run
+    logical, optional, intent(in) :: mock
+
+    integer :: i, fh, stat
+    logical :: dry_run
+    
+    dry_run = .false.
+    if (present(mock)) dry_run = mock
+
+    ! Check if target has already been processed (as a dependency)
+    if (target%sorted .or. target%skip) return
+
+    ! Check for a circular dependency
+    ! (If target has been touched but not processed)
+    if (target%touched) then
+        call fpm_stop(1,'(!) Circular dependency found with: '//target%output_file)
+    else
+        target%touched = .true.  ! Set touched flag
+    end if
+
+    ! Load cached source file digest if present
+    if (.not.allocated(target%digest_cached) .and. &
+         exists(target%output_file) .and. &
+         exists(target%output_file//'.digest') .and. &
+         (.not.dry_run)) then 
+
+        allocate(target%digest_cached)
+        open(newunit=fh,file=target%output_file//'.digest',status='old')
+        read(fh,*,iostat=stat) target%digest_cached
+        close(fh)
+
+        ! Cached digest is not recognized
+        if (stat /= 0) deallocate(target%digest_cached)
+
+    end if
+    
+    if (dry_run) then 
+        
+        target%skip = .false.
+        
+    elseif (allocated(target%source)) then
+
+        ! Skip if target is source-based and source file is unmodified
+        if (allocated(target%digest_cached)) then
+            if (target%digest_cached == target%source%digest) target%skip = .true.
+        end if
+
+    elseif (exists(target%output_file)) then
+
+        ! Skip if target is not source-based and already exists
+        target%skip = .true.
+
+    end if
+
+    ! Loop over target dependencies
+    target%schedule = 1
+    do i=1,size(target%dependencies)
+
+        ! Sort dependency
+        call sort_target(target%dependencies(i)%ptr, dry_run)
+
+        if (.not.target%dependencies(i)%ptr%skip) then
+
+            ! Can't skip target if any dependency is not skipped
+            target%skip = .false.
+
+            ! Set target schedule after all of its dependencies
+            target%schedule = max(target%schedule,target%dependencies(i)%ptr%schedule+1)
+
+        end if
+
+    end do
+
+    ! Mark flag as processed: either sorted or skipped
+    target%sorted = .not.target%skip
+
+end subroutine sort_target
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/split.html b/proc/split.html new file mode 100644 index 0000000000..636e842d92 --- /dev/null +++ b/proc/split.html @@ -0,0 +1,422 @@ + + + + + + + + + + + + + split – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

split + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine split(input_line, array, delimiters, order, nulls) +

+ + +

parse string on delimiter characters and store tokens into an allocatable array +given a line of structure ” par1 par2 par3 … parn ” store each par(n) into a separate variable in array.

+
    +
  • by default adjacent delimiters in the input string do not create an empty string in the output array
  • +
  • no quoting of delimiters is supported
  • +
+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::input_line +

input string to tokenize

+
+ + character(len=:), + intent(out), + allocatable + ::array(:) +

output array of tokens

+
+ + character(len=*), + intent(in),optional + + ::delimiters +

list of delimiter characters

+
+ + character(len=*), + intent(in),optional + + ::order +

order of output array sequential|[reverse|right]

+
+ + character(len=*), + intent(in),optional + + ::nulls +

return strings composed of delimiters or not ignore|return|ignoreend

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
subroutine split(input_line,array,delimiters,order,nulls)
+    !! given a line of structure " par1 par2 par3 ... parn " store each par(n) into a separate variable in array.
+    !!
+    !! * by default adjacent delimiters in the input string do not create an empty string in the output array
+    !! * no quoting of delimiters is supported
+    character(len=*),intent(in)              :: input_line  !! input string to tokenize
+    character(len=*),optional,intent(in)     :: delimiters  !! list of delimiter characters
+    character(len=*),optional,intent(in)     :: order       !! order of output array sequential|[reverse|right]
+    character(len=*),optional,intent(in)     :: nulls       !! return strings composed of delimiters or not ignore|return|ignoreend
+    character(len=:),allocatable,intent(out) :: array(:)    !! output array of tokens
+
+    integer                       :: n                      ! max number of strings INPUT_LINE could split into if all delimiter
+    integer,allocatable           :: ibegin(:)              ! positions in input string where tokens start
+    integer,allocatable           :: iterm(:)               ! positions in input string where tokens end
+    character(len=:),allocatable  :: dlim                   ! string containing delimiter characters
+    character(len=:),allocatable  :: ordr                   ! string containing order keyword
+    character(len=:),allocatable  :: nlls                   ! string containing nulls keyword
+    integer                       :: ii,iiii                ! loop parameters used to control print order
+    integer                       :: icount                 ! number of tokens found
+    integer                       :: ilen                   ! length of input string with trailing spaces trimmed
+    integer                       :: i10,i20,i30            ! loop counters
+    integer                       :: icol                   ! pointer into input string as it is being parsed
+    integer                       :: idlim                  ! number of delimiter characters
+    integer                       :: ifound                 ! where next delimiter character is found in remaining input string data
+    integer                       :: inotnull               ! count strings not composed of delimiters
+    integer                       :: ireturn                ! number of tokens returned
+    integer                       :: imax                   ! length of longest token
+
+    ! decide on value for optional DELIMITERS parameter
+    if (present(delimiters)) then                                     ! optional delimiter list was present
+        if(delimiters/='')then                                       ! if DELIMITERS was specified and not null use it
+            dlim=delimiters
+        else                                                           ! DELIMITERS was specified on call as empty string
+            dlim=' '//char(9)//char(10)//char(11)//char(12)//char(13)//char(0) ! use default delimiter when not specified
+        endif
+    else                                                              ! no delimiter value was specified
+        dlim=' '//char(9)//char(10)//char(11)//char(12)//char(13)//char(0)    ! use default delimiter when not specified
+    endif
+    idlim=len(dlim)                                                   ! dlim a lot of blanks on some machines if dlim is a big string
+
+    if(present(order))then; ordr=lower(adjustl(order)); else; ordr='sequential'; endif ! decide on value for optional ORDER parameter
+    if(present(nulls))then; nlls=lower(adjustl(nulls)); else; nlls='ignore'    ; endif ! optional parameter
+
+    n=len(input_line)+1                        ! max number of strings INPUT_LINE could split into if all delimiter
+    allocate(ibegin(n))                        ! allocate enough space to hold starting location of tokens if string all tokens
+    allocate(iterm(n))                         ! allocate enough space to hold ending location of tokens if string all tokens
+    ibegin(:)=1
+    iterm(:)=1
+
+    ilen=len(input_line)                                           ! ILEN is the column position of the last non-blank character
+    icount=0                                                       ! how many tokens found
+    inotnull=0                                                     ! how many tokens found not composed of delimiters
+    imax=0                                                         ! length of longest token found
+
+    select case (ilen)
+
+    case (0)                                                      ! command was totally blank
+
+    case default                                                   ! there is at least one non-delimiter in INPUT_LINE if get here
+        icol=1                                                      ! initialize pointer into input line
+        INFINITE: do i30=1,ilen,1                                   ! store into each array element
+            ibegin(i30)=icol                                         ! assume start new token on the character
+            if(index(dlim(1:idlim),input_line(icol:icol))==0)then  ! if current character is not a delimiter
+            iterm(i30)=ilen                                       ! initially assume no more tokens
+            do i10=1,idlim                                        ! search for next delimiter
+                ifound=index(input_line(ibegin(i30):ilen),dlim(i10:i10))
+                IF(ifound>0)then
+                    iterm(i30)=min(iterm(i30),ifound+ibegin(i30)-2)
+                endif
+            enddo
+            icol=iterm(i30)+2                                     ! next place to look as found end of this token
+            inotnull=inotnull+1                                   ! increment count of number of tokens not composed of delimiters
+            else                                                     ! character is a delimiter for a null string
+            iterm(i30)=icol-1                                     ! record assumed end of string. Will be less than beginning
+            icol=icol+1                                           ! advance pointer into input string
+            endif
+            imax=max(imax,iterm(i30)-ibegin(i30)+1)
+            icount=i30                                               ! increment count of number of tokens found
+            if(icol>ilen)then                                     ! no text left
+            exit INFINITE
+            endif
+        enddo INFINITE
+
+    end select
+
+    select case (trim(adjustl(nlls)))
+    case ('ignore','','ignoreend')
+        ireturn=inotnull
+    case default
+        ireturn=icount
+    end select
+    allocate(character(len=imax) :: array(ireturn))                ! allocate the array to return
+    !allocate(array(ireturn))                                       ! allocate the array to turn
+
+    select case (trim(adjustl(ordr)))                              ! decide which order to store tokens
+    case ('reverse','right') ; ii=ireturn ; iiii=-1                ! last to first
+    case default             ; ii=1       ; iiii=1                 ! first to last
+    end select
+
+    do i20=1,icount                                                ! fill the array with the tokens that were found
+        if(iterm(i20)<ibegin(i20))then
+            select case (trim(adjustl(nlls)))
+            case ('ignore','','ignoreend')
+            case default
+            array(ii)=' '
+            ii=ii+iiii
+            end select
+        else
+            array(ii)=input_line(ibegin(i20):iterm(i20))
+            ii=ii+iiii
+        endif
+    enddo
+end subroutine split
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/split_first_last.html b/proc/split_first_last.html new file mode 100644 index 0000000000..56d6e9ccd4 --- /dev/null +++ b/proc/split_first_last.html @@ -0,0 +1,312 @@ + + + + + + + + + + + + + split_first_last – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

split_first_last + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public pure subroutine split_first_last(string, set, first, last) +

+ + + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::string + +
+ + character(len=*), + intent(in) + + ::set + +
+ + integer, + intent(out), + allocatable + ::first(:) + +
+ + integer, + intent(out), + allocatable + ::last(:) + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
pure subroutine split_first_last(string, set, first, last)
+    character(*), intent(in) :: string
+    character(*), intent(in) :: set
+    integer, allocatable, intent(out) :: first(:)
+    integer, allocatable, intent(out) :: last(:)
+
+    integer, dimension(len(string) + 1) :: istart, iend
+    integer :: p, n, slen
+
+    slen = len(string)
+
+    n = 0
+    if (slen > 0) then
+        p = 0
+        do while (p < slen)
+            n = n + 1
+            istart(n) = min(p + 1, slen)
+            call split_pos(string, set, p)
+            iend(n) = p - 1
+        end do
+    end if
+
+    first = istart(:n)
+    last = iend(:n)
+
+end subroutine split_first_last
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/split_lines_first_last.html b/proc/split_lines_first_last.html new file mode 100644 index 0000000000..37dc756c5c --- /dev/null +++ b/proc/split_lines_first_last.html @@ -0,0 +1,311 @@ + + + + + + + + + + + + + split_lines_first_last – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

split_lines_first_last + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public pure subroutine split_lines_first_last(string, first, last) +

+ + + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::string + +
+ + integer, + intent(out), + allocatable + ::first(:) + +
+ + integer, + intent(out), + allocatable + ::last(:) + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
pure subroutine split_lines_first_last(string, first, last)
+    character(*), intent(in) :: string
+    integer, allocatable, intent(out) :: first(:)
+    integer, allocatable, intent(out) :: last(:)
+
+    integer, dimension(len(string) + 1) :: istart, iend
+    integer :: p, n, slen
+    character, parameter :: CR = achar(13)
+    character, parameter :: LF = new_line('A')
+
+    slen = len(string)
+
+    n = 0
+    if (slen > 0) then
+        p = 1
+        do while (p <= slen)
+            
+            if (index(CR//LF, string(p:p)) == 0) then
+                n = n + 1
+                istart(n) = p
+                do while (p <= slen)
+                    if (index(CR//LF, string(p:p)) /= 0) exit
+                    p = p + 1
+                end do
+                iend(n) = p - 1
+            end if
+            
+            ! Handle Windows CRLF by skipping LF after CR
+            if (p < slen) then 
+               if (string(p:p) == CR .and. string(p+1:p+1) == LF) p = p + 1
+            endif
+            
+            p = p + 1
+        end do
+    end if
+
+    first = istart(:n)
+    last = iend(:n)
+
+end subroutine split_lines_first_last
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/str_begins_with_str.html b/proc/str_begins_with_str.html new file mode 100644 index 0000000000..9fd123e3d4 --- /dev/null +++ b/proc/str_begins_with_str.html @@ -0,0 +1,302 @@ + + + + + + + + + + + + + str_begins_with_str – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

str_begins_with_str + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public pure function str_begins_with_str(s, e, case_sensitive) result(r) +

+ + +

test if a CHARACTER string begins with a specified prefix

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::s + +
+ + character(len=*), + intent(in) + + ::e + +
+ + logical, + intent(in),optional + + ::case_sensitive + +
+ +

Return Value + + + logical + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
pure logical function str_begins_with_str(s, e, case_sensitive) result(r)
+    character(*), intent(in) :: s, e
+    logical, optional, intent(in) :: case_sensitive ! Default option: case sensitive
+    integer :: n1, n2
+    logical :: lower_case
+
+    ! Check if case sensitive
+    if (present(case_sensitive)) then
+        lower_case = .not.case_sensitive
+    else
+        lower_case = .false.
+    end if
+
+    n1 = 1
+    n2 = 1 + len(e)-1
+    if (n2 > len(s)) then
+        r = .false.
+    elseif (lower_case) then
+        r = lower(s(n1:n2)) == lower(e)
+    else
+        r = (s(n1:n2) == e)
+    end if
+end function str_begins_with_str
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/string_array_contains.html b/proc/string_array_contains.html new file mode 100644 index 0000000000..48780f00eb --- /dev/null +++ b/proc/string_array_contains.html @@ -0,0 +1,274 @@ + + + + + + + + + + + + + string_array_contains – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

string_array_contains + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function string_array_contains(search_string, array) +

+ + +

Check if array of TYPE(STRING_T) matches a particular CHARACTER string

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::search_string + +
+ + type(string_t), + intent(in) + + ::array(:) + +
+ +

Return Value + + + logical + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
logical function string_array_contains(search_string,array)
+    character(*), intent(in) :: search_string
+    type(string_t), intent(in) :: array(:)
+
+    integer :: i
+
+    string_array_contains = any([(array(i)%s==search_string, &
+                                   i=1,size(array))])
+
+end function string_array_contains
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/string_cat.html b/proc/string_cat.html new file mode 100644 index 0000000000..6bda2f530a --- /dev/null +++ b/proc/string_cat.html @@ -0,0 +1,292 @@ + + + + + + + + + + + + + string_cat – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

string_cat + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function string_cat(strings, delim) result(cat) +

+ + +

Concatenate an array of type(string_t) into + a single CHARACTER variable

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(string_t), + intent(in) + + ::strings(:) + +
+ + character(len=*), + intent(in),optional + + ::delim + +
+ +

Return Value + + + character(len=:), allocatable + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
function string_cat(strings,delim) result(cat)
+    type(string_t), intent(in) :: strings(:)
+    character(*), intent(in), optional :: delim
+    character(:), allocatable :: cat
+
+    integer :: i
+    character(:), allocatable :: delim_str
+
+    if (size(strings) < 1) then
+        cat = ''
+        return
+    end if
+
+    if (present(delim)) then
+        delim_str = delim
+    else
+        delim_str = ''
+    end if
+
+    cat = strings(1)%s
+    do i=2,size(strings)
+
+        cat = cat//delim_str//strings(i)%s
+
+    end do
+
+end function string_cat
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/syntax_error.html b/proc/syntax_error.html new file mode 100644 index 0000000000..307380a0c4 --- /dev/null +++ b/proc/syntax_error.html @@ -0,0 +1,268 @@ + + + + + + + + + + + + + syntax_error – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

syntax_error + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine syntax_error(error, message) +

+ + + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(error_t), + intent(out), + allocatable + ::error +

Instance of the error data

+
+ + character(len=*), + intent(in) + + ::message +

Error message

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
    subroutine syntax_error(error, message)
+
+        !> Instance of the error data
+        type(error_t), allocatable, intent(out) :: error
+
+        !> Error message
+        character(len=*), intent(in) :: message
+
+        allocate(error)
+        error%message = message
+
+    end subroutine syntax_error
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/targets_from_sources.html b/proc/targets_from_sources.html new file mode 100644 index 0000000000..4388a52718 --- /dev/null +++ b/proc/targets_from_sources.html @@ -0,0 +1,339 @@ + + + + + + + + + + + + + targets_from_sources – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

targets_from_sources + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine targets_from_sources(targets, model, prune, library, error) +

+ + +

High-level wrapper to generate build target information

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(build_target_ptr), + intent(out), + allocatable + ::targets(:) +

The generated list of build targets

+
+ + type(fpm_model_t), + intent(inout), + target + ::model +

The package model from which to construct the target list

+
+ + logical, + intent(in) + + ::prune +

Enable tree-shaking/pruning of module dependencies

+
+ + type(library_config_t), + intent(in),optional + + ::library +

Library build configuration

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error structure

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
subroutine targets_from_sources(targets,model,prune,library,error)
+
+    !> The generated list of build targets
+    type(build_target_ptr), intent(out), allocatable :: targets(:)
+
+    !> The package model from which to construct the target list
+    type(fpm_model_t), intent(inout), target :: model
+    
+    !> Library build configuration
+    type(library_config_t), intent(in), optional :: library
+
+    !> Enable tree-shaking/pruning of module dependencies
+    logical, intent(in) :: prune
+
+    !> Error structure
+    type(error_t), intent(out), allocatable :: error
+    
+    logical :: should_prune
+
+    call build_target_list(targets,model,library)
+
+    call collect_exe_link_dependencies(targets)
+
+    call resolve_module_dependencies(targets,model%external_modules,error)
+    if (allocated(error)) return
+
+    ! Prune unused source files, unless we're building shared libraries that need 
+    ! all sources to be distributable
+    should_prune = prune
+    if (present(library)) should_prune = should_prune .and. library%monolithic()
+        
+    call prune_build_targets(targets,model%packages(1),should_prune)
+
+    call resolve_target_linking(targets,model,library,error)
+    if (allocated(error)) return
+
+end subroutine targets_from_sources
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/to_fortran_name.html b/proc/to_fortran_name.html new file mode 100644 index 0000000000..4265c74bc7 --- /dev/null +++ b/proc/to_fortran_name.html @@ -0,0 +1,257 @@ + + + + + + + + + + + + + to_fortran_name – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

to_fortran_name + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public pure function to_fortran_name(string) result(res) +

+ + +

Returns string with special characters replaced with an underscore. +For now, only a hyphen is treated as a special character, but this can be +expanded to other characters if needed.

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::string + +
+ +

Return Value + + + character(len=len(string)) + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
pure function to_fortran_name(string) result(res)
+    character(*), intent(in) :: string
+    character(len(string)) :: res
+    character, parameter :: SPECIAL_CHARACTERS(*) = ['-']
+    res = replace(string, SPECIAL_CHARACTERS, '_')
+end function to_fortran_name
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/tokenize_flags.html b/proc/tokenize_flags.html new file mode 100644 index 0000000000..94af487d51 --- /dev/null +++ b/proc/tokenize_flags.html @@ -0,0 +1,356 @@ + + + + + + + + + + + + + tokenize_flags – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

tokenize_flags + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine tokenize_flags(flags, flags_array) +

+ + +

Tokenize a string into an array of compiler flags

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::flags + +
+ + type(string_t), + intent(out), + allocatable + ::flags_array(:) + +
+ +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=:), + public, + allocatable + ::flags_char_array(:) + +
+ + integer, + public + + ::i + +
+ + logical, + public + + ::success + +
+ +
+
+ + + + + + + + + +
+

Source Code

+
subroutine tokenize_flags(flags, flags_array)
+    character(*), intent(in) :: flags
+    type(string_t), allocatable, intent(out) :: flags_array(:)
+    character(len=:), allocatable :: flags_char_array(:)
+
+    integer :: i
+    logical :: success
+
+    flags_char_array = sh_split(flags, join_spaced=.true., keep_quotes=.true., success=success)
+    if (.not. success) then
+        allocate(flags_array(0))
+        return
+    end if
+    allocate(flags_array(size(flags_char_array)))
+    do i = 1, size(flags_char_array)
+        flags_array(i)%s = trim(adjustl(flags_char_array(i)))
+    end do
+end subroutine tokenize_flags
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/traverse_compilers.html b/proc/traverse_compilers.html new file mode 100644 index 0000000000..9cc61b609f --- /dev/null +++ b/proc/traverse_compilers.html @@ -0,0 +1,524 @@ + + + + + + + + + + + + + traverse_compilers – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

traverse_compilers + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine traverse_compilers(profile_name, comp_list, table, error, profiles_size, profiles, profindex) +

+ + +

Traverse compiler tables

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=:), + intent(in), + allocatable + ::profile_name +

Name of profile

+
+ + type(toml_key), + intent(in), + allocatable + ::comp_list(:) +

List of OSs in table with profile name given

+
+ + type(toml_table), + intent(in), + pointer + ::table +

Table containing compiler tables

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + integer, + intent(inout),optional + + ::profiles_size +

Number of profiles in list of profiles

+
+ + type(profile_config_t), + intent(inout),optional, + allocatable + ::profiles(:) +

List of profiles

+
+ + integer, + intent(inout),optional + + ::profindex +

Index in the list of profiles

+
+ +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + type(toml_table), + public, + pointer + ::comp_node + +
+ + character(len=:), + public, + allocatable + ::compiler_name + +
+ + integer, + public + + ::icomp + +
+ + logical, + public + + ::is_valid + +
+ + type(toml_key), + public, + allocatable + ::os_list(:) + +
+ + integer, + public + + ::stat + +
+ +
+
+ + + + + + + + + +
+

Source Code

+
      subroutine traverse_compilers(profile_name, comp_list, table, error, profiles_size, profiles, profindex)
+
+        !> Name of profile
+        character(len=:), allocatable, intent(in) :: profile_name
+
+        !> List of OSs in table with profile name given
+        type(toml_key), allocatable, intent(in) :: comp_list(:)
+
+        !> Table containing compiler tables
+        type(toml_table), pointer, intent(in) :: table
+
+        !> Error handling
+        type(error_t), allocatable, intent(out) :: error
+
+        !> Number of profiles in list of profiles
+        integer, intent(inout), optional :: profiles_size
+
+        !> List of profiles
+        type(profile_config_t), allocatable, intent(inout), optional :: profiles(:)
+
+        !> Index in the list of profiles
+        integer, intent(inout), optional :: profindex
+
+        character(len=:), allocatable :: compiler_name
+        type(toml_table), pointer :: comp_node
+        type(toml_key), allocatable :: os_list(:)
+        integer :: icomp, stat
+        logical :: is_valid
+
+        if (size(comp_list)<1) return
+        do icomp = 1, size(comp_list)
+          call validate_compiler_name(comp_list(icomp)%key, is_valid)
+          if (is_valid) then
+            compiler_name = comp_list(icomp)%key
+            call get_value(table, compiler_name, comp_node, stat=stat)
+            if (stat /= toml_stat%success) then
+              call syntax_error(error, "Compiler "//comp_list(icomp)%key//" must be a table entry")
+              exit
+            end if
+            call comp_node%get_keys(os_list)
+            if (present(profiles_size)) then
+              call traverse_oss_for_size(profile_name, compiler_name, os_list, comp_node, profiles_size, error)
+              if (allocated(error)) return
+            else
+              if (.not.(present(profiles).and.present(profindex))) then
+                call fatal_error(error, "Both profiles and profindex have to be present")
+                return
+              end if
+              call traverse_oss(profile_name, compiler_name, os_list, comp_node, &
+                                & profiles, profindex, error)
+              if (allocated(error)) return
+            end if
+          else
+            call fatal_error(error,'*traverse_compilers*:Error: Compiler name not specified or invalid.')
+          end if
+        end do
+      end subroutine traverse_compilers
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/traverse_oss.html b/proc/traverse_oss.html new file mode 100644 index 0000000000..eae8c40d07 --- /dev/null +++ b/proc/traverse_oss.html @@ -0,0 +1,585 @@ + + + + + + + + + + + + + traverse_oss – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

traverse_oss + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine traverse_oss(profile_name, compiler_name, os_list, table, profiles, profindex, error) +

+ + +

Traverse operating system tables to obtain profiles

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=:), + intent(in), + allocatable + ::profile_name +

Name of profile

+
+ + character(len=:), + intent(in), + allocatable + ::compiler_name +

Name of compiler

+
+ + type(toml_key), + intent(in), + allocatable + ::os_list(:) +

List of OSs in table with profile name and compiler name given

+
+ + type(toml_table), + intent(in), + pointer + ::table +

Table containing OS tables

+
+ + type(profile_config_t), + intent(inout), + allocatable + ::profiles(:) +

List of profiles

+
+ + integer, + intent(inout) + + ::profindex +

Index in the list of profiles

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + integer, + public + + ::ios + +
+ + logical, + public + + ::is_key_val + +
+ + logical, + public + + ::is_valid + +
+ + type(toml_key), + public, + allocatable + ::key_list(:) + +
+ + character(len=:), + public, + allocatable + ::l_os_name + +
+ + character(len=:), + public, + allocatable + ::os_name + +
+ + type(toml_table), + public, + pointer + ::os_node + +
+ + integer, + public + + ::os_type + +
+ + integer, + public + + ::stat + +
+ +
+
+ + + + + + + + + +
+

Source Code

+
      subroutine traverse_oss(profile_name, compiler_name, os_list, table, profiles, profindex, error)
+
+        !> Name of profile
+        character(len=:), allocatable, intent(in) :: profile_name
+
+        !> Name of compiler
+        character(len=:), allocatable, intent(in) :: compiler_name
+
+        !> List of OSs in table with profile name and compiler name given
+        type(toml_key), allocatable, intent(in) :: os_list(:)
+
+        !> Table containing OS tables
+        type(toml_table), pointer, intent(in) :: table
+
+        !> Error handling
+        type(error_t), allocatable, intent(out) :: error
+
+        !> List of profiles
+        type(profile_config_t), allocatable, intent(inout) :: profiles(:)
+
+        !> Index in the list of profiles
+        integer, intent(inout) :: profindex
+
+        type(toml_key), allocatable :: key_list(:)
+        character(len=:), allocatable :: os_name, l_os_name
+        type(toml_table), pointer :: os_node
+        integer :: ios, stat, os_type
+        logical :: is_valid, is_key_val
+
+        if (size(os_list)<1) return
+        do ios = 1, size(os_list)
+          os_name = os_list(ios)%key
+          call validate_os_name(os_name, is_valid)
+          if (is_valid) then
+            call get_value(table, os_name, os_node, stat=stat)
+            if (stat /= toml_stat%success) then
+              call syntax_error(error, "os "//os_name//" has to be a table")
+              return
+            end if
+            call os_node%get_keys(key_list)
+            call match_os_type(os_name, os_type)
+            call get_flags(profile_name, compiler_name, os_type, key_list, os_node, profiles, profindex, .true.)
+          else
+            ! Not lowercase OS name
+            l_os_name = lower(os_name)
+            call validate_os_name(l_os_name, is_valid)
+            if (is_valid) then
+              call fatal_error(error,'*traverse_oss*:Error: Name of the operating system must be a lowercase string.')
+            end if
+            if (allocated(error)) return
+
+            ! Missing OS name
+            is_key_val = .false.
+            os_name = os_list(ios)%key
+            call get_value(table, os_name, os_node, stat=stat)
+            if (stat /= toml_stat%success) then
+              is_key_val = .true.
+            end if
+            os_node=>table
+            os_type = OS_ALL
+            call get_flags(profile_name, compiler_name, os_type, os_list, os_node, profiles, profindex, .false.)
+          end if
+        end do
+      end subroutine traverse_oss
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/traverse_oss_for_size.html b/proc/traverse_oss_for_size.html new file mode 100644 index 0000000000..6f1bf6d2f4 --- /dev/null +++ b/proc/traverse_oss_for_size.html @@ -0,0 +1,574 @@ + + + + + + + + + + + + + traverse_oss_for_size – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

traverse_oss_for_size + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine traverse_oss_for_size(profile_name, compiler_name, os_list, table, profiles_size, error) +

+ + +

Traverse operating system tables to obtain number of profiles

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=:), + intent(in), + allocatable + ::profile_name +

Name of profile

+
+ + character(len=:), + intent(in), + allocatable + ::compiler_name +

Name of compiler

+
+ + type(toml_key), + intent(in), + allocatable + ::os_list(:) +

List of OSs in table with profile name and compiler name given

+
+ + type(toml_table), + intent(in), + pointer + ::table +

Table containing OS tables

+
+ + integer, + intent(inout) + + ::profiles_size +

Number of profiles in list of profiles

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + integer, + public + + ::ios + +
+ + logical, + public + + ::is_key_val + +
+ + logical, + public + + ::is_valid + +
+ + type(toml_key), + public, + allocatable + ::key_list(:) + +
+ + logical, + public + + ::key_val_added + +
+ + character(len=:), + public, + allocatable + ::l_os_name + +
+ + character(len=:), + public, + allocatable + ::os_name + +
+ + type(toml_table), + public, + pointer + ::os_node + +
+ + integer, + public + + ::stat + +
+ +
+
+ + + + + + + + + +
+

Source Code

+
      subroutine traverse_oss_for_size(profile_name, compiler_name, os_list, table, profiles_size, error)
+
+        !> Name of profile
+        character(len=:), allocatable, intent(in) :: profile_name
+
+        !> Name of compiler
+        character(len=:), allocatable, intent(in) :: compiler_name
+
+        !> List of OSs in table with profile name and compiler name given
+        type(toml_key), allocatable, intent(in) :: os_list(:)
+
+        !> Table containing OS tables
+        type(toml_table), pointer, intent(in) :: table
+
+        !> Error handling
+        type(error_t), allocatable, intent(out) :: error
+
+        !> Number of profiles in list of profiles
+        integer, intent(inout) :: profiles_size
+
+        type(toml_key), allocatable :: key_list(:)
+        character(len=:), allocatable :: os_name, l_os_name
+        type(toml_table), pointer :: os_node
+        integer :: ios, stat
+        logical :: is_valid, key_val_added, is_key_val
+
+        if (size(os_list)<1) return
+        key_val_added = .false.
+        do ios = 1, size(os_list)
+          os_name = os_list(ios)%key
+          call validate_os_name(os_name, is_valid)
+          if (is_valid) then
+            call get_value(table, os_name, os_node, stat=stat)
+            if (stat /= toml_stat%success) then
+              call syntax_error(error, "os "//os_name//" has to be a table")
+              return
+            end if
+            call os_node%get_keys(key_list)
+            profiles_size = profiles_size + 1
+            call validate_profile_table(profile_name, compiler_name, key_list, os_node, error, .true.)
+          else
+            ! Not lowercase OS name
+            l_os_name = lower(os_name)
+            call validate_os_name(l_os_name, is_valid)
+            if (is_valid) then
+              call fatal_error(error,'*traverse_oss*:Error: Name of the operating system must be a lowercase string.')
+            end if
+            if (allocated(error)) return
+
+            ! Missing OS name
+            is_key_val = .false.
+            os_name = os_list(ios)%key
+            call get_value(table, os_name, os_node, stat=stat)
+            if (stat /= toml_stat%success) then
+              is_key_val = .true.
+            end if
+            os_node=>table
+            if (is_key_val.and..not.key_val_added) then
+              key_val_added = .true.
+              is_key_val = .false.
+              profiles_size = profiles_size + 1
+            else if (.not.is_key_val) then
+              profiles_size = profiles_size + 1
+            end if
+            call validate_profile_table(profile_name, compiler_name, os_list, os_node, error, .false.)
+          end if
+        end do
+      end subroutine traverse_oss_for_size
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/unix_path.html b/proc/unix_path.html new file mode 100644 index 0000000000..47020961d6 --- /dev/null +++ b/proc/unix_path.html @@ -0,0 +1,265 @@ + + + + + + + + + + + + + unix_path – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

unix_path + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function unix_path(path) result(nixpath) +

+ + +

Replace file system separators for unix

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::path + +
+ +

Return Value + + + character(len=:), allocatable + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
function unix_path(path) result(nixpath)
+
+    character(*), intent(in) :: path
+    character(:), allocatable :: nixpath
+
+    integer :: idx
+
+    nixpath = path
+
+    idx = index(nixpath,'\')
+    do while(idx > 0)
+        nixpath(idx:idx) = '/'
+        idx = index(nixpath,'\')
+    end do
+
+end function unix_path
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/upper.html b/proc/upper.html new file mode 100644 index 0000000000..13ca9c8816 --- /dev/null +++ b/proc/upper.html @@ -0,0 +1,306 @@ + + + + + + + + + + + + + upper – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

upper + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public pure elemental function upper(str, begin, end) result(string) +

+ + + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::str + +
+ + integer, + intent(in),optional + + ::begin + +
+ + integer, + intent(in),optional + + ::end + +
+ +

Return Value + + + character(len=len(str)) + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
elemental pure function upper(str,begin,end) result (string)
+
+    character(*), intent(In)     :: str
+    character(len(str))          :: string
+    integer,intent(in),optional  :: begin, end
+    integer                      :: i
+    integer                      :: ibegin, iend
+    string = str
+
+    ibegin = 1
+    if (present(begin))then
+        ibegin = max(ibegin,begin)
+    endif
+
+    iend = len_trim(str)
+    if (present(end))then
+        iend= min(iend,end)
+    endif
+
+    do i = ibegin, iend                               ! step thru each letter in the string in specified range
+        select case (str(i:i))
+        case ('a':'z')
+            string(i:i) = char(iachar(str(i:i))-32)   ! change letter to capitalized
+        case default
+        end select
+    end do
+
+end function upper
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/validate_compiler_name.html b/proc/validate_compiler_name.html new file mode 100644 index 0000000000..3116e08742 --- /dev/null +++ b/proc/validate_compiler_name.html @@ -0,0 +1,272 @@ + + + + + + + + + + + + + validate_compiler_name – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

validate_compiler_name + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine validate_compiler_name(compiler_name, is_valid) +

+ + +

Check if compiler name is a valid compiler name

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=:), + intent(in), + allocatable + ::compiler_name +

Name of a compiler

+
+ + logical, + intent(out) + + ::is_valid +

Boolean value of whether compiler_name is valid or not

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
      subroutine validate_compiler_name(compiler_name, is_valid)
+
+        !> Name of a compiler
+        character(len=:), allocatable, intent(in) :: compiler_name
+
+        !> Boolean value of whether compiler_name is valid or not
+        logical, intent(out) :: is_valid
+        select case(compiler_name)
+          case("gfortran", "ifort", "ifx", "pgfortran", "nvfortran", "flang", "caf", &
+                        & "f95", "lfortran", "lfc", "nagfor", "crayftn", "xlf90", "ftn95")
+            is_valid = .true.
+          case default
+            is_valid = .false.
+        end select
+      end subroutine validate_compiler_name
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/validate_os_name.html b/proc/validate_os_name.html new file mode 100644 index 0000000000..a0a9ab8a18 --- /dev/null +++ b/proc/validate_os_name.html @@ -0,0 +1,274 @@ + + + + + + + + + + + + + validate_os_name – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

validate_os_name + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine validate_os_name(os_name, is_valid) +

+ + +

Check if os_name is a valid name of a supported OS

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=:), + intent(in), + allocatable + ::os_name +

Name of an operating system

+
+ + logical, + intent(out) + + ::is_valid +

Boolean value of whether os_name is valid or not

+
+ +
+ + + + + + + + + + + +
+

Source Code

+
      subroutine validate_os_name(os_name, is_valid)
+
+        !> Name of an operating system
+        character(len=:), allocatable, intent(in) :: os_name
+
+        !> Boolean value of whether os_name is valid or not
+        logical, intent(out) :: is_valid
+
+        select case (os_name)
+          case ("linux", "macos", "windows", "cygwin", "solaris", "freebsd", &
+                          & "openbsd", "unknown")
+            is_valid = .true.
+          case default
+            is_valid = .false.
+        end select
+
+      end subroutine validate_os_name
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/validate_profile_table.html b/proc/validate_profile_table.html new file mode 100644 index 0000000000..4143001387 --- /dev/null +++ b/proc/validate_profile_table.html @@ -0,0 +1,677 @@ + + + + + + + + + + + + + validate_profile_table – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

validate_profile_table + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine validate_profile_table(profile_name, compiler_name, key_list, table, error, os_valid) +

+ + + + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=:), + intent(in), + allocatable + ::profile_name +

Name of profile

+
+ + character(len=:), + intent(in), + allocatable + ::compiler_name +

Name of compiler

+
+ + type(toml_key), + intent(in), + allocatable + ::key_list(:) +

List of keys in the table

+
+ + type(toml_table), + intent(in), + pointer + ::table +

Table containing OS tables

+
+ + type(error_t), + intent(out), + allocatable + ::error +

Error handling

+
+ + logical, + intent(in) + + ::os_valid +

Was called with valid operating system

+
+ +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + character(len=:), + public, + allocatable + ::c_flags + +
+ + character(len=:), + public, + allocatable + ::cxx_flags + +
+ + character(len=:), + public, + allocatable + ::err_message + +
+ + character(len=:), + public, + allocatable + ::file_flags + +
+ + type(toml_key), + public, + allocatable + ::file_list(:) + +
+ + character(len=:), + public, + allocatable + ::file_name + +
+ + type(toml_table), + public, + pointer + ::files + +
+ + character(len=:), + public, + allocatable + ::flags + +
+ + integer, + public + + ::ifile + +
+ + integer, + public + + ::ikey + +
+ + logical, + public + + ::is_valid + +
+ + character(len=:), + public, + allocatable + ::key_name + +
+ + character(len=:), + public, + allocatable + ::link_time_flags + +
+ + integer, + public + + ::stat + +
+ +
+
+ + + + + + + + + +
+

Source Code

+
      subroutine validate_profile_table(profile_name, compiler_name, key_list, table, error, os_valid)
+
+        !> Name of profile
+        character(len=:), allocatable, intent(in) :: profile_name
+
+        !> Name of compiler
+        character(len=:), allocatable, intent(in) :: compiler_name
+
+        !> List of keys in the table
+        type(toml_key), allocatable, intent(in) :: key_list(:)
+
+        !> Table containing OS tables
+        type(toml_table), pointer, intent(in) :: table
+
+        !> Error handling
+        type(error_t), allocatable, intent(out) :: error
+
+        !> Was called with valid operating system
+        logical, intent(in) :: os_valid
+
+        character(len=:), allocatable :: flags, c_flags, cxx_flags, link_time_flags, key_name, file_name, file_flags, err_message
+        type(toml_table), pointer :: files
+        type(toml_key), allocatable :: file_list(:)
+        integer :: ikey, ifile, stat
+        logical :: is_valid
+
+        if (size(key_list).ge.1) then
+          do ikey=1,size(key_list)
+            key_name = key_list(ikey)%key
+            if (key_name.eq.'flags') then
+              call get_value(table, 'flags', flags, stat=stat)
+              if (stat /= toml_stat%success) then
+                call syntax_error(error, "flags has to be a key-value pair")
+                return
+              end if
+            else if (key_name.eq.'c-flags') then
+              call get_value(table, 'c-flags', c_flags, stat=stat)
+              if (stat /= toml_stat%success) then
+                call syntax_error(error, "c-flags has to be a key-value pair")
+                return
+              end if
+            else if (key_name.eq.'cxx-flags') then
+              call get_value(table, 'cxx-flags', cxx_flags, stat=stat)
+              if (stat /= toml_stat%success) then
+                call syntax_error(error, "cxx-flags has to be a key-value pair")
+                return
+              end if
+            else if (key_name.eq.'link-time-flags') then
+              call get_value(table, 'link-time-flags', link_time_flags, stat=stat)
+              if (stat /= toml_stat%success) then
+                call syntax_error(error, "link-time-flags has to be a key-value pair")
+                return
+              end if
+            else if (key_name.eq.'files') then
+              call get_value(table, 'files', files, stat=stat)
+              if (stat /= toml_stat%success) then
+                call syntax_error(error, "files has to be a table")
+                return
+              end if
+              call files%get_keys(file_list)
+              do ifile=1,size(file_list)
+                file_name = file_list(ifile)%key
+                call get_value(files, file_name, file_flags, stat=stat)
+                if (stat /= toml_stat%success) then
+                  call syntax_error(error, "file scope flags has to be a key-value pair")
+                  return
+                end if
+              end do
+            else if (.not. os_valid) then
+                call validate_os_name(key_name, is_valid)
+                err_message = "Unexpected key " // key_name // " found in profile table "//profile_name//" "//compiler_name//"."
+                if (.not. is_valid) call syntax_error(error, err_message)
+            else
+                err_message = "Unexpected key " // key_name // " found in profile table "//profile_name//" "//compiler_name//"."
+                call syntax_error(error, err_message)
+            end if
+          end do
+        end if
+
+        if (allocated(error)) return
+
+      end subroutine validate_profile_table
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/warnwrite.html b/proc/warnwrite.html new file mode 100644 index 0000000000..f4b1a613ab --- /dev/null +++ b/proc/warnwrite.html @@ -0,0 +1,269 @@ + + + + + + + + + + + + + warnwrite – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

warnwrite + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine warnwrite(fname, data) +

+ + +

write trimmed character data to a file if it does not exist

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::fname + +
+ + character(len=*), + intent(in) + + ::data(:) + +
+ +
+ + + + + + + + + + + +
+

Source Code

+
subroutine warnwrite(fname,data)
+character(len=*),intent(in) :: fname
+character(len=*),intent(in) :: data(:)
+
+    if(.not.exists(fname))then
+        call filewrite(fname,data)
+    else
+        write(stderr,'(*(g0,1x))')'<INFO>  ',fname,&
+        & 'already exists. Not overwriting'
+    endif
+
+end subroutine warnwrite
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/which.html b/proc/which.html new file mode 100644 index 0000000000..c275ba9410 --- /dev/null +++ b/proc/which.html @@ -0,0 +1,324 @@ + + + + + + + + + + + + + which – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

which + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function which(command) result(pathname) +

+ + +

Name

+
 which(3f) - [M_io:ENVIRONMENT] given a command name find the pathname by searching
+             the directories in the environment variable $PATH
+ (LICENSE:PD)
+
+ +

Syntax

+

function which(command) result(pathname)

+
character(len=*),intent(in)  :: command
+character(len=:),allocatable :: pathname
+
+ +

Description

+
Given a command name find the first file with that name in the directories
+specified by the environment variable $PATH.
+
+ +

options

+
COMMAND   the command to search for
+
+ +

Returns

+
PATHNAME  the first pathname found in the current user path. Returns blank
+          if the command is not found.
+
+ +

Example

+

Sample program:

+

Checking the error message and counting lines:

+
 program demo_which
+ use M_io, only : which
+ implicit none
+    write(*,*)'ls is ',which('ls')
+    write(*,*)'dir is ',which('dir')
+    write(*,*)'install is ',which('install')
+ end program demo_which
+
+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::command + +
+ +

Return Value + + + character(len=:), allocatable + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
function which(command) result(pathname)
+character(len=*),intent(in)     :: command
+character(len=:),allocatable    :: pathname, checkon, paths(:), exts(:)
+integer                         :: i, j
+   pathname=''
+   call split(get_env('PATH'),paths,delimiters=merge(';',':',separator()=='\'))
+   SEARCH: do i=1,size(paths)
+      checkon=trim(join_path(trim(paths(i)),command))
+      select case(separator())
+      case('/')
+         if(exists(checkon))then
+            pathname=checkon
+            exit SEARCH
+         endif
+      case('\')
+         if(exists(checkon))then
+            pathname=checkon
+            exit SEARCH
+         endif
+         if(exists(checkon//'.bat'))then
+            pathname=checkon//'.bat'
+            exit SEARCH
+         endif
+         if(exists(checkon//'.exe'))then
+            pathname=checkon//'.exe'
+            exit SEARCH
+         endif
+         call split(get_env('PATHEXT'),exts,delimiters=';')
+         do j=1,size(exts)
+            if(exists(checkon//'.'//trim(exts(j))))then
+               pathname=checkon//'.'//trim(exts(j))
+               exit SEARCH
+            endif
+         enddo
+      end select
+   enddo SEARCH
+end function which
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/windows_path.html b/proc/windows_path.html new file mode 100644 index 0000000000..d2c1219ced --- /dev/null +++ b/proc/windows_path.html @@ -0,0 +1,265 @@ + + + + + + + + + + + + + windows_path – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

windows_path + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function windows_path(path) result(winpath) +

+ + +

Replace file system separators for windows

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::path + +
+ +

Return Value + + + character(len=:), allocatable + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
function windows_path(path) result(winpath)
+
+    character(*), intent(in) :: path
+    character(:), allocatable :: winpath
+
+    integer :: idx
+
+    winpath = path
+
+    idx = index(winpath,'/')
+    do while(idx > 0)
+        winpath(idx:idx) = '\'
+        idx = index(winpath,'/')
+    end do
+
+end function windows_path
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/with_qp.html b/proc/with_qp.html new file mode 100644 index 0000000000..dc3293d866 --- /dev/null +++ b/proc/with_qp.html @@ -0,0 +1,257 @@ + + + + + + + + + + + + + with_qp – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

with_qp + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function with_qp(self) +

+ + +

Check if the current compiler supports 128-bit real precision

+ +

Type Bound

+

compiler_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::self +

Instance of the compiler object

+
+ +

Return Value + + + logical + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
logical function with_qp(self)
+    !> Instance of the compiler object
+    class(compiler_t), intent(in) :: self
+    with_qp = self%check_fortran_source_runs &
+              ('if (selected_real_kind(33) == -1) stop 1; end')
+end function with_qp
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/with_xdp.html b/proc/with_xdp.html new file mode 100644 index 0000000000..628529a97b --- /dev/null +++ b/proc/with_xdp.html @@ -0,0 +1,257 @@ + + + + + + + + + + + + + with_xdp – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

with_xdp + Function + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public function with_xdp(self) +

+ + +

Check if the current compiler supports 80-bit “extended” real precision

+ +

Type Bound

+

compiler_t

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(compiler_t), + intent(in) + + ::self +

Instance of the compiler object

+
+ +

Return Value + + + logical + +

+ +
+ + + + + + + + + + + +
+

Source Code

+
logical function with_xdp(self)
+    !> Instance of the compiler object
+    class(compiler_t), intent(in) :: self
+    with_xdp = self%check_fortran_source_runs &
+               ('if (any(selected_real_kind(18) == [-1, selected_real_kind(33)])) stop 1; end')
+end function with_xdp
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/proc/write_response_file.html b/proc/write_response_file.html new file mode 100644 index 0000000000..81e202d9c8 --- /dev/null +++ b/proc/write_response_file.html @@ -0,0 +1,335 @@ + + + + + + + + + + + + + write_response_file – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

write_response_file + Subroutine + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+

public subroutine write_response_file(name, argv) +

+ + +

Response files allow to read command line options from files. +Whitespace is used to separate the arguments, we will use newlines +as separator to create readable response files which can be inspected +in case of errors.

+ + +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::name + +
+ + type(string_t), + intent(in) + + ::argv(:) + +
+ +
+ + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeVisibility AttributesNameInitial
+ + integer, + public + + ::iarg + +
+ + integer, + public + + ::io + +
+ +
+
+ + + + + + + + + +
+

Source Code

+
subroutine write_response_file(name, argv)
+    character(len=*), intent(in) :: name
+    type(string_t), intent(in) :: argv(:)
+
+    integer :: iarg, io
+
+    open(file=name, newunit=io, status='replace')
+    do iarg = 1, size(argv)
+        write(io, '(a)') unix_path(argv(iarg)%s)
+    end do
+    close(io)
+end subroutine write_response_file
+
+ +
+
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/program/main.html b/program/main.html new file mode 100644 index 0000000000..3feabd1621 --- /dev/null +++ b/program/main.html @@ -0,0 +1,653 @@ + + + + + + + + + + + + + main – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+

main Program + +

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+ + +
+ + + + + +
+

Variables

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeAttributesNameInitial
+ + class(fpm_cmd_settings), + + allocatable + ::cmd_settings + +
+ + type(error_t), + + allocatable + ::error + +
+ + character(len=:), + + allocatable + ::project_root + +
+ + character(len=:), + + allocatable + ::pwd_start + +
+ + character(len=:), + + allocatable + ::pwd_working + +
+ + character(len=:), + + allocatable + ::working_dir + +
+ +
+
+ + + + + + +
+

Functions

+
+

function has_manifest(dir) +

+
+ + + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + character(len=*), + intent(in) + + ::dir + +
+ +

+ Return Value + logical +

+ + +
+
+ +
+
+ + +
+

Subroutines

+
+

subroutine get_working_dir(settings, working_dir_) +

+
+ +

Save access to working directory in settings, in case setting have not been allocated

+ +

Arguments

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + class(fpm_cmd_settings), + intent(in),optional + + ::settings + +
+ + character(len=:), + intent(out), + allocatable + ::working_dir_ + +
+ + +
+
+ +
+

subroutine handle_error(error_) +

+
+ + + +

Arguments

+ + + + + + + + + + + + + + + + + + + +
TypeIntentOptional AttributesName
+ + type(error_t), + intent(in),optional + + ::error_ + +
+ + +
+
+ +
+ + +
+

Source Code

+
program main
+use, intrinsic :: iso_fortran_env, only : error_unit, output_unit
+use fpm_command_line, only: &
+        fpm_cmd_settings, &
+        fpm_new_settings, &
+        fpm_build_settings, &
+        fpm_export_settings, &
+        fpm_run_settings, &
+        fpm_test_settings, &
+        fpm_install_settings, &
+        fpm_update_settings, &
+        fpm_clean_settings, &
+        fpm_publish_settings, &
+        get_command_line_settings
+use fpm_error, only: error_t
+use fpm_filesystem, only: exists, parent_dir, join_path
+use fpm, only: cmd_build, cmd_run, cmd_clean
+use fpm_cmd_install, only: cmd_install
+use fpm_cmd_export, only: cmd_export
+use fpm_cmd_new, only: cmd_new
+use fpm_cmd_update, only : cmd_update
+use fpm_cmd_publish, only: cmd_publish
+use fpm_os,  only: change_directory, get_current_directory
+
+implicit none
+
+class(fpm_cmd_settings), allocatable :: cmd_settings
+type(error_t), allocatable :: error
+character(len=:), allocatable :: pwd_start, pwd_working, working_dir, project_root
+
+call get_command_line_settings(cmd_settings)
+
+call get_current_directory(pwd_start, error)
+call handle_error(error)
+
+call get_working_dir(cmd_settings, working_dir)
+if (allocated(working_dir)) then
+    ! Change working directory if requested
+    if (len_trim(working_dir) > 0) then
+        call change_directory(working_dir, error)
+        call handle_error(error)
+
+        call get_current_directory(pwd_working, error)
+        call handle_error(error)
+        write(output_unit, '(*(a))') "fpm: Entering directory '"//pwd_working//"'"
+    else
+        pwd_working = pwd_start
+    end if
+else
+    pwd_working = pwd_start
+end if
+
+select type (settings => cmd_settings)
+type is (fpm_new_settings)
+class default
+    if (.not.has_manifest(pwd_working)) then
+        project_root = pwd_working
+        do while(.not.has_manifest(project_root))
+            working_dir = parent_dir(project_root)
+            if (len(working_dir) == 0) exit
+            project_root = working_dir
+        end do
+
+        if (has_manifest(project_root)) then
+            call change_directory(project_root, error)
+            call handle_error(error)
+            write(output_unit, '(*(a))') "fpm: Entering directory '"//project_root//"'"
+        end if
+    end if
+end select
+
+select type(settings=>cmd_settings)
+type is (fpm_new_settings)
+    call cmd_new(settings)
+type is (fpm_build_settings)
+    call cmd_build(settings)
+type is (fpm_run_settings)
+    call cmd_run(settings,test=.false.)
+type is (fpm_test_settings)
+    call cmd_run(settings,test=.true.)
+type is (fpm_export_settings)
+    call cmd_export(settings)
+type is (fpm_install_settings)
+    call cmd_install(settings)
+type is (fpm_update_settings)
+    call cmd_update(settings)
+type is (fpm_clean_settings)
+    call cmd_clean(settings)
+type is (fpm_publish_settings)
+    call cmd_publish(settings)
+end select
+
+if (allocated(project_root)) then
+    write(output_unit, '(*(a))') "fpm: Leaving directory '"//project_root//"'"
+end if
+
+if (pwd_start /= pwd_working) then
+    write(output_unit, '(*(a))') "fpm: Leaving directory '"//pwd_working//"'"
+end if
+
+contains
+
+    function has_manifest(dir)
+        character(len=*), intent(in) :: dir
+        logical :: has_manifest
+
+        has_manifest = exists(join_path(dir, "fpm.toml"))
+    end function has_manifest
+
+    subroutine handle_error(error_)
+        type(error_t), optional, intent(in) :: error_
+        if (present(error_)) then
+            write (error_unit, '("[Error]", 1x, a)') error_%message
+            stop 1
+        end if
+    end subroutine handle_error
+
+    !> Save access to working directory in settings, in case setting have not been allocated
+    subroutine get_working_dir(settings, working_dir_)
+        class(fpm_cmd_settings), optional, intent(in) :: settings
+        character(len=:), allocatable, intent(out) :: working_dir_
+        if (present(settings)) then
+            working_dir_ = settings%working_dir
+        end if
+    end subroutine get_working_dir
+
+end program main
+
+ +
+ +
+
+ +
+
+
+
+
+
+

+ Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
© 2025 +

+
+
+

+ Documentation generated by + FORD + on 2025-06-07 07:02 +0000

+
+
+
+
+
+ + \ No newline at end of file diff --git a/search.html b/search.html new file mode 100644 index 0000000000..3f25ff078b --- /dev/null +++ b/search.html @@ -0,0 +1,116 @@ + + + + + + + + + + + Search Results – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+

Search Results

+
+
    +
    +
    +
    + + + + +
    +
    +
    +
    +
    +
    +

    + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
    © 2025 +

    +
    +
    +

    + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

    +
    +
    +
    +
    +
    + + \ No newline at end of file diff --git a/search/load_search.js b/search/load_search.js new file mode 100644 index 0000000000..3b6e61c362 --- /dev/null +++ b/search/load_search.js @@ -0,0 +1,62 @@ + var items = tipuesearch['pages']; + var documents = tipuesearch["pages"] + var counter = 0 + + for (item in documents){ + documents[item]['id'] = counter; + counter = counter +1; + } + + var idx = lunr(function () { + this.ref('id') + this.field('title') + this.field('url') + this.field('text', { boost: 10 }) + this.field('tags') + + items.forEach(function (doc) { + this.add(doc) + }, this) +}) + +function lunr_search(term) { + document.getElementById('lunrsearchresults').innerHTML = '
      '; + if(term) { + document.getElementById('lunrsearchresults').innerHTML = "

      Search results for '" + term + "'

      " + document.getElementById('lunrsearchresults').innerHTML; + //put results on the screen. + var results = idx.search(term); + if(results.length>0){ + //console.log(idx.search(term)); + //if results + for (var i = 0; i < results.length; i++) { + // more statements + var ref = results[i]['ref']; + var url = documents[ref]['url']; + var title = documents[ref]['title']; + var body = documents[ref]['text'].substring(0,160)+'...'; + document.querySelectorAll('#lunrsearchresults ul')[0].innerHTML = document.querySelectorAll('#lunrsearchresults ul')[0].innerHTML + "
    • " + title + "
      "+ body +"
      "+ url +"
    • "; + } + } else { + document.querySelectorAll('#lunrsearchresults ul')[0].innerHTML = "
    • No results found...
    • "; + } + } + return false; +} + +function getQueryVariable(variable) { + var query = window.location.search.substring(1); + var vars = query.split('&'); + + for (var i = 0; i < vars.length; i++) { + var pair = vars[i].split('='); + + if (pair[0] === variable) { + return decodeURIComponent(pair[1].replace(/\+/g, '%20')); + } + } +} + +var searchTerm = getQueryVariable('q'); +if (searchTerm) { + lunr_search(searchTerm) +} diff --git a/search/search_database.json b/search/search_database.json new file mode 100644 index 0000000000..4c6b030864 --- /dev/null +++ b/search/search_database.json @@ -0,0 +1 @@ +var tipuesearch = {"pages":[{"title":" Fortran-lang/fpm ","text":"Fortran-lang/fpm Fortran package manager developer documentation The package manifest Command line interface The package model The build backend Generating this documentation Fortran package manager developer documentation This is the main documentation of the Fortran package manager ( fpm ).\nThis document serves as developer documentation of fpm itself and contains general advice for developing in the fpm code base. The package manifest The central object describing an fpm project is the package manifest fpm.toml .\nThe manifest is written in TOML, you can find the TOML specification at the official TOML homepage . The fpm.toml file targets project developers and maintainers to relieve them from writing build files for their packages.\nWith the package manifest a central place to collect information about the project is provided.\nIt contains the versioning and licensing meta data, as well as the information on external dependencies and the required build-tools or compiler settings. The manifest format specific to fpm projects is documented in the manifest reference . Note For a more practical but less complete guide on creating fpm projects see the packaging guide . The details of the TOML parsing are implemented with using the tomlf module.\nGenerally, the interface to all TOML related functions for fpm is found in the proxy module fpm_toml . All the manifest types are bundled in fpm_manifest .\nWhile the specific subtables for the package configuration are found in the src/fpm/manifest directory, they should be reexported in the fpm_manifest module if they should be elsewhere in fpm . Command line interface fpm is mainly used as a command line tool.\nTo work with an fpm project as a user you can completely rely on the command line. The command line interface is build with the M_CLI2 module and can be found in fpm_command_line . The package model Once front-end inputs have been received from the package manifest and command line interface, fpm will construct an\ninternal representation of the package and its dependencies. This internal representation is known as the package model .\nThe model and its associated data types should encapsulate all the information required to correctly build a package and\nshould be independent of the intended backend build system. Information stored in the model includes: build targets and\ntheir inter-dependencies; compiler and compiler flags; library linking information. For more information on the contents of the package model and the process for constructing it, please see fpm_model . The build backend Once a complete package model has been constructed, it can be passed to a backend for either performing the compilation\nand linking of targets, or for generating configuration files for a third-party build system.\nCurrently, only a native backend is implemented in fpm . See fpm_backend for more information. Generating this documentation This documentation is generated by FORD .\nFor more details on the project file and the comment markup in the source code visit the FORD documentation . To regenerate this documentation run: ford docs.md Developer Info fortran-lang/fpm contributors","tags":"home","url":"index.html"},{"title":"fortran_features_t – Fortran-lang/fpm ","text":"type, public, extends( serializable_t ) :: fortran_features_t Enabled Fortran language features Components Type Visibility Attributes Name Initial logical, public :: implicit_external = .false. Use implicit external interface logical, public :: implicit_typing = .false. Use default implicit typing character(len=:), public, allocatable :: source_form Form to use for all Fortran sources Type-Bound Procedures generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit private subroutine srcfile_dump_to_toml(self, table, error) Dump dependency to toml table Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine dump_to_file(self, file, error, json) Write serializable object to file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine dump_to_unit(self, unit, error, json) Write serializable object to a formatted Fortran unit Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit Formatted unit type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format requested? procedure, public :: dump_to_toml => fft_dump_to_toml private subroutine fft_dump_to_toml(self, table, error) Dump fortran features to toml table Arguments Type Intent Optional Attributes Name class( fortran_features_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling generic, public :: load => load_from_toml , load_from_file, load_from_unit private subroutine srcfile_load_from_toml(self, table, error) Read dependency from toml table (no checks made at this stage) Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine load_from_file(self, file, error, json) Read dependency tree from file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine load_from_unit(self, unit, error, json) Read dependency tree from file\ninit JSON interpreter\nRead object from TOML table use default TOML parser Read object from TOML table Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format procedure, public :: load_from_toml => fft_load_from_toml private subroutine fft_load_from_toml(self, table, error) Read dependency from toml table (no checks made at this stage) Arguments Type Intent Optional Attributes Name class( fortran_features_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling generic, public :: operator(==) => serializable_is_same private function srcfile_is_same(this, that) Check that two source files are equal\nAll checks passed! Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical procedure, public :: serializable_is_same => fft_is_same Serialization interface private function fft_is_same(this, that) Check that two fortran feature objects are equal\nAll checks passed! Arguments Type Intent Optional Attributes Name class( fortran_features_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical procedure, public, non_overridable :: test_serialization Test load/write roundtrip private subroutine test_serialization(self, message, error) Test serialization of a serializable object\nDump to scratch file\nLoad from scratch file\nCheck same Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self character(len=*), intent(in) :: message type( error_t ), intent(out), allocatable :: error Source Code type , extends ( serializable_t ) :: fortran_features_t !> Use default implicit typing logical :: implicit_typing = . false . !> Use implicit external interface logical :: implicit_external = . false . !> Form to use for all Fortran sources character (:), allocatable :: source_form contains !> Serialization interface procedure :: serializable_is_same => fft_is_same procedure :: dump_to_toml => fft_dump_to_toml procedure :: load_from_toml => fft_load_from_toml end type fortran_features_t","tags":"","url":"type/fortran_features_t.html"},{"title":"fpm_model_t – Fortran-lang/fpm ","text":"type, public, extends( serializable_t ) :: fpm_model_t Type describing everything required to build\n the root package and its dependencies. Components Type Visibility Attributes Name Initial type( archiver_t ), public :: archiver Archiver object character(len=:), public, allocatable :: build_prefix Base directory for build character(len=:), public, allocatable :: c_compile_flags Command line flags passed to C for compilation type( compiler_t ), public :: compiler Compiler object character(len=:), public, allocatable :: cxx_compile_flags Command line flags passed to C++ for compilation type( dependency_tree_t ), public :: deps Project dependencies logical, public :: enforce_module_names = .false. Whether module names should be prefixed with the package name type( string_t ), public, allocatable :: external_modules (:) External modules used character(len=:), public, allocatable :: fortran_compile_flags Command line flags passed to fortran for compilation type( string_t ), public, allocatable :: include_dirs (:) Include directories logical, public :: include_tests = .true. Whether tests should be added to the build list character(len=:), public, allocatable :: link_flags Command line flags passed to the linker type( string_t ), public, allocatable :: link_libraries (:) Native libraries to link against type( string_t ), public :: module_prefix Prefix for all module names character(len=:), public, allocatable :: package_name Name of root package type( package_t ), public, allocatable :: packages (:) Array of packages (including the root package) Type-Bound Procedures generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit private subroutine srcfile_dump_to_toml(self, table, error) Dump dependency to toml table Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine dump_to_file(self, file, error, json) Write serializable object to file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine dump_to_unit(self, unit, error, json) Write serializable object to a formatted Fortran unit Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit Formatted unit type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format requested? procedure, public :: dump_to_toml => model_dump_to_toml private subroutine model_dump_to_toml(self, table, error) Dump dependency to toml table Array of packages (including the root package) Because dependencies are named, fallback if this has no name\nSo, serialization will work regardless of size(self%dep) == self%ndep Arguments Type Intent Optional Attributes Name class( fpm_model_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling procedure, public :: get_package_libraries_link Get target link flags private function get_package_libraries_link(model, package_name, prefix, exclude_self, dep_IDs, error) result(r) Arguments Type Intent Optional Attributes Name class( fpm_model_t ), intent(in) :: model character(len=*), intent(in) :: package_name character(len=*), intent(in) :: prefix logical, intent(in), optional :: exclude_self Option to exclude linking to the given package (needed building it as a library) integer, intent(out), optional, allocatable :: dep_IDs (:) Optionally export the list of dependency IDs type( error_t ), intent(out), allocatable :: error Return Value character(len=:), allocatable generic, public :: load => load_from_toml , load_from_file, load_from_unit private subroutine srcfile_load_from_toml(self, table, error) Read dependency from toml table (no checks made at this stage) Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine load_from_file(self, file, error, json) Read dependency tree from file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine load_from_unit(self, unit, error, json) Read dependency tree from file\ninit JSON interpreter\nRead object from TOML table use default TOML parser Read object from TOML table Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format procedure, public :: load_from_toml => model_load_from_toml private subroutine model_load_from_toml(self, table, error) Read dependency from toml table (no checks made at this stage) Read all packages Arguments Type Intent Optional Attributes Name class( fpm_model_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling generic, public :: operator(==) => serializable_is_same private function srcfile_is_same(this, that) Check that two source files are equal\nAll checks passed! Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical procedure, public :: serializable_is_same => model_is_same Serialization interface private function model_is_same(this, that) Check that two model objects are equal\nAll checks passed! Arguments Type Intent Optional Attributes Name class( fpm_model_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical procedure, public, non_overridable :: test_serialization Test load/write roundtrip private subroutine test_serialization(self, message, error) Test serialization of a serializable object\nDump to scratch file\nLoad from scratch file\nCheck same Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self character(len=*), intent(in) :: message type( error_t ), intent(out), allocatable :: error Source Code type , extends ( serializable_t ) :: fpm_model_t !> Name of root package character (:), allocatable :: package_name !> Array of packages (including the root package) type ( package_t ), allocatable :: packages (:) !> Compiler object type ( compiler_t ) :: compiler !> Archiver object type ( archiver_t ) :: archiver !> Command line flags passed to fortran for compilation character (:), allocatable :: fortran_compile_flags !> Command line flags passed to C for compilation character (:), allocatable :: c_compile_flags !> Command line flags passed to C++ for compilation character (:), allocatable :: cxx_compile_flags !> Command line flags passed to the linker character (:), allocatable :: link_flags !> Base directory for build character (:), allocatable :: build_prefix !> Include directories type ( string_t ), allocatable :: include_dirs (:) !> Native libraries to link against type ( string_t ), allocatable :: link_libraries (:) !> External modules used type ( string_t ), allocatable :: external_modules (:) !> Project dependencies type ( dependency_tree_t ) :: deps !> Whether tests should be added to the build list logical :: include_tests = . true . !> Whether module names should be prefixed with the package name logical :: enforce_module_names = . false . !> Prefix for all module names type ( string_t ) :: module_prefix contains !> Get target link flags procedure :: get_package_libraries_link !> Serialization interface procedure :: serializable_is_same => model_is_same procedure :: dump_to_toml => model_dump_to_toml procedure :: load_from_toml => model_load_from_toml end type fpm_model_t","tags":"","url":"type/fpm_model_t.html"},{"title":"package_t – Fortran-lang/fpm ","text":"type, public, extends( serializable_t ) :: package_t Type for describing a single package Components Type Visibility Attributes Name Initial logical, public :: enforce_module_names = .false. Module naming conventions type( fortran_features_t ), public :: features Language features type( string_t ), public :: module_prefix Prefix for all module names character(len=:), public, allocatable :: name Name of package type( preprocess_config_t ), public :: preprocess List of macros. type( srcfile_t ), public, allocatable :: sources (:) Array of sources character(len=:), public, allocatable :: version Package version number. Type-Bound Procedures generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit private subroutine srcfile_dump_to_toml(self, table, error) Dump dependency to toml table Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine dump_to_file(self, file, error, json) Write serializable object to file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine dump_to_unit(self, unit, error, json) Write serializable object to a formatted Fortran unit Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit Formatted unit type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format requested? procedure, public :: dump_to_toml => package_dump_to_toml private subroutine package_dump_to_toml(self, table, error) Dump dependency to toml table Create a preprocessor table\nCreate a fortran table\nCreate a sources table Arguments Type Intent Optional Attributes Name class( package_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling procedure, public :: has_library => package_has_library Check if a package will create a library private elemental function package_has_library(self) result(has_library) Check whether a package has an object library Arguments Type Intent Optional Attributes Name class( package_t ), intent(in) :: self Return Value logical generic, public :: load => load_from_toml , load_from_file, load_from_unit private subroutine srcfile_load_from_toml(self, table, error) Read dependency from toml table (no checks made at this stage) Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine load_from_file(self, file, error, json) Read dependency tree from file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine load_from_unit(self, unit, error, json) Read dependency tree from file\ninit JSON interpreter\nRead object from TOML table use default TOML parser Read object from TOML table Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format procedure, public :: load_from_toml => package_load_from_toml private subroutine package_load_from_toml(self, table, error) Read dependency from toml table (no checks made at this stage) Read all dependencies Arguments Type Intent Optional Attributes Name class( package_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling generic, public :: operator(==) => serializable_is_same private function srcfile_is_same(this, that) Check that two source files are equal\nAll checks passed! Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical procedure, public :: serializable_is_same => package_is_same Serialization interface private function package_is_same(this, that) Check that two package objects are equal\nModule naming\nFortran features All checks passed! Arguments Type Intent Optional Attributes Name class( package_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical procedure, public, non_overridable :: test_serialization Test load/write roundtrip private subroutine test_serialization(self, message, error) Test serialization of a serializable object\nDump to scratch file\nLoad from scratch file\nCheck same Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self character(len=*), intent(in) :: message type( error_t ), intent(out), allocatable :: error Source Code type , extends ( serializable_t ) :: package_t !> Name of package character (:), allocatable :: name !> Array of sources type ( srcfile_t ), allocatable :: sources (:) !> List of macros. type ( preprocess_config_t ) :: preprocess !> Package version number. character (:), allocatable :: version !> Module naming conventions logical :: enforce_module_names = . false . !> Prefix for all module names type ( string_t ) :: module_prefix !> Language features type ( fortran_features_t ) :: features contains !> Check if a package will create a library procedure :: has_library => package_has_library !> Serialization interface procedure :: serializable_is_same => package_is_same procedure :: dump_to_toml => package_dump_to_toml procedure :: load_from_toml => package_load_from_toml end type package_t","tags":"","url":"type/package_t.html"},{"title":"srcfile_t – Fortran-lang/fpm ","text":"type, public, extends( serializable_t ) :: srcfile_t Type for describing a source file Components Type Visibility Attributes Name Initial integer(kind=int64), public :: digest Current hash character(len=:), public, allocatable :: exe_name Name of executable for FPM_UNIT_PROGRAM character(len=:), public, allocatable :: file_name File path relative to cwd type( string_t ), public, allocatable :: include_dependencies (:) Files INCLUDEd by this source file type( string_t ), public, allocatable :: link_libraries (:) Native libraries to link against type( string_t ), public, allocatable :: modules_provided (:) Modules provided by this source file (lowerstring) type( string_t ), public, allocatable :: modules_used (:) Modules USEd by this source file (lowerstring) type( string_t ), public, allocatable :: parent_modules (:) Parent modules (submodules only) integer, public :: unit_scope = FPM_SCOPE_UNKNOWN Target module-use scope integer, public :: unit_type = FPM_UNIT_UNKNOWN Type of source unit Type-Bound Procedures generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit private subroutine srcfile_dump_to_toml(self, table, error) Dump dependency to toml table Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine dump_to_file(self, file, error, json) Write serializable object to file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine dump_to_unit(self, unit, error, json) Write serializable object to a formatted Fortran unit Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit Formatted unit type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format requested? procedure, public :: dump_to_toml => srcfile_dump_to_toml private subroutine srcfile_dump_to_toml(self, table, error) Dump dependency to toml table Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling generic, public :: load => load_from_toml , load_from_file, load_from_unit private subroutine srcfile_load_from_toml(self, table, error) Read dependency from toml table (no checks made at this stage) Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine load_from_file(self, file, error, json) Read dependency tree from file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine load_from_unit(self, unit, error, json) Read dependency tree from file\ninit JSON interpreter\nRead object from TOML table use default TOML parser Read object from TOML table Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format procedure, public :: load_from_toml => srcfile_load_from_toml private subroutine srcfile_load_from_toml(self, table, error) Read dependency from toml table (no checks made at this stage) Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling generic, public :: operator(==) => serializable_is_same private function srcfile_is_same(this, that) Check that two source files are equal\nAll checks passed! Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical procedure, public :: serializable_is_same => srcfile_is_same Serialization interface private function srcfile_is_same(this, that) Check that two source files are equal\nAll checks passed! Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical procedure, public, non_overridable :: test_serialization Test load/write roundtrip private subroutine test_serialization(self, message, error) Test serialization of a serializable object\nDump to scratch file\nLoad from scratch file\nCheck same Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self character(len=*), intent(in) :: message type( error_t ), intent(out), allocatable :: error Source Code type , extends ( serializable_t ) :: srcfile_t !> File path relative to cwd character (:), allocatable :: file_name !> Name of executable for FPM_UNIT_PROGRAM character (:), allocatable :: exe_name !> Target module-use scope integer :: unit_scope = FPM_SCOPE_UNKNOWN !> Modules provided by this source file (lowerstring) type ( string_t ), allocatable :: modules_provided (:) !> Type of source unit integer :: unit_type = FPM_UNIT_UNKNOWN !> Parent modules (submodules only) type ( string_t ), allocatable :: parent_modules (:) !> Modules USEd by this source file (lowerstring) type ( string_t ), allocatable :: modules_used (:) !> Files INCLUDEd by this source file type ( string_t ), allocatable :: include_dependencies (:) !> Native libraries to link against type ( string_t ), allocatable :: link_libraries (:) !> Current hash integer ( int64 ) :: digest contains !> Serialization interface procedure :: serializable_is_same => srcfile_is_same procedure :: dump_to_toml => srcfile_dump_to_toml procedure :: load_from_toml => srcfile_load_from_toml end type srcfile_t","tags":"","url":"type/srcfile_t.html"},{"title":"console_t – Fortran-lang/fpm ","text":"type, public :: console_t Console object Components Type Visibility Attributes Name Initial integer, public :: n_line = 1 Number of lines printed Type-Bound Procedures procedure, public :: update_line => console_update_line Update a previously-written console line private subroutine console_update_line(console, line_no, str) Overwrite a previously-written line in standard output Arguments Type Intent Optional Attributes Name class( console_t ), intent(in) :: console Console object integer, intent(in) :: line_no Integer output from [[console_write_line]] character(len=*), intent(in) :: str New string to overwrite line procedure, public :: write_line => console_write_line Write a single line to the console private subroutine console_write_line(console, str, line, advance) Write a single line to the standard output Arguments Type Intent Optional Attributes Name class( console_t ), intent(inout) :: console Console object character(len=*), intent(in) :: str String to write integer, intent(out), optional :: line Integer needed to later update console line logical, intent(in), optional :: advance Advancing output (print newline?) Source Code type console_t !> Number of lines printed integer :: n_line = 1 contains !> Write a single line to the console procedure :: write_line => console_write_line !> Update a previously-written console line procedure :: update_line => console_update_line end type console_t","tags":"","url":"type/console_t.html"},{"title":"package_config_t – Fortran-lang/fpm ","text":"type, public, extends( serializable_t ) :: package_config_t Package meta data Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: author Author meta data type( build_config_t ), public :: build Build configuration data character(len=:), public, allocatable :: copyright Copyright meta data type( dependency_config_t ), public, allocatable :: dependency (:) Dependency meta data type( dependency_config_t ), public, allocatable :: dev_dependency (:) Development dependency meta data type( example_config_t ), public, allocatable :: example (:) Example meta data type( executable_config_t ), public, allocatable :: executable (:) Executable meta data type( fortran_config_t ), public :: fortran Fortran meta data type( install_config_t ), public :: install Installation configuration data type( library_config_t ), public, allocatable :: library Library meta data character(len=:), public, allocatable :: license License meta data character(len=:), public, allocatable :: maintainer Maintainer meta data type( metapackage_config_t ), public :: meta Metapackage data character(len=:), public, allocatable :: name Name of the package type( preprocess_config_t ), public, allocatable :: preprocess (:) Preprocess meta data type( profile_config_t ), public, allocatable :: profiles (:) Profiles meta data type( test_config_t ), public, allocatable :: test (:) Test meta data type( version_t ), public :: version Package version Type-Bound Procedures generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit private subroutine srcfile_dump_to_toml(self, table, error) Dump dependency to toml table Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine dump_to_file(self, file, error, json) Write serializable object to file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine dump_to_unit(self, unit, error, json) Write serializable object to a formatted Fortran unit Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit Formatted unit type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format requested? procedure, public :: dump_to_toml private subroutine dump_to_toml(self, table, error) Dump manifest to toml table Because dependencies are named, fallback if this has no name\nSo, serialization will work regardless of size(self%dep) == self%ndep\nBecause dependencies are named, fallback if this has no name\nSo, serialization will work regardless of size(self%dep) == self%ndep\nBecause dependencies are named, fallback if this has no name\nSo, serialization will work regardless of size(self%dep) == self%ndep\nDuplicate profile names are possible, as multiple profiles are possible with the\nsame name, same compiler, etc. So, use a unique name here\nBecause dependencies are named, fallback if this has no name\nSo, serialization will work regardless of size(self%dep) == self%ndep\nBecause dependencies are named, fallback if this has no name\nSo, serialization will work regardless of size(self%dep) == self%ndep\nBecause dependencies are named, fallback if this has no name\nSo, serialization will work regardless of size(self%dep) == self%ndep Arguments Type Intent Optional Attributes Name class( package_config_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling procedure, public :: info Print information on this instance private subroutine info(self, unit, verbosity) Write information on instance Arguments Type Intent Optional Attributes Name class( package_config_t ), intent(in) :: self Instance of the package configuration integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout generic, public :: load => load_from_toml , load_from_file, load_from_unit private subroutine srcfile_load_from_toml(self, table, error) Read dependency from toml table (no checks made at this stage) Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine load_from_file(self, file, error, json) Read dependency tree from file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine load_from_unit(self, unit, error, json) Read dependency tree from file\ninit JSON interpreter\nRead object from TOML table use default TOML parser Read object from TOML table Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format procedure, public :: load_from_toml private subroutine load_from_toml(self, table, error) Read manifest from toml table (no checks made at this stage) Read all packages\nRead all packages\nRead all packages\nRead all packages\nRead all packages\nRead all packages\nRead all packages Arguments Type Intent Optional Attributes Name class( package_config_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling generic, public :: operator(==) => serializable_is_same private function srcfile_is_same(this, that) Check that two source files are equal\nAll checks passed! Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical procedure, public :: serializable_is_same => manifest_is_same Serialization interface private function manifest_is_same(this, that) All checks passed! Arguments Type Intent Optional Attributes Name class( package_config_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical procedure, public, non_overridable :: test_serialization Test load/write roundtrip private subroutine test_serialization(self, message, error) Test serialization of a serializable object\nDump to scratch file\nLoad from scratch file\nCheck same Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self character(len=*), intent(in) :: message type( error_t ), intent(out), allocatable :: error Source Code type , extends ( serializable_t ) :: package_config_t !> Name of the package character ( len = :), allocatable :: name !> Package version type ( version_t ) :: version !> Build configuration data type ( build_config_t ) :: build !> Metapackage data type ( metapackage_config_t ) :: meta !> Installation configuration data type ( install_config_t ) :: install !> Fortran meta data type ( fortran_config_t ) :: fortran !> License meta data character ( len = :), allocatable :: license !> Author meta data character ( len = :), allocatable :: author !> Maintainer meta data character ( len = :), allocatable :: maintainer !> Copyright meta data character ( len = :), allocatable :: copyright !> Library meta data type ( library_config_t ), allocatable :: library !> Executable meta data type ( executable_config_t ), allocatable :: executable (:) !> Dependency meta data type ( dependency_config_t ), allocatable :: dependency (:) !> Development dependency meta data type ( dependency_config_t ), allocatable :: dev_dependency (:) !> Profiles meta data type ( profile_config_t ), allocatable :: profiles (:) !> Example meta data type ( example_config_t ), allocatable :: example (:) !> Test meta data type ( test_config_t ), allocatable :: test (:) !> Preprocess meta data type ( preprocess_config_t ), allocatable :: preprocess (:) contains !> Print information on this instance procedure :: info !> Serialization interface procedure :: serializable_is_same => manifest_is_same procedure :: dump_to_toml procedure :: load_from_toml end type package_config_t","tags":"","url":"type/package_config_t.html"},{"title":"error_t – Fortran-lang/fpm ","text":"type, public :: error_t Data type defining an error Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: message Error message Source Code type :: error_t !> Error message character ( len = :), allocatable :: message end type error_t","tags":"","url":"type/error_t.html"},{"title":"build_config_t – Fortran-lang/fpm ","text":"type, public, extends( serializable_t ) :: build_config_t Configuration data for build Components Type Visibility Attributes Name Initial logical, public :: auto_examples = .true. Automatic discovery of examples logical, public :: auto_executables = .true. Automatic discovery of executables logical, public :: auto_tests = .true. Automatic discovery of tests type( string_t ), public, allocatable :: external_modules (:) External modules to use type( string_t ), public, allocatable :: link (:) Libraries to link against logical, public :: module_naming = .false. Enforcing of package module names type( string_t ), public :: module_prefix Type-Bound Procedures generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit private subroutine srcfile_dump_to_toml(self, table, error) Dump dependency to toml table Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine dump_to_file(self, file, error, json) Write serializable object to file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine dump_to_unit(self, unit, error, json) Write serializable object to a formatted Fortran unit Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit Formatted unit type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format requested? procedure, public :: dump_to_toml private subroutine dump_to_toml(self, table, error) Dump build config to toml table Arguments Type Intent Optional Attributes Name class( build_config_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling procedure, public :: info Print information on this instance private subroutine info(self, unit, verbosity) Write information on build configuration instance Arguments Type Intent Optional Attributes Name class( build_config_t ), intent(in) :: self Instance of the build configuration integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout generic, public :: load => load_from_toml , load_from_file, load_from_unit private subroutine srcfile_load_from_toml(self, table, error) Read dependency from toml table (no checks made at this stage) Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine load_from_file(self, file, error, json) Read dependency tree from file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine load_from_unit(self, unit, error, json) Read dependency tree from file\ninit JSON interpreter\nRead object from TOML table use default TOML parser Read object from TOML table Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format procedure, public :: load_from_toml private subroutine load_from_toml(self, table, error) Read build config from toml table (no checks made at this stage) Module naming: fist, attempt boolean value first\nValue found, but not a boolean. Attempt to read a prefix string Arguments Type Intent Optional Attributes Name class( build_config_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling generic, public :: operator(==) => serializable_is_same private function srcfile_is_same(this, that) Check that two source files are equal\nAll checks passed! Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical procedure, public :: serializable_is_same => build_conf_is_same Serialization interface private function build_conf_is_same(this, that) Check that two dependency trees are equal\nAll checks passed! Arguments Type Intent Optional Attributes Name class( build_config_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical procedure, public, non_overridable :: test_serialization Test load/write roundtrip private subroutine test_serialization(self, message, error) Test serialization of a serializable object\nDump to scratch file\nLoad from scratch file\nCheck same Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self character(len=*), intent(in) :: message type( error_t ), intent(out), allocatable :: error Source Code type , extends ( serializable_t ) :: build_config_t !> Automatic discovery of executables logical :: auto_executables = . true . !> Automatic discovery of examples logical :: auto_examples = . true . !> Automatic discovery of tests logical :: auto_tests = . true . !> Enforcing of package module names logical :: module_naming = . false . type ( string_t ) :: module_prefix !> Libraries to link against type ( string_t ), allocatable :: link (:) !> External modules to use type ( string_t ), allocatable :: external_modules (:) contains !> Print information on this instance procedure :: info !> Serialization interface procedure :: serializable_is_same => build_conf_is_same procedure :: dump_to_toml procedure :: load_from_toml end type build_config_t","tags":"","url":"type/build_config_t.html"},{"title":"fpm_global_settings – Fortran-lang/fpm ","text":"type, public :: fpm_global_settings Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: config_file_name Name of the global config file. The default is config.toml . character(len=:), public, allocatable :: path_to_config_folder Path to the global config file excluding the file name. type(fpm_registry_settings), public, allocatable :: registry_settings Registry configs. Type-Bound Procedures procedure, public :: full_path private function full_path(self) result(result) The full path to the global config file. Arguments Type Intent Optional Attributes Name class( fpm_global_settings ), intent(in) :: self Return Value character(len=:), allocatable procedure, public :: has_custom_location private elemental function has_custom_location(self) True if the global config file is not at the default location. Arguments Type Intent Optional Attributes Name class( fpm_global_settings ), intent(in) :: self Return Value logical procedure, public :: path_to_config_folder_or_empty private pure function path_to_config_folder_or_empty(self) The path to the global config directory. Arguments Type Intent Optional Attributes Name class( fpm_global_settings ), intent(in) :: self Return Value character(len=:), allocatable","tags":"","url":"type/fpm_global_settings.html"},{"title":"dependency_node_t – Fortran-lang/fpm ","text":"type, public, extends( dependency_config_t ) :: dependency_node_t Dependency node in the projects dependency tree Components Type Visibility Attributes Name Initial logical, public :: cached = .false. Dependency was loaded from a cache logical, public :: done = .false. Dependency is handled type( git_target_t ), public, allocatable :: git Git descriptor character(len=:), public, allocatable :: name Name of the dependency character(len=:), public, allocatable :: namespace Namespace which the dependency belongs to.\nEnables multiple dependencies with the same name.\nRequired for dependencies that are obtained via the official registry. type( string_t ), public, allocatable :: package_dep (:) Package dependencies of this node character(len=:), public, allocatable :: path Local target type( preprocess_config_t ), public, allocatable :: preprocess (:) Requested macros for the dependency character(len=:), public, allocatable :: proj_dir Installation prefix of this dependencies type( version_t ), public, allocatable :: requested_version The requested version of the dependency.\nThe latest version is used if not specified. character(len=:), public, allocatable :: revision Checked out revision of the version control system logical, public :: update = .false. Dependency should be updated type( version_t ), public, allocatable :: version Actual version of this dependency Type-Bound Procedures procedure, public :: add_preprocess Add a preprocessor configuration private subroutine add_preprocess(dep, preprocess) Arguments Type Intent Optional Attributes Name class( dependency_config_t ), intent(inout) :: dep Instance of the dependency config type( preprocess_config_t ), intent(in) :: preprocess Instance of the preprocessor configuration generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit private subroutine srcfile_dump_to_toml(self, table, error) Dump dependency to toml table Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine dump_to_file(self, file, error, json) Write serializable object to file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine dump_to_unit(self, unit, error, json) Write serializable object to a formatted Fortran unit Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit Formatted unit type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format requested? procedure, public :: dump_to_toml => node_dump_to_toml private subroutine node_dump_to_toml(self, table, error) Dump dependency to toml table Arguments Type Intent Optional Attributes Name class( dependency_node_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling procedure, public :: get_from_registry Get dependency from the registry. private subroutine get_from_registry(self, target_dir, global_settings, error, downloader_) Get a dependency from the registry. Whether the dependency is fetched\nfrom a local, a custom remote or the official registry is determined\nby the global configuration settings. Arguments Type Intent Optional Attributes Name class( dependency_node_t ), intent(in) :: self Instance of the dependency configuration. character(len=:), intent(out), allocatable :: target_dir The target directory of the dependency. type( fpm_global_settings ), intent(in) :: global_settings Global configuration settings. type( error_t ), intent(out), allocatable :: error Error handling. class( downloader_t ), intent(in), optional :: downloader_ Downloader instance. procedure, public :: info Print information on this instance private subroutine info(self, unit, verbosity) Write information on instance Call base object info Arguments Type Intent Optional Attributes Name class( dependency_node_t ), intent(in) :: self Instance of the dependency configuration integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout generic, public :: load => load_from_toml , load_from_file, load_from_unit private subroutine srcfile_load_from_toml(self, table, error) Read dependency from toml table (no checks made at this stage) Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine load_from_file(self, file, error, json) Read dependency tree from file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine load_from_unit(self, unit, error, json) Read dependency tree from file\ninit JSON interpreter\nRead object from TOML table use default TOML parser Read object from TOML table Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format procedure, public :: load_from_toml => node_load_from_toml private subroutine node_load_from_toml(self, table, error) Read dependency from toml table (no checks made at this stage) Arguments Type Intent Optional Attributes Name class( dependency_node_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling generic, public :: operator(==) => serializable_is_same private function srcfile_is_same(this, that) Check that two source files are equal\nAll checks passed! Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical procedure, public :: register Update dependency from project manifest. private subroutine register(node, package, root, fetch, revision, error) Update dependency from project manifest Arguments Type Intent Optional Attributes Name class( dependency_node_t ), intent(inout) :: node Instance of the dependency node type( package_config_t ), intent(in) :: package Package configuration data character(len=*), intent(in) :: root Root directory of the project logical, intent(in) :: fetch Project has been fetched character(len=*), intent(in), optional :: revision Git revision of the project type( error_t ), intent(out), allocatable :: error Error handling procedure, public :: serializable_is_same => dependency_node_is_same Serialization interface private function dependency_node_is_same(this, that) Check that two dependency nodes are equal\nAll checks passed! Arguments Type Intent Optional Attributes Name class( dependency_node_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical procedure, public, non_overridable :: test_serialization Test load/write roundtrip private subroutine test_serialization(self, message, error) Test serialization of a serializable object\nDump to scratch file\nLoad from scratch file\nCheck same Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self character(len=*), intent(in) :: message type( error_t ), intent(out), allocatable :: error Source Code type , extends ( dependency_config_t ) :: dependency_node_t !> Actual version of this dependency type ( version_t ), allocatable :: version !> Installation prefix of this dependencies character ( len = :), allocatable :: proj_dir !> Checked out revision of the version control system character ( len = :), allocatable :: revision !> Dependency is handled logical :: done = . false . !> Dependency should be updated logical :: update = . false . !> Dependency was loaded from a cache logical :: cached = . false . !> Package dependencies of this node type ( string_t ), allocatable :: package_dep (:) contains !> Update dependency from project manifest. procedure :: register !> Get dependency from the registry. procedure :: get_from_registry procedure , private :: get_from_local_registry !> Print information on this instance procedure :: info !> Serialization interface procedure :: serializable_is_same => dependency_node_is_same procedure :: dump_to_toml => node_dump_to_toml procedure :: load_from_toml => node_load_from_toml end type dependency_node_t","tags":"","url":"type/dependency_node_t.html"},{"title":"dependency_tree_t – Fortran-lang/fpm ","text":"type, public, extends( serializable_t ) :: dependency_tree_t Respresentation of a projects dependencies The dependencies are stored in a simple array for now, this can be replaced\nwith a binary-search tree or a hash table in the future. Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: cache Cache file type( dependency_node_t ), public, allocatable :: dep (:) Flattend list of all dependencies character(len=:), public, allocatable :: dep_dir Installation prefix for dependencies integer, public :: ndep = 0 Number of currently registered dependencies character(len=:), public, allocatable :: path_to_config Custom path to the global config file integer, public :: unit = output_unit Unit for IO integer, public :: verbosity = 1 Verbosity of printout Type-Bound Procedures generic, public :: add => add_project, add_project_dependencies, add_dependencies, add_dependency, add_dependency_node Overload procedure to add new dependencies to the tree private subroutine add_project(self, package, error) Add project dependencies, each depth level after each other. We implement this algorithm in an interative rather than a recursive fashion\nas a choice of design. Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(inout) :: self Instance of the dependency tree type( package_config_t ), intent(in) :: package Project configuration to add type( error_t ), intent(out), allocatable :: error Error handling private recursive subroutine add_project_dependencies(self, package, root, main, error) Add a project and its dependencies to the dependency tree\nEnsure allocation fits Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(inout) :: self Instance of the dependency tree type( package_config_t ), intent(in) :: package Project configuration to add character(len=*), intent(in) :: root Current project root directory logical, intent(in) :: main Is the main project type( error_t ), intent(out), allocatable :: error Error handling private subroutine add_dependencies(self, dependency, error) Add a list of dependencies to the dependency tree\nEnsure allocation fits ndep Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(inout) :: self Instance of the dependency tree type( dependency_config_t ), intent(in) :: dependency (:) Dependency configuration to add type( error_t ), intent(out), allocatable :: error Error handling private subroutine add_dependency(self, dependency, error) Add a single dependency to the dependency tree Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(inout) :: self Instance of the dependency tree type( dependency_config_t ), intent(in) :: dependency Dependency configuration to add type( error_t ), intent(out), allocatable :: error Error handling private subroutine add_dependency_node(self, dependency, error) Add a single dependency node to the dependency tree\nDependency nodes contain additional information (version, git, revision)\nSafety: reallocate if necessary Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(inout) :: self Instance of the dependency tree type( dependency_node_t ), intent(in) :: dependency Dependency configuration to add type( error_t ), intent(out), allocatable :: error Error handling generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit private subroutine srcfile_dump_to_toml(self, table, error) Dump dependency to toml table Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine dump_to_file(self, file, error, json) Write serializable object to file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine dump_to_unit(self, unit, error, json) Write serializable object to a formatted Fortran unit Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit Formatted unit type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format requested? generic, public :: dump_cache => dump_cache_to_file, dump_cache_to_unit, dump_cache_to_toml Writing of dependency tree private subroutine dump_cache_to_file(self, file, error) Write dependency tree to file Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling private subroutine dump_cache_to_unit(self, unit, error) Write dependency tree to file Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit Formatted unit type( error_t ), intent(out), allocatable :: error Error handling private subroutine dump_cache_to_toml(self, table, error) Write dependency tree to TOML datastructure Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(inout) :: self Instance of the dependency tree type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling procedure, public :: dump_to_toml => tree_dump_to_toml private subroutine tree_dump_to_toml(self, table, error) Dump dependency to toml table Because dependencies are named, fallback if this has no name\nSo, serialization will work regardless of size(self%dep) == self%ndep Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling generic, public :: find => find_name Find a dependency in the tree private pure function find_name(self, name) result(pos) Find a dependency in the dependency tree Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(in) :: self Instance of the dependency tree character(len=*), intent(in) :: name Dependency configuration to add Return Value integer Index of the dependency procedure, public :: finished Depedendncy resolution finished private pure function finished(self) Check if we are done with the dependency resolution Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(in) :: self Instance of the dependency tree Return Value logical All dependencies are updated generic, public :: has => has_dependency True if entity can be found private pure function has_dependency(self, dependency) True if dependency is part of the tree Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(in) :: self Instance of the dependency tree class( dependency_node_t ), intent(in) :: dependency Dependency configuration to check Return Value logical generic, public :: load => load_from_toml , load_from_file, load_from_unit private subroutine srcfile_load_from_toml(self, table, error) Read dependency from toml table (no checks made at this stage) Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine load_from_file(self, file, error, json) Read dependency tree from file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine load_from_unit(self, unit, error, json) Read dependency tree from file\ninit JSON interpreter\nRead object from TOML table use default TOML parser Read object from TOML table Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format generic, public :: load_cache => load_cache_from_file, load_cache_from_unit, load_cache_from_toml Reading of dependency tree private subroutine load_cache_from_file(self, file, error) Read dependency tree from file Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling private subroutine load_cache_from_unit(self, unit, error) Read dependency tree from file Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit File name type( error_t ), intent(out), allocatable :: error Error handling private subroutine load_cache_from_toml(self, table, error) Read dependency tree from TOML data structure Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(inout) :: self Instance of the dependency tree type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling procedure, public :: load_from_toml => tree_load_from_toml private subroutine tree_load_from_toml(self, table, error) Read dependency from toml table (no checks made at this stage) Read all dependencies Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling procedure, public :: local_link_order Establish local link order for a node’s package dependencies private subroutine local_link_order(tree, root_id, order, error) Build a correct topological link order for a given dependency node. This routine returns the list of dependencies required to build root_id ,\nsorted such that each dependency appears before any node that depends on it.\nThis is suitable for correct linker ordering: -lA -lB means B can use symbols from A. The returned list includes both the transitive dependencies and the node itself.\nExample: if node 3 requires [5, 7, 9, 2] and 9 also requires 2,\nthen the result will ensure that 2 appears before 9, etc.\nDepth-First Search from root node\nThe final link order is the reverse of the DFS post-order Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(in) :: tree The full dependency graph integer, intent(in) :: root_id Index of the node for which to compute link order (e.g., the target being linked) integer, intent(out), allocatable :: order (:) Ordered list of dependency indices (subset of tree%dep(:)) in link-safe order type( error_t ), intent(out), allocatable :: error Optional fatal error if a cycle is detected (not expected) generic, public :: operator(==) => serializable_is_same private function srcfile_is_same(this, that) Check that two source files are equal\nAll checks passed! Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical generic, public :: resolve => resolve_dependencies, resolve_dependency Resolve dependencies private subroutine resolve_dependencies(self, root, error) Resolve all dependencies in the tree Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: root Current installation prefix type( error_t ), intent(out), allocatable :: error Error handling private subroutine resolve_dependency(self, dependency, global_settings, root, error) Resolve a single dependency node Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(inout) :: self Instance of the dependency tree type( dependency_node_t ), intent(inout) :: dependency Dependency configuration to add type( fpm_global_settings ), intent(in) :: global_settings Global configuration settings. character(len=*), intent(in) :: root Current installation prefix type( error_t ), intent(out), allocatable :: error Error handling procedure, public :: serializable_is_same => dependency_tree_is_same Serialization interface private function dependency_tree_is_same(this, that) Check that two dependency trees are equal\nAll checks passed! Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical procedure, public, non_overridable :: test_serialization Test load/write roundtrip private subroutine test_serialization(self, message, error) Test serialization of a serializable object\nDump to scratch file\nLoad from scratch file\nCheck same Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self character(len=*), intent(in) :: message type( error_t ), intent(out), allocatable :: error generic, public :: update => update_dependency, update_tree Update dependency tree private subroutine update_dependency(self, name, error) Update dependency tree Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: name Name of the dependency to update type( error_t ), intent(out), allocatable :: error Error handling private subroutine update_tree(self, error) Update whole dependency tree Arguments Type Intent Optional Attributes Name class( dependency_tree_t ), intent(inout) :: self Instance of the dependency tree type( error_t ), intent(out), allocatable :: error Error handling Source Code type , extends ( serializable_t ) :: dependency_tree_t !> Unit for IO integer :: unit = output_unit !> Verbosity of printout integer :: verbosity = 1 !> Installation prefix for dependencies character ( len = :), allocatable :: dep_dir !> Number of currently registered dependencies integer :: ndep = 0 !> Flattend list of all dependencies type ( dependency_node_t ), allocatable :: dep (:) !> Cache file character ( len = :), allocatable :: cache !> Custom path to the global config file character ( len = :), allocatable :: path_to_config contains !> Overload procedure to add new dependencies to the tree generic :: add => add_project , add_project_dependencies , add_dependencies , & add_dependency , add_dependency_node !> Main entry point to add a project procedure , private :: add_project !> Add a project and its dependencies to the dependency tree procedure , private :: add_project_dependencies !> Add a list of dependencies to the dependency tree procedure , private :: add_dependencies !> Add a single dependency to the dependency tree procedure , private :: add_dependency !> Add a single dependency node to the dependency tree procedure , private :: add_dependency_node !> Resolve dependencies generic :: resolve => resolve_dependencies , resolve_dependency !> Resolve dependencies procedure , private :: resolve_dependencies !> Resolve dependency procedure , private :: resolve_dependency !> True if entity can be found generic :: has => has_dependency !> True if dependency is part of the tree procedure , private :: has_dependency !> Find a dependency in the tree generic :: find => find_name !> Find a dependency by its name procedure , private :: find_name !> Establish local link order for a node's package dependencies procedure :: local_link_order !> Depedendncy resolution finished procedure :: finished !> Reading of dependency tree generic :: load_cache => load_cache_from_file , load_cache_from_unit , load_cache_from_toml !> Read dependency tree from file procedure , private :: load_cache_from_file !> Read dependency tree from formatted unit procedure , private :: load_cache_from_unit !> Read dependency tree from TOML data structure procedure , private :: load_cache_from_toml !> Writing of dependency tree generic :: dump_cache => dump_cache_to_file , dump_cache_to_unit , dump_cache_to_toml !> Write dependency tree to file procedure , private :: dump_cache_to_file !> Write dependency tree to formatted unit procedure , private :: dump_cache_to_unit !> Write dependency tree to TOML data structure procedure , private :: dump_cache_to_toml !> Update dependency tree generic :: update => update_dependency , update_tree !> Update a list of dependencies procedure , private :: update_dependency !> Update all dependencies in the tree procedure , private :: update_tree !> Serialization interface procedure :: serializable_is_same => dependency_tree_is_same procedure :: dump_to_toml => tree_dump_to_toml procedure :: load_from_toml => tree_load_from_toml end type dependency_tree_t","tags":"","url":"type/dependency_tree_t.html"},{"title":"enum_descriptor – Fortran-lang/fpm ","text":"type, public :: enum_descriptor Possible git target Components Type Visibility Attributes Name Initial integer, public :: branch = 201 Branch in git repository integer, public :: default = 200 Default target integer, public :: error = -999 Invalid descriptor integer, public :: revision = 203 Commit hash integer, public :: tag = 202 Tag in git repository Source Code type :: enum_descriptor !> Default target integer :: default = 200 !> Branch in git repository integer :: branch = 201 !> Tag in git repository integer :: tag = 202 !> Commit hash integer :: revision = 203 !> Invalid descriptor integer :: error = - 999 end type enum_descriptor","tags":"","url":"type/enum_descriptor.html"},{"title":"git_target_t – Fortran-lang/fpm ","text":"type, public, extends( serializable_t ) :: git_target_t Description of an git target Components Type Visibility Attributes Name Initial integer, public :: descriptor = git_descriptor%default Kind of the git target character(len=:), public, allocatable :: object Additional descriptor of the git object character(len=:), public, allocatable :: url Target URL of the git repository Type-Bound Procedures procedure, public :: checkout Fetch and checkout in local directory public subroutine checkout (self, local_path, error) Arguments Type Intent Optional Attributes Name class( git_target_t ), intent(in) :: self Instance of the git target character(len=*), intent(in) :: local_path Local path to checkout in type( error_t ), intent(out), allocatable :: error Error generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit private subroutine srcfile_dump_to_toml(self, table, error) Dump dependency to toml table Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine dump_to_file(self, file, error, json) Write serializable object to file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine dump_to_unit(self, unit, error, json) Write serializable object to a formatted Fortran unit Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit Formatted unit type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format requested? procedure, public :: dump_to_toml public subroutine dump_to_toml (self, table, error) Dump dependency to toml table Arguments Type Intent Optional Attributes Name class( git_target_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling procedure, public :: info Show information on instance public subroutine info (self, unit, verbosity) Show information on git target Arguments Type Intent Optional Attributes Name class( git_target_t ), intent(in) :: self Instance of the git target integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout generic, public :: load => load_from_toml , load_from_file, load_from_unit private subroutine srcfile_load_from_toml(self, table, error) Read dependency from toml table (no checks made at this stage) Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine load_from_file(self, file, error, json) Read dependency tree from file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine load_from_unit(self, unit, error, json) Read dependency tree from file\ninit JSON interpreter\nRead object from TOML table use default TOML parser Read object from TOML table Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format procedure, public :: load_from_toml public subroutine load_from_toml (self, table, error) Read dependency from toml table (no checks made at this stage) Read more… Arguments Type Intent Optional Attributes Name class( git_target_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling generic, public :: operator(==) => serializable_is_same private function srcfile_is_same(this, that) Check that two source files are equal\nAll checks passed! Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical procedure, public :: serializable_is_same => git_is_same Serialization interface public function git_is_same (this, that) Check that two git targets are equal\nAll checks passed! Arguments Type Intent Optional Attributes Name class( git_target_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical procedure, public, non_overridable :: test_serialization Test load/write roundtrip private subroutine test_serialization(self, message, error) Test serialization of a serializable object\nDump to scratch file\nLoad from scratch file\nCheck same Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self character(len=*), intent(in) :: message type( error_t ), intent(out), allocatable :: error Source Code type , extends ( serializable_t ) :: git_target_t !> Kind of the git target integer :: descriptor = git_descriptor % default !> Target URL of the git repository character ( len = :), allocatable :: url !> Additional descriptor of the git object character ( len = :), allocatable :: object contains !> Fetch and checkout in local directory procedure :: checkout !> Show information on instance procedure :: info !> Serialization interface procedure :: serializable_is_same => git_is_same procedure :: dump_to_toml procedure :: load_from_toml end type git_target_t","tags":"","url":"type/git_target_t.html"},{"title":"metapackage_config_t – Fortran-lang/fpm ","text":"type, public :: metapackage_config_t Configuration data for metapackages Components Type Visibility Attributes Name Initial type( metapackage_request_t ), public :: blas BLAS type( metapackage_request_t ), public :: hdf5 HDF5 type( metapackage_request_t ), public :: minpack fortran-lang minpack type( metapackage_request_t ), public :: mpi Request MPI support type( metapackage_request_t ), public :: netcdf NetCDF type( metapackage_request_t ), public :: openmp Request OpenMP support type( metapackage_request_t ), public :: stdlib Request stdlib support Type-Bound Procedures procedure, public :: get_requests private function get_requests(meta) result(requests) Return a list of metapackages requested for the current build Count requests\nPrepare requests Arguments Type Intent Optional Attributes Name class( metapackage_config_t ), intent(in) :: meta Instance of the build configuration Return Value type( metapackage_request_t ), allocatable, (:) The list of requested metapackages (always allocated) Source Code type :: metapackage_config_t !> Request MPI support type ( metapackage_request_t ) :: mpi !> Request OpenMP support type ( metapackage_request_t ) :: openmp !> Request stdlib support type ( metapackage_request_t ) :: stdlib !> fortran-lang minpack type ( metapackage_request_t ) :: minpack !> HDF5 type ( metapackage_request_t ) :: hdf5 !> NetCDF type ( metapackage_request_t ) :: netcdf !> BLAS type ( metapackage_request_t ) :: blas contains procedure :: get_requests end type metapackage_config_t","tags":"","url":"type/metapackage_config_t.html"},{"title":"metapackage_request_t – Fortran-lang/fpm ","text":"type, public :: metapackage_request_t Configuration data for a single metapackage request Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: name Metapackage name logical, public :: on = .false. Request flag character(len=:), public, allocatable :: version Version Specification string Source Code type :: metapackage_request_t !> Request flag logical :: on = . false . !> Metapackage name character ( len = :), allocatable :: name !> Version Specification string character ( len = :), allocatable :: version end type metapackage_request_t","tags":"","url":"type/metapackage_request_t.html"},{"title":"fortran_config_t – Fortran-lang/fpm ","text":"type, public, extends( serializable_t ) :: fortran_config_t Configuration data for Fortran Components Type Visibility Attributes Name Initial logical, public :: implicit_external = .false. Enable implicit external interfaces logical, public :: implicit_typing = .false. Enable default implicit typing character(len=:), public, allocatable :: source_form Form to use for all Fortran sources Type-Bound Procedures generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit private subroutine srcfile_dump_to_toml(self, table, error) Dump dependency to toml table Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine dump_to_file(self, file, error, json) Write serializable object to file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine dump_to_unit(self, unit, error, json) Write serializable object to a formatted Fortran unit Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit Formatted unit type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format requested? procedure, public :: dump_to_toml private subroutine dump_to_toml(self, table, error) Dump install config to toml table Arguments Type Intent Optional Attributes Name class( fortran_config_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling generic, public :: load => load_from_toml , load_from_file, load_from_unit private subroutine srcfile_load_from_toml(self, table, error) Read dependency from toml table (no checks made at this stage) Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine load_from_file(self, file, error, json) Read dependency tree from file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine load_from_unit(self, unit, error, json) Read dependency tree from file\ninit JSON interpreter\nRead object from TOML table use default TOML parser Read object from TOML table Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format procedure, public :: load_from_toml private subroutine load_from_toml(self, table, error) Read install config from toml table (no checks made at this stage) Arguments Type Intent Optional Attributes Name class( fortran_config_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling generic, public :: operator(==) => serializable_is_same private function srcfile_is_same(this, that) Check that two source files are equal\nAll checks passed! Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical procedure, public :: serializable_is_same => fortran_is_same Serialization interface private function fortran_is_same(this, that) All checks passed! Arguments Type Intent Optional Attributes Name class( fortran_config_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical procedure, public, non_overridable :: test_serialization Test load/write roundtrip private subroutine test_serialization(self, message, error) Test serialization of a serializable object\nDump to scratch file\nLoad from scratch file\nCheck same Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self character(len=*), intent(in) :: message type( error_t ), intent(out), allocatable :: error Source Code type , extends ( serializable_t ) :: fortran_config_t !> Enable default implicit typing logical :: implicit_typing = . false . !> Enable implicit external interfaces logical :: implicit_external = . false . !> Form to use for all Fortran sources character (:), allocatable :: source_form contains !> Serialization interface procedure :: serializable_is_same => fortran_is_same procedure :: dump_to_toml procedure :: load_from_toml end type fortran_config_t","tags":"","url":"type/fortran_config_t.html"},{"title":"test_config_t – Fortran-lang/fpm ","text":"type, public, extends( executable_config_t ) :: test_config_t Configuation meta data for an test Components Type Visibility Attributes Name Initial type( dependency_config_t ), public, allocatable :: dependency (:) Dependency meta data for this executable type( string_t ), public, allocatable :: link (:) Libraries to link against character(len=:), public, allocatable :: main Name of the source file declaring the main program character(len=:), public, allocatable :: name Name of the resulting executable character(len=:), public, allocatable :: source_dir Source directory for collecting the executable Type-Bound Procedures generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit private subroutine srcfile_dump_to_toml(self, table, error) Dump dependency to toml table Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine dump_to_file(self, file, error, json) Write serializable object to file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine dump_to_unit(self, unit, error, json) Write serializable object to a formatted Fortran unit Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit Formatted unit type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format requested? procedure, public :: dump_to_toml private subroutine dump_to_toml(self, table, error) Dump install config to toml table Because dependencies are named, fallback if this has no name\nSo, serialization will work regardless of size(self%dep) == self%ndep Arguments Type Intent Optional Attributes Name class( executable_config_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling procedure, public :: info Print information on this instance private subroutine info(self, unit, verbosity) Write information on instance Arguments Type Intent Optional Attributes Name class( test_config_t ), intent(in) :: self Instance of the test configuration integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout generic, public :: load => load_from_toml , load_from_file, load_from_unit private subroutine srcfile_load_from_toml(self, table, error) Read dependency from toml table (no checks made at this stage) Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine load_from_file(self, file, error, json) Read dependency tree from file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine load_from_unit(self, unit, error, json) Read dependency tree from file\ninit JSON interpreter\nRead object from TOML table use default TOML parser Read object from TOML table Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format procedure, public :: load_from_toml private subroutine load_from_toml(self, table, error) Read install config from toml table (no checks made at this stage) Read all dependencies Arguments Type Intent Optional Attributes Name class( executable_config_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling generic, public :: operator(==) => serializable_is_same private function srcfile_is_same(this, that) Check that two source files are equal\nAll checks passed! Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical procedure, public :: serializable_is_same => exe_is_same Serialization interface private function exe_is_same(this, that) All checks passed! Arguments Type Intent Optional Attributes Name class( executable_config_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical procedure, public, non_overridable :: test_serialization Test load/write roundtrip private subroutine test_serialization(self, message, error) Test serialization of a serializable object\nDump to scratch file\nLoad from scratch file\nCheck same Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self character(len=*), intent(in) :: message type( error_t ), intent(out), allocatable :: error Source Code type , extends ( executable_config_t ) :: test_config_t contains !> Print information on this instance procedure :: info end type test_config_t","tags":"","url":"type/test_config_t.html"},{"title":"install_config_t – Fortran-lang/fpm ","text":"type, public, extends( serializable_t ) :: install_config_t Configuration data for installation Components Type Visibility Attributes Name Initial logical, public :: library = .false. Install library with this project logical, public :: test = .false. Install tests with this project Type-Bound Procedures generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit private subroutine srcfile_dump_to_toml(self, table, error) Dump dependency to toml table Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine dump_to_file(self, file, error, json) Write serializable object to file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine dump_to_unit(self, unit, error, json) Write serializable object to a formatted Fortran unit Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit Formatted unit type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format requested? procedure, public :: dump_to_toml private subroutine dump_to_toml(self, table, error) Dump install config to toml table Arguments Type Intent Optional Attributes Name class( install_config_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling procedure, public :: info Print information on this instance private subroutine info(self, unit, verbosity) Write information on install configuration instance Arguments Type Intent Optional Attributes Name class( install_config_t ), intent(in) :: self Instance of the build configuration integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout generic, public :: load => load_from_toml , load_from_file, load_from_unit private subroutine srcfile_load_from_toml(self, table, error) Read dependency from toml table (no checks made at this stage) Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine load_from_file(self, file, error, json) Read dependency tree from file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine load_from_unit(self, unit, error, json) Read dependency tree from file\ninit JSON interpreter\nRead object from TOML table use default TOML parser Read object from TOML table Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format procedure, public :: load_from_toml private subroutine load_from_toml(self, table, error) Read install config from toml table (no checks made at this stage) Arguments Type Intent Optional Attributes Name class( install_config_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling generic, public :: operator(==) => serializable_is_same private function srcfile_is_same(this, that) Check that two source files are equal\nAll checks passed! Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical procedure, public :: serializable_is_same => install_conf_same Serialization interface private function install_conf_same(this, that) All checks passed! Arguments Type Intent Optional Attributes Name class( install_config_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical procedure, public, non_overridable :: test_serialization Test load/write roundtrip private subroutine test_serialization(self, message, error) Test serialization of a serializable object\nDump to scratch file\nLoad from scratch file\nCheck same Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self character(len=*), intent(in) :: message type( error_t ), intent(out), allocatable :: error Source Code type , extends ( serializable_t ) :: install_config_t !> Install library with this project logical :: library = . false . !> Install tests with this project logical :: test = . false . contains !> Print information on this instance procedure :: info !> Serialization interface procedure :: serializable_is_same => install_conf_same procedure :: dump_to_toml procedure :: load_from_toml end type install_config_t","tags":"","url":"type/install_config_t.html"},{"title":"fpm_build_settings – Fortran-lang/fpm ","text":"type, public, extends( fpm_cmd_settings ) :: fpm_build_settings Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: archiver logical, public :: build_tests = .false. character(len=:), public, allocatable :: c_compiler character(len=:), public, allocatable :: cflag character(len=:), public, allocatable :: compiler character(len=:), public, allocatable :: cxx_compiler character(len=:), public, allocatable :: cxxflag character(len=:), public, allocatable :: dump character(len=:), public, allocatable :: flag character(len=:), public, allocatable :: ldflag logical, public :: list = .false. character(len=:), public, allocatable :: path_to_config character(len=:), public, allocatable :: profile logical, public :: prune = .true. logical, public :: show_model = .false. logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir","tags":"","url":"type/fpm_build_settings.html"},{"title":"fpm_clean_settings – Fortran-lang/fpm ","text":"type, public, extends( fpm_cmd_settings ) :: fpm_clean_settings Components Type Visibility Attributes Name Initial logical, public :: clean_all = .false. logical, public :: clean_skip = .false. character(len=:), public, allocatable :: path_to_config logical, public :: registry_cache = .false. logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir","tags":"","url":"type/fpm_clean_settings.html"},{"title":"fpm_cmd_settings – Fortran-lang/fpm ","text":"type, public, abstract :: fpm_cmd_settings Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: path_to_config logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir","tags":"","url":"type/fpm_cmd_settings.html"},{"title":"fpm_export_settings – Fortran-lang/fpm ","text":"type, public, extends( fpm_build_settings ) :: fpm_export_settings Settings for exporting model data Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: archiver logical, public :: build_tests = .false. character(len=:), public, allocatable :: c_compiler character(len=:), public, allocatable :: cflag character(len=:), public, allocatable :: compiler character(len=:), public, allocatable :: cxx_compiler character(len=:), public, allocatable :: cxxflag character(len=:), public, allocatable :: dump character(len=:), public, allocatable :: dump_dependencies character(len=:), public, allocatable :: dump_manifest character(len=:), public, allocatable :: dump_model character(len=:), public, allocatable :: flag character(len=:), public, allocatable :: ldflag logical, public :: list = .false. character(len=:), public, allocatable :: path_to_config character(len=:), public, allocatable :: profile logical, public :: prune = .true. logical, public :: show_model = .false. logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir","tags":"","url":"type/fpm_export_settings.html"},{"title":"fpm_install_settings – Fortran-lang/fpm ","text":"type, public, extends( fpm_build_settings ) :: fpm_install_settings Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: archiver character(len=:), public, allocatable :: bindir logical, public :: build_tests = .false. character(len=:), public, allocatable :: c_compiler character(len=:), public, allocatable :: cflag character(len=:), public, allocatable :: compiler character(len=:), public, allocatable :: cxx_compiler character(len=:), public, allocatable :: cxxflag character(len=:), public, allocatable :: dump character(len=:), public, allocatable :: flag character(len=:), public, allocatable :: includedir character(len=:), public, allocatable :: ldflag character(len=:), public, allocatable :: libdir logical, public :: list = .false. logical, public :: no_rebuild character(len=:), public, allocatable :: path_to_config character(len=:), public, allocatable :: prefix character(len=:), public, allocatable :: profile logical, public :: prune = .true. logical, public :: show_model = .false. character(len=:), public, allocatable :: testdir logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir","tags":"","url":"type/fpm_install_settings.html"},{"title":"fpm_new_settings – Fortran-lang/fpm ","text":"type, public, extends( fpm_cmd_settings ) :: fpm_new_settings Components Type Visibility Attributes Name Initial logical, public :: backfill = .true. character(len=:), public, allocatable :: name character(len=:), public, allocatable :: path_to_config logical, public :: verbose = .true. logical, public :: with_bare = .false. logical, public :: with_example = .false. logical, public :: with_executable = .false. logical, public :: with_full = .false. logical, public :: with_lib = .true. logical, public :: with_test = .false. character(len=:), public, allocatable :: working_dir","tags":"","url":"type/fpm_new_settings.html"},{"title":"fpm_publish_settings – Fortran-lang/fpm ","text":"type, public, extends( fpm_build_settings ) :: fpm_publish_settings Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: archiver logical, public :: build_tests = .false. character(len=:), public, allocatable :: c_compiler character(len=:), public, allocatable :: cflag character(len=:), public, allocatable :: compiler character(len=:), public, allocatable :: cxx_compiler character(len=:), public, allocatable :: cxxflag character(len=:), public, allocatable :: dump character(len=:), public, allocatable :: flag logical, public :: is_dry_run = .false. character(len=:), public, allocatable :: ldflag logical, public :: list = .false. character(len=:), public, allocatable :: path_to_config character(len=:), public, allocatable :: profile logical, public :: prune = .true. logical, public :: show_model = .false. logical, public :: show_package_version = .false. logical, public :: show_upload_data = .false. character(len=:), public, allocatable :: token logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir","tags":"","url":"type/fpm_publish_settings.html"},{"title":"fpm_run_settings – Fortran-lang/fpm ","text":"type, public, extends( fpm_build_settings ) :: fpm_run_settings Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: archiver character(len=:), public, allocatable :: args logical, public :: build_tests = .false. character(len=:), public, allocatable :: c_compiler character(len=:), public, allocatable :: cflag character(len=:), public, allocatable :: compiler character(len=:), public, allocatable :: cxx_compiler character(len=:), public, allocatable :: cxxflag character(len=:), public, allocatable :: dump logical, public :: example character(len=:), public, allocatable :: flag character(len=:), public, allocatable :: ldflag logical, public :: list = .false. character(len=ibug), public, allocatable :: name (:) character(len=:), public, allocatable :: path_to_config character(len=:), public, allocatable :: profile logical, public :: prune = .true. character(len=:), public, allocatable :: runner character(len=:), public, allocatable :: runner_args logical, public :: show_model = .false. logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir Type-Bound Procedures procedure, public :: name_ID private function name_ID(cmd, name) Check name in list ID. return 0 if not found\nDefault: not found Arguments Type Intent Optional Attributes Name class( fpm_run_settings ), intent(in) :: cmd character(len=*), intent(in) :: name Return Value integer procedure, public :: runner_command private function runner_command(cmd) result(run_cmd) Build a full runner command (executable + command-line arguments)\nGet executable\nAppend command-line arguments Arguments Type Intent Optional Attributes Name class( fpm_run_settings ), intent(in) :: cmd Return Value character(len=:), allocatable","tags":"","url":"type/fpm_run_settings.html"},{"title":"fpm_test_settings – Fortran-lang/fpm ","text":"type, public, extends( fpm_run_settings ) :: fpm_test_settings Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: archiver character(len=:), public, allocatable :: args logical, public :: build_tests = .false. character(len=:), public, allocatable :: c_compiler character(len=:), public, allocatable :: cflag character(len=:), public, allocatable :: compiler character(len=:), public, allocatable :: cxx_compiler character(len=:), public, allocatable :: cxxflag character(len=:), public, allocatable :: dump logical, public :: example character(len=:), public, allocatable :: flag character(len=:), public, allocatable :: ldflag logical, public :: list = .false. character(len=ibug), public, allocatable :: name (:) character(len=:), public, allocatable :: path_to_config character(len=:), public, allocatable :: profile logical, public :: prune = .true. character(len=:), public, allocatable :: runner character(len=:), public, allocatable :: runner_args logical, public :: show_model = .false. logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir Type-Bound Procedures procedure, public :: name_ID private function name_ID(cmd, name) Check name in list ID. return 0 if not found\nDefault: not found Arguments Type Intent Optional Attributes Name class( fpm_run_settings ), intent(in) :: cmd character(len=*), intent(in) :: name Return Value integer procedure, public :: runner_command private function runner_command(cmd) result(run_cmd) Build a full runner command (executable + command-line arguments)\nGet executable\nAppend command-line arguments Arguments Type Intent Optional Attributes Name class( fpm_run_settings ), intent(in) :: cmd Return Value character(len=:), allocatable","tags":"","url":"type/fpm_test_settings.html"},{"title":"fpm_update_settings – Fortran-lang/fpm ","text":"type, public, extends( fpm_cmd_settings ) :: fpm_update_settings Settings for interacting and updating with project dependencies Components Type Visibility Attributes Name Initial logical, public :: clean character(len=:), public, allocatable :: dump logical, public :: fetch_only character(len=ibug), public, allocatable :: name (:) character(len=:), public, allocatable :: path_to_config logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir","tags":"","url":"type/fpm_update_settings.html"},{"title":"serializable_t – Fortran-lang/fpm ","text":"type, public, abstract :: serializable_t An abstract interface for any fpm class that should be fully serializable to/from TOML/JSON Type-Bound Procedures generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit private subroutine srcfile_dump_to_toml(self, table, error) Dump dependency to toml table Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine dump_to_file(self, file, error, json) Write serializable object to file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine dump_to_unit(self, unit, error, json) Write serializable object to a formatted Fortran unit Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit Formatted unit type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format requested? procedure(to_toml), public, deferred :: dump_to_toml Dump to TOML table, unit, file subroutine to_toml(self, table, error) Prototype Write object to TOML datastructure Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling generic, public :: load => load_from_toml , load_from_file, load_from_unit private subroutine srcfile_load_from_toml(self, table, error) Read dependency from toml table (no checks made at this stage) Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine load_from_file(self, file, error, json) Read dependency tree from file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine load_from_unit(self, unit, error, json) Read dependency tree from file\ninit JSON interpreter\nRead object from TOML table use default TOML parser Read object from TOML table Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format procedure(from_toml), public, deferred :: load_from_toml Load from TOML table, unit, file subroutine from_toml(self, table, error) Prototype Read dependency tree from TOML data structure Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling generic, public :: operator(==) => serializable_is_same private function srcfile_is_same(this, that) Check that two source files are equal\nAll checks passed! Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical procedure(is_equal), public, deferred :: serializable_is_same Serializable entities need a way to check that they’re equal function is_equal(this, that) Prototype Compare two serializable objects Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical procedure, public, non_overridable :: test_serialization Test load/write roundtrip private subroutine test_serialization(self, message, error) Test serialization of a serializable object\nDump to scratch file\nLoad from scratch file\nCheck same Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self character(len=*), intent(in) :: message type( error_t ), intent(out), allocatable :: error Source Code type , abstract , public :: serializable_t contains !> Dump to TOML table, unit, file procedure ( to_toml ), deferred :: dump_to_toml procedure , non_overridable , private :: dump_to_file procedure , non_overridable , private :: dump_to_unit generic :: dump => dump_to_toml , dump_to_file , dump_to_unit !> Load from TOML table, unit, file procedure ( from_toml ), deferred :: load_from_toml procedure , non_overridable , private :: load_from_file procedure , non_overridable , private :: load_from_unit generic :: load => load_from_toml , load_from_file , load_from_unit !> Serializable entities need a way to check that they're equal procedure ( is_equal ), deferred :: serializable_is_same generic :: operator ( == ) => serializable_is_same !> Test load/write roundtrip procedure , non_overridable :: test_serialization end type serializable_t","tags":"","url":"type/serializable_t.html"},{"title":"dependency_config_t – Fortran-lang/fpm ","text":"type, public, extends( serializable_t ) :: dependency_config_t Configuration meta data for a dependency Components Type Visibility Attributes Name Initial type( git_target_t ), public, allocatable :: git Git descriptor character(len=:), public, allocatable :: name Name of the dependency character(len=:), public, allocatable :: namespace Namespace which the dependency belongs to.\nEnables multiple dependencies with the same name.\nRequired for dependencies that are obtained via the official registry. character(len=:), public, allocatable :: path Local target type( preprocess_config_t ), public, allocatable :: preprocess (:) Requested macros for the dependency type( version_t ), public, allocatable :: requested_version The requested version of the dependency.\nThe latest version is used if not specified. Type-Bound Procedures procedure, public :: add_preprocess Add a preprocessor configuration private subroutine add_preprocess(dep, preprocess) Arguments Type Intent Optional Attributes Name class( dependency_config_t ), intent(inout) :: dep Instance of the dependency config type( preprocess_config_t ), intent(in) :: preprocess Instance of the preprocessor configuration generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit private subroutine srcfile_dump_to_toml(self, table, error) Dump dependency to toml table Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine dump_to_file(self, file, error, json) Write serializable object to file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine dump_to_unit(self, unit, error, json) Write serializable object to a formatted Fortran unit Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit Formatted unit type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format requested? procedure, public :: dump_to_toml private subroutine dump_to_toml(self, table, error) Dump dependency to toml table Arguments Type Intent Optional Attributes Name class( dependency_config_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error procedure, public :: info Print information on this instance private subroutine info(self, unit, verbosity) Write information on instance Arguments Type Intent Optional Attributes Name class( dependency_config_t ), intent(in) :: self Instance of the dependency configuration integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout generic, public :: load => load_from_toml , load_from_file, load_from_unit private subroutine srcfile_load_from_toml(self, table, error) Read dependency from toml table (no checks made at this stage) Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine load_from_file(self, file, error, json) Read dependency tree from file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine load_from_unit(self, unit, error, json) Read dependency tree from file\ninit JSON interpreter\nRead object from TOML table use default TOML parser Read object from TOML table Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format procedure, public :: load_from_toml private subroutine load_from_toml(self, table, error) Read dependency from toml table (no checks made at this stage) Arguments Type Intent Optional Attributes Name class( dependency_config_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling generic, public :: operator(==) => serializable_is_same private function srcfile_is_same(this, that) Check that two source files are equal\nAll checks passed! Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical procedure, public :: serializable_is_same => dependency_is_same Serialization interface private function dependency_is_same(this, that) Check that two dependency configs are equal\nAll checks passed! Arguments Type Intent Optional Attributes Name class( dependency_config_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical procedure, public, non_overridable :: test_serialization Test load/write roundtrip private subroutine test_serialization(self, message, error) Test serialization of a serializable object\nDump to scratch file\nLoad from scratch file\nCheck same Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self character(len=*), intent(in) :: message type( error_t ), intent(out), allocatable :: error Source Code type , extends ( serializable_t ) :: dependency_config_t !> Name of the dependency character ( len = :), allocatable :: name !> Local target character ( len = :), allocatable :: path !> Namespace which the dependency belongs to. !> Enables multiple dependencies with the same name. !> Required for dependencies that are obtained via the official registry. character ( len = :), allocatable :: namespace !> The requested version of the dependency. !> The latest version is used if not specified. type ( version_t ), allocatable :: requested_version !> Requested macros for the dependency type ( preprocess_config_t ), allocatable :: preprocess (:) !> Git descriptor type ( git_target_t ), allocatable :: git contains !> Print information on this instance procedure :: info !> Add a preprocessor configuration procedure :: add_preprocess !> Serialization interface procedure :: serializable_is_same => dependency_is_same procedure :: dump_to_toml procedure :: load_from_toml end type dependency_config_t","tags":"","url":"type/dependency_config_t.html"},{"title":"installer_t – Fortran-lang/fpm ","text":"type, public :: installer_t Declaration of the installer type Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: bindir Binary dir relative to the installation prefix character(len=:), public, allocatable :: copy Command to copy objects into the installation prefix character(len=:), public, allocatable :: includedir Include directory relative to the installation prefix character(len=:), public, allocatable :: libdir Library directory relative to the installation prefix character(len=:), public, allocatable :: move Command to move objects into the installation prefix integer, public :: os Cached operating system character(len=:), public, allocatable :: prefix Path to installation directory character(len=:), public, allocatable :: testdir Test program directory relative to the installation prefix integer, public :: unit = output_unit Output unit for informative printout integer, public :: verbosity = 1 Verbosity of the installer Type-Bound Procedures procedure, public :: install Install a generic file into a subdirectory in the installation prefix private subroutine install(self, source, destination, error) Install a generic file into a subdirectory in the installation prefix Arguments Type Intent Optional Attributes Name class( installer_t ), intent(inout) :: self Instance of the installer character(len=*), intent(in) :: source Path to the original file character(len=*), intent(in) :: destination Path to the destination inside the prefix type( error_t ), intent(out), allocatable :: error Error handling procedure, public :: install_destination Evaluate the installation path private function install_destination(self, destination) result(install_dest) Evaluate the installation path Arguments Type Intent Optional Attributes Name class( installer_t ), intent(inout) :: self Instance of the installer character(len=*), intent(in) :: destination Path to the destination inside the prefix Return Value character(len=:), allocatable procedure, public :: install_executable Install an executable in its correct subdirectory private subroutine install_executable(self, executable, error) Install an executable in its correct subdirectory Arguments Type Intent Optional Attributes Name class( installer_t ), intent(inout) :: self Instance of the installer character(len=*), intent(in) :: executable Path to the executable type( error_t ), intent(out), allocatable :: error Error handling procedure, public :: install_header Install a header/module in its correct subdirectory private subroutine install_header(self, header, error) Install a header/module in its correct subdirectory Arguments Type Intent Optional Attributes Name class( installer_t ), intent(inout) :: self Instance of the installer character(len=*), intent(in) :: header Path to the header type( error_t ), intent(out), allocatable :: error Error handling procedure, public :: install_library Install a library in its correct subdirectory private subroutine install_library(self, library, error) Install a library in its correct subdirectory Arguments Type Intent Optional Attributes Name class( installer_t ), intent(inout) :: self Instance of the installer type( build_target_t ), intent(in) :: library Library target type( error_t ), intent(out), allocatable :: error Error handling procedure, public :: install_test Install a test program in its correct subdirectory private subroutine install_test(self, test, error) Install a test program in its correct subdirectory Arguments Type Intent Optional Attributes Name class( installer_t ), intent(inout) :: self Instance of the installer character(len=*), intent(in) :: test Path to the test executable type( error_t ), intent(out), allocatable :: error Error handling procedure, public :: make_dir Create a new directory in the prefix, type-bound for unit testing purposes private subroutine make_dir(self, dir, error) Create a new directory in the prefix Arguments Type Intent Optional Attributes Name class( installer_t ), intent(inout) :: self Instance of the installer character(len=*), intent(in) :: dir Directory to be created type( error_t ), intent(out), allocatable :: error Error handling procedure, public :: run Run an installation command, type-bound for unit testing purposes private subroutine run(self, command, error) Run an installation command Arguments Type Intent Optional Attributes Name class( installer_t ), intent(inout) :: self Instance of the installer character(len=*), intent(in) :: command Command to be launched type( error_t ), intent(out), allocatable :: error Error handling Source Code type :: installer_t !> Path to installation directory character ( len = :), allocatable :: prefix !> Binary dir relative to the installation prefix character ( len = :), allocatable :: bindir !> Library directory relative to the installation prefix character ( len = :), allocatable :: libdir !> Test program directory relative to the installation prefix character ( len = :), allocatable :: testdir !> Include directory relative to the installation prefix character ( len = :), allocatable :: includedir !> Output unit for informative printout integer :: unit = output_unit !> Verbosity of the installer integer :: verbosity = 1 !> Command to copy objects into the installation prefix character ( len = :), allocatable :: copy !> Command to move objects into the installation prefix character ( len = :), allocatable :: move !> Cached operating system integer :: os contains !> Evaluate the installation path procedure :: install_destination !> Install an executable in its correct subdirectory procedure :: install_executable !> Install a library in its correct subdirectory procedure :: install_library !> Install a header/module in its correct subdirectory procedure :: install_header !> Install a test program in its correct subdirectory procedure :: install_test !> Install a generic file into a subdirectory in the installation prefix procedure :: install !> Run an installation command, type-bound for unit testing purposes procedure :: run !> Create a new directory in the prefix, type-bound for unit testing purposes procedure :: make_dir end type installer_t","tags":"","url":"type/installer_t.html"},{"title":"file_scope_flag – Fortran-lang/fpm ","text":"type, public, extends( serializable_t ) :: file_scope_flag Type storing file name - file scope compiler flags pairs Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: file_name Name of the file character(len=:), public, allocatable :: flags File scope flags Type-Bound Procedures generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit private subroutine srcfile_dump_to_toml(self, table, error) Dump dependency to toml table Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine dump_to_file(self, file, error, json) Write serializable object to file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine dump_to_unit(self, unit, error, json) Write serializable object to a formatted Fortran unit Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit Formatted unit type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format requested? procedure, public :: dump_to_toml => file_scope_dump public subroutine file_scope_dump (self, table, error) Dump to toml table Arguments Type Intent Optional Attributes Name class( file_scope_flag ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling generic, public :: load => load_from_toml , load_from_file, load_from_unit private subroutine srcfile_load_from_toml(self, table, error) Read dependency from toml table (no checks made at this stage) Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine load_from_file(self, file, error, json) Read dependency tree from file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine load_from_unit(self, unit, error, json) Read dependency tree from file\ninit JSON interpreter\nRead object from TOML table use default TOML parser Read object from TOML table Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format procedure, public :: load_from_toml => file_scope_load public subroutine file_scope_load (self, table, error) Read from toml table (no checks made at this stage) Arguments Type Intent Optional Attributes Name class( file_scope_flag ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling generic, public :: operator(==) => serializable_is_same private function srcfile_is_same(this, that) Check that two source files are equal\nAll checks passed! Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical procedure, public :: serializable_is_same => file_scope_same Serialization interface public function file_scope_same (this, that) All checks passed! Arguments Type Intent Optional Attributes Name class( file_scope_flag ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical procedure, public, non_overridable :: test_serialization Test load/write roundtrip private subroutine test_serialization(self, message, error) Test serialization of a serializable object\nDump to scratch file\nLoad from scratch file\nCheck same Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self character(len=*), intent(in) :: message type( error_t ), intent(out), allocatable :: error Source Code type , extends ( serializable_t ) :: file_scope_flag !> Name of the file character ( len = :), allocatable :: file_name !> File scope flags character ( len = :), allocatable :: flags contains !> Serialization interface procedure :: serializable_is_same => file_scope_same procedure :: dump_to_toml => file_scope_dump procedure :: load_from_toml => file_scope_load end type file_scope_flag","tags":"","url":"type/file_scope_flag.html"},{"title":"profile_config_t – Fortran-lang/fpm ","text":"type, public, extends( serializable_t ) :: profile_config_t Configuration meta data for a profile Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: c_flags C compiler flags character(len=:), public, allocatable :: compiler Name of the compiler character(len=:), public, allocatable :: cxx_flags C++ compiler flags type( file_scope_flag ), public, allocatable :: file_scope_flags (:) File scope flags character(len=:), public, allocatable :: flags Fortran compiler flags logical, public :: is_built_in = .false. Is this profile one of the built-in ones? character(len=:), public, allocatable :: link_time_flags Link time compiler flags integer, public :: os_type = OS_ALL Value repesenting OS character(len=:), public, allocatable :: profile_name Name of the profile Type-Bound Procedures generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit private subroutine srcfile_dump_to_toml(self, table, error) Dump dependency to toml table Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine dump_to_file(self, file, error, json) Write serializable object to file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine dump_to_unit(self, unit, error, json) Write serializable object to a formatted Fortran unit Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit Formatted unit type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format requested? procedure, public :: dump_to_toml => profile_dump public subroutine profile_dump (self, table, error) Dump to toml table Read more… Arguments Type Intent Optional Attributes Name class( profile_config_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling procedure, public :: info Print information on this instance public subroutine info (self, unit, verbosity) Write information on instance Arguments Type Intent Optional Attributes Name class( profile_config_t ), intent(in) :: self Instance of the profile configuration integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout generic, public :: load => load_from_toml , load_from_file, load_from_unit private subroutine srcfile_load_from_toml(self, table, error) Read dependency from toml table (no checks made at this stage) Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine load_from_file(self, file, error, json) Read dependency tree from file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine load_from_unit(self, unit, error, json) Read dependency tree from file\ninit JSON interpreter\nRead object from TOML table use default TOML parser Read object from TOML table Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format procedure, public :: load_from_toml => profile_load public subroutine profile_load (self, table, error) Read from toml table (no checks made at this stage) Read more… Arguments Type Intent Optional Attributes Name class( profile_config_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling generic, public :: operator(==) => serializable_is_same private function srcfile_is_same(this, that) Check that two source files are equal\nAll checks passed! Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical procedure, public :: serializable_is_same => profile_same Serialization interface public function profile_same (this, that) All checks passed! Arguments Type Intent Optional Attributes Name class( profile_config_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical procedure, public, non_overridable :: test_serialization Test load/write roundtrip private subroutine test_serialization(self, message, error) Test serialization of a serializable object\nDump to scratch file\nLoad from scratch file\nCheck same Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self character(len=*), intent(in) :: message type( error_t ), intent(out), allocatable :: error Source Code type , extends ( serializable_t ) :: profile_config_t !> Name of the profile character ( len = :), allocatable :: profile_name !> Name of the compiler character ( len = :), allocatable :: compiler !> Value repesenting OS integer :: os_type = OS_ALL !> Fortran compiler flags character ( len = :), allocatable :: flags !> C compiler flags character ( len = :), allocatable :: c_flags !> C++ compiler flags character ( len = :), allocatable :: cxx_flags !> Link time compiler flags character ( len = :), allocatable :: link_time_flags !> File scope flags type ( file_scope_flag ), allocatable :: file_scope_flags (:) !> Is this profile one of the built-in ones? logical :: is_built_in = . false . contains !> Print information on this instance procedure :: info !> Serialization interface procedure :: serializable_is_same => profile_same procedure :: dump_to_toml => profile_dump procedure :: load_from_toml => profile_load end type profile_config_t","tags":"","url":"type/profile_config_t.html"},{"title":"string_t – Fortran-lang/fpm ","text":"type, public :: string_t Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: s Constructor public interface string_t private function new_string_t(s) result(string) Helper function to generate a new string_t instance\n (Required due to the allocatable component) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: s Return Value type( string_t )","tags":"","url":"type/string_t.html"},{"title":"version_t – Fortran-lang/fpm ","text":"type, public :: version_t Type-Bound Procedures generic, public :: operator(.match.) => match Compare a version against a version constraint (x.x.0 <= v < x.x.HUGE) private elemental function match(lhs, rhs) Try to match first version against second version Arguments Type Intent Optional Attributes Name class( version_t ), intent(in) :: lhs First version number class( version_t ), intent(in) :: rhs Second version number Return Value logical Version match following semantic versioning rules generic, public :: operator(/=) => not_equals private elemental function not_equals(lhs, rhs) result(not_equal) Check two versions for inequality Arguments Type Intent Optional Attributes Name class( version_t ), intent(in) :: lhs First version number class( version_t ), intent(in) :: rhs Second version number Return Value logical Version mismatch generic, public :: operator(<) => less private elemental function less(lhs, rhs) result(is_less) Relative comparison of two versions Arguments Type Intent Optional Attributes Name class( version_t ), intent(in) :: lhs First version number class( version_t ), intent(in) :: rhs Second version number Return Value logical First version is less generic, public :: operator(<=) => less_equals private elemental function less_equals(lhs, rhs) result(is_less_equal) Relative comparison of two versions Arguments Type Intent Optional Attributes Name class( version_t ), intent(in) :: lhs First version number class( version_t ), intent(in) :: rhs Second version number Return Value logical First version is less or equal generic, public :: operator(==) => equals private elemental function equals(lhs, rhs) result(is_equal) Check to version numbers for equality Arguments Type Intent Optional Attributes Name class( version_t ), intent(in) :: lhs First version number class( version_t ), intent(in) :: rhs Second version number Return Value logical Version match generic, public :: operator(>) => greater private elemental function greater(lhs, rhs) result(is_greater) Relative comparison of two versions Arguments Type Intent Optional Attributes Name class( version_t ), intent(in) :: lhs First version number class( version_t ), intent(in) :: rhs Second version number Return Value logical First version is greater generic, public :: operator(>=) => greater_equals private elemental function greater_equals(lhs, rhs) result(is_greater_equal) Relative comparison of two versions Arguments Type Intent Optional Attributes Name class( version_t ), intent(in) :: lhs First version number class( version_t ), intent(in) :: rhs Second version number Return Value logical First version is greater or equal procedure, public :: s Create a printable string from a version data type private pure function s(self) result(string) Arguments Type Intent Optional Attributes Name class( version_t ), intent(in) :: self Version number Return Value character(len=:), allocatable Character representation of the version Source Code type :: version_t private !> Version numbers found integer , allocatable :: num (:) contains generic :: operator ( == ) => equals procedure , private :: equals generic :: operator ( /= ) => not_equals procedure , private :: not_equals generic :: operator ( > ) => greater procedure , private :: greater generic :: operator ( < ) => less procedure , private :: less generic :: operator ( >= ) => greater_equals procedure , private :: greater_equals generic :: operator ( <= ) => less_equals procedure , private :: less_equals !> Compare a version against a version constraint (x.x.0 <= v < x.x.HUGE) generic :: operator (. match .) => match procedure , private :: match !> Create a printable string from a version data type procedure :: s end type version_t","tags":"","url":"type/version_t.html"},{"title":"build_target_ptr – Fortran-lang/fpm ","text":"type, public :: build_target_ptr Wrapper type for constructing arrays of [[build_target_t]] pointers Components Type Visibility Attributes Name Initial type( build_target_t ), public, pointer :: ptr => null() Source Code type build_target_ptr type ( build_target_t ), pointer :: ptr => null () end type build_target_ptr","tags":"","url":"type/build_target_ptr.html"},{"title":"build_target_t – Fortran-lang/fpm ","text":"type, public :: build_target_t Type describing a generated build target Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: compile_flags Compile flags for this build target type( build_target_ptr ), public, allocatable :: dependencies (:) Resolved build dependencies integer(kind=int64), public, allocatable :: digest_cached Previous source file hash type( fortran_features_t ), public :: features Language features character(len=:), public, allocatable :: link_flags Link flags for this build target type( string_t ), public, allocatable :: link_libraries (:) Native libraries to link against type( string_t ), public, allocatable :: link_objects (:) Objects needed to link this target type( string_t ), public, allocatable :: macros (:) List of macros character(len=:), public, allocatable :: output_dir File path of output directory character(len=:), public, allocatable :: output_file File path of build target object relative to cwd character(len=:), public, allocatable :: output_log_file File path of build log file relative to cwd character(len=:), public, allocatable :: output_name File path of build target object relative to output_dir character(len=:), public, allocatable :: package_name Name of parent package integer, public :: schedule = -1 Targets in the same schedule group are guaranteed to be independent logical, public :: skip = .false. Flag set if build target will be skipped (not built) logical, public :: sorted = .false. Flag set if build target is sorted for building type( srcfile_t ), public, allocatable :: source Primary source for this build target integer, public :: target_type = FPM_TARGET_UNKNOWN Target type logical, public :: touched = .false. Flag set when first visited to check for circular dependencies character(len=:), public, allocatable :: version Version number Type-Bound Procedures procedure, public :: info Print information on this instance private subroutine info(self, unit, verbosity) Write information on a build target Arguments Type Intent Optional Attributes Name class( build_target_t ), intent(in) :: self integer, intent(in) :: unit integer, intent(in), optional :: verbosity procedure, public :: is_executable_target private elemental function is_executable_target(target_ptr, scope) result(is_exe) Arguments Type Intent Optional Attributes Name class( build_target_t ), intent(in) :: target_ptr integer, intent(in) :: scope Return Value logical procedure, public :: set_output_dir Set output directory private subroutine set_output_dir(self, output_dir) Helper function: update output directory of a target Arguments Type Intent Optional Attributes Name class( build_target_t ), intent(inout) :: self character(len=*), intent(in), optional :: output_dir Source Code type build_target_t !> File path of build target object relative to cwd character (:), allocatable :: output_file !> File path of build target object relative to output_dir character (:), allocatable :: output_name !> File path of output directory character (:), allocatable :: output_dir !> File path of build log file relative to cwd character (:), allocatable :: output_log_file !> Name of parent package character (:), allocatable :: package_name !> Primary source for this build target type ( srcfile_t ), allocatable :: source !> Resolved build dependencies type ( build_target_ptr ), allocatable :: dependencies (:) !> Target type integer :: target_type = FPM_TARGET_UNKNOWN !> Native libraries to link against type ( string_t ), allocatable :: link_libraries (:) !> Objects needed to link this target type ( string_t ), allocatable :: link_objects (:) !> Link flags for this build target character (:), allocatable :: link_flags !> Compile flags for this build target character (:), allocatable :: compile_flags !> Flag set when first visited to check for circular dependencies logical :: touched = . false . !> Flag set if build target is sorted for building logical :: sorted = . false . !> Flag set if build target will be skipped (not built) logical :: skip = . false . !> Language features type ( fortran_features_t ) :: features !> Targets in the same schedule group are guaranteed to be independent integer :: schedule = - 1 !> Previous source file hash integer ( int64 ), allocatable :: digest_cached !> List of macros type ( string_t ), allocatable :: macros (:) !> Version number character (:), allocatable :: version contains !> Print information on this instance procedure :: info !> Set output directory procedure :: set_output_dir procedure :: is_executable_target end type build_target_t","tags":"","url":"type/build_target_t.html"},{"title":"preprocess_config_t – Fortran-lang/fpm ","text":"type, public, extends( serializable_t ) :: preprocess_config_t Configuration meta data for a preprocessor Components Type Visibility Attributes Name Initial type( string_t ), public, allocatable :: directories (:) Directories to search for files to be preprocessed type( string_t ), public, allocatable :: macros (:) Macros to be defined for the preprocessor character(len=:), public, allocatable :: name Name of the preprocessor type( string_t ), public, allocatable :: suffixes (:) Suffixes of the files to be preprocessed Type-Bound Procedures procedure, public :: add_config private subroutine add_config(this, that) Add preprocessor settings Arguments Type Intent Optional Attributes Name class( preprocess_config_t ), intent(inout) :: this type( preprocess_config_t ), intent(in) :: that procedure, public :: destroy Operations private elemental subroutine destroy(this) Clean preprocessor structure Arguments Type Intent Optional Attributes Name class( preprocess_config_t ), intent(inout) :: this generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit private subroutine srcfile_dump_to_toml(self, table, error) Dump dependency to toml table Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine dump_to_file(self, file, error, json) Write serializable object to file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine dump_to_unit(self, unit, error, json) Write serializable object to a formatted Fortran unit Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit Formatted unit type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format requested? procedure, public :: dump_to_toml private subroutine dump_to_toml(self, table, error) Dump install config to toml table Arguments Type Intent Optional Attributes Name class( preprocess_config_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling procedure, public :: info Print information on this instance private subroutine info(self, unit, verbosity) Write information on this instance Arguments Type Intent Optional Attributes Name class( preprocess_config_t ), intent(in) :: self Instance of the preprocess configuration integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout procedure, public :: is_cpp Properties private function is_cpp(this) Arguments Type Intent Optional Attributes Name class( preprocess_config_t ), intent(in) :: this Return Value logical procedure, public :: is_fypp private function is_fypp(this) Arguments Type Intent Optional Attributes Name class( preprocess_config_t ), intent(in) :: this Return Value logical generic, public :: load => load_from_toml , load_from_file, load_from_unit private subroutine srcfile_load_from_toml(self, table, error) Read dependency from toml table (no checks made at this stage) Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine load_from_file(self, file, error, json) Read dependency tree from file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine load_from_unit(self, unit, error, json) Read dependency tree from file\ninit JSON interpreter\nRead object from TOML table use default TOML parser Read object from TOML table Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format procedure, public :: load_from_toml private subroutine load_from_toml(self, table, error) Read install config from toml table (no checks made at this stage) Arguments Type Intent Optional Attributes Name class( preprocess_config_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling generic, public :: new => new_cpp_config_with_macros, new_preprocess_config private subroutine new_cpp_config_with_macros(self, macros) Construct a new cpp preprocessor configuration with a list of macros Set cpp Set macros Arguments Type Intent Optional Attributes Name class( preprocess_config_t ), intent(out) :: self Instance of the preprocess configuration type( string_t ), intent(in) :: macros (:) List of macros private subroutine new_preprocess_config(self, table, error) Construct a new preprocess configuration from TOML data structure Arguments Type Intent Optional Attributes Name class( preprocess_config_t ), intent(out) :: self Instance of the preprocess configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure. type( error_t ), intent(out), allocatable :: error Error handling generic, public :: operator(==) => serializable_is_same private function srcfile_is_same(this, that) Check that two source files are equal\nAll checks passed! Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical procedure, public :: serializable_is_same => preprocess_is_same Serialization interface private function preprocess_is_same(this, that) All checks passed! Arguments Type Intent Optional Attributes Name class( preprocess_config_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical procedure, public, non_overridable :: test_serialization Test load/write roundtrip private subroutine test_serialization(self, message, error) Test serialization of a serializable object\nDump to scratch file\nLoad from scratch file\nCheck same Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self character(len=*), intent(in) :: message type( error_t ), intent(out), allocatable :: error Source Code type , extends ( serializable_t ) :: preprocess_config_t !> Name of the preprocessor character ( len = :), allocatable :: name !> Suffixes of the files to be preprocessed type ( string_t ), allocatable :: suffixes (:) !> Directories to search for files to be preprocessed type ( string_t ), allocatable :: directories (:) !> Macros to be defined for the preprocessor type ( string_t ), allocatable :: macros (:) contains !> Print information on this instance procedure :: info !> Initialization procedure , private :: new_cpp_config_with_macros procedure , private :: new_preprocess_config generic :: new => new_cpp_config_with_macros , new_preprocess_config !> Serialization interface procedure :: serializable_is_same => preprocess_is_same procedure :: dump_to_toml procedure :: load_from_toml !> Operations procedure :: destroy procedure :: add_config !> Properties procedure :: is_cpp procedure :: is_fypp end type preprocess_config_t","tags":"","url":"type/preprocess_config_t.html"},{"title":"compile_command_t – Fortran-lang/fpm ","text":"type, public, extends( serializable_t ) :: compile_command_t Definition of a build command Components Type Visibility Attributes Name Initial type( string_t ), public, allocatable :: arguments (:) type( string_t ), public :: directory type( string_t ), public :: file Constructor public interface compile_command_t public function cct_new (directory, arguments, file) result(cct) Override default initializer (GCC 15 bug) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: directory character(len=*), intent(in), optional :: arguments (:) character(len=*), intent(in) :: file Return Value type( compile_command_t ) Type-Bound Procedures procedure, public :: destroy => compile_command_destroy Operation public elemental subroutine compile_command_destroy (self) Cleanup compile command Arguments Type Intent Optional Attributes Name class( compile_command_t ), intent(inout) :: self Instance of the serializable object generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit private subroutine srcfile_dump_to_toml(self, table, error) Dump dependency to toml table Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine dump_to_file(self, file, error, json) Write serializable object to file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine dump_to_unit(self, unit, error, json) Write serializable object to a formatted Fortran unit Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit Formatted unit type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format requested? procedure, public :: dump_to_toml => compile_command_dump_toml public subroutine compile_command_dump_toml (self, table, error) Dump compile_command_t to toml table Arguments Type Intent Optional Attributes Name class( compile_command_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling generic, public :: load => load_from_toml , load_from_file, load_from_unit private subroutine srcfile_load_from_toml(self, table, error) Read dependency from toml table (no checks made at this stage) Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine load_from_file(self, file, error, json) Read dependency tree from file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine load_from_unit(self, unit, error, json) Read dependency tree from file\ninit JSON interpreter\nRead object from TOML table use default TOML parser Read object from TOML table Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format procedure, public :: load_from_toml => compile_command_load_toml public subroutine compile_command_load_toml (self, table, error) Read compile_command_t from toml table (no checks made at this stage) Arguments Type Intent Optional Attributes Name class( compile_command_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling generic, public :: operator(==) => serializable_is_same private function srcfile_is_same(this, that) Check that two source files are equal\nAll checks passed! Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical procedure, public :: serializable_is_same => compile_command_is_same Serialization interface public function compile_command_is_same (this, that) Check that two compile_command_t objects are equal\nAll checks passed! Arguments Type Intent Optional Attributes Name class( compile_command_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical procedure, public, non_overridable :: test_serialization Test load/write roundtrip private subroutine test_serialization(self, message, error) Test serialization of a serializable object\nDump to scratch file\nLoad from scratch file\nCheck same Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self character(len=*), intent(in) :: message type( error_t ), intent(out), allocatable :: error Source Code type , extends ( serializable_t ) :: compile_command_t type ( string_t ) :: directory type ( string_t ), allocatable :: arguments (:) type ( string_t ) :: file contains !> Operation procedure :: destroy => compile_command_destroy !> Serialization interface procedure :: serializable_is_same => compile_command_is_same procedure :: dump_to_toml => compile_command_dump_toml procedure :: load_from_toml => compile_command_load_toml end type compile_command_t","tags":"","url":"type/compile_command_t.html"},{"title":"compile_command_table_t – Fortran-lang/fpm ","text":"type, public, extends( serializable_t ) :: compile_command_table_t Components Type Visibility Attributes Name Initial type( compile_command_t ), public, allocatable :: command (:) Type-Bound Procedures procedure, public :: destroy => cct_destroy Operation public elemental subroutine cct_destroy (self) Cleanup a compile command table Arguments Type Intent Optional Attributes Name class( compile_command_table_t ), intent(inout) :: self Instance of the serializable object generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit private subroutine srcfile_dump_to_toml(self, table, error) Dump dependency to toml table Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine dump_to_file(self, file, error, json) Write serializable object to file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine dump_to_unit(self, unit, error, json) Write serializable object to a formatted Fortran unit Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit Formatted unit type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format requested? procedure, public :: dump_to_toml => cct_dump_toml public subroutine cct_dump_toml (self, table, error) Dump compile_command_table_t to toml table Arguments Type Intent Optional Attributes Name class( compile_command_table_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling generic, public :: load => load_from_toml , load_from_file, load_from_unit private subroutine srcfile_load_from_toml(self, table, error) Read dependency from toml table (no checks made at this stage) Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine load_from_file(self, file, error, json) Read dependency tree from file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine load_from_unit(self, unit, error, json) Read dependency tree from file\ninit JSON interpreter\nRead object from TOML table use default TOML parser Read object from TOML table Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format procedure, public :: load_from_toml => cct_load_toml public subroutine cct_load_toml (self, table, error) Read compile_command_table_t from toml table (no checks made at this stage) Arguments Type Intent Optional Attributes Name class( compile_command_table_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling generic, public :: operator(==) => serializable_is_same private function srcfile_is_same(this, that) Check that two source files are equal\nAll checks passed! Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical generic, public :: register => cct_register, cct_register_object public subroutine cct_register (self, command, target_os, error) Register a new compile command Arguments Type Intent Optional Attributes Name class( compile_command_table_t ), intent(inout) :: self Instance of the serializable object character(len=*), intent(in) :: command Data structure integer, intent(in) :: target_os The target OS of the compile_commands.json (may be cross-compiling) type( error_t ), intent(out), allocatable :: error Error handling public pure subroutine cct_register_object (self, command, error) Arguments Type Intent Optional Attributes Name class( compile_command_table_t ), intent(inout) :: self Instance of the serializable object type( compile_command_t ), intent(in) :: command Data structure type( error_t ), intent(out), allocatable :: error Error handling procedure, public :: serializable_is_same => cct_is_same Serialization interface public function cct_is_same (this, that) Check that two compile_command_table_t objects are equal\nAll checks passed! Arguments Type Intent Optional Attributes Name class( compile_command_table_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical procedure, public, non_overridable :: test_serialization Test load/write roundtrip private subroutine test_serialization(self, message, error) Test serialization of a serializable object\nDump to scratch file\nLoad from scratch file\nCheck same Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self character(len=*), intent(in) :: message type( error_t ), intent(out), allocatable :: error procedure, public :: write => cct_write public subroutine cct_write (self, filename, error) Write compile_commands.json file. Because Jonquil does not support non-named arrays,\ncreate a custom json here. Arguments Type Intent Optional Attributes Name class( compile_command_table_t ), intent(inout) :: self Instance of the serializable object character(len=*), intent(in) :: filename The file name type( error_t ), intent(out), allocatable :: error Error handling Source Code type , extends ( serializable_t ) :: compile_command_table_t type ( compile_command_t ), allocatable :: command (:) contains !> Operation procedure :: destroy => cct_destroy procedure :: write => cct_write procedure , private :: cct_register procedure , private :: cct_register_object generic :: register => cct_register , & cct_register_object !> Serialization interface procedure :: serializable_is_same => cct_is_same procedure :: dump_to_toml => cct_dump_toml procedure :: load_from_toml => cct_load_toml end type compile_command_table_t","tags":"","url":"type/compile_command_table_t.html"},{"title":"build_progress_t – Fortran-lang/fpm ","text":"type, public :: build_progress_t Build progress object Components Type Visibility Attributes Name Initial type( compile_command_table_t ), public :: compile_commands The compile_commands.json table type( console_t ), public :: console Console object for updating console lines integer, public :: n_complete Number of completed targets integer, public :: n_target Total number of targets scheduled integer, public, allocatable :: output_lines (:) Store needed when updating previous console lines logical, public :: plain_mode = .true. ‘Plain’ output (no colors or updating) type( build_target_ptr ), public, pointer :: target_queue (:) Queue of scheduled build targets Constructor public interface build_progress_t Constructor for build_progress_t private function new_build_progress(target_queue, plain_mode) result(progress) Initialise a new build progress object Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(in), target :: target_queue (:) The queue of scheduled targets logical, intent(in), optional :: plain_mode Enable ‘plain’ output for progress object Return Value type( build_progress_t ) Progress object to initialise Type-Bound Procedures procedure, public :: compiling_status => output_status_compiling Output ‘compiling’ status for build target private subroutine output_status_compiling(progress, queue_index) Output ‘compiling’ status for build target and overall percentage progress Arguments Type Intent Optional Attributes Name class( build_progress_t ), intent(inout) :: progress Progress object integer, intent(in) :: queue_index Index of build target in the target queue procedure, public :: completed_status => output_status_complete Output ‘complete’ status for build target private subroutine output_status_complete(progress, queue_index, build_stat) Output ‘complete’ status for build target and update overall percentage progress Arguments Type Intent Optional Attributes Name class( build_progress_t ), intent(inout) :: progress Progress object integer, intent(in) :: queue_index Index of build target in the target queue integer, intent(in) :: build_stat Build status flag procedure, public :: dump_commands => output_write_compile_commands Output ‘compile_commands.json’ to build/ folder private subroutine output_write_compile_commands(progress, error) Write compile commands table Arguments Type Intent Optional Attributes Name class( build_progress_t ), intent(inout) :: progress type( error_t ), allocatable :: error procedure, public :: success => output_progress_success Output finished status for whole package private subroutine output_progress_success(progress) Output finished status for whole package Arguments Type Intent Optional Attributes Name class( build_progress_t ), intent(inout) :: progress Source Code type build_progress_t !> Console object for updating console lines type ( console_t ) :: console !> Number of completed targets integer :: n_complete !> Total number of targets scheduled integer :: n_target !> 'Plain' output (no colors or updating) logical :: plain_mode = . true . !> Store needed when updating previous console lines integer , allocatable :: output_lines (:) !> Queue of scheduled build targets type ( build_target_ptr ), pointer :: target_queue (:) !> The compile_commands.json table type ( compile_command_table_t ) :: compile_commands contains !> Output 'compiling' status for build target procedure :: compiling_status => output_status_compiling !> Output 'complete' status for build target procedure :: completed_status => output_status_complete !> Output finished status for whole package procedure :: success => output_progress_success !> Output 'compile_commands.json' to build/ folder procedure :: dump_commands => output_write_compile_commands end type build_progress_t","tags":"","url":"type/build_progress_t.html"},{"title":"example_config_t – Fortran-lang/fpm ","text":"type, public, extends( executable_config_t ) :: example_config_t Configuation meta data for an example Components Type Visibility Attributes Name Initial type( dependency_config_t ), public, allocatable :: dependency (:) Dependency meta data for this executable type( string_t ), public, allocatable :: link (:) Libraries to link against character(len=:), public, allocatable :: main Name of the source file declaring the main program character(len=:), public, allocatable :: name Name of the resulting executable character(len=:), public, allocatable :: source_dir Source directory for collecting the executable Type-Bound Procedures generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit private subroutine srcfile_dump_to_toml(self, table, error) Dump dependency to toml table Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine dump_to_file(self, file, error, json) Write serializable object to file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine dump_to_unit(self, unit, error, json) Write serializable object to a formatted Fortran unit Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit Formatted unit type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format requested? procedure, public :: dump_to_toml private subroutine dump_to_toml(self, table, error) Dump install config to toml table Because dependencies are named, fallback if this has no name\nSo, serialization will work regardless of size(self%dep) == self%ndep Arguments Type Intent Optional Attributes Name class( executable_config_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling procedure, public :: info Print information on this instance private subroutine info(self, unit, verbosity) Write information on instance Arguments Type Intent Optional Attributes Name class( example_config_t ), intent(in) :: self Instance of the example configuration integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout generic, public :: load => load_from_toml , load_from_file, load_from_unit private subroutine srcfile_load_from_toml(self, table, error) Read dependency from toml table (no checks made at this stage) Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine load_from_file(self, file, error, json) Read dependency tree from file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine load_from_unit(self, unit, error, json) Read dependency tree from file\ninit JSON interpreter\nRead object from TOML table use default TOML parser Read object from TOML table Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format procedure, public :: load_from_toml private subroutine load_from_toml(self, table, error) Read install config from toml table (no checks made at this stage) Read all dependencies Arguments Type Intent Optional Attributes Name class( executable_config_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling generic, public :: operator(==) => serializable_is_same private function srcfile_is_same(this, that) Check that two source files are equal\nAll checks passed! Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical procedure, public :: serializable_is_same => exe_is_same Serialization interface private function exe_is_same(this, that) All checks passed! Arguments Type Intent Optional Attributes Name class( executable_config_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical procedure, public, non_overridable :: test_serialization Test load/write roundtrip private subroutine test_serialization(self, message, error) Test serialization of a serializable object\nDump to scratch file\nLoad from scratch file\nCheck same Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self character(len=*), intent(in) :: message type( error_t ), intent(out), allocatable :: error Source Code type , extends ( executable_config_t ) :: example_config_t contains !> Print information on this instance procedure :: info end type example_config_t","tags":"","url":"type/example_config_t.html"},{"title":"archiver_t – Fortran-lang/fpm ","text":"type, public, extends( serializable_t ) :: archiver_t Definition of archiver object Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: ar Path to archiver logical, public :: echo = .true. Print all command logical, public :: use_response_file = .false. Use response files to pass arguments logical, public :: verbose = .true. Verbose output of command Type-Bound Procedures generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit private subroutine srcfile_dump_to_toml(self, table, error) Dump dependency to toml table Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine dump_to_file(self, file, error, json) Write serializable object to file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine dump_to_unit(self, unit, error, json) Write serializable object to a formatted Fortran unit Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit Formatted unit type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format requested? procedure, public :: dump_to_toml public subroutine dump_to_toml (self, table, error) Dump dependency to toml table Read more… Arguments Type Intent Optional Attributes Name class( archiver_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling generic, public :: load => load_from_toml , load_from_file, load_from_unit private subroutine srcfile_load_from_toml(self, table, error) Read dependency from toml table (no checks made at this stage) Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine load_from_file(self, file, error, json) Read dependency tree from file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine load_from_unit(self, unit, error, json) Read dependency tree from file\ninit JSON interpreter\nRead object from TOML table use default TOML parser Read object from TOML table Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format procedure, public :: load_from_toml public subroutine load_from_toml (self, table, error) Read dependency from toml table (no checks made at this stage) Arguments Type Intent Optional Attributes Name class( archiver_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling procedure, public :: make_archive Create static archive public subroutine make_archive (self, output, args, log_file, stat, dry_run) Create an archive Read more… Arguments Type Intent Optional Attributes Name class( archiver_t ), intent(in) :: self Instance of the archiver object character(len=*), intent(in) :: output Name of the archive to generate type( string_t ), intent(in) :: args (:) Object files to include into the archive character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag logical, intent(in), optional :: dry_run Optional mocking generic, public :: operator(==) => serializable_is_same private function srcfile_is_same(this, that) Check that two source files are equal\nAll checks passed! Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical procedure, public :: serializable_is_same => ar_is_same Serialization interface public function ar_is_same (this, that) Check that two archiver_t objects are equal\nAll checks passed! Arguments Type Intent Optional Attributes Name class( archiver_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical procedure, public, non_overridable :: test_serialization Test load/write roundtrip private subroutine test_serialization(self, message, error) Test serialization of a serializable object\nDump to scratch file\nLoad from scratch file\nCheck same Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self character(len=*), intent(in) :: message type( error_t ), intent(out), allocatable :: error Source Code type , extends ( serializable_t ) :: archiver_t !> Path to archiver character ( len = :), allocatable :: ar !> Use response files to pass arguments logical :: use_response_file = . false . !> Print all command logical :: echo = . true . !> Verbose output of command logical :: verbose = . true . contains !> Create static archive procedure :: make_archive !> Serialization interface procedure :: serializable_is_same => ar_is_same procedure :: dump_to_toml procedure :: load_from_toml end type archiver_t","tags":"","url":"type/archiver_t.html"},{"title":"compiler_t – Fortran-lang/fpm ","text":"type, public, extends( serializable_t ) :: compiler_t Definition of compiler object Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: cc Path to the C compiler character(len=:), public, allocatable :: cxx Path to the C++ compiler logical, public :: echo = .true. Print all commands character(len=:), public, allocatable :: fc Path to the Fortran compiler integer(kind=compiler_enum), public :: id = id_unknown Identifier of the compiler logical, public :: verbose = .true. Verbose output of command Type-Bound Procedures procedure, public :: check_flags_supported public function check_flags_supported (self, compile_flags, link_flags) Check if the given compile and/or link flags are accepted by the compiler Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in), optional :: compile_flags character(len=*), intent(in), optional :: link_flags Return Value logical procedure, public :: check_fortran_source_runs Fortran feature support public function check_fortran_source_runs (self, input, compile_flags, link_flags) result(success) Run a single-source Fortran program using the current compiler\nCompile a Fortran object\nCreate temporary source file\nWrite contents\nGet flags\nIntel: Needs -warn last for error on unknown command line arguments to work\nCompile and link program\nRun and retrieve exit code Read more… Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object character(len=*), intent(in) :: input Program Source character(len=*), intent(in), optional :: compile_flags Optional build and link flags character(len=*), intent(in), optional :: link_flags Optional build and link flags Return Value logical procedure, public :: compile_c Compile a C object public subroutine compile_c (self, input, output, args, log_file, stat, table, dry_run) Compile a C object Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object character(len=*), intent(in) :: input Source file input character(len=*), intent(in) :: output Output file of object character(len=*), intent(in) :: args Arguments for compiler character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag type( compile_command_table_t ), intent(inout), optional :: table Optional compile_commands table logical, intent(in), optional :: dry_run Optional mocking procedure, public :: compile_cpp Compile a CPP object public subroutine compile_cpp (self, input, output, args, log_file, stat, table, dry_run) Compile a CPP object Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object character(len=*), intent(in) :: input Source file input character(len=*), intent(in) :: output Output file of object character(len=*), intent(in) :: args Arguments for compiler character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag type( compile_command_table_t ), intent(inout), optional :: table Optional compile_commands table logical, intent(in), optional :: dry_run Optional mocking procedure, public :: compile_fortran Compile a Fortran object public subroutine compile_fortran (self, input, output, args, log_file, stat, table, dry_run) Compile a Fortran object Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object character(len=*), intent(in) :: input Source file input character(len=*), intent(in) :: output Output file of object character(len=*), intent(in) :: args Arguments for compiler character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag type( compile_command_table_t ), intent(inout), optional :: table Optional compile_commands table logical, intent(in), optional :: dry_run Optional mocking generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit private subroutine srcfile_dump_to_toml(self, table, error) Dump dependency to toml table Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine dump_to_file(self, file, error, json) Write serializable object to file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine dump_to_unit(self, unit, error, json) Write serializable object to a formatted Fortran unit Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit Formatted unit type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format requested? procedure, public :: dump_to_toml => compiler_dump public subroutine compiler_dump (self, table, error) Dump dependency to toml table Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling procedure, public :: enumerate_libraries Enumerate libraries, based on compiler and platform public function enumerate_libraries (self, prefix, libs) result(r) Enumerate libraries, based on compiler and platform Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: prefix type( string_t ), intent(in) :: libs (:) Return Value character(len=:), allocatable procedure, public :: get_default_flags Get default compiler flags public function get_default_flags (self, release) result(flags) Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self logical, intent(in) :: release Return Value character(len=:), allocatable procedure, public :: get_export_flags Get library export flags public function get_export_flags (self, target_dir, target_name) result(export_flags) Generate library export flags for a shared library build Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler character(len=*), intent(in) :: target_dir Path and package name character(len=*), intent(in) :: target_name Path and package name Return Value character(len=:), allocatable procedure, public :: get_feature_flag Get feature flag public function get_feature_flag (self, feature) result(flags) Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: feature Return Value character(len=:), allocatable procedure, public :: get_headerpad_flags Generate header padding flags for macOS executables public function get_headerpad_flags (self) result(flags) Generate header padding flags for install_name_tool compatibility on macOS Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Return Value character(len=:), allocatable procedure, public :: get_include_flag Get flag for include directories public function get_include_flag (self, path) result(flags) Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: path Return Value character(len=:), allocatable procedure, public :: get_install_name_flags Get library install name flags public function get_install_name_flags (self, target_dir, target_name) result(flags) Generate install_name flag for a shared library build on macOS Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: target_dir character(len=*), intent(in) :: target_name Return Value character(len=:), allocatable procedure, public :: get_main_flags Get flags for the main linking command public subroutine get_main_flags (self, language, flags) Get special flags for the main linker Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: language character(len=:), intent(out), allocatable :: flags procedure, public :: get_module_flag Get flag for module output directories public function get_module_flag (self, path) result(flags) Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: path Return Value character(len=:), allocatable procedure, public :: is_gnu Check whether this is a GNU compiler public pure function is_gnu (self) Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Return Value logical procedure, public :: is_intel Check whether this is an Intel compiler public pure function is_intel (self) Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Return Value logical procedure, public :: is_unknown Check whether compiler is recognized public pure function is_unknown (self) Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Return Value logical procedure, public :: link => link_executable Link executable public subroutine link_executable (self, output, args, log_file, stat, dry_run) Link an executable Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object character(len=*), intent(in) :: output Output file of object character(len=*), intent(in) :: args Arguments for compiler character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag logical, intent(in), optional :: dry_run Optional mocking procedure, public :: link_shared Link a shared library public subroutine link_shared (self, output, args, log_file, stat, dry_run) Link a shared library Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object character(len=*), intent(in) :: output Output file of shared library object character(len=*), intent(in) :: args Arguments for the compiler character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag logical, intent(in), optional :: dry_run Optional mocking generic, public :: load => load_from_toml , load_from_file, load_from_unit private subroutine srcfile_load_from_toml(self, table, error) Read dependency from toml table (no checks made at this stage) Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine load_from_file(self, file, error, json) Read dependency tree from file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine load_from_unit(self, unit, error, json) Read dependency tree from file\ninit JSON interpreter\nRead object from TOML table use default TOML parser Read object from TOML table Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format procedure, public :: load_from_toml => compiler_load public subroutine compiler_load (self, table, error) Read dependency from toml table (no checks made at this stage) Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling procedure, public :: name => compiler_name Return compiler name public pure function compiler_name (self) result(name) Return a compiler name string Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object Return Value character(len=:), allocatable Representation as string generic, public :: operator(==) => serializable_is_same private function srcfile_is_same(this, that) Check that two source files are equal\nAll checks passed! Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical procedure, public :: serializable_is_same => compiler_is_same Serialization interface public function compiler_is_same (this, that) Check that two compiler_t objects are equal\nAll checks passed! Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical procedure, public, non_overridable :: test_serialization Test load/write roundtrip private subroutine test_serialization(self, message, error) Test serialization of a serializable object\nDump to scratch file\nLoad from scratch file\nCheck same Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self character(len=*), intent(in) :: message type( error_t ), intent(out), allocatable :: error procedure, public :: with_qp public function with_qp (self) Check if the current compiler supports 128-bit real precision Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object Return Value logical procedure, public :: with_xdp public function with_xdp (self) Check if the current compiler supports 80-bit “extended” real precision Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object Return Value logical Source Code type , extends ( serializable_t ) :: compiler_t !> Identifier of the compiler integer ( compiler_enum ) :: id = id_unknown !> Path to the Fortran compiler character ( len = :), allocatable :: fc !> Path to the C compiler character ( len = :), allocatable :: cc !> Path to the C++ compiler character ( len = :), allocatable :: cxx !> Print all commands logical :: echo = . true . !> Verbose output of command logical :: verbose = . true . contains !> Get default compiler flags procedure :: get_default_flags !> Get flag for module output directories procedure :: get_module_flag !> Get flag for include directories procedure :: get_include_flag !> Get feature flag procedure :: get_feature_flag !> Get flags for the main linking command procedure :: get_main_flags !> Get library export flags procedure :: get_export_flags !> Get library install name flags procedure :: get_install_name_flags !> Generate header padding flags for macOS executables procedure :: get_headerpad_flags !> Compile a Fortran object procedure :: compile_fortran !> Compile a C object procedure :: compile_c !> Compile a CPP object procedure :: compile_cpp !> Link a shared library procedure :: link_shared !> Link executable procedure :: link => link_executable !> Check whether compiler is recognized procedure :: is_unknown !> Check whether this is an Intel compiler procedure :: is_intel !> Check whether this is a GNU compiler procedure :: is_gnu !> Enumerate libraries, based on compiler and platform procedure :: enumerate_libraries !> Serialization interface procedure :: serializable_is_same => compiler_is_same procedure :: dump_to_toml => compiler_dump procedure :: load_from_toml => compiler_load !> Fortran feature support procedure :: check_fortran_source_runs procedure :: check_flags_supported procedure :: with_xdp procedure :: with_qp !> Return compiler name procedure :: name => compiler_name end type compiler_t","tags":"","url":"type/compiler_t.html"},{"title":"metapackage_t – Fortran-lang/fpm ","text":"type, public :: metapackage_t Type for describing a source file Components Type Visibility Attributes Name Initial type( string_t ), public :: cflags type( string_t ), public :: cxxflags type( dependency_config_t ), public, allocatable :: dependency (:) List of Development dependency meta data.\nMetapackage dependencies are never exported from the model type( string_t ), public, allocatable :: external_modules (:) type( string_t ), public :: fflags type( string_t ), public :: flags List of compiler flags and options to be added type( fortran_features_t ), public, allocatable :: fortran Special fortran features logical, public :: has_build_flags = .false. logical, public :: has_c_flags = .false. logical, public :: has_cxx_flags = .false. logical, public :: has_dependencies = .false. logical, public :: has_external_modules = .false. logical, public :: has_fortran_flags = .false. logical, public :: has_include_dirs = .false. logical, public :: has_link_flags = .false. logical, public :: has_link_libraries = .false. logical, public :: has_run_command = .false. type( string_t ), public, allocatable :: incl_dirs (:) type( string_t ), public :: link_flags type( string_t ), public, allocatable :: link_libs (:) character(len=:), public, allocatable :: name Package name type( preprocess_config_t ), public, allocatable :: preprocess Preprocessor configuration type( string_t ), public :: run_command type( version_t ), public, allocatable :: version Package version (if supported) Type-Bound Procedures procedure, public :: destroy Clean metapackage structure public elemental subroutine destroy (this) Arguments Type Intent Optional Attributes Name class( metapackage_t ), intent(inout) :: this generic, public :: resolve => resolve_cmd, resolve_model, resolve_package_config private subroutine resolve_cmd(self, settings, error) Resolve metapackage dependencies into the command line settings Arguments Type Intent Optional Attributes Name class( metapackage_t ), intent(in) :: self class( fpm_cmd_settings ), intent(inout) :: settings type( error_t ), intent(out), allocatable :: error private subroutine resolve_model(self, model, error) Resolve metapackage dependencies into the model Arguments Type Intent Optional Attributes Name class( metapackage_t ), intent(in) :: self type( fpm_model_t ), intent(inout) :: model type( error_t ), intent(out), allocatable :: error private subroutine resolve_package_config(self, package, error) Arguments Type Intent Optional Attributes Name class( metapackage_t ), intent(in) :: self type( package_config_t ), intent(inout) :: package type( error_t ), intent(out), allocatable :: error Source Code type , public :: metapackage_t !> Package name character (:), allocatable :: name !> Package version (if supported) type ( version_t ), allocatable :: version logical :: has_link_libraries = . false . logical :: has_link_flags = . false . logical :: has_build_flags = . false . logical :: has_fortran_flags = . false . logical :: has_c_flags = . false . logical :: has_cxx_flags = . false . logical :: has_include_dirs = . false . logical :: has_dependencies = . false . logical :: has_run_command = . false . logical :: has_external_modules = . false . !> List of compiler flags and options to be added type ( string_t ) :: flags type ( string_t ) :: fflags type ( string_t ) :: cflags type ( string_t ) :: cxxflags type ( string_t ) :: link_flags type ( string_t ) :: run_command type ( string_t ), allocatable :: incl_dirs (:) type ( string_t ), allocatable :: link_libs (:) type ( string_t ), allocatable :: external_modules (:) !> Special fortran features type ( fortran_features_t ), allocatable :: fortran !> Preprocessor configuration type ( preprocess_config_t ), allocatable :: preprocess !> List of Development dependency meta data. !> Metapackage dependencies are never exported from the model type ( dependency_config_t ), allocatable :: dependency (:) contains !> Clean metapackage structure procedure :: destroy !> Add metapackage dependencies to the model procedure , private :: resolve_cmd procedure , private :: resolve_model procedure , private :: resolve_package_config generic :: resolve => resolve_cmd , resolve_model , resolve_package_config end type metapackage_t","tags":"","url":"type/metapackage_t.html"},{"title":"downloader_t – Fortran-lang/fpm ","text":"type, public :: downloader_t This type could be entirely avoided but it is quite practical because it can be mocked for testing. Type-Bound Procedures procedure, public, nopass :: get_file private subroutine get_file(url, tmp_pkg_file, error) Download a file from a url using either curl or wget. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: url character(len=*), intent(in) :: tmp_pkg_file type( error_t ), intent(out), allocatable :: error procedure, public, nopass :: get_pkg_data private subroutine get_pkg_data(url, version, tmp_pkg_file, json, error) Perform an http get request, save output to file, and parse json. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: url type( version_t ), intent(in), allocatable :: version character(len=*), intent(in) :: tmp_pkg_file type(json_object), intent(out) :: json type( error_t ), intent(out), allocatable :: error procedure, public, nopass :: unpack private subroutine unpack(tmp_pkg_file, destination, error) Unpack a tarball to a destination. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: tmp_pkg_file Path to tarball. character(len=*), intent(in) :: destination Destination to unpack to. type( error_t ), intent(out), allocatable :: error Error handling. procedure, public, nopass :: upload_form private subroutine upload_form(endpoint, form_data, verbose, error) Perform an http post request with form data. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: endpoint Endpoint to upload to. type( string_t ), intent(in) :: form_data (:) Form data to upload. logical, intent(in) :: verbose Print additional information if true. type( error_t ), intent(out), allocatable :: error Error handling.","tags":"","url":"type/downloader_t.html"},{"title":"executable_config_t – Fortran-lang/fpm ","text":"type, public, extends( serializable_t ) :: executable_config_t Configuation meta data for an executable Components Type Visibility Attributes Name Initial type( dependency_config_t ), public, allocatable :: dependency (:) Dependency meta data for this executable type( string_t ), public, allocatable :: link (:) Libraries to link against character(len=:), public, allocatable :: main Name of the source file declaring the main program character(len=:), public, allocatable :: name Name of the resulting executable character(len=:), public, allocatable :: source_dir Source directory for collecting the executable Type-Bound Procedures generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit private subroutine srcfile_dump_to_toml(self, table, error) Dump dependency to toml table Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine dump_to_file(self, file, error, json) Write serializable object to file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine dump_to_unit(self, unit, error, json) Write serializable object to a formatted Fortran unit Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit Formatted unit type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format requested? procedure, public :: dump_to_toml private subroutine dump_to_toml(self, table, error) Dump install config to toml table Because dependencies are named, fallback if this has no name\nSo, serialization will work regardless of size(self%dep) == self%ndep Arguments Type Intent Optional Attributes Name class( executable_config_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling procedure, public :: info Print information on this instance private subroutine info(self, unit, verbosity) Write information on instance Arguments Type Intent Optional Attributes Name class( executable_config_t ), intent(in) :: self Instance of the executable configuration integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout generic, public :: load => load_from_toml , load_from_file, load_from_unit private subroutine srcfile_load_from_toml(self, table, error) Read dependency from toml table (no checks made at this stage) Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine load_from_file(self, file, error, json) Read dependency tree from file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine load_from_unit(self, unit, error, json) Read dependency tree from file\ninit JSON interpreter\nRead object from TOML table use default TOML parser Read object from TOML table Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format procedure, public :: load_from_toml private subroutine load_from_toml(self, table, error) Read install config from toml table (no checks made at this stage) Read all dependencies Arguments Type Intent Optional Attributes Name class( executable_config_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling generic, public :: operator(==) => serializable_is_same private function srcfile_is_same(this, that) Check that two source files are equal\nAll checks passed! Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical procedure, public :: serializable_is_same => exe_is_same Serialization interface private function exe_is_same(this, that) All checks passed! Arguments Type Intent Optional Attributes Name class( executable_config_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical procedure, public, non_overridable :: test_serialization Test load/write roundtrip private subroutine test_serialization(self, message, error) Test serialization of a serializable object\nDump to scratch file\nLoad from scratch file\nCheck same Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self character(len=*), intent(in) :: message type( error_t ), intent(out), allocatable :: error Source Code type , extends ( serializable_t ) :: executable_config_t !> Name of the resulting executable character ( len = :), allocatable :: name !> Source directory for collecting the executable character ( len = :), allocatable :: source_dir !> Name of the source file declaring the main program character ( len = :), allocatable :: main !> Dependency meta data for this executable type ( dependency_config_t ), allocatable :: dependency (:) !> Libraries to link against type ( string_t ), allocatable :: link (:) contains !> Print information on this instance procedure :: info !> Serialization interface procedure :: serializable_is_same => exe_is_same procedure :: dump_to_toml procedure :: load_from_toml end type executable_config_t","tags":"","url":"type/executable_config_t.html"},{"title":"library_config_t – Fortran-lang/fpm ","text":"type, public, extends( serializable_t ) :: library_config_t Configuration meta data for a library Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: build_script Alternative build script to be invoked type( string_t ), public, allocatable :: include_dir (:) Include path prefix character(len=:), public, allocatable :: lib_type Shared / Static / Monolithic library character(len=:), public, allocatable :: source_dir Source path prefix Type-Bound Procedures generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit private subroutine srcfile_dump_to_toml(self, table, error) Dump dependency to toml table Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine dump_to_file(self, file, error, json) Write serializable object to file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine dump_to_unit(self, unit, error, json) Write serializable object to a formatted Fortran unit Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit Formatted unit type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format requested? procedure, public :: dump_to_toml private subroutine dump_to_toml(self, table, error) Dump install config to toml table Arguments Type Intent Optional Attributes Name class( library_config_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling procedure, public :: info Print information on this instance private subroutine info(self, unit, verbosity) Write information on instance Arguments Type Intent Optional Attributes Name class( library_config_t ), intent(in) :: self Instance of the library configuration integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout generic, public :: load => load_from_toml , load_from_file, load_from_unit private subroutine srcfile_load_from_toml(self, table, error) Read dependency from toml table (no checks made at this stage) Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling private subroutine load_from_file(self, file, error, json) Read dependency tree from file Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree character(len=*), intent(in) :: file File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format private subroutine load_from_unit(self, unit, error, json) Read dependency tree from file\ninit JSON interpreter\nRead object from TOML table use default TOML parser Read object from TOML table Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self Instance of the dependency tree integer, intent(in) :: unit File name type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in), optional :: json Optional JSON format procedure, public :: load_from_toml private subroutine load_from_toml(self, table, error) Read install config from toml table (no checks made at this stage) Arguments Type Intent Optional Attributes Name class( library_config_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling procedure, public, non_overridable :: monolithic Check library types private elemental function monolithic(self) Check if this is a monolithic library config\n(single monolithic archive with all objects used by this project) Arguments Type Intent Optional Attributes Name class( library_config_t ), intent(in) :: self Instance of the library configuration Return Value logical generic, public :: operator(==) => serializable_is_same private function srcfile_is_same(this, that) Check that two source files are equal\nAll checks passed! Arguments Type Intent Optional Attributes Name class( srcfile_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical procedure, public :: serializable_is_same => library_is_same Serialization interface private function library_is_same(this, that) All checks passed! Arguments Type Intent Optional Attributes Name class( library_config_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical procedure, public, non_overridable :: shared private elemental function shared(self) Check if this is a shared library config \n(full packages built as shared libs) Arguments Type Intent Optional Attributes Name class( library_config_t ), intent(in) :: self Instance of the library configuration Return Value logical procedure, public, non_overridable :: static private elemental function static(self) Check if this is a static library config\n(full packages built as static libs) Arguments Type Intent Optional Attributes Name class( library_config_t ), intent(in) :: self Instance of the library configuration Return Value logical procedure, public, non_overridable :: test_serialization Test load/write roundtrip private subroutine test_serialization(self, message, error) Test serialization of a serializable object\nDump to scratch file\nLoad from scratch file\nCheck same Arguments Type Intent Optional Attributes Name class( serializable_t ), intent(inout) :: self character(len=*), intent(in) :: message type( error_t ), intent(out), allocatable :: error Source Code type , extends ( serializable_t ) :: library_config_t !> Source path prefix character ( len = :), allocatable :: source_dir !> Include path prefix type ( string_t ), allocatable :: include_dir (:) !> Alternative build script to be invoked character ( len = :), allocatable :: build_script !> Shared / Static / Monolithic library character (:), allocatable :: lib_type contains !> Print information on this instance procedure :: info !> Serialization interface procedure :: serializable_is_same => library_is_same procedure :: dump_to_toml procedure :: load_from_toml !> Check library types procedure , non_overridable :: monolithic procedure , non_overridable :: shared procedure , non_overridable :: static end type library_config_t","tags":"","url":"type/library_config_t.html"},{"title":"FPM_SCOPE_NAME – Fortran-lang/fpm","text":"public function FPM_SCOPE_NAME(flag) result(name) Return the character name of a scope flag Arguments Type Intent Optional Attributes Name integer, intent(in) :: flag Return Value character(len=:), allocatable Source Code function FPM_SCOPE_NAME ( flag ) result ( name ) integer , intent ( in ) :: flag character ( len = :), allocatable :: name select case ( flag ) case ( FPM_SCOPE_UNKNOWN ); name = \"FPM_SCOPE_UNKNOWN\" case ( FPM_SCOPE_LIB ); name = \"FPM_SCOPE_LIB\" case ( FPM_SCOPE_DEP ); name = \"FPM_SCOPE_DEP\" case ( FPM_SCOPE_APP ); name = \"FPM_SCOPE_APP\" case ( FPM_SCOPE_TEST ); name = \"FPM_SCOPE_TEST\" case ( FPM_SCOPE_EXAMPLE ); name = \"FPM_SCOPE_EXAMPLE\" case default ; name = \"INVALID\" end select end function FPM_SCOPE_NAME","tags":"","url":"proc/fpm_scope_name.html"},{"title":"FPM_UNIT_NAME – Fortran-lang/fpm","text":"public function FPM_UNIT_NAME(flag) result(name) Return the character name of a unit flag Arguments Type Intent Optional Attributes Name integer, intent(in) :: flag Return Value character(len=:), allocatable Source Code function FPM_UNIT_NAME ( flag ) result ( name ) integer , intent ( in ) :: flag character ( len = :), allocatable :: name select case ( flag ) case ( FPM_UNIT_UNKNOWN ); name = \"FPM_UNIT_UNKNOWN\" case ( FPM_UNIT_PROGRAM ); name = \"FPM_UNIT_PROGRAM\" case ( FPM_UNIT_MODULE ); name = \"FPM_UNIT_MODULE\" case ( FPM_UNIT_SUBMODULE ); name = \"FPM_UNIT_SUBMODULE\" case ( FPM_UNIT_SUBPROGRAM ); name = \"FPM_UNIT_SUBPROGRAM\" case ( FPM_UNIT_CSOURCE ); name = \"FPM_UNIT_CSOURCE\" case ( FPM_UNIT_CPPSOURCE ); name = \"FPM_UNIT_CPPSOURCE\" case ( FPM_UNIT_CHEADER ); name = \"FPM_UNIT_CHEADER\" case default ; name = \"INVALID\" end select end function FPM_UNIT_NAME","tags":"","url":"proc/fpm_unit_name.html"},{"title":"show_model – Fortran-lang/fpm","text":"public subroutine show_model(model) Arguments Type Intent Optional Attributes Name type( fpm_model_t ), intent(in) :: model Source Code subroutine show_model ( model ) ! Prints a human readable representation of the Model type ( fpm_model_t ), intent ( in ) :: model print * , info_model ( model ) end subroutine show_model","tags":"","url":"proc/show_model.html"},{"title":"OS_NAME – Fortran-lang/fpm","text":"public pure function OS_NAME(os) Return string describing the OS type flag Arguments Type Intent Optional Attributes Name integer, intent(in) :: os Return Value character(len=:), allocatable Source Code pure function OS_NAME ( os ) integer , intent ( in ) :: os character ( len = :), allocatable :: OS_NAME select case ( os ) case ( OS_LINUX ); OS_NAME = \"Linux\" case ( OS_MACOS ); OS_NAME = \"macOS\" case ( OS_WINDOWS ); OS_NAME = \"Windows\" case ( OS_CYGWIN ); OS_NAME = \"Cygwin\" case ( OS_SOLARIS ); OS_NAME = \"Solaris\" case ( OS_FREEBSD ); OS_NAME = \"FreeBSD\" case ( OS_OPENBSD ); OS_NAME = \"OpenBSD\" case ( OS_UNKNOWN ); OS_NAME = \"Unknown\" case default ; OS_NAME = \"UNKNOWN\" end select end function OS_NAME","tags":"","url":"proc/os_name.html"},{"title":"delete_env – Fortran-lang/fpm","text":"public function delete_env(name) result(success) Deletes an environment variable for the current environment using the C standard library\nReturns an error if the variable did not exist in the first place C strings Call setenv Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: name Variable name Return Value logical Source Code logical function delete_env ( name ) result ( success ) !> Variable name character ( * ), intent ( in ) :: name ! Local variables integer ( c_int ) :: cerr character ( kind = c_char , len = 1 ), allocatable :: c_name (:) interface integer ( c_int ) function c_unsetenv ( envname ) bind ( C , name = \"c_unsetenv\" ) import c_int , c_char implicit none !> Pointer to the name string character ( kind = c_char , len = 1 ), intent ( in ) :: envname ( * ) end function c_unsetenv end interface !> C strings call f2cs ( name , c_name ) !> Call setenv #ifndef FPM_BOOTSTRAP cerr = c_unsetenv ( c_name ) #endif success = cerr == 0_c_int end function delete_env","tags":"","url":"proc/delete_env.html"},{"title":"get_command_arguments_quoted – Fortran-lang/fpm","text":"public function get_command_arguments_quoted() result(args) Arguments None Return Value character(len=:), allocatable Source Code function get_command_arguments_quoted () result ( args ) character ( len = :), allocatable :: args character ( len = :), allocatable :: arg character ( len = 1 ) :: quote integer :: ilength , istatus , i ilength = 0 args = '' quote = merge ( '\"' , \"'\" , separator () == '\\') do i=2,command_argument_count() ! look at all arguments after subcommand call get_command_argument(number=i,length=ilength,status=istatus) if(istatus /= 0) then write(stderr,' ( * ( g0 , 1 x )) ')' < ERROR >* get_command_arguments_stack * error obtaining argument ',i exit else if(allocated(arg))deallocate(arg) allocate(character(len=ilength) :: arg) call get_command_argument(number=i,value=arg,length=ilength,status=istatus) if(istatus /= 0) then write(stderr,' ( * ( g0 , 1 x )) ')' < ERROR >* get_command_arguments_stack * error obtaining argument ',i exit elseif(ilength>0)then if(index(arg//' ',' - ')/=1)then args=args//quote//arg//quote//' ' elseif(index(arg,' ')/=0)then args=args//quote//arg//quote//' ' else args=args//arg//' ' endif else args=args//repeat(quote,2)//' ' endif endif enddo end function get_command_arguments_quoted","tags":"","url":"proc/get_command_arguments_quoted.html"},{"title":"get_env – Fortran-lang/fpm","text":"public function get_env(NAME, DEFAULT) result(VALUE) get named environment variable value. It it is blank or\n not set return the optional default value\n!print , NAME, ” is not defined in the environment. Strange…”\n!print , “This processor doesn’t support environment variables. Boooh!” Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: NAME name of environment variable to get the value of character(len=*), intent(in), optional :: DEFAULT default value to return if the requested value is undefined or blank Return Value character(len=:), allocatable the returned value Source Code function get_env ( NAME , DEFAULT ) result ( VALUE ) implicit none !> name of environment variable to get the value of character ( len =* ), intent ( in ) :: NAME !> default value to return if the requested value is undefined or blank character ( len =* ), intent ( in ), optional :: DEFAULT !> the returned value character ( len = :), allocatable :: VALUE integer :: howbig integer :: stat integer :: length ! get length required to hold value length = 0 if ( NAME /= '' ) then call get_environment_variable ( NAME , length = howbig , status = stat , trim_name = . true .) select case ( stat ) case ( 1 ) !*!print *, NAME, \" is not defined in the environment. Strange...\" VALUE = '' case ( 2 ) !*!print *, \"This processor doesn't support environment variables. Boooh!\" VALUE = '' case default ! make string to hold value of sufficient size allocate ( character ( len = max ( howbig , 1 )) :: VALUE ) ! get value call get_environment_variable ( NAME , VALUE , status = stat , trim_name = . true .) if ( stat /= 0 ) VALUE = '' end select else VALUE = '' endif if ( VALUE == '' . and . present ( DEFAULT )) VALUE = DEFAULT end function get_env","tags":"","url":"proc/get_env.html"},{"title":"get_os_type – Fortran-lang/fpm","text":"public function get_os_type() result(r) Determine the OS type Returns one of OS_UNKNOWN, OS_LINUX, OS_MACOS, OS_WINDOWS, OS_CYGWIN,\nOS_SOLARIS, OS_FREEBSD, OS_OPENBSD. At first, the environment variable OS is checked, which is usually\nfound on Windows. Then, OSTYPE is read in and compared with common\nnames. If this fails too, check the existence of files that can be\nfound on specific system types only. Returns OS_UNKNOWN if the operating system cannot be determined. Arguments None Return Value integer Source Code integer function get_os_type () result ( r ) !! !! Returns one of OS_UNKNOWN, OS_LINUX, OS_MACOS, OS_WINDOWS, OS_CYGWIN, !! OS_SOLARIS, OS_FREEBSD, OS_OPENBSD. !! !! At first, the environment variable `OS` is checked, which is usually !! found on Windows. Then, `OSTYPE` is read in and compared with common !! names. If this fails too, check the existence of files that can be !! found on specific system types only. !! !! Returns OS_UNKNOWN if the operating system cannot be determined. character ( len = 255 ) :: val integer :: length , rc logical :: file_exists logical , save :: first_run = . true . integer , save :: ret = OS_UNKNOWN !$omp threadprivate(ret, first_run) if (. not . first_run ) then r = ret return end if first_run = . false . r = OS_UNKNOWN ! Check environment variable `OSTYPE`. call get_environment_variable ( 'OSTYPE' , val , length , rc ) if ( rc == 0 . and . length > 0 ) then ! Linux if ( index ( val , 'linux' ) > 0 ) then r = OS_LINUX ret = r return end if ! macOS if ( index ( val , 'darwin' ) > 0 ) then r = OS_MACOS ret = r return end if ! Windows, MSYS, MinGW, Git Bash if ( index ( val , 'win' ) > 0 . or . index ( val , 'msys' ) > 0 ) then r = OS_WINDOWS ret = r return end if ! Cygwin if ( index ( val , 'cygwin' ) > 0 ) then r = OS_CYGWIN ret = r return end if ! Solaris, OpenIndiana, ... if ( index ( val , 'SunOS' ) > 0 . or . index ( val , 'solaris' ) > 0 ) then r = OS_SOLARIS ret = r return end if ! FreeBSD if ( index ( val , 'FreeBSD' ) > 0 . or . index ( val , 'freebsd' ) > 0 ) then r = OS_FREEBSD ret = r return end if ! OpenBSD if ( index ( val , 'OpenBSD' ) > 0 . or . index ( val , 'openbsd' ) > 0 ) then r = OS_OPENBSD ret = r return end if end if ! Check environment variable `OS`. call get_environment_variable ( 'OS' , val , length , rc ) if ( rc == 0 . and . length > 0 . and . index ( val , 'Windows_NT' ) > 0 ) then r = OS_WINDOWS ret = r return end if ! Linux inquire ( file = '/etc/os-release' , exist = file_exists ) if ( file_exists ) then r = OS_LINUX ret = r return end if ! macOS inquire ( file = '/usr/bin/sw_vers' , exist = file_exists ) if ( file_exists ) then r = OS_MACOS ret = r return end if ! FreeBSD inquire ( file = '/bin/freebsd-version' , exist = file_exists ) if ( file_exists ) then r = OS_FREEBSD ret = r return end if end function get_os_type","tags":"","url":"proc/get_os_type.html"},{"title":"library_filename – Fortran-lang/fpm","text":"public pure function library_filename(package_name, shared, import, target_os) result(name) Utility function: return library filename Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: package_name logical, intent(in) :: shared Whether it’s a shared library logical, intent(in) :: import Whether it’s for linking (import library) or actual library integer, intent(in) :: target_os Build target OS: one of OS_WINDOWS, OS_MACOS, … Return Value character(len=:), allocatable Source Code pure function library_filename ( package_name , shared , import , target_os ) result ( name ) character ( * ), intent ( in ) :: package_name !> Whether it's a shared library logical , intent ( in ) :: shared !> Whether it's for linking (import library) or actual library logical , intent ( in ) :: import !> Build target OS: one of OS_WINDOWS, OS_MACOS, ... integer , intent ( in ) :: target_os character ( len = :), allocatable :: name if ( shared ) then select case ( target_os ) case ( OS_WINDOWS ) if ( import ) then ! Linking requires the import library name = 'lib' // package_name // '.lib' else ! The actual shared object is a DLL name = 'lib' // package_name // '.dll' end if case ( OS_MACOS ) name = 'lib' // package_name // '.dylib' case default name = 'lib' // package_name // '.so' end select else ! Static library (same for all platforms) name = 'lib' // package_name // '.a' end if end function library_filename","tags":"","url":"proc/library_filename.html"},{"title":"os_is_unix – Fortran-lang/fpm","text":"public function os_is_unix(os) Compare the output of get_os_type or the optional\npassed INTEGER value to the value for OS_WINDOWS\nand return .TRUE. if they match and .FALSE. otherwise Arguments Type Intent Optional Attributes Name integer, intent(in), optional :: os Return Value logical Source Code logical function os_is_unix ( os ) integer , intent ( in ), optional :: os integer :: build_os if ( present ( os )) then build_os = os else build_os = get_os_type () end if os_is_unix = build_os /= OS_WINDOWS end function os_is_unix","tags":"","url":"proc/os_is_unix.html"},{"title":"separator – Fortran-lang/fpm","text":"public function separator() result(sep) NAME separator(3f) - [M_io:ENVIRONMENT] try to determine pathname directory separator character\n(LICENSE:PD) SYNOPSIS function separator() result ( sep ) character ( len = 1 ) :: sep DESCRIPTION First using the name the program was invoked with , then the name returned by an INQUIRE ( 3 f ) of that name , then \".\\NAME\" and \"./NAME\" try to determine the separator character used to separate directory names from file basenames . If a slash or backslash is not found in the name , the environment variable PATH is examined first for a backslash , then a slash . Can be very system dependent . If the queries fail the default returned is \"/\" . EXAMPLE sample usage program demo_separator use M_io , only : separator implicit none write ( * , * ) ' separator = ' , separator () end program demo_separator !write( , )’ unknown system directory path separator’\nifort_bug*!sep_cache=sep Arguments None Return Value character(len=1) ifort_bug*!character(len=1),save :: sep_cache=’ ‘ Source Code function separator () result ( sep ) !> !!##NAME !! separator(3f) - [M_io:ENVIRONMENT] try to determine pathname directory separator character !! (LICENSE:PD) !! !!##SYNOPSIS !! !! function separator() result(sep) !! !! character(len=1) :: sep !! !!##DESCRIPTION !! First using the name the program was invoked with, then the name !! returned by an INQUIRE(3f) of that name, then \".\\NAME\" and \"./NAME\" !! try to determine the separator character used to separate directory !! names from file basenames. !! !! If a slash or backslash is not found in the name, the environment !! variable PATH is examined first for a backslash, then a slash. !! !! Can be very system dependent. If the queries fail the default returned !! is \"/\". !! !!##EXAMPLE !! !! sample usage !! !! program demo_separator !! use M_io, only : separator !! implicit none !! write(*,*)'separator=',separator() !! end program demo_separator ! use the pathname returned as arg0 to determine pathname separator implicit none character ( len = :), allocatable :: arg0 integer :: arg0_length integer :: istat logical :: existing character ( len = 1 ) :: sep !*ifort_bug*!character(len=1),save :: sep_cache=' ' character ( len = 4096 ) :: name character ( len = :), allocatable :: fname !*ifort_bug*! if(sep_cache/=' ')then ! use cached value. NOTE: A parallel code might theoretically use multiple OS !*ifort_bug*! sep=sep_cache !*ifort_bug*! return !*ifort_bug*! endif arg0_length = 0 name = ' ' call get_command_argument ( 0 , length = arg0_length , status = istat ) if ( allocated ( arg0 )) deallocate ( arg0 ) allocate ( character ( len = arg0_length ) :: arg0 ) call get_command_argument ( 0 , arg0 , status = istat ) ! check argument name if ( index ( arg0 , '\\')/=0)then sep=' \\ ' elseif(index(arg0,' / ')/=0)then sep=' / ' else ! try name returned by INQUIRE(3f) existing=.false. name=' ' inquire(file=arg0,iostat=istat,exist=existing,name=name) if(index(name,' \\ ')/=0)then sep=' \\ ' elseif(index(name,' / ')/=0)then sep=' / ' else ! well, try some common syntax and assume in current directory fname=' . \\ '//arg0 inquire(file=fname,iostat=istat,exist=existing) if(existing)then sep=' \\ ' else fname=' . / '//arg0 inquire(file=fname,iostat=istat,exist=existing) if(existing)then sep=' / ' else ! check environment variable PATH sep=merge(' \\ ',' / ',index(get_env(' PATH '),' \\ ')/=0) !*!write(*,*)' < WARNING > unknown system directory path separator ' endif endif endif endif !*ifort_bug*!sep_cache=sep end function separator","tags":"","url":"proc/separator.html"},{"title":"set_env – Fortran-lang/fpm","text":"public function set_env(name, value, overwrite) Set an environment variable for the current environment using the C standard library Overwrite setting\nC strings\nCall setenv Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: name Variable name character(len=*), intent(in) :: value Variable value logical, intent(in), optional :: overwrite Should a former value be overwritten? default = .true. Return Value logical Source Code logical function set_env ( name , value , overwrite ) !> Variable name character ( * ), intent ( in ) :: name !> Variable value character ( * ), intent ( in ) :: value !> Should a former value be overwritten? default = .true. logical , optional , intent ( in ) :: overwrite ! Local variables logical :: can_overwrite integer ( c_int ) :: cover , cerr character ( kind = c_char , len = 1 ), allocatable :: c_value (:), c_name (:) interface integer ( c_int ) function c_setenv ( envname , envval , overwrite ) & bind ( C , name = \"c_setenv\" ) import c_int , c_char implicit none !> Pointer to the name string character ( kind = c_char , len = 1 ), intent ( in ) :: envname ( * ) !> Pointer to the value string character ( kind = c_char , len = 1 ), intent ( in ) :: envval ( * ) !> Overwrite option integer ( c_int ), intent ( in ), value :: overwrite end function c_setenv end interface !> Overwrite setting cerr = 0_c_int can_overwrite = . true . if ( present ( overwrite )) can_overwrite = overwrite cover = merge ( 1_c_int , 0_c_int , can_overwrite ) !> C strings call f2cs ( name , c_name ) call f2cs ( value , c_value ) !> Call setenv #ifndef FPM_BOOTSTRAP cerr = c_setenv ( c_name , c_value , cover ) #endif set_env = cerr == 0_c_int end function set_env","tags":"","url":"proc/set_env.html"},{"title":"init_blas – Fortran-lang/fpm","text":"public subroutine init_blas(this, compiler, all_meta, error) Initialize blas metapackage for the current system\nCleanup\nSet name Assert pkg-config is installed Arguments Type Intent Optional Attributes Name class( metapackage_t ), intent(inout) :: this type( compiler_t ), intent(in) :: compiler type( metapackage_request_t ), intent(in) :: all_meta (:) type( error_t ), intent(out), allocatable :: error Source Code subroutine init_blas ( this , compiler , all_meta , error ) class ( metapackage_t ), intent ( inout ) :: this type ( compiler_t ), intent ( in ) :: compiler type ( metapackage_request_t ), intent ( in ) :: all_meta (:) type ( error_t ), allocatable , intent ( out ) :: error integer :: i character ( len = :), allocatable :: include_flag , libdir character ( * ), parameter :: candidates ( * ) = & [ character ( 20 ) :: 'mkl-dynamic-lp64-tbb' , 'openblas' , 'blas' ] include_flag = get_include_flag ( compiler , \"\" ) !> Cleanup call destroy ( this ) allocate ( this % link_libs ( 0 ), this % incl_dirs ( 0 ), this % external_modules ( 0 )) this % link_flags = string_t ( \"\" ) this % flags = string_t ( \"\" ) this % has_external_modules = . false . !> Set name this % name = \"\" if ( get_os_type () == OS_MACOS ) then if ( compile_and_link_flags_supported ( compiler , \"-framework Accelerate\" )) then call set_compile_and_link_flags ( this , compiler , \"-framework Accelerate\" ) return end if end if if ( compiler % is_intel ()) then if ( get_os_type () == OS_WINDOWS ) then if ( compile_and_link_flags_supported ( compiler , \"/Qmkl\" )) then call set_compile_and_link_flags ( this , compiler , \"/Qmkl\" ) return end if else if ( compile_and_link_flags_supported ( compiler , \"-qmkl\" )) then call set_compile_and_link_flags ( this , compiler , \"-qmkl\" ) return endif end if !> Assert pkg-config is installed if (. not . assert_pkg_config ()) then call fatal_error ( error , 'blas metapackage requires pkg-config to continue lookup' ) return end if do i = 1 , size ( candidates ) if ( pkgcfg_has_package ( trim ( candidates ( i )))) then call add_pkg_config_compile_options ( & this , trim ( candidates ( i )), include_flag , libdir , error ) print * , 'found blas package: ' , trim ( candidates ( i )) return end if end do call fatal_error ( error , 'pkg-config could not find a suitable blas package.' ) end subroutine init_blas","tags":"","url":"proc/init_blas.html"},{"title":"assert_pkg_config – Fortran-lang/fpm","text":"public function assert_pkg_config() Check whether pkg-config is available on the local system Arguments None Return Value logical Source Code logical function assert_pkg_config () integer :: exitcode logical :: success type ( string_t ) :: log call run_wrapper ( wrapper = string_t ( 'pkg-config' ), args = [ string_t ( '-h' )], & exitcode = exitcode , cmd_success = success , screen_output = log ) assert_pkg_config = exitcode == 0 . and . success end function assert_pkg_config","tags":"","url":"proc/assert_pkg_config.html"},{"title":"pkgcfg_get_build_flags – Fortran-lang/fpm","text":"public function pkgcfg_get_build_flags(name, allow_system, error) result(flags) Get build flags (option to include flags from system directories, that \ngfortran does not look into by default) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: name Package name logical, intent(in) :: allow_system Should pkg-config look in system paths? This is necessary for gfortran \nthat doesn’t otherwise look into them type( error_t ), intent(out), allocatable :: error Error flag Return Value type( string_t ), allocatable, (:) List of compile flags Source Code function pkgcfg_get_build_flags ( name , allow_system , error ) result ( flags ) !> Package name character ( * ), intent ( in ) :: name !> Should pkg-config look in system paths? This is necessary for gfortran !> that doesn't otherwise look into them logical , intent ( in ) :: allow_system !> Error flag type ( error_t ), allocatable , intent ( out ) :: error !> List of compile flags type ( string_t ), allocatable :: flags (:) integer :: exitcode , i , nlib logical :: old_had , success , old_allow character (:), allocatable :: old , tokens (:) type ( string_t ) :: log ! Check if the current environment includes system flags old = get_env ( 'PKG_CONFIG_ALLOW_SYSTEM_CFLAGS' , default = 'ERROR' ) old_had = old /= 'ERROR' old_allow = merge ( old == '1' ,. false ., old_had ) ! Set system flags success = set_env ( 'PKG_CONFIG_ALLOW_SYSTEM_CFLAGS' , value = merge ( '1' , '0' , allow_system )) if (. not . success ) then call fatal_error ( error , 'Cannot get pkg-config build flags: environment variable error.' ) return end if ! Now run wrapper call run_wrapper ( wrapper = string_t ( 'pkg-config' ), & args = [ string_t ( name ), string_t ( '--cflags' )], & exitcode = exitcode , cmd_success = success , screen_output = log ) if ( success . and . exitcode == 0 ) then call remove_newline_characters ( log ) ! Split all arguments tokens = shlex_split ( log % s ) nlib = size ( tokens ) allocate ( flags ( nlib )) do i = 1 , nlib flags ( i ) = string_t ( trim ( adjustl ( tokens ( i )))) end do else allocate ( flags ( 0 )) call fatal_error ( error , 'cannot get <' // name // '> build flags from pkg-config' ) end if ! Restore environment variable if ( old_had ) then success = set_env ( 'PKG_CONFIG_ALLOW_SYSTEM_CFLAGS' , value = old ) else success = delete_env ( 'PKG_CONFIG_ALLOW_SYSTEM_CFLAGS' ) end if if (. not . success ) then call fatal_error ( error , 'Cannot get pkg-config build flags: environment variable error.' ) return end if end function pkgcfg_get_build_flags","tags":"","url":"proc/pkgcfg_get_build_flags.html"},{"title":"pkgcfg_get_libs – Fortran-lang/fpm","text":"public function pkgcfg_get_libs(package, error) result(libraries) Get package libraries from pkg-config Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: package Package name type( error_t ), intent(out), allocatable :: error Error handler Return Value type( string_t ), allocatable, (:) A list of libraries Source Code function pkgcfg_get_libs ( package , error ) result ( libraries ) !> Package name character ( * ), intent ( in ) :: package !> Error handler type ( error_t ), allocatable , intent ( out ) :: error !> A list of libraries type ( string_t ), allocatable :: libraries (:) integer :: exitcode , nlib , i logical :: success character ( len = :), allocatable :: tokens (:) type ( string_t ) :: log call run_wrapper ( wrapper = string_t ( 'pkg-config' ), & args = [ string_t ( package ), string_t ( '--libs' )], & exitcode = exitcode , cmd_success = success , screen_output = log ) if ( success . and . exitcode == 0 ) then call remove_newline_characters ( log ) ! Split all arguments tokens = shlex_split ( log % s ) nlib = size ( tokens ) allocate ( libraries ( nlib )) do i = 1 , nlib libraries ( i ) = string_t ( trim ( adjustl ( tokens ( i )))) end do else allocate ( libraries ( 0 )) call fatal_error ( error , 'cannot get <' // package // '> libraries from pkg-config' ) end if end function pkgcfg_get_libs","tags":"","url":"proc/pkgcfg_get_libs.html"},{"title":"pkgcfg_get_version – Fortran-lang/fpm","text":"public function pkgcfg_get_version(package, error) result(screen) Get package version from pkg-config Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: package Package name type( error_t ), intent(out), allocatable :: error Error handler Return Value type( string_t ) Source Code type ( string_t ) function pkgcfg_get_version ( package , error ) result ( screen ) !> Package name character ( * ), intent ( in ) :: package !> Error handler type ( error_t ), allocatable , intent ( out ) :: error integer :: exitcode logical :: success type ( string_t ) :: log call run_wrapper ( wrapper = string_t ( 'pkg-config' ), & args = [ string_t ( package ), string_t ( '--modversion' )], & exitcode = exitcode , cmd_success = success , screen_output = log ) if ( success . and . exitcode == 0 ) then call remove_newline_characters ( log ) screen = log else screen = string_t ( \"\" ) end if end function pkgcfg_get_version","tags":"","url":"proc/pkgcfg_get_version.html"},{"title":"pkgcfg_has_package – Fortran-lang/fpm","text":"public function pkgcfg_has_package(name) result(success) Check if pkgcfg has package pkg-config –exists returns 0 only if the package exists Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: name Package name Return Value logical Source Code logical function pkgcfg_has_package ( name ) result ( success ) !> Package name character ( * ), intent ( in ) :: name integer :: exitcode logical :: cmdok type ( string_t ) :: log call run_wrapper ( wrapper = string_t ( 'pkg-config' ), & args = [ string_t ( name ), string_t ( '--exists' )], & exitcode = exitcode , cmd_success = cmdok , screen_output = log ) !> pkg-config --exists returns 0 only if the package exists success = cmdok . and . exitcode == 0 end function pkgcfg_has_package","tags":"","url":"proc/pkgcfg_has_package.html"},{"title":"pkgcfg_list_all – Fortran-lang/fpm","text":"public function pkgcfg_list_all(error, descriptions) result(modules) Return whole list of available pkg-cfg packages Extract list Arguments Type Intent Optional Attributes Name type( error_t ), intent(out), allocatable :: error Error handler type( string_t ), intent(out), optional, allocatable :: descriptions (:) An optional list of package descriptions Return Value type( string_t ), allocatable, (:) A list of all available packages Source Code function pkgcfg_list_all ( error , descriptions ) result ( modules ) !> Error handler type ( error_t ), allocatable , intent ( out ) :: error !> A list of all available packages type ( string_t ), allocatable :: modules (:) !> An optional list of package descriptions type ( string_t ), optional , allocatable , intent ( out ) :: descriptions (:) integer :: exitcode , i , spc logical :: success character ( len = :), allocatable :: lines (:) type ( string_t ) :: log type ( string_t ), allocatable :: mods (:), descr (:) character ( * ), parameter :: CRLF = achar ( 13 ) // new_line ( 'a' ) call run_wrapper ( wrapper = string_t ( 'pkg-config' ), & args = [ string_t ( '--list-all' )], & exitcode = exitcode , cmd_success = success , screen_output = log ) if (. not .( success . and . exitcode == 0 )) then call fatal_error ( error , 'cannot get pkg-config modules' ) allocate ( modules ( 0 )) return end if !> Extract list call split ( log % s , lines , CRLF ) allocate ( mods ( size ( lines )), descr ( size ( lines ))) do i = 1 , size ( lines ) ! Module names have no spaces spc = index ( lines ( i ), ' ' ) if ( spc > 0 ) then mods ( i ) = string_t ( trim ( adjustl ( lines ( i )( 1 : spc )))) descr ( i ) = string_t ( trim ( adjustl ( lines ( i )( spc + 1 :)))) else mods ( i ) = string_t ( trim ( adjustl ( lines ( i )))) descr ( i ) = string_t ( \"\" ) end if end do call move_alloc ( from = mods , to = modules ) if ( present ( descriptions )) call move_alloc ( from = descr , to = descriptions ) end function pkgcfg_list_all","tags":"","url":"proc/pkgcfg_list_all.html"},{"title":"run_wrapper – Fortran-lang/fpm","text":"public subroutine run_wrapper(wrapper, args, verbose, exitcode, cmd_success, screen_output) Simple call to execute_command_line involving one mpi* wrapper Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: wrapper type( string_t ), intent(in), optional :: args (:) logical, intent(in), optional :: verbose integer, intent(out), optional :: exitcode logical, intent(out), optional :: cmd_success type( string_t ), intent(out), optional :: screen_output Source Code subroutine run_wrapper ( wrapper , args , verbose , exitcode , cmd_success , screen_output ) type ( string_t ), intent ( in ) :: wrapper type ( string_t ), intent ( in ), optional :: args (:) logical , intent ( in ), optional :: verbose integer , intent ( out ), optional :: exitcode logical , intent ( out ), optional :: cmd_success type ( string_t ), intent ( out ), optional :: screen_output logical :: echo_local character (:), allocatable :: redirect_str , command , redirect , line integer :: iunit , iarg , stat , cmdstat if ( present ( verbose )) then echo_local = verbose else echo_local = . false . end if ! No redirection and non-verbose output if ( present ( screen_output )) then redirect = get_temp_filename () redirect_str = \">\" // redirect // \" 2>&1\" else if ( os_is_unix ()) then redirect_str = \" >/dev/null 2>&1\" else redirect_str = \" >NUL 2>&1\" end if end if ! Empty command if ( len_trim ( wrapper ) <= 0 ) then if ( echo_local ) print * , '+ ' if ( present ( exitcode )) exitcode = 0 if ( present ( cmd_success )) cmd_success = . true . if ( present ( screen_output )) screen_output = string_t ( \"\" ) return end if ! Init command command = trim ( wrapper % s ) add_arguments : if ( present ( args )) then do iarg = 1 , size ( args ) if ( len_trim ( args ( iarg )) <= 0 ) cycle command = trim ( command ) // ' ' // args ( iarg )% s end do endif add_arguments if ( echo_local ) print * , '+ ' , command ! Test command call execute_command_line ( command // redirect_str , exitstat = stat , cmdstat = cmdstat ) ! Command successful? if ( present ( cmd_success )) cmd_success = cmdstat == 0 ! Program exit code? if ( present ( exitcode )) exitcode = stat ! Want screen output? if ( present ( screen_output ) . and . cmdstat == 0 ) then allocate ( character ( len = 0 ) :: screen_output % s ) open ( newunit = iunit , file = redirect , status = 'old' , iostat = stat ) if ( stat == 0 ) then do call getline ( iunit , line , stat ) if ( stat /= 0 ) exit screen_output % s = screen_output % s // new_line ( 'a' ) // line if ( echo_local ) write ( * , '(A)' ) trim ( line ) end do ! Close and delete file close ( iunit , status = 'delete' ) else call fpm_stop ( 1 , 'cannot read temporary file from successful MPI wrapper' ) endif end if end subroutine run_wrapper","tags":"","url":"proc/run_wrapper.html"},{"title":"MPI_TYPE_NAME – Fortran-lang/fpm","text":"public pure function MPI_TYPE_NAME(mpilib) result(name) Return a name for the MPI library Arguments Type Intent Optional Attributes Name integer, intent(in) :: mpilib Return Value character(len=:), allocatable Source Code pure function MPI_TYPE_NAME ( mpilib ) result ( name ) integer , intent ( in ) :: mpilib character ( len = :), allocatable :: name select case ( mpilib ) case ( MPI_TYPE_NONE ); name = \"none\" case ( MPI_TYPE_OPENMPI ); name = \"OpenMPI\" case ( MPI_TYPE_MPICH ); name = \"MPICH\" case ( MPI_TYPE_INTEL ); name = \"INTELMPI\" case ( MPI_TYPE_MSMPI ); name = \"MS-MPI\" case default ; name = \"UNKNOWN\" end select end function MPI_TYPE_NAME","tags":"","url":"proc/mpi_type_name.html"},{"title":"init_mpi – Fortran-lang/fpm","text":"public subroutine init_mpi(this, compiler, all_meta, error) Initialize MPI metapackage for the current system\nCleanup Set name Get all candidate MPI wrappers\nNo wrapper compiler fit. Are we on Windows? use MSMPI-specific search\nAll attempts failed\nIf there’s only an available Fortran wrapper, and the compiler’s different than fpm’s baseline\nfortran compiler suite, we still want to enable C language flags as that is most likely being\nABI-compatible anyways. However, issues may arise.\nsee e.g. Homebrew with clabng C/C++ and GNU fortran at https://gitlab.kitware.com/cmake/cmake/-/issues/18139\nInitialize MPI package from wrapper command\nRequest Fortran implicit typing\nNot all MPI implementations offer modules mpi and mpi_f08: hence, include them\nto the list of external modules, so they won’t be requested as standard source files Arguments Type Intent Optional Attributes Name class( metapackage_t ), intent(inout) :: this type( compiler_t ), intent(in) :: compiler type( metapackage_request_t ), intent(in) :: all_meta (:) type( error_t ), intent(out), allocatable :: error Source Code subroutine init_mpi ( this , compiler , all_meta , error ) class ( metapackage_t ), intent ( inout ) :: this type ( compiler_t ), intent ( in ) :: compiler type ( metapackage_request_t ), intent ( in ) :: all_meta (:) type ( error_t ), allocatable , intent ( out ) :: error type ( string_t ), allocatable :: c_wrappers (:), cpp_wrappers (:), fort_wrappers (:) type ( string_t ) :: output , fwrap , cwrap , cxxwrap character ( 256 ) :: msg_out character ( len = :), allocatable :: tokens (:) integer :: wcfit ( 3 ), mpilib ( 3 ), ic , icpp , i logical :: found !> Cleanup call destroy ( this ) !> Set name this % name = \"mpi\" !> Get all candidate MPI wrappers call mpi_wrappers ( compiler , fort_wrappers , c_wrappers , cpp_wrappers ) if ( verbose ) print 1 , size ( fort_wrappers ), size ( c_wrappers ), size ( cpp_wrappers ) call wrapper_compiler_fit ( fort_wrappers , c_wrappers , cpp_wrappers , compiler , wcfit , mpilib , error ) if ( allocated ( error ) . or . all ( wcfit == 0 )) then !> No wrapper compiler fit. Are we on Windows? use MSMPI-specific search found = msmpi_init ( this , compiler , error ) if ( allocated ( error )) return !> All attempts failed if (. not . found ) then call fatal_error ( error , \"cannot find MPI wrappers or libraries for \" // compiler % name () // \" compiler\" ) return endif else if ( wcfit ( LANG_FORTRAN ) > 0 ) fwrap = fort_wrappers ( wcfit ( LANG_FORTRAN )) if ( wcfit ( LANG_C ) > 0 ) cwrap = c_wrappers ( wcfit ( LANG_C )) if ( wcfit ( LANG_CXX ) > 0 ) cxxwrap = cpp_wrappers ( wcfit ( LANG_CXX )) !> If there's only an available Fortran wrapper, and the compiler's different than fpm's baseline !> fortran compiler suite, we still want to enable C language flags as that is most likely being !> ABI-compatible anyways. However, issues may arise. !> see e.g. Homebrew with clabng C/C++ and GNU fortran at https://gitlab.kitware.com/cmake/cmake/-/issues/18139 if ( wcfit ( LANG_FORTRAN ) > 0 . and . all ( wcfit ([ LANG_C , LANG_CXX ]) == 0 )) then cwrap = fort_wrappers ( wcfit ( LANG_FORTRAN )) cxxwrap = fort_wrappers ( wcfit ( LANG_FORTRAN )) end if if ( verbose ) print * , '+ MPI fortran wrapper: ' , fwrap % s if ( verbose ) print * , '+ MPI c wrapper: ' , cwrap % s if ( verbose ) print * , '+ MPI c++ wrapper: ' , cxxwrap % s !> Initialize MPI package from wrapper command call init_mpi_from_wrappers ( this , compiler , mpilib ( LANG_FORTRAN ), fwrap , cwrap , cxxwrap , error ) if ( allocated ( error )) return !> Request Fortran implicit typing if ( mpilib ( LANG_FORTRAN ) /= MPI_TYPE_INTEL ) then allocate ( this % fortran ) this % fortran % implicit_typing = . true . this % fortran % implicit_external = . true . endif end if !> Not all MPI implementations offer modules mpi and mpi_f08: hence, include them !> to the list of external modules, so they won't be requested as standard source files this % has_external_modules = . true . this % external_modules = [ string_t ( \"mpi\" ), string_t ( \"mpi_f08\" )] 1 format ( 'MPI wrappers found: fortran=' , i0 , ' c=' , i0 , ' c++=' , i0 ) end subroutine init_mpi","tags":"","url":"proc/init_mpi.html"},{"title":"new_package – Fortran-lang/fpm","text":"public subroutine new_package(self, table, root, error) Construct a new package configuration from a TOML data structure Arguments Type Intent Optional Attributes Name type( package_config_t ), intent(out) :: self Instance of the package configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in), optional :: root Root directory of the manifest type( error_t ), intent(out), allocatable :: error Error handling Source Code subroutine new_package ( self , table , root , error ) !> Instance of the package configuration type ( package_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Root directory of the manifest character ( len =* ), intent ( in ), optional :: root !> Error handling type ( error_t ), allocatable , intent ( out ) :: error ! Backspace (8), tabulator (9), newline (10), formfeed (12) and carriage ! return (13) are invalid in package names character ( len =* ), parameter :: invalid_chars = & achar ( 8 ) // achar ( 9 ) // achar ( 10 ) // achar ( 12 ) // achar ( 13 ) type ( toml_table ), pointer :: child , node type ( toml_array ), pointer :: children character ( len = :), allocatable :: version , version_file integer :: ii , nn , stat , io call check ( table , error ) if ( allocated ( error )) return call get_value ( table , \"name\" , self % name ) if (. not . allocated ( self % name )) then call syntax_error ( error , \"Could not retrieve package name\" ) return end if if ( bad_name_error ( error , 'package' , self % name )) then return endif call get_value ( table , \"license\" , self % license ) call get_value ( table , \"author\" , self % author ) call get_value ( table , \"maintainer\" , self % maintainer ) call get_value ( table , \"copyright\" , self % copyright ) if ( len ( self % name ) <= 0 ) then call syntax_error ( error , \"Package name must be a non-empty string\" ) return end if ii = scan ( self % name , invalid_chars ) if ( ii > 0 ) then call syntax_error ( error , \"Package name contains invalid characters\" ) return end if call get_value ( table , \"build\" , child , requested = . true ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Type mismatch for build entry, must be a table\" ) return end if call new_build_config ( self % build , child , self % name , error ) if ( allocated ( error )) return call get_value ( table , \"install\" , child , requested = . true ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Type mismatch for install entry, must be a table\" ) return end if call new_install_config ( self % install , child , error ) if ( allocated ( error )) return call get_value ( table , \"fortran\" , child , requested = . true ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Type mismatch for fortran entry, must be a table\" ) return end if call new_fortran_config ( self % fortran , child , error ) if ( allocated ( error )) return call get_value ( table , \"version\" , version , \"0\" ) call new_version ( self % version , version , error ) if ( allocated ( error ) . and . present ( root )) then version_file = join_path ( root , version ) if ( exists ( version_file )) then deallocate ( error ) open ( file = version_file , newunit = io , iostat = stat ) if ( stat == 0 ) then call getline ( io , version , iostat = stat ) end if if ( stat == 0 ) then close ( io , iostat = stat ) end if if ( stat == 0 ) then call new_version ( self % version , version , error ) else call fatal_error ( error , \"Reading version number from file '\" & & // version_file // \"' failed\" ) end if end if end if if ( allocated ( error )) return call get_value ( table , \"dependencies\" , child , requested = . false .) if ( associated ( child )) then call new_dependencies ( self % dependency , child , root , self % meta , error ) if ( allocated ( error )) return end if call get_value ( table , \"dev-dependencies\" , child , requested = . false .) if ( associated ( child )) then call new_dependencies ( self % dev_dependency , child , root , error = error ) if ( allocated ( error )) return end if call get_value ( table , \"library\" , child , requested = . false .) if ( associated ( child )) then allocate ( self % library ) call new_library ( self % library , child , error ) if ( allocated ( error )) return end if call get_value ( table , \"profiles\" , child , requested = . false .) if ( associated ( child )) then call new_profiles ( self % profiles , child , error ) if ( allocated ( error )) return else self % profiles = get_default_profiles ( error ) if ( allocated ( error )) return end if call get_value ( table , \"executable\" , children , requested = . false .) if ( associated ( children )) then nn = len ( children ) allocate ( self % executable ( nn )) do ii = 1 , nn call get_value ( children , ii , node , stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Could not retrieve executable from array entry\" ) exit end if call new_executable ( self % executable ( ii ), node , error ) if ( allocated ( error )) exit end do if ( allocated ( error )) return call unique_programs ( self % executable , error ) if ( allocated ( error )) return end if call get_value ( table , \"example\" , children , requested = . false .) if ( associated ( children )) then nn = len ( children ) allocate ( self % example ( nn )) do ii = 1 , nn call get_value ( children , ii , node , stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Could not retrieve example from array entry\" ) exit end if call new_example ( self % example ( ii ), node , error ) if ( allocated ( error )) exit end do if ( allocated ( error )) return call unique_programs ( self % example , error ) if ( allocated ( error )) return if ( allocated ( self % executable )) then call unique_programs ( self % executable , self % example , error ) if ( allocated ( error )) return end if end if call get_value ( table , \"test\" , children , requested = . false .) if ( associated ( children )) then nn = len ( children ) allocate ( self % test ( nn )) do ii = 1 , nn call get_value ( children , ii , node , stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Could not retrieve test from array entry\" ) exit end if call new_test ( self % test ( ii ), node , error ) if ( allocated ( error )) exit end do if ( allocated ( error )) return call unique_programs ( self % test , error ) if ( allocated ( error )) return end if call get_value ( table , \"preprocess\" , child , requested = . false .) if ( associated ( child )) then call new_preprocessors ( self % preprocess , child , error ) if ( allocated ( error )) return end if end subroutine new_package","tags":"","url":"proc/new_package.html"},{"title":"bad_name_error – Fortran-lang/fpm","text":"public function bad_name_error(error, label, name) Arguments Type Intent Optional Attributes Name type( error_t ), intent(out), allocatable :: error Instance of the error data character(len=*), intent(in) :: label Error message label to add to message character(len=*), intent(in) :: name name value to check Return Value logical Source Code function bad_name_error ( error , label , name ) !> Instance of the error data type ( error_t ), allocatable , intent ( out ) :: error !> Error message label to add to message character ( len =* ), intent ( in ) :: label !> name value to check character ( len =* ), intent ( in ) :: name logical :: bad_name_error if (. not . is_fortran_name ( to_fortran_name ( name ))) then bad_name_error = . true . allocate ( error ) error % message = 'manifest file syntax error: ' // label // ' name must be composed only of & &alphanumerics, \"-\" and \"_\" and start with a letter ::' // name else bad_name_error = . false . endif end function bad_name_error","tags":"","url":"proc/bad_name_error.html"},{"title":"fatal_error – Fortran-lang/fpm","text":"public subroutine fatal_error(error, message) Generic fatal runtime error Arguments Type Intent Optional Attributes Name type( error_t ), intent(out), allocatable :: error Instance of the error data character(len=*), intent(in) :: message Error message Source Code subroutine fatal_error ( error , message ) !> Instance of the error data type ( error_t ), allocatable , intent ( out ) :: error !> Error message character ( len =* ), intent ( in ) :: message allocate ( error ) error % message = message end subroutine fatal_error","tags":"","url":"proc/fatal_error.html"},{"title":"file_not_found_error – Fortran-lang/fpm","text":"public subroutine file_not_found_error(error, file_name) Error created when a file is missing or not found Arguments Type Intent Optional Attributes Name type( error_t ), intent(out), allocatable :: error Instance of the error data character(len=*), intent(in) :: file_name Name of the missing file Source Code subroutine file_not_found_error ( error , file_name ) !> Instance of the error data type ( error_t ), allocatable , intent ( out ) :: error !> Name of the missing file character ( len =* ), intent ( in ) :: file_name allocate ( error ) error % message = \"'\" // file_name // \"' could not be found, check if the file exists\" end subroutine file_not_found_error","tags":"","url":"proc/file_not_found_error.html"},{"title":"file_parse_error – Fortran-lang/fpm","text":"public subroutine file_parse_error(error, file_name, message, line_num, line_string, line_col) Error created when file parsing fails Arguments Type Intent Optional Attributes Name type( error_t ), intent(out), allocatable :: error Instance of the error data character(len=*), intent(in) :: file_name Name of file character(len=*), intent(in) :: message Parse error message integer, intent(in), optional :: line_num Line number of parse error character(len=*), intent(in), optional :: line_string Line context string integer, intent(in), optional :: line_col Line context column Source Code subroutine file_parse_error ( error , file_name , message , line_num , & line_string , line_col ) !> Instance of the error data type ( error_t ), allocatable , intent ( out ) :: error !> Name of file character ( len =* ), intent ( in ) :: file_name !> Parse error message character ( len =* ), intent ( in ) :: message !> Line number of parse error integer , intent ( in ), optional :: line_num !> Line context string character ( len =* ), intent ( in ), optional :: line_string !> Line context column integer , intent ( in ), optional :: line_col character ( 50 ) :: temp_string allocate ( error ) error % message = 'Parse error: ' // message // new_line ( 'a' ) error % message = error % message // file_name if ( present ( line_num )) then write ( temp_string , '(I0)' ) line_num error % message = error % message // ':' // trim ( temp_string ) end if if ( present ( line_col )) then if ( line_col > 0 ) then write ( temp_string , '(I0)' ) line_col error % message = error % message // ':' // trim ( temp_string ) end if end if if ( present ( line_string )) then error % message = error % message // new_line ( 'a' ) error % message = error % message // ' | ' // line_string if ( present ( line_col )) then if ( line_col > 0 ) then error % message = error % message // new_line ( 'a' ) error % message = error % message // ' | ' // repeat ( ' ' , line_col - 1 ) // '^' end if end if end if end subroutine file_parse_error","tags":"","url":"proc/file_parse_error.html"},{"title":"fpm_stop – Fortran-lang/fpm","text":"public subroutine fpm_stop(value, message) Arguments Type Intent Optional Attributes Name integer, intent(in) :: value value to use on STOP character(len=*), intent(in) :: message Error message Source Code subroutine fpm_stop ( value , message ) ! TODO: if verbose mode, call ERROR STOP instead of STOP ! TODO: if M_escape is used, add color ! to work with older compilers might need a case statement for values !> value to use on STOP integer , intent ( in ) :: value !> Error message character ( len =* ), intent ( in ) :: message integer :: iostat if ( message /= '' ) then flush ( unit = stderr , iostat = iostat ) flush ( unit = stdout , iostat = iostat ) if ( value > 0 ) then write ( stderr , '(\" \",a)' ) trim ( message ) else write ( stderr , '(\" \",a)' ) trim ( message ) endif flush ( unit = stderr , iostat = iostat ) endif stop value end subroutine fpm_stop","tags":"","url":"proc/fpm_stop.html"},{"title":"syntax_error – Fortran-lang/fpm","text":"public subroutine syntax_error(error, message) Arguments Type Intent Optional Attributes Name type( error_t ), intent(out), allocatable :: error Instance of the error data character(len=*), intent(in) :: message Error message Source Code subroutine syntax_error ( error , message ) !> Instance of the error data type ( error_t ), allocatable , intent ( out ) :: error !> Error message character ( len =* ), intent ( in ) :: message allocate ( error ) error % message = message end subroutine syntax_error","tags":"","url":"proc/syntax_error.html"},{"title":"init_openmp – Fortran-lang/fpm","text":"public subroutine init_openmp(this, compiler, all_meta, error) Initialize OpenMP metapackage for the current system\nCleanup Set name OpenMP has compiler flags\nOpenMP flags should be added to Arguments Type Intent Optional Attributes Name class( metapackage_t ), intent(inout) :: this type( compiler_t ), intent(in) :: compiler type( metapackage_request_t ), intent(in) :: all_meta (:) type( error_t ), intent(out), allocatable :: error Source Code subroutine init_openmp ( this , compiler , all_meta , error ) class ( metapackage_t ), intent ( inout ) :: this type ( compiler_t ), intent ( in ) :: compiler type ( metapackage_request_t ), intent ( in ) :: all_meta (:) type ( error_t ), allocatable , intent ( out ) :: error !> Cleanup call destroy ( this ) !> Set name this % name = \"openmp\" !> OpenMP has compiler flags this % has_build_flags = . true . this % has_link_flags = . true . !> OpenMP flags should be added to which_compiler : select case ( compiler % id ) case ( id_gcc , id_f95 ) this % flags = string_t ( flag_gnu_openmp ) this % link_flags = string_t ( flag_gnu_openmp ) case ( id_intel_classic_windows , id_intel_llvm_windows ) this % flags = string_t ( flag_intel_openmp_win ) this % link_flags = string_t ( flag_intel_openmp_win ) case ( id_intel_classic_nix , id_intel_classic_mac ,& id_intel_llvm_nix ) this % flags = string_t ( flag_intel_openmp ) this % link_flags = string_t ( flag_intel_openmp ) case ( id_pgi , id_nvhpc ) this % flags = string_t ( flag_pgi_openmp ) this % link_flags = string_t ( flag_pgi_openmp ) case ( id_ibmxl ) this % flags = string_t ( \" -qsmp=omp\" ) this % link_flags = string_t ( \" -qsmp=omp\" ) case ( id_nag ) this % flags = string_t ( flag_nag_openmp ) this % link_flags = string_t ( flag_nag_openmp ) case ( id_lfortran ) this % flags = string_t ( flag_lfortran_openmp ) this % link_flags = string_t ( flag_lfortran_openmp ) case ( id_flang , id_flang_new ) this % flags = string_t ( flag_flang_new_openmp ) this % link_flags = string_t ( flag_flang_new_openmp ) case default call fatal_error ( error , 'openmp not supported on compiler ' // compiler % name () // ' yet' ) end select which_compiler end subroutine init_openmp","tags":"","url":"proc/init_openmp.html"},{"title":"new_build_config – Fortran-lang/fpm","text":"public subroutine new_build_config(self, table, package_name, error) Construct a new build configuration from a TOML data structure Module naming: fist, attempt boolean value first Value found, but not a boolean. Attempt to read a prefix string Arguments Type Intent Optional Attributes Name type( build_config_t ), intent(out) :: self Instance of the build configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in) :: package_name Package name type( error_t ), intent(out), allocatable :: error Error handling Source Code subroutine new_build_config ( self , table , package_name , error ) !> Instance of the build configuration type ( build_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Package name character ( len =* ), intent ( in ) :: package_name !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: stat call check ( table , package_name , error ) if ( allocated ( error )) return call get_value ( table , \"auto-executables\" , self % auto_executables , . true ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error while reading value for 'auto-executables' in fpm.toml, expecting logical\" ) return end if call get_value ( table , \"auto-tests\" , self % auto_tests , . true ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error while reading value for 'auto-tests' in fpm.toml, expecting logical\" ) return end if call get_value ( table , \"auto-examples\" , self % auto_examples , . true ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error while reading value for 'auto-examples' in fpm.toml, expecting logical\" ) return end if !> Module naming: fist, attempt boolean value first call get_value ( table , \"module-naming\" , self % module_naming , . false ., stat = stat ) if ( stat == toml_stat % success ) then ! Boolean value found. Set no custom prefix. This also falls back to key not provided if ( allocated ( self % module_prefix % s )) deallocate ( self % module_prefix % s ) else !> Value found, but not a boolean. Attempt to read a prefix string call get_value ( table , \"module-naming\" , self % module_prefix % s ) if (. not . allocated ( self % module_prefix % s )) then call syntax_error ( error , \"Could not read value for 'module-naming' in fpm.toml, expecting logical or a string\" ) return end if if (. not . is_valid_module_prefix ( self % module_prefix )) then call syntax_error ( error , \"Invalid custom module name prefix for in fpm.toml: <\" // self % module_prefix % s // & \">, expecting a valid alphanumeric string\" ) return end if ! Set module naming to ON self % module_naming = . true . end if call get_list ( table , \"link\" , self % link , error ) if ( allocated ( error )) return call get_list ( table , \"external-modules\" , self % external_modules , error ) if ( allocated ( error )) return end subroutine new_build_config","tags":"","url":"proc/new_build_config.html"},{"title":"get_global_settings – Fortran-lang/fpm","text":"public subroutine get_global_settings(global_settings, error) Obtain global settings from the global config file. Arguments Type Intent Optional Attributes Name type( fpm_global_settings ), intent(inout) :: global_settings Global settings to be obtained. type( error_t ), intent(out), allocatable :: error Error reading config file.","tags":"","url":"proc/get_global_settings.html"},{"title":"get_registry_settings – Fortran-lang/fpm","text":"public subroutine get_registry_settings(table, global_settings, error) Read registry settings from the global config file. Arguments Type Intent Optional Attributes Name type(toml_table), intent(inout), target :: table The [registry] subtable from the global config file. type( fpm_global_settings ), intent(inout) :: global_settings The global settings which can be filled with the registry settings. type( error_t ), intent(out), allocatable :: error Error handling.","tags":"","url":"proc/get_registry_settings.html"},{"title":"check_and_read_pkg_data – Fortran-lang/fpm","text":"public subroutine check_and_read_pkg_data(json, node, download_url, version, error) Arguments Type Intent Optional Attributes Name type(json_object), intent(inout) :: json class( dependency_node_t ), intent(in) :: node character(len=:), intent(out), allocatable :: download_url type( version_t ), intent(out) :: version type( error_t ), intent(out), allocatable :: error","tags":"","url":"proc/check_and_read_pkg_data.html"},{"title":"destroy_dependency_node – Fortran-lang/fpm","text":"public elemental subroutine destroy_dependency_node(self) Destructor Arguments Type Intent Optional Attributes Name class( dependency_node_t ), intent(inout) :: self Source Code elemental subroutine destroy_dependency_node ( self ) class ( dependency_node_t ), intent ( inout ) :: self integer :: ierr call dependency_destroy ( self ) deallocate ( self % version , stat = ierr ) deallocate ( self % proj_dir , stat = ierr ) deallocate ( self % revision , stat = ierr ) deallocate ( self % package_dep , stat = ierr ) self % done = . false . self % update = . false . self % cached = . false . end subroutine destroy_dependency_node","tags":"","url":"proc/destroy_dependency_node.html"},{"title":"new_dependency_node – Fortran-lang/fpm","text":"public subroutine new_dependency_node(self, dependency, version, proj_dir, update) Create a new dependency node from a configuration Arguments Type Intent Optional Attributes Name type( dependency_node_t ), intent(out) :: self Instance of the dependency node type( dependency_config_t ), intent(in) :: dependency Dependency configuration data type( version_t ), intent(in), optional :: version Version of the dependency character(len=*), intent(in), optional :: proj_dir Installation prefix of the dependency logical, intent(in), optional :: update Dependency should be updated Source Code subroutine new_dependency_node ( self , dependency , version , proj_dir , update ) !> Instance of the dependency node type ( dependency_node_t ), intent ( out ) :: self !> Dependency configuration data type ( dependency_config_t ), intent ( in ) :: dependency !> Version of the dependency type ( version_t ), intent ( in ), optional :: version !> Installation prefix of the dependency character ( len =* ), intent ( in ), optional :: proj_dir !> Dependency should be updated logical , intent ( in ), optional :: update self % dependency_config_t = dependency if ( present ( version )) then self % version = version end if if ( present ( proj_dir )) then self % proj_dir = proj_dir end if if ( present ( update )) then self % update = update end if end subroutine new_dependency_node","tags":"","url":"proc/new_dependency_node.html"},{"title":"new_dependency_tree – Fortran-lang/fpm","text":"public subroutine new_dependency_tree(self, verbosity, cache, path_to_config) Create a new dependency tree Arguments Type Intent Optional Attributes Name type( dependency_tree_t ), intent(out) :: self Instance of the dependency tree integer, intent(in), optional :: verbosity Verbosity of printout character(len=*), intent(in), optional :: cache Name of the cache file character(len=*), intent(in), optional :: path_to_config Path to the global config file. Source Code subroutine new_dependency_tree ( self , verbosity , cache , path_to_config ) !> Instance of the dependency tree type ( dependency_tree_t ), intent ( out ) :: self !> Verbosity of printout integer , intent ( in ), optional :: verbosity !> Name of the cache file character ( len =* ), intent ( in ), optional :: cache !> Path to the global config file. character ( len =* ), intent ( in ), optional :: path_to_config call resize ( self % dep ) self % dep_dir = join_path ( \"build\" , \"dependencies\" ) if ( present ( verbosity )) self % verbosity = verbosity if ( present ( cache )) self % cache = cache if ( present ( path_to_config )) self % path_to_config = path_to_config end subroutine new_dependency_tree","tags":"","url":"proc/new_dependency_tree.html"},{"title":"resize – Fortran-lang/fpm","text":"public interface resize Overloaded reallocation interface Module Procedures private pure subroutine resize_dependency_node(var, n) Reallocate a list of dependencies Arguments Type Intent Optional Attributes Name type( dependency_node_t ), intent(inout), allocatable :: var (:) Instance of the array to be resized integer, intent(in), optional :: n Dimension of the final array size","tags":"","url":"interface/resize.html"},{"title":"descriptor_name – Fortran-lang/fpm","text":"public pure function descriptor_name(descriptor) result(name) Code git descriptor to a string Arguments Type Intent Optional Attributes Name integer, intent(in) :: descriptor Return Value character(len=:), allocatable Source Code pure function descriptor_name ( descriptor ) result ( name ) integer , intent ( in ) :: descriptor character ( len = :), allocatable :: name select case ( descriptor ) case ( git_descriptor % default ); name = \"default\" case ( git_descriptor % branch ); name = \"branch\" case ( git_descriptor % tag ); name = \"tag\" case ( git_descriptor % revision ); name = \"revision\" case default ; name = \"ERROR\" end select end function descriptor_name","tags":"","url":"proc/descriptor_name.html"},{"title":"git_is_same – Fortran-lang/fpm","text":"public function git_is_same(this, that) Check that two git targets are equal\nAll checks passed! Type Bound git_target_t Arguments Type Intent Optional Attributes Name class( git_target_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical Source Code logical function git_is_same ( this , that ) class ( git_target_t ), intent ( in ) :: this class ( serializable_t ), intent ( in ) :: that git_is_same = . false . select type ( other => that ) type is ( git_target_t ) if (. not .( this % descriptor == other % descriptor )) return if ( allocated ( this % url ) . neqv . allocated ( other % url )) return if ( allocated ( this % url )) then if (. not .( this % url == other % url )) return end if if ( allocated ( this % object ) . neqv . allocated ( other % object )) return if ( allocated ( this % object )) then if (. not .( this % object == other % object )) return end if class default ! Not the same type return end select !> All checks passed! git_is_same = . true . end function git_is_same","tags":"","url":"proc/git_is_same.html"},{"title":"git_matches_manifest – Fortran-lang/fpm","text":"public function git_matches_manifest(cached, manifest, verbosity, iunit) Check that a cached dependency matches a manifest request The manifest dependency only contains partial information (what’s requested),\nwhile the cached dependency always stores a commit hash because it’s built\nafter the repo is available (saved as git_descriptor%revision==revision).\nSo, comparing against the descriptor is not reliable Arguments Type Intent Optional Attributes Name type( git_target_t ), intent(in) :: cached Two input git targets type( git_target_t ), intent(in) :: manifest Two input git targets integer, intent(in) :: verbosity integer, intent(in) :: iunit Return Value logical Source Code logical function git_matches_manifest ( cached , manifest , verbosity , iunit ) !> Two input git targets type ( git_target_t ), intent ( in ) :: cached , manifest integer , intent ( in ) :: verbosity , iunit git_matches_manifest = cached % url == manifest % url if (. not . git_matches_manifest ) then if ( verbosity > 1 ) write ( iunit , out_fmt ) \"GIT URL has changed: \" , cached % url , \" vs. \" , manifest % url return endif !> The manifest dependency only contains partial information (what's requested), !> while the cached dependency always stores a commit hash because it's built !> after the repo is available (saved as git_descriptor%revision==revision). !> So, comparing against the descriptor is not reliable git_matches_manifest = allocated ( cached % object ) . eqv . allocated ( manifest % object ) if ( git_matches_manifest . and . allocated ( cached % object )) & git_matches_manifest = cached % object == manifest % object if (. not . git_matches_manifest ) then if ( verbosity > 1 ) write ( iunit , out_fmt ) \"GIT OBJECT has changed: \" , cached % object , \" vs. \" , manifest % object end if end function git_matches_manifest","tags":"","url":"proc/git_matches_manifest.html"},{"title":"git_target_branch – Fortran-lang/fpm","text":"public function git_target_branch(url, branch) result(self) Target a branch in the git repository Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: url Target URL of the git repository character(len=*), intent(in) :: branch Name of the branch of interest Return Value type( git_target_t ) New git target Source Code function git_target_branch ( url , branch ) result ( self ) !> Target URL of the git repository character ( len =* ), intent ( in ) :: url !> Name of the branch of interest character ( len =* ), intent ( in ) :: branch !> New git target type ( git_target_t ) :: self self % descriptor = git_descriptor % branch self % url = url self % object = branch end function git_target_branch","tags":"","url":"proc/git_target_branch.html"},{"title":"git_target_default – Fortran-lang/fpm","text":"public function git_target_default(url) result(self) Default target Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: url Target URL of the git repository Return Value type( git_target_t ) New git target Source Code function git_target_default ( url ) result ( self ) !> Target URL of the git repository character ( len =* ), intent ( in ) :: url !> New git target type ( git_target_t ) :: self self % descriptor = git_descriptor % default self % url = url end function git_target_default","tags":"","url":"proc/git_target_default.html"},{"title":"git_target_revision – Fortran-lang/fpm","text":"public function git_target_revision(url, sha1) result(self) Target a specific git revision Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: url Target URL of the git repository character(len=*), intent(in) :: sha1 Commit hash of interest Return Value type( git_target_t ) New git target Source Code function git_target_revision ( url , sha1 ) result ( self ) !> Target URL of the git repository character ( len =* ), intent ( in ) :: url !> Commit hash of interest character ( len =* ), intent ( in ) :: sha1 !> New git target type ( git_target_t ) :: self self % descriptor = git_descriptor % revision self % url = url self % object = sha1 end function git_target_revision","tags":"","url":"proc/git_target_revision.html"},{"title":"git_target_tag – Fortran-lang/fpm","text":"public function git_target_tag(url, tag) result(self) Target a git tag Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: url Target URL of the git repository character(len=*), intent(in) :: tag Tag name of interest Return Value type( git_target_t ) New git target Source Code function git_target_tag ( url , tag ) result ( self ) !> Target URL of the git repository character ( len =* ), intent ( in ) :: url !> Tag name of interest character ( len =* ), intent ( in ) :: tag !> New git target type ( git_target_t ) :: self self % descriptor = git_descriptor % tag self % url = url self % object = tag end function git_target_tag","tags":"","url":"proc/git_target_tag.html"},{"title":"parse_descriptor – Fortran-lang/fpm","text":"public pure function parse_descriptor(name) Parse git descriptor identifier from a string Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: name Return Value integer Source Code pure integer function parse_descriptor ( name ) character ( len =* ), intent ( in ) :: name select case ( name ) case ( \"default\" ); parse_descriptor = git_descriptor % default case ( \"branch\" ); parse_descriptor = git_descriptor % branch case ( \"tag\" ); parse_descriptor = git_descriptor % tag case ( \"revision\" ); parse_descriptor = git_descriptor % revision case default ; parse_descriptor = git_descriptor % error end select end function parse_descriptor","tags":"","url":"proc/parse_descriptor.html"},{"title":"checkout – Fortran-lang/fpm","text":"public subroutine checkout(self, local_path, error) Type Bound git_target_t Arguments Type Intent Optional Attributes Name class( git_target_t ), intent(in) :: self Instance of the git target character(len=*), intent(in) :: local_path Local path to checkout in type( error_t ), intent(out), allocatable :: error Error Variables Type Visibility Attributes Name Initial character(len=:), public, allocatable :: object integer, public :: stat character(len=:), public, allocatable :: workdir Source Code subroutine checkout ( self , local_path , error ) !> Instance of the git target class ( git_target_t ), intent ( in ) :: self !> Local path to checkout in character ( * ), intent ( in ) :: local_path !> Error type ( error_t ), allocatable , intent ( out ) :: error integer :: stat character ( len = :), allocatable :: object , workdir if ( allocated ( self % object )) then object = self % object else object = 'HEAD' end if workdir = \"--work-tree=\" // local_path // \" --git-dir=\" // join_path ( local_path , \".git\" ) call execute_command_line ( \"git init \" // local_path , exitstat = stat ) if ( stat /= 0 ) then call fatal_error ( error , 'Error while initiating git repository for remote dependency' ) return end if call execute_command_line ( \"git \" // workdir // \" fetch --depth=1 \" // & self % url // \" \" // object , exitstat = stat ) if ( stat /= 0 ) then call fatal_error ( error , 'Error while fetching git repository for remote dependency' ) return end if call execute_command_line ( \"git \" // workdir // \" checkout -qf FETCH_HEAD\" , exitstat = stat ) if ( stat /= 0 ) then call fatal_error ( error , 'Error while checking out git repository for remote dependency' ) return end if end subroutine checkout","tags":"","url":"proc/checkout.html"},{"title":"dump_to_toml – Fortran-lang/fpm","text":"public subroutine dump_to_toml(self, table, error) Dump dependency to toml table Type Bound git_target_t Arguments Type Intent Optional Attributes Name class( git_target_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling Variables Type Visibility Attributes Name Initial integer, public :: ierr Source Code subroutine dump_to_toml ( self , table , error ) !> Instance of the serializable object class ( git_target_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: ierr call set_string ( table , \"descriptor\" , descriptor_name ( self % descriptor ), error , 'git_target_t' ) if ( allocated ( error )) return call set_string ( table , \"url\" , self % url , error , 'git_target_t' ) if ( allocated ( error )) return call set_string ( table , \"object\" , self % object , error , 'git_target_t' ) if ( allocated ( error )) return end subroutine dump_to_toml","tags":"","url":"proc/dump_to_toml~3.html"},{"title":"git_archive – Fortran-lang/fpm","text":"public subroutine git_archive(source, destination, ref, additional_files, verbose, error) Archive a folder using git archive . Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: source Directory to archive. character(len=*), intent(in) :: destination Destination of the archive. character(len=*), intent(in) :: ref (Symbolic) Reference to be archived. character(len=*), intent(in), optional :: additional_files (:) (Optional) list of additional untracked files to be added to the archive. logical, intent(in) :: verbose Print additional information if true. type( error_t ), intent(out), allocatable :: error Error handling. Variables Type Visibility Attributes Name Initial character(len=:), public, allocatable :: add_files character(len=:), public, allocatable :: archive_format character(len=:), public, allocatable :: cmd_output integer, public :: i integer, public :: stat","tags":"","url":"proc/git_archive.html"},{"title":"git_revision – Fortran-lang/fpm","text":"public subroutine git_revision(local_path, object, error) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: local_path Local path to checkout in character(len=:), intent(out), allocatable :: object Git object reference type( error_t ), intent(out), allocatable :: error Error Variables Type Visibility Attributes Name Initial character(len=*), public, parameter :: hexdigits = '0123456789abcdef' integer, public :: iend character(len=:), public, allocatable :: iomsg integer, public :: istart character(len=:), public, allocatable :: line integer, public :: stat character(len=:), public, allocatable :: temp_file integer, public :: unit character(len=:), public, allocatable :: workdir Source Code subroutine git_revision ( local_path , object , error ) !> Local path to checkout in character ( * ), intent ( in ) :: local_path !> Git object reference character ( len = :), allocatable , intent ( out ) :: object !> Error type ( error_t ), allocatable , intent ( out ) :: error integer :: stat , unit , istart , iend character ( len = :), allocatable :: temp_file , line , iomsg , workdir character ( len =* ), parameter :: hexdigits = '0123456789abcdef' workdir = \"--work-tree=\" // local_path // \" --git-dir=\" // join_path ( local_path , \".git\" ) allocate ( temp_file , source = get_temp_filename ()) line = \"git \" // workdir // \" log -n 1 > \" // temp_file call execute_command_line ( line , exitstat = stat ) if ( stat /= 0 ) then call fatal_error ( error , \"Error while retrieving commit information\" ) return end if open ( file = temp_file , newunit = unit ) call getline ( unit , line , stat , iomsg ) if ( stat /= 0 ) then call fatal_error ( error , iomsg ) return end if close ( unit , status = \"delete\" ) ! Tokenize: ! commit 0123456789abcdef (HEAD, ...) istart = scan ( line , ' ' ) + 1 iend = verify ( line ( istart :), hexdigits ) + istart - 1 if ( iend < istart ) iend = len ( line ) object = line ( istart : iend ) end subroutine git_revision","tags":"","url":"proc/git_revision.html"},{"title":"info – Fortran-lang/fpm","text":"public subroutine info(self, unit, verbosity) Show information on git target Type Bound git_target_t Arguments Type Intent Optional Attributes Name class( git_target_t ), intent(in) :: self Instance of the git target integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout Variables Type Visibility Attributes Name Initial character(len=*), public, parameter :: fmt = '(\"#\", 1x, a, t30, a)' integer, public :: pr Source Code subroutine info ( self , unit , verbosity ) !> Instance of the git target class ( git_target_t ), intent ( in ) :: self !> Unit for IO integer , intent ( in ) :: unit !> Verbosity of the printout integer , intent ( in ), optional :: verbosity integer :: pr character ( len =* ), parameter :: fmt = '(\"#\", 1x, a, t30, a)' if ( present ( verbosity )) then pr = verbosity else pr = 1 end if if ( pr < 1 ) return write ( unit , fmt ) \"Git target\" if ( allocated ( self % url )) then write ( unit , fmt ) \"- URL\" , self % url end if if ( allocated ( self % object )) then select case ( self % descriptor ) case default write ( unit , fmt ) \"- object\" , self % object case ( git_descriptor % tag ) write ( unit , fmt ) \"- tag\" , self % object case ( git_descriptor % branch ) write ( unit , fmt ) \"- branch\" , self % object case ( git_descriptor % revision ) write ( unit , fmt ) \"- sha1\" , self % object end select end if end subroutine info","tags":"","url":"proc/info~4.html"},{"title":"load_from_toml – Fortran-lang/fpm","text":"public subroutine load_from_toml(self, table, error) Read dependency from toml table (no checks made at this stage) Target URL of the git repository Additional descriptor of the git object Type Bound git_target_t Arguments Type Intent Optional Attributes Name class( git_target_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling Variables Type Visibility Attributes Name Initial character(len=:), public, allocatable :: descriptor_name Local variables Source Code subroutine load_from_toml ( self , table , error ) !> Instance of the serializable object class ( git_target_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Local variables character ( len = :), allocatable :: descriptor_name call get_value ( table , \"descriptor\" , descriptor_name ) self % descriptor = parse_descriptor ( descriptor_name ) if ( self % descriptor == git_descriptor % error ) then call fatal_error ( error , \"invalid descriptor ID <\" // descriptor_name // \"> in TOML entry\" ) return end if !> Target URL of the git repository call get_value ( table , \"url\" , self % url ) !> Additional descriptor of the git object call get_value ( table , \"object\" , self % object ) end subroutine load_from_toml","tags":"","url":"proc/load_from_toml~3.html"},{"title":"is_meta_package – Fortran-lang/fpm","text":"public function is_meta_package(key) Check local schema for allowed entries Supported metapackages Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: key Instance of the TOML data structure Return Value logical Source Code logical function is_meta_package ( key ) !> Instance of the TOML data structure character ( * ), intent ( in ) :: key select case ( key ) !> Supported metapackages case ( \"openmp\" , \"stdlib\" , \"mpi\" , \"minpack\" , \"hdf5\" , \"netcdf\" , \"blas\" ) is_meta_package = . true . case default is_meta_package = . false . end select end function is_meta_package","tags":"","url":"proc/is_meta_package.html"},{"title":"new_meta_config – Fortran-lang/fpm","text":"public subroutine new_meta_config(self, table, meta_allowed, error) Construct a new build configuration from a TOML data structure The toml table is not checked here because it already passed\nthe “new_dependencies” check Arguments Type Intent Optional Attributes Name type( metapackage_config_t ), intent(out) :: self Instance of the build configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure logical, intent(in) :: meta_allowed (:) List of keys allowed to be metapackages type( error_t ), intent(out), allocatable :: error Error handling Source Code subroutine new_meta_config ( self , table , meta_allowed , error ) !> Instance of the build configuration type ( metapackage_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> List of keys allowed to be metapackages logical , intent ( in ) :: meta_allowed (:) !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: stat !> The toml table is not checked here because it already passed !> the \"new_dependencies\" check call new_meta_request ( self % openmp , \"openmp\" , table , meta_allowed , error ) if ( allocated ( error )) return call new_meta_request ( self % stdlib , \"stdlib\" , table , meta_allowed , error ) if ( allocated ( error )) return call new_meta_request ( self % minpack , \"minpack\" , table , meta_allowed , error ) if ( allocated ( error )) return call new_meta_request ( self % mpi , \"mpi\" , table , meta_allowed , error ) if ( allocated ( error )) return call new_meta_request ( self % hdf5 , \"hdf5\" , table , meta_allowed , error ) if ( allocated ( error )) return call new_meta_request ( self % netcdf , \"netcdf\" , table , meta_allowed , error ) if ( allocated ( error )) return call new_meta_request ( self % blas , \"blas\" , table , meta_allowed , error ) if ( allocated ( error )) return end subroutine new_meta_config","tags":"","url":"proc/new_meta_config.html"},{"title":"new_meta_request – Fortran-lang/fpm","text":"public subroutine new_meta_request(self, key, table, meta_allowed, error) Construct a new metapackage request from the dependencies table Set name\nThe toml table is not checked here because it already passed\nthe “new_dependencies” check Set list of entries that are allowed to be metapackages Arguments Type Intent Optional Attributes Name type( metapackage_request_t ), intent(out) :: self character(len=*), intent(in) :: key The package name type(toml_table), intent(inout) :: table Instance of the TOML data structure logical, intent(in), optional :: meta_allowed (:) List of keys allowed to be metapackages type( error_t ), intent(out), allocatable :: error Error handling Source Code subroutine new_meta_request ( self , key , table , meta_allowed , error ) type ( metapackage_request_t ), intent ( out ) :: self !> The package name character ( len =* ), intent ( in ) :: key !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> List of keys allowed to be metapackages logical , intent ( in ), optional :: meta_allowed (:) !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: stat , i character ( len = :), allocatable :: value logical , allocatable :: allow_meta (:) type ( toml_key ), allocatable :: keys (:) call request_destroy ( self ) !> Set name self % name = key if (. not . is_meta_package ( key )) then call fatal_error ( error , \"Error reading fpm.toml: <\" // key // \"> is not a valid metapackage name\" ) return end if !> The toml table is not checked here because it already passed !> the \"new_dependencies\" check call table % get_keys ( keys ) !> Set list of entries that are allowed to be metapackages if ( present ( meta_allowed )) then if ( size ( meta_allowed ) /= size ( keys )) then call fatal_error ( error , \"Internal error: list of metapackage-enable entries does not match table size\" ) return end if allow_meta = meta_allowed else allocate ( allow_meta ( size ( keys )), source = . true .) endif do i = 1 , size ( keys ) ! Skip standard dependencies if (. not . allow_meta ( i )) cycle if ( keys ( i )% key == key ) then call get_value ( table , key , value ) if (. not . allocated ( value )) then call syntax_error ( error , \"Could not retrieve version string for metapackage key <\" // key // \">. Check syntax\" ) return else call request_parse ( self , value , error ) return endif end if end do ! Key is not present, metapackage not requested return end subroutine new_meta_request","tags":"","url":"proc/new_meta_request.html"},{"title":"change_directory – Fortran-lang/fpm","text":"public subroutine change_directory(path, error) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path type( error_t ), intent(out), allocatable :: error Source Code subroutine change_directory ( path , error ) character ( len =* ), intent ( in ) :: path type ( error_t ), allocatable , intent ( out ) :: error character ( kind = c_char , len = 1 ), allocatable :: cpath (:) integer :: stat allocate ( cpath ( len ( path ) + 1 )) call f_c_character ( path , cpath , len ( path ) + 1 ) stat = chdir_ ( cpath ) if ( stat /= 0 ) then call fatal_error ( error , \"Failed to change directory to '\" // path // \"'\" ) end if end subroutine change_directory","tags":"","url":"proc/change_directory.html"},{"title":"convert_to_absolute_path – Fortran-lang/fpm","text":"public subroutine convert_to_absolute_path(path, error) Converts a path to an absolute, canonical path. Arguments Type Intent Optional Attributes Name character(len=:), intent(inout), allocatable :: path type( error_t ), intent(out), allocatable :: error","tags":"","url":"proc/convert_to_absolute_path.html"},{"title":"get_absolute_path – Fortran-lang/fpm","text":"public subroutine get_absolute_path(path, absolute_path, error) Determine the canonical, absolute path for the given path.\nExpands home folder (~) on both Unix and Windows. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path character(len=:), intent(out), allocatable :: absolute_path type( error_t ), intent(out), allocatable :: error","tags":"","url":"proc/get_absolute_path.html"},{"title":"get_absolute_path_by_cd – Fortran-lang/fpm","text":"public subroutine get_absolute_path_by_cd(path, absolute_path, error) Alternative to get_absolute_path that uses chdir / _chdir to determine the absolute path. get_absolute_path is preferred but get_absolute_path_by_cd can be used in bootstrap mode. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path character(len=:), intent(out), allocatable :: absolute_path type( error_t ), intent(out), allocatable :: error","tags":"","url":"proc/get_absolute_path_by_cd.html"},{"title":"get_current_directory – Fortran-lang/fpm","text":"public subroutine get_current_directory(path, error) Arguments Type Intent Optional Attributes Name character(len=:), intent(out), allocatable :: path type( error_t ), intent(out), allocatable :: error Source Code subroutine get_current_directory ( path , error ) character ( len = :), allocatable , intent ( out ) :: path type ( error_t ), allocatable , intent ( out ) :: error character ( kind = c_char , len = 1 ), allocatable :: cpath (:) type ( c_ptr ) :: tmp allocate ( cpath ( buffersize )) tmp = getcwd_ ( cpath , buffersize ) if ( c_associated ( tmp )) then call c_f_character ( cpath , path ) else call fatal_error ( error , \"Failed to retrieve current directory\" ) end if end subroutine get_current_directory","tags":"","url":"proc/get_current_directory.html"},{"title":"new_fortran_config – Fortran-lang/fpm","text":"public subroutine new_fortran_config(self, table, error) Construct a new build configuration from a TOML data structure Arguments Type Intent Optional Attributes Name type( fortran_config_t ), intent(out) :: self Instance of the fortran configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling Source Code subroutine new_fortran_config ( self , table , error ) !> Instance of the fortran configuration type ( fortran_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: stat character (:), allocatable :: source_form call check ( table , error ) if ( allocated ( error )) return call get_value ( table , \"implicit-typing\" , self % implicit_typing , . false ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error while reading value for 'implicit-typing' in fpm.toml, expecting logical\" ) return end if call get_value ( table , \"implicit-external\" , self % implicit_external , . false ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error while reading value for 'implicit-external' in fpm.toml, expecting logical\" ) return end if call get_value ( table , \"source-form\" , source_form , \"free\" , stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error while reading value for 'source-form' in fpm.toml, expecting logical\" ) return end if select case ( source_form ) case default call fatal_error ( error , \"Value of source-form cannot be '\" // source_form // \"'\" ) return case ( \"free\" , \"fixed\" , \"default\" ) self % source_form = source_form end select end subroutine new_fortran_config","tags":"","url":"proc/new_fortran_config.html"},{"title":"new_test – Fortran-lang/fpm","text":"public subroutine new_test(self, table, error) Construct a new test configuration from a TOML data structure Arguments Type Intent Optional Attributes Name type( test_config_t ), intent(out) :: self Instance of the test configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling Source Code subroutine new_test ( self , table , error ) !> Instance of the test configuration type ( test_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_table ), pointer :: child call check ( table , error ) if ( allocated ( error )) return call get_value ( table , \"name\" , self % name ) if (. not . allocated ( self % name )) then call syntax_error ( error , \"Could not retrieve test name\" ) return end if if ( bad_name_error ( error , 'test' , self % name )) then return endif call get_value ( table , \"source-dir\" , self % source_dir , \"test\" ) call get_value ( table , \"main\" , self % main , \"main.f90\" ) call get_value ( table , \"dependencies\" , child , requested = . false .) if ( associated ( child )) then call new_dependencies ( self % dependency , child , error = error ) if ( allocated ( error )) return end if call get_list ( table , \"link\" , self % link , error ) if ( allocated ( error )) return end subroutine new_test","tags":"","url":"proc/new_test.html"},{"title":"new_install_config – Fortran-lang/fpm","text":"public subroutine new_install_config(self, table, error) Create a new installation configuration from a TOML data structure Arguments Type Intent Optional Attributes Name type( install_config_t ), intent(out) :: self Instance of the install configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling Source Code subroutine new_install_config ( self , table , error ) !> Instance of the install configuration type ( install_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error call check ( table , error ) if ( allocated ( error )) return call get_value ( table , \"library\" , self % library , . false .) call get_value ( table , \"test\" , self % test , . false .) end subroutine new_install_config","tags":"","url":"proc/new_install_config.html"},{"title":"resolve_metapackages – Fortran-lang/fpm","text":"public interface resolve_metapackages Module Procedures private subroutine resolve_metapackage_model(model, package, settings, error) Resolve all metapackages into the package config Arguments Type Intent Optional Attributes Name type( fpm_model_t ), intent(inout) :: model type( package_config_t ), intent(inout) :: package class( fpm_build_settings ), intent(inout) :: settings type( error_t ), intent(out), allocatable :: error","tags":"","url":"interface/resolve_metapackages.html"},{"title":"cmd_install – Fortran-lang/fpm","text":"public subroutine cmd_install(settings) Entry point for the fpm-install subcommand Arguments Type Intent Optional Attributes Name type( fpm_install_settings ), intent(inout) :: settings Representation of the command line settings Source Code subroutine cmd_install ( settings ) !> Representation of the command line settings type ( fpm_install_settings ), intent ( inout ) :: settings type ( package_config_t ) :: package type ( error_t ), allocatable :: error type ( fpm_model_t ) :: model type ( build_target_ptr ), allocatable :: targets (:), libraries (:) type ( installer_t ) :: installer type ( string_t ), allocatable :: list (:) logical :: installable integer :: ntargets , i call get_package_data ( package , \"fpm.toml\" , error , apply_defaults = . true .) call handle_error ( error ) call build_model ( model , settings , package , error ) call handle_error ( error ) ! ifx bug: does not resolve allocatable -> optional if ( allocated ( package % library )) then call targets_from_sources ( targets , model , settings % prune , package % library , error ) else call targets_from_sources ( targets , model , settings % prune , error = error ) endif call handle_error ( error ) call install_info ( output_unit , settings % list , targets , ntargets ) if ( settings % list ) return installable = ( allocated ( package % library ) . and . package % install % library ) & . or . allocated ( package % executable ) . or . ntargets > 0 if (. not . installable ) then call fatal_error ( error , \"Project does not contain any installable targets\" ) call handle_error ( error ) end if if (. not . settings % no_rebuild ) then call build_package ( targets , model , verbose = settings % verbose , dry_run = settings % list ) end if call new_installer ( installer , prefix = settings % prefix , & bindir = settings % bindir , libdir = settings % libdir , testdir = settings % testdir , & includedir = settings % includedir , & verbosity = merge ( 2 , 1 , settings % verbose )) if ( allocated ( package % library ) . and . package % install % library ) then call filter_library_targets ( targets , libraries ) if ( size ( libraries ) > 0 ) then do i = 1 , size ( libraries ) call installer % install_library ( libraries ( i )% ptr , error ) call handle_error ( error ) end do call install_module_files ( installer , targets , error ) call handle_error ( error ) end if end if if ( allocated ( package % executable ) . or . ntargets > 0 ) then call install_executables ( installer , targets , error ) call handle_error ( error ) end if if ( allocated ( package % test ) . and . ( package % install % test . or . model % include_tests )) then call install_tests ( installer , targets , error ) call handle_error ( error ) end if end subroutine cmd_install","tags":"","url":"proc/cmd_install.html"},{"title":"get_fpm_env – Fortran-lang/fpm","text":"public function get_fpm_env(env, default) result(val) Get an environment variable for fpm, this routine ensures that every variable\nused by fpm is prefixed with FPM_. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: env character(len=*), intent(in) :: default Return Value character(len=:), allocatable Source Code function get_fpm_env ( env , default ) result ( val ) character ( len =* ), intent ( in ) :: env character ( len =* ), intent ( in ) :: default character ( len = :), allocatable :: val character ( len =* ), parameter :: fpm_prefix = \"FPM_\" val = get_env ( fpm_prefix // env , default ) end function get_fpm_env","tags":"","url":"proc/get_fpm_env.html"},{"title":"get_command_line_settings – Fortran-lang/fpm","text":"public subroutine get_command_line_settings(cmd_settings) ! canon_path is not converting “.”, etc.\n& ‘ unknown help topic “’//trim(unnamed(i)).’not found in:’,manual] Arguments Type Intent Optional Attributes Name class( fpm_cmd_settings ), intent(out), allocatable :: cmd_settings Source Code subroutine get_command_line_settings ( cmd_settings ) class ( fpm_cmd_settings ), allocatable , intent ( out ) :: cmd_settings integer , parameter :: widest = 256 character ( len = 4096 ) :: cmdarg integer :: i integer :: os type ( fpm_install_settings ), allocatable :: install_settings type ( fpm_publish_settings ), allocatable :: publish_settings type ( fpm_export_settings ) , allocatable :: export_settings type ( version_t ) :: version character ( len = :), allocatable :: common_args , compiler_args , run_args , working_dir , & & c_compiler , cxx_compiler , archiver , version_s , token_s , config_file character ( len =* ), parameter :: fc_env = \"FC\" , cc_env = \"CC\" , ar_env = \"AR\" , & & fflags_env = \"FFLAGS\" , cflags_env = \"CFLAGS\" , cxxflags_env = \"CXXFLAGS\" , ldflags_env = \"LDFLAGS\" , & & fc_default = \"gfortran\" , cc_default = \" \" , ar_default = \" \" , flags_default = \" \" , & & cxx_env = \"CXX\" , cxx_default = \" \" type ( error_t ), allocatable :: error call set_help () os = get_os_type () ! text for --version switch, select case ( os ) case ( OS_LINUX ); os_type = \"OS Type: Linux\" case ( OS_MACOS ); os_type = \"OS Type: macOS\" case ( OS_WINDOWS ); os_type = \"OS Type: Windows\" case ( OS_CYGWIN ); os_type = \"OS Type: Cygwin\" case ( OS_SOLARIS ); os_type = \"OS Type: Solaris\" case ( OS_FREEBSD ); os_type = \"OS Type: FreeBSD\" case ( OS_OPENBSD ); os_type = \"OS Type: OpenBSD\" case ( OS_UNKNOWN ); os_type = \"OS Type: Unknown\" case default ; os_type = \"OS Type: UNKNOWN\" end select ! Get current release version version = fpm_version () version_s = version % s () version_text = [ character ( len = 80 ) :: & & 'Version: ' // trim ( version_s ) // ', alpha' , & & 'Program: fpm(1)' , & & 'Description: A Fortran package manager and build system' , & & 'Home Page: https://github.com/fortran-lang/fpm' , & & 'License: MIT' , & & os_type ] ! find the subcommand name by looking for first word on command ! not starting with dash CLI_RESPONSE_FILE = . true . cmdarg = get_subcommand () common_args = & ' --directory:C \" \"' // & ' --verbose F' run_args = & ' --target \" \"' // & ' --list F' // & ' --runner \" \"' // & ' --runner-args \" \"' compiler_args = & ' --profile \" \"' // & ' --no-prune F' // & ' --compiler \"' // get_fpm_env ( fc_env , fc_default ) // '\"' // & ' --c-compiler \"' // get_fpm_env ( cc_env , cc_default ) // '\"' // & ' --cxx-compiler \"' // get_fpm_env ( cxx_env , cxx_default ) // '\"' // & ' --archiver \"' // get_fpm_env ( ar_env , ar_default ) // '\"' // & ' --flag:: \"' // get_fpm_env ( fflags_env , flags_default ) // '\"' // & ' --c-flag:: \"' // get_fpm_env ( cflags_env , flags_default ) // '\"' // & ' --cxx-flag:: \"' // get_fpm_env ( cxxflags_env , flags_default ) // '\"' // & ' --link-flag:: \"' // get_fpm_env ( ldflags_env , flags_default ) // '\"' ! now set subcommand-specific help text and process commandline ! arguments. Then call subcommand routine select case ( trim ( cmdarg )) case ( 'run' ) call set_args ( common_args // compiler_args // run_args // '& & --all F & & --example F & & --config-file \" \" & & --' , help_run , version_text ) call check_build_vals () if ( size ( unnamed ) > 1 ) then names = unnamed ( 2 :) else names = [ character ( len = len ( names )) :: ] endif if ( specified ( 'target' ) ) then call split ( sget ( 'target' ), tnames , delimiters = ' ,:' ) names = [ character ( len = max ( len ( names ), len ( tnames ))) :: names , tnames ] endif ! convert --all to '*' if ( lget ( 'all' )) then names = [ character ( len = max ( len ( names ), 1 )) :: names , '*' ] endif ! convert special string '..' to equivalent (shorter) '*' ! to allow for a string that does not require shift-key and quoting do i = 1 , size ( names ) if ( names ( i ) == '..' ) names ( i ) = '*' enddo ! If there are additional command-line arguments, remove the additional ! double quotes which have been added by M_CLI2 val_runner_args = sget ( 'runner-args' ) call remove_characters_in_set ( val_runner_args , set = '\"' ) c_compiler = sget ( 'c-compiler' ) cxx_compiler = sget ( 'cxx-compiler' ) archiver = sget ( 'archiver' ) config_file = sget ( 'config-file' ) allocate ( fpm_run_settings :: cmd_settings ) val_runner = sget ( 'runner' ) if ( specified ( 'runner' ) . and . val_runner == '' ) val_runner = 'echo' cmd_settings = fpm_run_settings (& & args = remaining ,& & profile = val_profile ,& & prune = . not . lget ( 'no-prune' ), & & compiler = val_compiler , & & c_compiler = c_compiler , & & cxx_compiler = cxx_compiler , & & archiver = archiver , & & path_to_config = config_file , & & flag = val_flag , & & cflag = val_cflag , & & cxxflag = val_cxxflag , & & ldflag = val_ldflag , & & example = lget ( 'example' ), & & list = lget ( 'list' ),& & build_tests = . false .,& & name = names ,& & runner = val_runner ,& & runner_args = val_runner_args , & & verbose = lget ( 'verbose' ) ) case ( 'build' ) call set_args ( common_args // compiler_args // '& & --list F & & --show-model F & & --dump \" \" & & --tests F & & --config-file \" \" & & --' , help_build , version_text ) call check_build_vals () c_compiler = sget ( 'c-compiler' ) cxx_compiler = sget ( 'cxx-compiler' ) archiver = sget ( 'archiver' ) config_file = sget ( 'config-file' ) val_dump = sget ( 'dump' ) if ( specified ( 'dump' ) . and . val_dump == '' ) val_dump = 'fpm_model.toml' allocate ( fpm_build_settings :: cmd_settings ) cmd_settings = fpm_build_settings ( & & profile = val_profile ,& & dump = val_dump ,& & prune = . not . lget ( 'no-prune' ), & & compiler = val_compiler , & & c_compiler = c_compiler , & & cxx_compiler = cxx_compiler , & & archiver = archiver , & & path_to_config = config_file , & & flag = val_flag , & & cflag = val_cflag , & & cxxflag = val_cxxflag , & & ldflag = val_ldflag , & & list = lget ( 'list' ),& & show_model = lget ( 'show-model' ),& & build_tests = lget ( 'tests' ),& & verbose = lget ( 'verbose' ) ) case ( 'new' ) call set_args ( common_args // '& & --src F & & --lib F & & --app F & & --test F & & --example F & & --backfill F & & --full F & & --bare F & &' , help_new , version_text ) select case ( size ( unnamed )) case ( 1 ) if ( lget ( 'backfill' )) then name = '.' else write ( stderr , '(*(7x,g0,/))' ) & & ' fpm new NAME [[--lib|--src] [--app] [--test] [--example]]|[--full|--bare] [--backfill]' call fpm_stop ( 1 , 'directory name required' ) endif case ( 2 ) name = trim ( unnamed ( 2 )) case default write ( stderr , '(7x,g0)' ) & & ' fpm new NAME [[--lib|--src] [--app] [--test] [--example]]| [--full|--bare] [--backfill]' call fpm_stop ( 2 , 'only one directory name allowed' ) end select !*! canon_path is not converting \".\", etc. if ( name == '.' ) then call get_current_directory ( name , error ) if ( allocated ( error )) then write ( stderr , '(\"[Error]\", 1x, a)' ) error % message stop 1 endif endif name = canon_path ( name ) if ( . not . is_fortran_name ( to_fortran_name ( basename ( name ))) ) then write ( stderr , '(g0)' ) [ character ( len = 72 ) :: & & ' the fpm project name must be made of up to 63 ASCII letters,' , & & ' numbers, underscores, or hyphens, and start with a letter.' ] call fpm_stop ( 4 , ' ' ) endif allocate ( fpm_new_settings :: cmd_settings ) if ( any ( specified ([ character ( len = 10 ) :: 'src' , 'lib' , 'app' , 'test' , 'example' , 'bare' ])) & & . and . lget ( 'full' ) ) then write ( stderr , '(*(a))' )& & ' --full and any of [--src|--lib,--app,--test,--example,--bare]' , & & ' are mutually exclusive.' call fpm_stop ( 5 , ' ' ) elseif ( any ( specified ([ character ( len = 10 ) :: 'src' , 'lib' , 'app' , 'test' , 'example' , 'full' ])) & & . and . lget ( 'bare' ) ) then write ( stderr , '(*(a))' )& & ' --bare and any of [--src|--lib,--app,--test,--example,--full]' , & & ' are mutually exclusive.' call fpm_stop ( 3 , ' ' ) elseif ( any ( specified ([ character ( len = 10 ) :: 'src' , 'lib' , 'app' , 'test' , 'example' ]) ) ) then cmd_settings = fpm_new_settings (& & backfill = lget ( 'backfill' ), & & name = name , & & with_executable = lget ( 'app' ), & & with_lib = any ([ lget ( 'lib' ), lget ( 'src' )]), & & with_test = lget ( 'test' ), & & with_example = lget ( 'example' ), & & verbose = lget ( 'verbose' ) ) else ! default if no specific directories are requested cmd_settings = fpm_new_settings (& & backfill = lget ( 'backfill' ) , & & name = name , & & with_executable = . true ., & & with_lib = . true ., & & with_test = . true ., & & with_example = lget ( 'full' ), & & with_full = lget ( 'full' ), & & with_bare = lget ( 'bare' ), & & verbose = lget ( 'verbose' ) ) endif case ( 'help' , 'manual' ) call set_args ( common_args , help_help , version_text ) if ( size ( unnamed ) < 2 ) then if ( unnamed ( 1 ) == 'help' ) then unnamed = [ ' ' , 'fpm' ] else unnamed = manual endif elseif ( unnamed ( 2 ) == 'manual' ) then unnamed = manual endif allocate ( character ( len = widest ) :: help_text ( 0 )) do i = 2 , size ( unnamed ) select case ( unnamed ( i )) case ( ' ' ) case ( 'fpm ' ) help_text = [ character ( len = widest ) :: help_text , help_fpm ] case ( 'new ' ) help_text = [ character ( len = widest ) :: help_text , help_new ] case ( 'build ' ) help_text = [ character ( len = widest ) :: help_text , help_build ] case ( 'install' ) help_text = [ character ( len = widest ) :: help_text , help_install ] case ( 'run ' ) help_text = [ character ( len = widest ) :: help_text , help_run ] case ( 'test ' ) help_text = [ character ( len = widest ) :: help_text , help_test ] case ( 'runner' ) help_text = [ character ( len = widest ) :: help_text , help_runner ] case ( 'list ' ) help_text = [ character ( len = widest ) :: help_text , help_list ] case ( 'update ' ) help_text = [ character ( len = widest ) :: help_text , help_update ] case ( 'help ' ) help_text = [ character ( len = widest ) :: help_text , help_help ] case ( 'version' ) help_text = [ character ( len = widest ) :: help_text , version_text ] case ( 'clean' ) help_text = [ character ( len = widest ) :: help_text , help_clean ] case ( 'publish' ) help_text = [ character ( len = widest ) :: help_text , help_publish ] case default help_text = [ character ( len = widest ) :: help_text , & & ' unknown help topic \"' // trim ( unnamed ( i )) // '\"' ] !!& ' unknown help topic \"'//trim(unnamed(i)).'not found in:',manual] end select enddo call printhelp ( help_text ) case ( 'install' ) call set_args ( common_args // compiler_args // '& & --no-rebuild F & & --prefix \" \" & & --list F & & --test F & & --libdir \"lib\" & & --bindir \"bin\" & & --testdir \"test\" & & --includedir \"include\" & & --config-file \" \" & &' , help_install , version_text ) call check_build_vals () c_compiler = sget ( 'c-compiler' ) cxx_compiler = sget ( 'cxx-compiler' ) archiver = sget ( 'archiver' ) config_file = sget ( 'config-file' ) allocate ( install_settings , source = fpm_install_settings (& list = lget ( 'list' ), & build_tests = lget ( 'test' ), & profile = val_profile ,& prune = . not . lget ( 'no-prune' ), & compiler = val_compiler , & c_compiler = c_compiler , & cxx_compiler = cxx_compiler , & archiver = archiver , & path_to_config = config_file , & flag = val_flag , & cflag = val_cflag , & cxxflag = val_cxxflag , & ldflag = val_ldflag , & no_rebuild = lget ( 'no-rebuild' ), & verbose = lget ( 'verbose' ))) call get_char_arg ( install_settings % prefix , 'prefix' ) call get_char_arg ( install_settings % libdir , 'libdir' ) call get_char_arg ( install_settings % testdir , 'testdir' ) call get_char_arg ( install_settings % bindir , 'bindir' ) call get_char_arg ( install_settings % includedir , 'includedir' ) call move_alloc ( install_settings , cmd_settings ) case ( 'list' ) call set_args ( common_args // '& & --list F & &' , help_list , version_text ) if ( lget ( 'list' )) then help_text = [ character ( widest ) :: help_list_nodash , help_list_dash ] else help_text = help_list_nodash endif call printhelp ( help_text ) case ( 'test' ) call set_args ( common_args // compiler_args // run_args // '& & --config-file \" \" & & -- ' , help_test , version_text ) call check_build_vals () if ( size ( unnamed ) > 1 ) then names = unnamed ( 2 :) else names = [ character ( len = len ( names )) :: ] endif if ( specified ( 'target' ) ) then call split ( sget ( 'target' ), tnames , delimiters = ' ,:' ) names = [ character ( len = max ( len ( names ), len ( tnames ))) :: names , tnames ] endif ! convert special string '..' to equivalent (shorter) '*' ! to allow for a string that does not require shift-key and quoting do i = 1 , size ( names ) if ( names ( i ) == '..' ) names ( i ) = '*' enddo ! If there are additional command-line arguments, remove the additional ! double quotes which have been added by M_CLI2 val_runner_args = sget ( 'runner-args' ) call remove_characters_in_set ( val_runner_args , set = '\"' ) c_compiler = sget ( 'c-compiler' ) cxx_compiler = sget ( 'cxx-compiler' ) archiver = sget ( 'archiver' ) config_file = sget ( 'config-file' ) allocate ( fpm_test_settings :: cmd_settings ) val_runner = sget ( 'runner' ) if ( specified ( 'runner' ) . and . val_runner == '' ) val_runner = 'echo' cmd_settings = fpm_test_settings (& & args = remaining , & & profile = val_profile , & & prune = . not . lget ( 'no-prune' ), & & compiler = val_compiler , & & c_compiler = c_compiler , & & cxx_compiler = cxx_compiler , & & archiver = archiver , & & path_to_config = config_file , & & flag = val_flag , & & cflag = val_cflag , & & cxxflag = val_cxxflag , & & ldflag = val_ldflag , & & example = . false ., & & list = lget ( 'list' ), & & build_tests = . true ., & & name = names , & & runner = val_runner , & & runner_args = val_runner_args , & & verbose = lget ( 'verbose' )) case ( 'update' ) call set_args ( common_args // '& & --fetch-only F & & --clean F & & --dump \" \" & & --config-file \" \" & &' , help_update , version_text ) if ( size ( unnamed ) > 1 ) then names = unnamed ( 2 :) else names = [ character ( len = len ( names )) :: ] endif config_file = sget ( 'config-file' ) val_dump = sget ( 'dump' ) if ( specified ( 'dump' ) . and . val_dump == '' ) val_dump = 'fpm_dependencies.toml' allocate ( fpm_update_settings :: cmd_settings ) cmd_settings = fpm_update_settings ( name = names , & & fetch_only = lget ( 'fetch-only' ), & & dump = val_dump , & & verbose = lget ( 'verbose' ), & & path_to_config = config_file , & & clean = lget ( 'clean' )) case ( 'export' ) call set_args ( common_args // compiler_args // '& & --manifest \"filename\" & & --model \"filename\" & & --dependencies \"filename\" ' , & help_build , version_text ) call check_build_vals () c_compiler = sget ( 'c-compiler' ) cxx_compiler = sget ( 'cxx-compiler' ) archiver = sget ( 'archiver' ) allocate ( export_settings , source = fpm_export_settings (& profile = val_profile ,& prune = . not . lget ( 'no-prune' ), & compiler = val_compiler , & c_compiler = c_compiler , & cxx_compiler = cxx_compiler , & archiver = archiver , & flag = val_flag , & cflag = val_cflag , & show_model = . true ., & cxxflag = val_cxxflag , & ldflag = val_ldflag , & verbose = lget ( 'verbose' ))) call get_char_arg ( export_settings % dump_model , 'model' ) call get_char_arg ( export_settings % dump_manifest , 'manifest' ) call get_char_arg ( export_settings % dump_dependencies , 'dependencies' ) call move_alloc ( export_settings , cmd_settings ) case ( 'clean' ) call set_args ( common_args // & & ' --registry-cache' // & & ' --skip' // & & ' --all' // & & ' --config-file \"\"' , help_clean , version_text ) block logical :: skip , clean_all skip = lget ( 'skip' ) clean_all = lget ( 'all' ) config_file = sget ( 'config-file' ) if ( all ([ skip , clean_all ])) then call fpm_stop ( 6 , 'Do not specify both --skip and --all options on the clean subcommand.' ) end if allocate ( fpm_clean_settings :: cmd_settings ) call get_current_directory ( working_dir , error ) cmd_settings = fpm_clean_settings ( & & working_dir = working_dir , & & clean_skip = skip , & & registry_cache = lget ( 'registry-cache' ), & & clean_all = clean_all , & & path_to_config = config_file ) end block case ( 'publish' ) call set_args ( common_args // compiler_args // '& & --show-package-version F & & --show-upload-data F & & --dry-run F & & --token \" \" & & --list F & & --show-model F & & --tests F & & --config-file \" \" & & --' , help_publish , version_text ) call check_build_vals () c_compiler = sget ( 'c-compiler' ) cxx_compiler = sget ( 'cxx-compiler' ) archiver = sget ( 'archiver' ) config_file = sget ( 'config-file' ) token_s = sget ( 'token' ) allocate ( fpm_publish_settings :: cmd_settings ) cmd_settings = fpm_publish_settings ( & & show_package_version = lget ( 'show-package-version' ), & & show_upload_data = lget ( 'show-upload-data' ), & & is_dry_run = lget ( 'dry-run' ), & & profile = val_profile ,& & prune = . not . lget ( 'no-prune' ), & & compiler = val_compiler , & & c_compiler = c_compiler , & & cxx_compiler = cxx_compiler , & & archiver = archiver , & & flag = val_flag , & & cflag = val_cflag , & & cxxflag = val_cxxflag , & & ldflag = val_ldflag , & & list = lget ( 'list' ),& & show_model = lget ( 'show-model' ),& & build_tests = lget ( 'tests' ),& & path_to_config = config_file , & & verbose = lget ( 'verbose' ),& & token = token_s ) case default if ( cmdarg . ne . '' . and . which ( 'fpm-' // cmdarg ). ne . '' ) then call run ( 'fpm-' // trim ( cmdarg ) // ' ' // get_command_arguments_quoted (),. false .) stop else call set_args ( '& & --list F& &' , help_fpm , version_text ) ! Note: will not get here if --version or --usage or --help ! is present on commandline if ( lget ( 'list' )) then help_text = help_list_dash elseif ( len_trim ( cmdarg ) == 0 ) then write ( stdout , '(*(a))' ) 'Fortran Package Manager:' write ( stdout , '(*(a))' ) ' ' help_text = [ character ( widest ) :: help_list_nodash , help_usage ] else write ( stderr , '(*(a))' ) ' unknown subcommand [' , & & trim ( cmdarg ), ']' help_text = [ character ( widest ) :: help_list_dash , help_usage ] endif call printhelp ( help_text ) endif end select if ( allocated ( cmd_settings )) then working_dir = sget ( \"directory\" ) call move_alloc ( working_dir , cmd_settings % working_dir ) end if contains subroutine check_build_vals () val_compiler = sget ( 'compiler' ) if ( val_compiler == '' ) val_compiler = 'gfortran' val_flag = \" \" // sget ( 'flag' ) val_cflag = \" \" // sget ( 'c-flag' ) val_cxxflag = \" \" // sget ( 'cxx-flag' ) val_ldflag = \" \" // sget ( 'link-flag' ) val_profile = sget ( 'profile' ) end subroutine check_build_vals !> Print help text and stop subroutine printhelp ( lines ) character ( len = :), intent ( in ), allocatable :: lines (:) integer :: iii , ii if ( allocated ( lines )) then ii = size ( lines ) if ( ii > 0 . and . len ( lines ) > 0 ) then write ( stdout , '(g0)' )( trim ( lines ( iii )), iii = 1 , ii ) else write ( stdout , '(a)' ) ' *printhelp* output requested is empty' endif endif stop end subroutine printhelp end subroutine get_command_line_settings","tags":"","url":"proc/get_command_line_settings.html"},{"title":"cmd_update – Fortran-lang/fpm","text":"public subroutine cmd_update(settings) Entry point for the update subcommand Arguments Type Intent Optional Attributes Name type( fpm_update_settings ), intent(in) :: settings Representation of the command line arguments Source Code subroutine cmd_update ( settings ) !> Representation of the command line arguments type ( fpm_update_settings ), intent ( in ) :: settings type ( package_config_t ) :: package type ( dependency_tree_t ) :: deps type ( error_t ), allocatable :: error integer :: ii character ( len = :), allocatable :: cache call get_package_data ( package , \"fpm.toml\" , error , apply_defaults = . true .) call handle_error ( error ) if (. not . exists ( \"build\" )) then call mkdir ( \"build\" ) call filewrite ( join_path ( \"build\" , \".gitignore\" ),[ \"*\" ]) end if cache = join_path ( \"build\" , \"cache.toml\" ) if ( settings % clean ) call delete_file ( cache ) call new_dependency_tree ( deps , cache = cache , verbosity = merge ( 2 , 1 , settings % verbose ), & & path_to_config = settings % path_to_config ) call deps % add ( package , error ) call handle_error ( error ) ! Force-update all dependencies if `--clean` if ( settings % clean ) then do ii = 1 , deps % ndep deps % dep ( ii )% update = . true . end do end if if ( settings % fetch_only ) return if ( size ( settings % name ) == 0 ) then call deps % update ( error ) call handle_error ( error ) else do ii = 1 , size ( settings % name ) call deps % update ( trim ( settings % name ( ii )), error ) call handle_error ( error ) end do end if if ( len_trim ( settings % dump ) > 0 ) then call deps % dump ( trim ( settings % dump ), error , json = name_is_json ( trim ( settings % dump ))) call handle_error ( error ) end if end subroutine cmd_update","tags":"","url":"proc/cmd_update.html"},{"title":"init_stdlib – Fortran-lang/fpm","text":"public subroutine init_stdlib(this, compiler, all_meta, error) Initialize stdlib metapackage for the current system\nCleanup Set name Stdlib is queried as a dependency from the official repository 1) Test-drive\n2) stdlib\nIf an external BLAS is available, deploy appropriate macros Arguments Type Intent Optional Attributes Name class( metapackage_t ), intent(inout) :: this type( compiler_t ), intent(in) :: compiler type( metapackage_request_t ), intent(in) :: all_meta (:) type( error_t ), intent(out), allocatable :: error Source Code subroutine init_stdlib ( this , compiler , all_meta , error ) class ( metapackage_t ), intent ( inout ) :: this type ( compiler_t ), intent ( in ) :: compiler type ( metapackage_request_t ), intent ( in ) :: all_meta (:) type ( error_t ), allocatable , intent ( out ) :: error integer :: i logical :: with_blas !> Cleanup call destroy ( this ) !> Set name this % name = \"stdlib\" !> Stdlib is queried as a dependency from the official repository this % has_dependencies = . true . allocate ( this % dependency ( 2 )) !> 1) Test-drive this % dependency ( 1 )% name = \"test-drive\" this % dependency ( 1 )% git = git_target_branch ( \"https://github.com/fortran-lang/test-drive\" , \"v0.4.0\" ) if (. not . allocated ( this % dependency ( 1 )% git )) then call fatal_error ( error , 'cannot initialize test-drive git dependency for stdlib metapackage' ) return end if !> 2) stdlib this % dependency ( 2 )% name = \"stdlib\" this % dependency ( 2 )% git = git_target_branch ( \"https://github.com/fortran-lang/stdlib\" , \"stdlib-fpm\" ) if (. not . allocated ( this % dependency ( 2 )% git )) then call fatal_error ( error , 'cannot initialize git repo dependency for stdlib metapackage' ) return end if !> If an external BLAS is available, deploy appropriate macros with_blas = external_blas ( all_meta ) if ( with_blas ) then allocate ( this % preprocess ) call this % preprocess % new ([ string_t ( 'STDLIB_EXTERNAL_BLAS' ), string_t ( 'STDLIB_EXTERNAL_LAPACK' )]) call this % dependency ( 2 )% add_preprocess ( this % preprocess ) end if ! Stdlib is not 100% thread safe. print a warning to the user do i = 1 , size ( all_meta ) if ( all_meta ( i )% name == \"openmp\" ) then write ( stdout , '(a)' ) ' both openmp and stdlib requested: some functions may not be thread-safe!' end if end do end subroutine init_stdlib","tags":"","url":"proc/init_stdlib.html"},{"title":"build_model – Fortran-lang/fpm","text":"public subroutine build_model(model, settings, package, error) Constructs a valid fpm model from command line settings and the toml manifest.\nAdd this dependency’s manifest macros\nAdd this dependency’s package-level macros Arguments Type Intent Optional Attributes Name type( fpm_model_t ), intent(out) :: model class( fpm_build_settings ), intent(inout) :: settings type( package_config_t ), intent(inout), target :: package type( error_t ), intent(out), allocatable :: error Source Code subroutine build_model ( model , settings , package , error ) type ( fpm_model_t ), intent ( out ) :: model class ( fpm_build_settings ), intent ( inout ) :: settings type ( package_config_t ), intent ( inout ), target :: package type ( error_t ), allocatable , intent ( out ) :: error integer :: i , j type ( package_config_t ), target :: dependency type ( package_config_t ), pointer :: manifest character ( len = :), allocatable :: file_name , lib_dir logical :: has_cpp logical :: duplicates_found type ( string_t ) :: include_dir model % package_name = package % name allocate ( model % include_dirs ( 0 )) allocate ( model % link_libraries ( 0 )) allocate ( model % external_modules ( 0 )) call new_compiler ( model % compiler , settings % compiler , settings % c_compiler , & & settings % cxx_compiler , echo = settings % verbose , verbose = settings % verbose ) call new_archiver ( model % archiver , settings % archiver , & & echo = settings % verbose , verbose = settings % verbose ) if ( model % compiler % is_unknown ()) then write ( * , '(*(a:,1x))' ) & \"\" , \"Unknown compiler\" , model % compiler % fc , \"requested!\" , & \"Defaults for this compiler might be incorrect\" end if call new_compiler_flags ( model , settings ) model % build_prefix = join_path ( \"build\" , basename ( model % compiler % fc )) model % include_tests = settings % build_tests model % enforce_module_names = package % build % module_naming model % module_prefix = package % build % module_prefix ! Resolve meta-dependencies into the package and the model call resolve_metapackages ( model , package , settings , error ) if ( allocated ( error )) return ! Create dependencies call new_dependency_tree ( model % deps , cache = join_path ( \"build\" , \"cache.toml\" ), & & path_to_config = settings % path_to_config ) ! Build and resolve model dependencies call model % deps % add ( package , error ) if ( allocated ( error )) return ! Update dependencies where needed call model % deps % update ( error ) if ( allocated ( error )) return ! build/ directory should now exist if (. not . exists ( \"build/.gitignore\" )) then call filewrite ( join_path ( \"build\" , \".gitignore\" ),[ \"*\" ]) end if allocate ( model % packages ( model % deps % ndep )) has_cpp = . false . do i = 1 , model % deps % ndep associate ( dep => model % deps % dep ( i )) file_name = join_path ( dep % proj_dir , \"fpm.toml\" ) ! The main package manifest should not be reloaded, because it may have been ! affected by model dependencies and metapackages if ( i == 1 ) then manifest => package else call get_package_data ( dependency , file_name , error , apply_defaults = . true .) if ( allocated ( error )) exit manifest => dependency end if model % packages ( i )% name = manifest % name associate ( features => model % packages ( i )% features ) features % implicit_typing = manifest % fortran % implicit_typing features % implicit_external = manifest % fortran % implicit_external features % source_form = manifest % fortran % source_form end associate model % packages ( i )% version = package % version % s () !> Add this dependency's manifest macros if ( allocated ( manifest % preprocess )) then do j = 1 , size ( manifest % preprocess ) call model % packages ( i )% preprocess % add_config ( manifest % preprocess ( j )) end do end if !> Add this dependency's package-level macros if ( allocated ( dep % preprocess )) then do j = 1 , size ( dep % preprocess ) call model % packages ( i )% preprocess % add_config ( dep % preprocess ( j )) end do end if if ( model % packages ( i )% preprocess % is_cpp ()) has_cpp = . true . if (. not . allocated ( model % packages ( i )% sources )) allocate ( model % packages ( i )% sources ( 0 )) if ( allocated ( manifest % library )) then if ( allocated ( manifest % library % source_dir )) then lib_dir = join_path ( dep % proj_dir , manifest % library % source_dir ) if ( is_dir ( lib_dir )) then call add_sources_from_dir ( model % packages ( i )% sources , lib_dir , FPM_SCOPE_LIB , & with_f_ext = model % packages ( i )% preprocess % suffixes , error = error ) if ( allocated ( error )) exit end if end if if ( allocated ( manifest % library % include_dir )) then do j = 1 , size ( manifest % library % include_dir ) include_dir % s = join_path ( dep % proj_dir , manifest % library % include_dir ( j )% s ) if ( is_dir ( include_dir % s )) then model % include_dirs = [ model % include_dirs , include_dir ] end if end do end if end if if ( allocated ( manifest % build % link )) then model % link_libraries = [ model % link_libraries , manifest % build % link ] end if if ( allocated ( manifest % build % external_modules )) then model % external_modules = [ model % external_modules , manifest % build % external_modules ] end if ! Copy naming conventions from this dependency's manifest model % packages ( i )% enforce_module_names = manifest % build % module_naming model % packages ( i )% module_prefix = manifest % build % module_prefix end associate end do if ( allocated ( error )) return ! Add optional flags if ( has_cpp ) call set_cpp_preprocessor_flags ( model % compiler % id , model % fortran_compile_flags ) ! Add sources from executable directories if ( is_dir ( 'app' ) . and . package % build % auto_executables ) then call add_sources_from_dir ( model % packages ( 1 )% sources , 'app' , FPM_SCOPE_APP , & with_executables = . true ., with_f_ext = model % packages ( 1 )% preprocess % suffixes ,& error = error ) if ( allocated ( error )) then return end if end if if ( is_dir ( 'example' ) . and . package % build % auto_examples ) then call add_sources_from_dir ( model % packages ( 1 )% sources , 'example' , FPM_SCOPE_EXAMPLE , & with_executables = . true ., & with_f_ext = model % packages ( 1 )% preprocess % suffixes , error = error ) if ( allocated ( error )) then return end if end if if ( is_dir ( 'test' ) . and . package % build % auto_tests ) then call add_sources_from_dir ( model % packages ( 1 )% sources , 'test' , FPM_SCOPE_TEST , & with_executables = . true ., & with_f_ext = model % packages ( 1 )% preprocess % suffixes , error = error ) if ( allocated ( error )) then return endif end if if ( allocated ( package % executable )) then call add_executable_sources ( model % packages ( 1 )% sources , package % executable , FPM_SCOPE_APP , & auto_discover = package % build % auto_executables , & with_f_ext = model % packages ( 1 )% preprocess % suffixes , & error = error ) if ( allocated ( error )) then return end if end if if ( allocated ( package % example )) then call add_executable_sources ( model % packages ( 1 )% sources , package % example , FPM_SCOPE_EXAMPLE , & auto_discover = package % build % auto_examples , & with_f_ext = model % packages ( 1 )% preprocess % suffixes , & error = error ) if ( allocated ( error )) then return end if end if if ( allocated ( package % test )) then call add_executable_sources ( model % packages ( 1 )% sources , package % test , FPM_SCOPE_TEST , & auto_discover = package % build % auto_tests , & with_f_ext = model % packages ( 1 )% preprocess % suffixes , & error = error ) if ( allocated ( error )) then return endif endif if ( settings % verbose ) then write ( * , * ) ' BUILD_NAME: ' , model % build_prefix write ( * , * ) ' COMPILER: ' , model % compiler % fc write ( * , * ) ' C COMPILER: ' , model % compiler % cc write ( * , * ) ' CXX COMPILER: ' , model % compiler % cxx write ( * , * ) ' COMPILER OPTIONS: ' , model % fortran_compile_flags write ( * , * ) ' C COMPILER OPTIONS: ' , model % c_compile_flags write ( * , * ) ' CXX COMPILER OPTIONS: ' , model % cxx_compile_flags write ( * , * ) ' LINKER OPTIONS: ' , model % link_flags write ( * , * ) ' INCLUDE DIRECTORIES: [' , string_cat ( model % include_dirs , ',' ), ']' end if ! Check for invalid module names call check_module_names ( model , error ) if ( allocated ( error )) return ! Check for duplicate modules duplicates_found = . false . call check_modules_for_duplicates ( model , duplicates_found ) if ( duplicates_found ) then call fpm_stop ( 1 , '*build_model*:Error: One or more duplicate module names found.' ) end if end subroutine build_model","tags":"","url":"proc/build_model.html"},{"title":"check_modules_for_duplicates – Fortran-lang/fpm","text":"public subroutine check_modules_for_duplicates(model, duplicates_found) Arguments Type Intent Optional Attributes Name type( fpm_model_t ), intent(in) :: model logical :: duplicates_found Source Code subroutine check_modules_for_duplicates ( model , duplicates_found ) type ( fpm_model_t ), intent ( in ) :: model integer :: maxsize integer :: i , j , k , l , m , modi type ( string_t ), allocatable :: modules (:) logical :: duplicates_found ! Initialise the size of array maxsize = 0 ! Get number of modules provided by each source file of every package do i = 1 , size ( model % packages ) do j = 1 , size ( model % packages ( i )% sources ) if ( allocated ( model % packages ( i )% sources ( j )% modules_provided )) then maxsize = maxsize + size ( model % packages ( i )% sources ( j )% modules_provided ) end if end do end do ! Allocate array to contain distinct names of modules allocate ( modules ( maxsize )) ! Initialise index to point at start of the newly allocated array modi = 1 ! Loop through modules provided by each source file of every package ! Add it to the array if it is not already there ! Otherwise print out warning about duplicates do k = 1 , size ( model % packages ) do l = 1 , size ( model % packages ( k )% sources ) if ( allocated ( model % packages ( k )% sources ( l )% modules_provided )) then do m = 1 , size ( model % packages ( k )% sources ( l )% modules_provided ) if ( model % packages ( k )% sources ( l )% modules_provided ( m )% s . in . modules (: modi - 1 )) then write ( stderr , * ) \"Warning: Module \" , model % packages ( k )% sources ( l )% modules_provided ( m )% s , & \" in \" , model % packages ( k )% sources ( l )% file_name , \" is a duplicate\" duplicates_found = . true . else modules ( modi ) = model % packages ( k )% sources ( l )% modules_provided ( m ) modi = modi + 1 end if end do end if end do end do end subroutine check_modules_for_duplicates","tags":"","url":"proc/check_modules_for_duplicates.html"},{"title":"cmd_build – Fortran-lang/fpm","text":"public subroutine cmd_build(settings) Dump model to file Arguments Type Intent Optional Attributes Name type( fpm_build_settings ), intent(inout) :: settings Source Code subroutine cmd_build ( settings ) type ( fpm_build_settings ), intent ( inout ) :: settings type ( package_config_t ) :: package type ( fpm_model_t ) :: model type ( build_target_ptr ), allocatable :: targets (:) type ( error_t ), allocatable :: error integer :: i call get_package_data ( package , \"fpm.toml\" , error , apply_defaults = . true .) if ( allocated ( error )) then call fpm_stop ( 1 , '*cmd_build* Package error: ' // error % message ) end if call build_model ( model , settings , package , error ) if ( allocated ( error )) then call fpm_stop ( 1 , '*cmd_build* Model error: ' // error % message ) end if call targets_from_sources ( targets , model , settings % prune , package % library , error ) if ( allocated ( error )) then call fpm_stop ( 1 , '*cmd_build* Target error: ' // error % message ) end if !> Dump model to file if ( len_trim ( settings % dump ) > 0 ) then call model % dump ( trim ( settings % dump ), error , json = name_is_json ( trim ( settings % dump ))) if ( allocated ( error )) call fpm_stop ( 1 , '*cmd_build* Model dump error: ' // error % message ) endif if ( settings % list ) then do i = 1 , size ( targets ) write ( stderr , * ) targets ( i )% ptr % output_file enddo endif if ( settings % show_model ) then call show_model ( model ) else call build_package ( targets , model , verbose = settings % verbose , dry_run = settings % list ) endif end subroutine cmd_build","tags":"","url":"proc/cmd_build.html"},{"title":"cmd_clean – Fortran-lang/fpm","text":"public subroutine cmd_clean(settings) Delete the build directory including or excluding dependencies. Can be used\nto clear the registry cache. Arguments Type Intent Optional Attributes Name class( fpm_clean_settings ), intent(in) :: settings Settings for the clean command. Source Code subroutine cmd_clean ( settings ) !> Settings for the clean command. class ( fpm_clean_settings ), intent ( in ) :: settings character :: user_response type ( fpm_global_settings ) :: global_settings type ( error_t ), allocatable :: error ! Clear registry cache if ( settings % registry_cache ) then call get_global_settings ( global_settings , error ) if ( allocated ( error )) return call os_delete_dir ( os_is_unix (), global_settings % registry_settings % cache_path ) end if if ( is_dir ( 'build' )) then ! Remove the entire build directory if ( settings % clean_all ) then call os_delete_dir ( os_is_unix (), 'build' ); return ! Remove the build directory but skip dependencies else if ( settings % clean_skip ) then call delete_skip ( os_is_unix ()); return end if ! Prompt to remove the build directory but skip dependencies write ( stdout , '(A)' , advance = 'no' ) \"Delete build, excluding dependencies (y/n)? \" read ( stdin , '(A1)' ) user_response if ( lower ( user_response ) == 'y' ) call delete_skip ( os_is_unix ()) else write ( stdout , '(A)' ) \"fpm: No build directory found.\" end if end subroutine cmd_clean","tags":"","url":"proc/cmd_clean.html"},{"title":"cmd_run – Fortran-lang/fpm","text":"public subroutine cmd_run(settings, test) Arguments Type Intent Optional Attributes Name class( fpm_run_settings ), intent(inout) :: settings logical, intent(in) :: test Source Code subroutine cmd_run ( settings , test ) class ( fpm_run_settings ), intent ( inout ) :: settings logical , intent ( in ) :: test integer :: i , j , col_width logical :: found ( size ( settings % name )) type ( error_t ), allocatable :: error type ( package_config_t ) :: package type ( fpm_model_t ) :: model type ( build_target_ptr ), allocatable :: targets (:) type ( string_t ) :: exe_cmd type ( string_t ), allocatable :: executables (:) type ( build_target_t ), pointer :: exe_target type ( srcfile_t ), pointer :: exe_source integer :: run_scope , firsterror integer , allocatable :: stat (:), target_ID (:) character ( len = :), allocatable :: line , run_cmd , library_path call get_package_data ( package , \"fpm.toml\" , error , apply_defaults = . true .) if ( allocated ( error )) then call fpm_stop ( 1 , '*cmd_run* Package error: ' // error % message ) end if call build_model ( model , settings , package , error ) if ( allocated ( error )) then call fpm_stop ( 1 , '*cmd_run* Model error: ' // error % message ) end if call targets_from_sources ( targets , model , settings % prune , package % library , error ) if ( allocated ( error )) then call fpm_stop ( 1 , '*cmd_run* Targets error: ' // error % message ) end if if ( test ) then run_scope = FPM_SCOPE_TEST else run_scope = merge ( FPM_SCOPE_EXAMPLE , FPM_SCOPE_APP , settings % example ) end if ! Enumerate executable targets to run col_width = - 1 found (:) = . false . allocate ( executables ( size ( targets )), target_ID ( size ( targets ))) enumerate : do i = 1 , size ( targets ) exe_target => targets ( i )% ptr if ( should_be_run ( settings , run_scope , exe_target )) then exe_source => exe_target % dependencies ( 1 )% ptr % source col_width = max ( col_width , len ( basename ( exe_target % output_file )) + 2 ) ! Priority by name ID, or 0 if no name present (run first) j = settings % name_ID ( exe_source % exe_name ) target_ID ( i ) = j if ( j > 0 ) found ( j ) = . true . exe_cmd % s = exe_target % output_file executables ( i ) = exe_cmd else target_ID ( i ) = huge ( target_ID ( i )) endif end do enumerate ! sort executables by ascending name ID, resize call sort_executables ( target_ID , executables ) ! Check if any apps/tests were found if ( col_width < 0 ) then if ( test ) then call fpm_stop ( 0 , 'No tests to run' ) else call fpm_stop ( 0 , 'No executables to run' ) end if end if ! Check all names are valid ! or no name and found more than one file if ( any (. not . found ) ) then line = join ( settings % name ) if ( line /= '.' ) then ! do not report these special strings if ( any (. not . found )) then write ( stderr , '(A)' , advance = \"no\" ) '*cmd_run*:specified names ' do j = 1 , size ( settings % name ) if (. not . found ( j )) write ( stderr , '(A)' , advance = \"no\" ) '\"' // trim ( settings % name ( j )) // '\" ' end do write ( stderr , '(A)' ) 'not found.' write ( stderr , * ) else if ( settings % verbose ) then write ( stderr , '(A)' , advance = \"yes\" ) 'when more than one executable is available' write ( stderr , '(A)' , advance = \"yes\" ) ' program names must be specified.' endif endif call compact_list_all () if ( line == '.' . or . line == ' ' ) then ! do not report these special strings call fpm_stop ( 0 , '' ) else call fpm_stop ( 1 , '' ) endif end if call build_package ( targets , model , verbose = settings % verbose , dry_run = settings % list ) if ( settings % list ) then call compact_list () else ! Save current library path and set a new one that includes the local ! dynamic library folders library_path = save_library_path () call set_library_path ( model , targets , error ) if ( allocated ( error )) call fpm_stop ( 1 , '*cmd_run* Run error: ' // error % message ) allocate ( stat ( size ( executables ))) do i = 1 , size ( executables ) if ( exists ( executables ( i )% s )) then ! Prepare command line run_cmd = executables ( i )% s if ( settings % runner /= ' ' ) run_cmd = settings % runner_command () // ' ' // run_cmd if ( allocated ( settings % args )) run_cmd = run_cmd // \" \" // settings % args ! System Integrity Protection will not propagate the .dylib environment variables ! to the child process: add paths manually if ( get_os_type () == OS_MACOS ) run_cmd = \"env DYLD_LIBRARY_PATH=\" // & get_env ( \"DYLD_LIBRARY_PATH\" , \"\" ) // & \" \" // run_cmd call run ( run_cmd , echo = settings % verbose , exitstat = stat ( i )) else call fpm_stop ( 1 , '*cmd_run*:' // executables ( i )% s // ' not found' ) end if end do if ( any ( stat /= 0 )) then do i = 1 , size ( stat ) if ( stat ( i ) /= 0 ) then write ( stderr , '(*(g0:,1x))' ) ' Execution for object \"' , basename ( executables ( i )% s ),& '\" returned exit code ' , stat ( i ) end if end do firsterror = findloc ( stat /= 0 , value = . true ., dim = 1 ) call fpm_stop ( stat ( firsterror ), '*cmd_run*:stopping due to failed executions' ) end if ! Restore original library path call restore_library_path ( library_path , error ) if ( allocated ( error )) call fpm_stop ( 1 , '*cmd_run* Environment error: ' // error % message ) end if contains subroutine compact_list_all () integer , parameter :: LINE_WIDTH = 80 integer :: ii , jj , nCol jj = 1 nCol = LINE_WIDTH / col_width write ( stderr , * ) 'Available names:' do ii = 1 , size ( targets ) exe_target => targets ( ii )% ptr if ( exe_target % target_type == FPM_TARGET_EXECUTABLE . and . & allocated ( exe_target % dependencies )) then exe_source => exe_target % dependencies ( 1 )% ptr % source if ( exe_source % unit_scope == run_scope ) then write ( stderr , '(A)' , advance = ( merge ( \"yes\" , \"no \" , modulo ( jj , nCol ) == 0 ))) & & [ character ( len = col_width ) :: basename ( exe_target % output_file , suffix = . false .)] jj = jj + 1 end if end if end do write ( stderr , * ) end subroutine compact_list_all subroutine compact_list () integer , parameter :: LINE_WIDTH = 80 integer :: ii , jj , nCol jj = 1 nCol = LINE_WIDTH / col_width write ( stderr , * ) 'Matched names:' do ii = 1 , size ( executables ) write ( stderr , '(A)' , advance = ( merge ( \"yes\" , \"no \" , modulo ( jj , nCol ) == 0 ))) & & [ character ( len = col_width ) :: basename ( executables ( ii )% s , suffix = . false .)] jj = jj + 1 end do write ( stderr , * ) end subroutine compact_list end subroutine cmd_run","tags":"","url":"proc/cmd_run.html"},{"title":"cmd_publish – Fortran-lang/fpm","text":"public subroutine cmd_publish(settings) The publish command first builds the root package to obtain all the relevant information such as the\npackage version. It then creates a tarball of the package and uploads it to the registry.\nChecks before uploading the package. Arguments Type Intent Optional Attributes Name type( fpm_publish_settings ), intent(inout) :: settings","tags":"","url":"proc/cmd_publish.html"},{"title":"init_minpack – Fortran-lang/fpm","text":"public subroutine init_minpack(this, compiler, all_meta, error) Initialize minpack metapackage for the current system\nCleanup Set name minpack is queried as a dependency from the official repository 1) minpack. There are no true releases currently. Fetch HEAD Arguments Type Intent Optional Attributes Name class( metapackage_t ), intent(inout) :: this type( compiler_t ), intent(in) :: compiler type( metapackage_request_t ), intent(in) :: all_meta (:) type( error_t ), intent(out), allocatable :: error Source Code subroutine init_minpack ( this , compiler , all_meta , error ) class ( metapackage_t ), intent ( inout ) :: this type ( compiler_t ), intent ( in ) :: compiler type ( metapackage_request_t ), intent ( in ) :: all_meta (:) type ( error_t ), allocatable , intent ( out ) :: error !> Cleanup call destroy ( this ) !> Set name this % name = \"minpack\" !> minpack is queried as a dependency from the official repository this % has_dependencies = . true . allocate ( this % dependency ( 1 )) !> 1) minpack. There are no true releases currently. Fetch HEAD this % dependency ( 1 )% name = \"minpack\" this % dependency ( 1 )% git = git_target_tag ( \"https://github.com/fortran-lang/minpack\" , \"v2.0.0-rc.1\" ) if (. not . allocated ( this % dependency ( 1 )% git )) then call fatal_error ( error , 'cannot initialize git repo dependency for minpack metapackage' ) return end if end subroutine init_minpack","tags":"","url":"proc/init_minpack.html"},{"title":"has_list – Fortran-lang/fpm","text":"public function has_list(table, key) Check if an instance of the TOML data structure contains a list Arguments Type Intent Optional Attributes Name type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in) :: key Key to read from Return Value logical Source Code logical function has_list ( table , key ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Key to read from character ( len =* ), intent ( in ) :: key type ( toml_array ), pointer :: children has_list = . false . if (. not . table % has_key ( key )) return call get_value ( table , key , children , requested = . false .) ! There is an allocated list has_list = associated ( children ) end function has_list","tags":"","url":"proc/has_list.html"},{"title":"name_is_json – Fortran-lang/fpm","text":"public function name_is_json(filename) Choose between JSON or TOML based on a file name Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: filename Return Value logical Source Code logical function name_is_json ( filename ) character ( * ), intent ( in ) :: filename character ( * ), parameter :: json_identifier = \".json\" name_is_json = . false . if ( len_trim ( filename ) < len ( json_identifier )) return name_is_json = str_ends_with ( lower ( filename ), json_identifier ) end function name_is_json","tags":"","url":"proc/name_is_json.html"},{"title":"check_keys – Fortran-lang/fpm","text":"public subroutine check_keys(table, valid_keys, error) Check if table contains only keys that are part of the list. If a key is\nfound that is not part of the list, an error is allocated. Arguments Type Intent Optional Attributes Name type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in) :: valid_keys (:) List of keys to check. type( error_t ), intent(out), allocatable :: error Error handling Source Code subroutine check_keys ( table , valid_keys , error ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> List of keys to check. character ( len =* ), intent ( in ) :: valid_keys (:) !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_key ), allocatable :: keys (:) type ( toml_table ), pointer :: child character (:), allocatable :: name , value , valid_keys_string integer :: ikey , ivalid call table % get_key ( name ) call table % get_keys ( keys ) do ikey = 1 , size ( keys ) if (. not . any ( keys ( ikey )% key == valid_keys )) then ! Generate error message valid_keys_string = new_line ( 'a' ) // new_line ( 'a' ) do ivalid = 1 , size ( valid_keys ) valid_keys_string = valid_keys_string // trim ( valid_keys ( ivalid )) // new_line ( 'a' ) end do allocate ( error ) error % message = \"Key '\" // keys ( ikey )% key // \"' not allowed in the '\" // & & name // \"' table.\" // new_line ( 'a' ) // new_line ( 'a' ) // 'Valid keys: ' // valid_keys_string return end if ! Check if value can be mapped or else (wrong type) show error message with the error location. ! Right now, it can only be mapped to a string or to a child node, but this can be extended in the future. call get_value ( table , keys ( ikey )% key , value ) if (. not . allocated ( value )) then ! If value is not a string, check if it is a child node call get_value ( table , keys ( ikey )% key , child ) if (. not . associated ( child )) then allocate ( error ) error % message = \"'\" // name // \"' has an invalid '\" // keys ( ikey )% key // \"' entry.\" return endif end if end do end subroutine check_keys","tags":"","url":"proc/check_keys.html"},{"title":"get_list – Fortran-lang/fpm","text":"public subroutine get_list(table, key, list, error) Arguments Type Intent Optional Attributes Name type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in) :: key Key to read from type( string_t ), intent(out), allocatable :: list (:) List of strings to read type( error_t ), intent(out), allocatable :: error Error handling Source Code subroutine get_list ( table , key , list , error ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Key to read from character ( len =* ), intent ( in ) :: key !> List of strings to read type ( string_t ), allocatable , intent ( out ) :: list (:) !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: stat , ilist , nlist type ( toml_array ), pointer :: children character ( len = :), allocatable :: str if (. not . table % has_key ( key )) return call get_value ( table , key , children , requested = . false .) if ( associated ( children )) then nlist = len ( children ) allocate ( list ( nlist )) do ilist = 1 , nlist call get_value ( children , ilist , str , stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Entry in \" // key // \" field cannot be read\" ) exit end if call move_alloc ( str , list ( ilist )% s ) end do if ( allocated ( error )) return else call get_value ( table , key , str , stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Entry in \" // key // \" field cannot be read\" ) return end if if ( allocated ( str )) then allocate ( list ( 1 )) call move_alloc ( str , list ( 1 )% s ) end if end if end subroutine get_list","tags":"","url":"proc/get_list.html"},{"title":"read_package_file – Fortran-lang/fpm","text":"public subroutine read_package_file(table, manifest, error) Process the configuration file to a TOML data structure Arguments Type Intent Optional Attributes Name type(toml_table), intent(out), allocatable :: table TOML data structure character(len=*), intent(in) :: manifest Name of the package configuration file type( error_t ), intent(out), allocatable :: error Error status of the operation Source Code subroutine read_package_file ( table , manifest , error ) !> TOML data structure type ( toml_table ), allocatable , intent ( out ) :: table !> Name of the package configuration file character ( len =* ), intent ( in ) :: manifest !> Error status of the operation type ( error_t ), allocatable , intent ( out ) :: error type ( toml_error ), allocatable :: parse_error integer :: unit logical :: exist inquire ( file = manifest , exist = exist ) if (. not . exist ) then call file_not_found_error ( error , manifest ) return end if open ( file = manifest , newunit = unit ) call toml_load ( table , unit , error = parse_error ) close ( unit ) if ( allocated ( parse_error )) then allocate ( error ) call move_alloc ( parse_error % message , error % message ) return end if end subroutine read_package_file","tags":"","url":"proc/read_package_file.html"},{"title":"set_list – Fortran-lang/fpm","text":"public subroutine set_list(table, key, list, error) Set no key if array is not present Check the key is not empty\nString array Arguments Type Intent Optional Attributes Name type(toml_table), intent(inout) :: table Instance of the toml table character(len=*), intent(in) :: key Key to save to type( string_t ), intent(in), allocatable :: list (:) Instance of the string array type( error_t ), intent(out), allocatable :: error Error handling Source Code subroutine set_list ( table , key , list , error ) !> Instance of the string array type ( string_t ), allocatable , intent ( in ) :: list (:) !> Key to save to character ( len =* ), intent ( in ) :: key !> Instance of the toml table type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Local variables integer :: stat , ilist type ( toml_array ), pointer :: children character ( len = :), allocatable :: str !> Set no key if array is not present if (. not . allocated ( list )) return !> Check the key is not empty if ( len_trim ( key ) <= 0 ) then call fatal_error ( error , 'key is empty dumping string array to TOML table' ) return end if if ( size ( list ) /= 1 ) then ! includes empty list case !> String array call add_array ( table , key , children , stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Cannot set array table in \" // key // \" field\" ) return end if do ilist = 1 , size ( list ) call set_value ( children , ilist , list ( ilist )% s , stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Cannot store array entry in \" // key // \" field\" ) return end if end do else ! Single value: set string call set_value ( table , key , list ( 1 )% s , stat = stat ) if ( stat /= toml_stat % success ) & call fatal_error ( error , \"Cannot store entry in \" // key // \" field\" ) return end if end subroutine set_list","tags":"","url":"proc/set_list.html"},{"title":"add_table – Fortran-lang/fpm","text":"public interface add_table add_table: fpm interface Module Procedures private subroutine add_table_fpm(table, key, ptr, error, whereAt) Function wrapper to add a toml table and return an fpm error Nullify pointer Arguments Type Intent Optional Attributes Name type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in) :: key Table key type(toml_table), intent(out), pointer :: ptr The character variable type( error_t ), intent(out), allocatable :: error Error handling character(len=*), intent(in), optional :: whereAt Optional description","tags":"","url":"interface/add_table.html"},{"title":"get_value – Fortran-lang/fpm","text":"public interface get_value get_value: fpm interface Module Procedures private subroutine get_logical(table, key, var, error, whereAt) Function wrapper to get a logical variable from a toml table, returning an fpm error Arguments Type Intent Optional Attributes Name type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in) :: key The key logical, intent(inout) :: var The variable type( error_t ), intent(out), allocatable :: error Error handling character(len=*), intent(in), optional :: whereAt Optional description private subroutine get_integer(table, key, var, error, whereAt) Function wrapper to get a default integer variable from a toml table, returning an fpm error Arguments Type Intent Optional Attributes Name type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in) :: key The key integer, intent(inout) :: var The variable type( error_t ), intent(out), allocatable :: error Error handling character(len=*), intent(in), optional :: whereAt Optional description private subroutine get_integer_64(table, key, var, error, whereAt) Function wrapper to get a integer(int64) variable from a toml table, returning an fpm error Arguments Type Intent Optional Attributes Name type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in) :: key The key integer(kind=int64), intent(inout) :: var The variable type( error_t ), intent(out), allocatable :: error Error handling character(len=*), intent(in), optional :: whereAt Optional description private subroutine get_char(table, key, var, error, whereAt) Function wrapper to get a default character variable from a toml table, returning an fpm error Arguments Type Intent Optional Attributes Name type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in) :: key The key character(len=:), intent(inout), allocatable :: var The variable type( error_t ), intent(out), allocatable :: error Error handling character(len=*), intent(in), optional :: whereAt Optional description private subroutine get_string(table, key, var, error, whereAt) Function wrapper to get a default string variable from a toml table, returning an fpm error Arguments Type Intent Optional Attributes Name type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in) :: key The key type( string_t ), intent(inout) :: var The variable type( error_t ), intent(out), allocatable :: error Error handling character(len=*), intent(in), optional :: whereAt Optional description","tags":"","url":"interface/get_value.html"},{"title":"set_string – Fortran-lang/fpm","text":"public interface set_string Module Procedures private subroutine set_character(table, key, var, error, whereAt) Function wrapper to set a character(len=:), allocatable variable to a toml table Check the key is not empty Arguments Type Intent Optional Attributes Name type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in) :: key List of keys to check. character(len=*), intent(in), optional :: var The character variable type( error_t ), intent(out), allocatable :: error Error handling character(len=*), intent(in), optional :: whereAt Optional description private subroutine set_string_type(table, key, var, error, whereAt) Function wrapper to set a character(len=:), allocatable variable to a toml table Arguments Type Intent Optional Attributes Name type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in) :: key List of keys to check. type( string_t ), intent(in) :: var The character variable type( error_t ), intent(out), allocatable :: error Error handling character(len=*), intent(in), optional :: whereAt Optional description","tags":"","url":"interface/set_string.html"},{"title":"set_value – Fortran-lang/fpm","text":"public interface set_value set_value: fpm interface Module Procedures private subroutine set_logical(table, key, var, error, whereAt) Function wrapper to set a logical variable to a toml table, returning an fpm error Arguments Type Intent Optional Attributes Name type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in) :: key The key logical, intent(in) :: var The variable type( error_t ), intent(out), allocatable :: error Error handling character(len=*), intent(in), optional :: whereAt Optional description private subroutine set_integer(table, key, var, error, whereAt) Function wrapper to set a default integer variable to a toml table, returning an fpm error Arguments Type Intent Optional Attributes Name type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in) :: key The key integer, intent(in) :: var The variable type( error_t ), intent(out), allocatable :: error Error handling character(len=*), intent(in), optional :: whereAt Optional description private subroutine set_integer_64(table, key, var, error, whereAt) Function wrapper to set a default integer variable to a toml table, returning an fpm error Arguments Type Intent Optional Attributes Name type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in) :: key The key integer(kind=int64), intent(in) :: var The variable type( error_t ), intent(out), allocatable :: error Error handling character(len=*), intent(in), optional :: whereAt Optional description","tags":"","url":"interface/set_value.html"},{"title":"cmd_export – Fortran-lang/fpm","text":"public subroutine cmd_export(settings) Entry point for the export subcommand\nRead in manifest\nExport manifest\nExport dependency tree Generate dependency tree\nExport dependency tree\nExport full model Arguments Type Intent Optional Attributes Name type( fpm_export_settings ), intent(inout) :: settings Representation of the command line arguments Source Code subroutine cmd_export ( settings ) !> Representation of the command line arguments type ( fpm_export_settings ), intent ( inout ) :: settings type ( package_config_t ) :: package type ( dependency_tree_t ) :: deps type ( fpm_model_t ) :: model type ( error_t ), allocatable :: error character ( len = :), allocatable :: filename if ( len_trim ( settings % dump_manifest ) <= 0 . and . & len_trim ( settings % dump_model ) <= 0 . and . & len_trim ( settings % dump_dependencies ) <= 0 ) then call fpm_stop ( 0 , '*cmd_export* exiting: no manifest/model/dependencies keyword provided' ) end if !> Read in manifest call get_package_data ( package , \"fpm.toml\" , error , apply_defaults = . true .) call handle_error ( error ) !> Export manifest if ( len_trim ( settings % dump_manifest ) > 0 ) then filename = trim ( settings % dump_manifest ) call package % dump ( filename , error , json = name_is_json ( filename )) end if !> Export dependency tree if ( len_trim ( settings % dump_dependencies ) > 0 ) then !> Generate dependency tree filename = join_path ( \"build\" , \"cache.toml\" ) call new_dependency_tree ( deps , cache = filename , verbosity = merge ( 2 , 1 , settings % verbose )) call deps % add ( package , error ) call handle_error ( error ) !> Export dependency tree filename = settings % dump_dependencies call deps % dump ( filename , error , json = name_is_json ( filename )) call handle_error ( error ) end if !> Export full model if ( len_trim ( settings % dump_model ) > 0 ) then call build_model ( model , settings % fpm_build_settings , package , error ) if ( allocated ( error )) then call fpm_stop ( 1 , '*cmd_export* Model error: ' // error % message ) end if filename = settings % dump_model call model % dump ( filename , error , json = name_is_json ( filename )) call handle_error ( error ) end if end subroutine cmd_export","tags":"","url":"proc/cmd_export.html"},{"title":"manifest_has_changed – Fortran-lang/fpm","text":"public function manifest_has_changed(cached, manifest, verbosity, iunit) result(has_changed) Check if two dependency configurations are different Perform all checks\nAll checks passed! The two instances are equal Arguments Type Intent Optional Attributes Name class( dependency_config_t ), intent(in) :: cached Two instances of the dependency configuration class( dependency_config_t ), intent(in) :: manifest Two instances of the dependency configuration integer, intent(in) :: verbosity Log verbosity integer, intent(in) :: iunit Log verbosity Return Value logical Source Code logical function manifest_has_changed ( cached , manifest , verbosity , iunit ) result ( has_changed ) !> Two instances of the dependency configuration class ( dependency_config_t ), intent ( in ) :: cached , manifest !> Log verbosity integer , intent ( in ) :: verbosity , iunit has_changed = . true . !> Perform all checks if ( allocated ( cached % git ). neqv . allocated ( manifest % git )) then if ( verbosity > 1 ) write ( iunit , out_fmt ) \"GIT presence has changed. \" return endif if ( allocated ( cached % git )) then if (. not . git_matches_manifest ( cached % git , manifest % git , verbosity , iunit )) return end if !> All checks passed! The two instances are equal has_changed = . false . end function manifest_has_changed","tags":"","url":"proc/manifest_has_changed.html"},{"title":"dependency_destroy – Fortran-lang/fpm","text":"public elemental subroutine dependency_destroy(self) Clean memory Arguments Type Intent Optional Attributes Name class( dependency_config_t ), intent(inout) :: self Source Code elemental subroutine dependency_destroy ( self ) class ( dependency_config_t ), intent ( inout ) :: self if ( allocated ( self % name )) deallocate ( self % name ) if ( allocated ( self % path )) deallocate ( self % path ) if ( allocated ( self % namespace )) deallocate ( self % namespace ) if ( allocated ( self % requested_version )) deallocate ( self % requested_version ) if ( allocated ( self % git )) deallocate ( self % git ) end subroutine dependency_destroy","tags":"","url":"proc/dependency_destroy.html"},{"title":"new_dependencies – Fortran-lang/fpm","text":"public subroutine new_dependencies(deps, table, root, meta, error) Construct new dependency array from a TOML data structure Flag dependencies that should be treated as metapackages\nParse all meta- and non-metapackage dependencies Neither a standard dep nor a metapackage\nValid meta dependency Arguments Type Intent Optional Attributes Name type( dependency_config_t ), intent(out), allocatable :: deps (:) Instance of the dependency configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in), optional :: root Root directory of the manifest type( metapackage_config_t ), intent(out), optional :: meta (optional) metapackages type( error_t ), intent(out), allocatable :: error Error handling Source Code subroutine new_dependencies ( deps , table , root , meta , error ) !> Instance of the dependency configuration type ( dependency_config_t ), allocatable , intent ( out ) :: deps (:) !> (optional) metapackages type ( metapackage_config_t ), optional , intent ( out ) :: meta !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Root directory of the manifest character ( * ), intent ( in ), optional :: root !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_table ), pointer :: node type ( toml_key ), allocatable :: list (:) type ( dependency_config_t ), allocatable :: all_deps (:) type ( metapackage_request_t ) :: meta_request logical , allocatable :: is_meta (:) logical :: metapackages_allowed integer :: idep , stat , ndep call table % get_keys ( list ) ! An empty table is okay if ( size ( list ) < 1 ) return !> Flag dependencies that should be treated as metapackages metapackages_allowed = present ( meta ) allocate ( is_meta ( size ( list )), source = . false .) allocate ( all_deps ( size ( list ))) !> Parse all meta- and non-metapackage dependencies do idep = 1 , size ( list ) ! Check if this is a standard dependency node call get_value ( table , list ( idep )% key , node , stat = stat ) is_standard_dependency : if ( stat /= toml_stat % success ) then ! See if it can be a valid metapackage name call new_meta_request ( meta_request , list ( idep )% key , table , error = error ) !> Neither a standard dep nor a metapackage if ( allocated ( error )) then call syntax_error ( error , \"Dependency \" // list ( idep )% key // \" is not a valid metapackage or a table entry\" ) return endif !> Valid meta dependency is_meta ( idep ) = . true . else ! Parse as a standard dependency is_meta ( idep ) = . false . call new_dependency ( all_deps ( idep ), node , root , error ) if ( allocated ( error )) return end if is_standard_dependency end do ! Non-meta dependencies ndep = count (. not . is_meta ) ! Finalize standard dependencies allocate ( deps ( ndep )) ndep = 0 do idep = 1 , size ( list ) if ( is_meta ( idep )) cycle ndep = ndep + 1 deps ( ndep ) = all_deps ( idep ) end do ! Finalize meta dependencies if ( metapackages_allowed ) call new_meta_config ( meta , table , is_meta , error ) end subroutine new_dependencies","tags":"","url":"proc/new_dependencies.html"},{"title":"new_dependency – Fortran-lang/fpm","text":"public subroutine new_dependency(self, table, root, error) Construct a new dependency configuration from a TOML data structure Get optional preprocessor directives Arguments Type Intent Optional Attributes Name type( dependency_config_t ), intent(out) :: self Instance of the dependency configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in), optional :: root Root directory of the manifest type( error_t ), intent(out), allocatable :: error Error handling Source Code subroutine new_dependency ( self , table , root , error ) !> Instance of the dependency configuration type ( dependency_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Root directory of the manifest character ( * ), intent ( in ), optional :: root !> Error handling type ( error_t ), allocatable , intent ( out ) :: error character ( len = :), allocatable :: uri , value , requested_version type ( toml_table ), pointer :: child call check ( table , error ) if ( allocated ( error )) return call table % get_key ( self % name ) call get_value ( table , \"namespace\" , self % namespace ) call get_value ( table , \"v\" , requested_version ) if ( allocated ( requested_version )) then if (. not . allocated ( self % requested_version )) allocate ( self % requested_version ) call new_version ( self % requested_version , requested_version , error ) if ( allocated ( error )) return end if !> Get optional preprocessor directives call get_value ( table , \"preprocess\" , child , requested = . false .) if ( associated ( child )) then call new_preprocessors ( self % preprocess , child , error ) if ( allocated ( error )) return endif call get_value ( table , \"path\" , uri ) if ( allocated ( uri )) then if ( get_os_type () == OS_WINDOWS ) uri = windows_path ( uri ) if ( present ( root )) uri = join_path ( root , uri ) ! Relative to the fpm.toml it’s written in call move_alloc ( uri , self % path ) return end if call get_value ( table , \"git\" , uri ) if ( allocated ( uri )) then call get_value ( table , \"tag\" , value ) if ( allocated ( value )) then self % git = git_target_tag ( uri , value ) end if if (. not . allocated ( self % git )) then call get_value ( table , \"branch\" , value ) if ( allocated ( value )) then self % git = git_target_branch ( uri , value ) end if end if if (. not . allocated ( self % git )) then call get_value ( table , \"rev\" , value ) if ( allocated ( value )) then self % git = git_target_revision ( uri , value ) end if end if if (. not . allocated ( self % git )) then self % git = git_target_default ( uri ) end if return end if end subroutine new_dependency","tags":"","url":"proc/new_dependency.html"},{"title":"resize – Fortran-lang/fpm","text":"public interface resize Module Procedures private pure subroutine resize_dependency_config(var, n) Reallocate a list of dependencies Arguments Type Intent Optional Attributes Name type( dependency_config_t ), intent(inout), allocatable :: var (:) Instance of the array to be resized integer, intent(in), optional :: n Dimension of the final array size","tags":"","url":"interface/resize~2.html"},{"title":"init_netcdf – Fortran-lang/fpm","text":"public subroutine init_netcdf(this, compiler, all_meta, error) Initialize NetCDF metapackage for the current system\nCleanup\nSet name Assert pkg-config is installed\nAdd NetCDF modules as external Arguments Type Intent Optional Attributes Name class( metapackage_t ), intent(inout) :: this type( compiler_t ), intent(in) :: compiler type( metapackage_request_t ), intent(in) :: all_meta (:) type( error_t ), intent(out), allocatable :: error Source Code subroutine init_netcdf ( this , compiler , all_meta , error ) class ( metapackage_t ), intent ( inout ) :: this type ( compiler_t ), intent ( in ) :: compiler type ( metapackage_request_t ), intent ( in ) :: all_meta (:) type ( error_t ), allocatable , intent ( out ) :: error logical :: s character ( len = :), allocatable :: include_flag , libdir include_flag = get_include_flag ( compiler , \"\" ) !> Cleanup call destroy ( this ) allocate ( this % link_libs ( 0 ), this % incl_dirs ( 0 ), this % external_modules ( 0 )) this % link_flags = string_t ( \"\" ) this % flags = string_t ( \"\" ) !> Set name this % name = \"netcdf\" !> Assert pkg-config is installed if (. not . assert_pkg_config ()) then call fatal_error ( error , 'netcdf metapackage requires pkg-config' ) return end if if (. not . pkgcfg_has_package ( 'netcdf' )) then call fatal_error ( error , 'pkg-config could not find a suitable netcdf package.' ) return end if call add_pkg_config_compile_options ( this , 'netcdf' , include_flag , libdir , error ) if ( allocated ( error )) return if (. not . pkgcfg_has_package ( 'netcdf-fortran' )) then call fatal_error ( error , & 'pkg-config could not find a suitable netcdf-fortran package.' ) return end if call add_pkg_config_compile_options ( this , 'netcdf-fortran' , include_flag , libdir , error ) if ( allocated ( error )) return !> Add NetCDF modules as external this % has_external_modules = . true . this % external_modules = [ string_t ( 'netcdf' ), & string_t ( 'netcdf4_f03' ), & string_t ( 'netcdf4_nc_interfaces' ), & string_t ( 'netcdf4_nf_interfaces' ), & string_t ( 'netcdf_f03' ), & string_t ( 'netcdf_fortv2_c_interfaces' ), & string_t ( 'netcdf_nc_data' ), & string_t ( 'netcdf_nc_interfaces' ), & string_t ( 'netcdf_nf_data' ), & string_t ( 'netcdf_nf_interfaces' )] end subroutine init_netcdf","tags":"","url":"proc/init_netcdf.html"},{"title":"new_installer – Fortran-lang/fpm","text":"public subroutine new_installer(self, prefix, bindir, libdir, includedir, testdir, verbosity, copy, move) Create a new instance of an installer Arguments Type Intent Optional Attributes Name type( installer_t ), intent(out) :: self Instance of the installer character(len=*), intent(in), optional :: prefix Path to installation directory character(len=*), intent(in), optional :: bindir Binary dir relative to the installation prefix character(len=*), intent(in), optional :: libdir Library directory relative to the installation prefix character(len=*), intent(in), optional :: includedir Include directory relative to the installation prefix character(len=*), intent(in), optional :: testdir Test directory relative to the installation prefix integer, intent(in), optional :: verbosity Verbosity of the installer character(len=*), intent(in), optional :: copy Copy command character(len=*), intent(in), optional :: move Move command Source Code subroutine new_installer ( self , prefix , bindir , libdir , includedir , testdir , verbosity , & copy , move ) !> Instance of the installer type ( installer_t ), intent ( out ) :: self !> Path to installation directory character ( len =* ), intent ( in ), optional :: prefix !> Binary dir relative to the installation prefix character ( len =* ), intent ( in ), optional :: bindir !> Library directory relative to the installation prefix character ( len =* ), intent ( in ), optional :: libdir !> Include directory relative to the installation prefix character ( len =* ), intent ( in ), optional :: includedir !> Test directory relative to the installation prefix character ( len =* ), intent ( in ), optional :: testdir !> Verbosity of the installer integer , intent ( in ), optional :: verbosity !> Copy command character ( len =* ), intent ( in ), optional :: copy !> Move command character ( len =* ), intent ( in ), optional :: move self % os = get_os_type () ! By default, never prompt the user for overwrites if ( present ( copy )) then self % copy = copy else if ( os_is_unix ( self % os )) then self % copy = default_force_copy_unix else self % copy = default_force_copy_win end if end if if ( present ( move )) then self % move = move else if ( os_is_unix ( self % os )) then self % move = default_move_unix else self % move = default_move_win end if end if if ( present ( includedir )) then self % includedir = includedir else self % includedir = default_includedir end if if ( present ( testdir )) then self % testdir = testdir else self % testdir = default_testdir end if if ( present ( prefix )) then self % prefix = prefix else self % prefix = get_local_prefix ( self % os ) end if if ( present ( bindir )) then self % bindir = bindir else self % bindir = default_bindir end if if ( present ( libdir )) then self % libdir = libdir else self % libdir = default_libdir end if if ( present ( verbosity )) then self % verbosity = verbosity else self % verbosity = 1 end if end subroutine new_installer","tags":"","url":"proc/new_installer.html"},{"title":"file_scope_same – Fortran-lang/fpm","text":"public function file_scope_same(this, that) All checks passed! Type Bound file_scope_flag Arguments Type Intent Optional Attributes Name class( file_scope_flag ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical Source Code logical function file_scope_same ( this , that ) class ( file_scope_flag ), intent ( in ) :: this class ( serializable_t ), intent ( in ) :: that file_scope_same = . false . select type ( other => that ) type is ( file_scope_flag ) if ( allocated ( this % file_name ). neqv . allocated ( other % file_name )) return if ( allocated ( this % file_name )) then if (. not .( this % file_name == other % file_name )) return endif if ( allocated ( this % flags ). neqv . allocated ( other % flags )) return if ( allocated ( this % flags )) then if (. not .( this % flags == other % flags )) return endif class default ! Not the same type return end select !> All checks passed! file_scope_same = . true . end function file_scope_same","tags":"","url":"proc/file_scope_same.html"},{"title":"get_default_profiles – Fortran-lang/fpm","text":"public function get_default_profiles(error) result(default_profiles) Construct an array of built-in profiles Arguments Type Intent Optional Attributes Name type( error_t ), intent(out), allocatable :: error Error handling Return Value type( profile_config_t ), allocatable, (:) Source Code function get_default_profiles ( error ) result ( default_profiles ) !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( profile_config_t ), allocatable :: default_profiles (:) default_profiles = [ & & new_profile ( 'release' , & & 'caf' , & & OS_ALL , & & flags = ' -O3 -Wimplicit-interface -fPIC -fmax-errors=1 -funroll-loops' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'gfortran' , & & OS_ALL , & & flags = ' -O3 -Wimplicit-interface -fPIC -fmax-errors=1 -funroll-loops -fcoarray=single' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'f95' , & & OS_ALL , & & flags = ' -O3 -Wimplicit-interface -fPIC -fmax-errors=1 -ffast-math -funroll-loops' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'nvfortran' , & & OS_ALL , & & flags = ' -Mbackslash' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'ifort' , & & OS_ALL , & & flags = ' -fp-model precise -pc64 -align all -error-limit 1 -reentrancy& & threaded -nogen-interfaces -assume byterecl' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'ifort' , & & OS_WINDOWS , & & flags = ' /fp:precise /align:all /error-limit:1 /reentrancy:threaded& & /nogen-interfaces /assume:byterecl' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'ifx' , & & OS_ALL , & & flags = ' -fp-model=precise -pc64 -align all -error-limit 1 -reentrancy& & threaded -nogen-interfaces -assume byterecl' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'ifx' , & & OS_WINDOWS , & & flags = ' /fp:precise /align:all /error-limit:1 /reentrancy:threaded& & /nogen-interfaces /assume:byterecl' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'nagfor' , & & OS_ALL , & & flags = ' -O4 -coarray=single -PIC' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'lfortran' , & & OS_ALL , & & flags = ' flag_lfortran_opt' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'caf' , & & OS_ALL , & & flags = ' -Wall -Wextra -Wimplicit-interface -fPIC -fmax-errors=1 -g -fcheck=bounds& & -fcheck=array-temps -fbacktrace' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'gfortran' , & & OS_ALL , & & flags = ' -Wall -Wextra -Wimplicit-interface -fPIC -fmax-errors=1 -g -fcheck=bounds& & -fcheck=array-temps -fbacktrace -fcoarray=single' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'f95' , & & OS_ALL , & & flags = ' -Wall -Wextra -Wimplicit-interface -fPIC -fmax-errors=1 -g -fcheck=bounds& & -fcheck=array-temps -Wno-maybe-uninitialized -Wno-uninitialized -fbacktrace' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'nvfortran' , & & OS_ALL , & & flags = ' -Minform=inform -Mbackslash -g -Mbounds -Mchkptr -Mchkstk -traceback' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'ifort' , & & OS_ALL , & & flags = ' -warn all -check all -error-limit 1 -O0 -g -assume byterecl -traceback' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'ifort' , & & OS_WINDOWS , & & flags = ' /warn:all /check:all /error-limit:1& & /Od /Z7 /assume:byterecl /traceback' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'ifx' , & & OS_ALL , & & flags = ' -warn all -check all -error-limit 1 -O0 -g -assume byterecl -traceback' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'ifx' , & & OS_WINDOWS , & & flags = ' /warn:all /check:all /error-limit:1 /Od /Z7 /assume:byterecl' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'ifx' , & & OS_WINDOWS , & & flags = ' /warn:all /check:all /error-limit:1 /Od /Z7 /assume:byterecl' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'lfortran' , & & OS_ALL , & & flags = '' , & & is_built_in = . true .) & &] end function get_default_profiles","tags":"","url":"proc/get_default_profiles.html"},{"title":"info_profile – Fortran-lang/fpm","text":"public function info_profile(profile) result(s) Print a representation of profile_config_t Arguments Type Intent Optional Attributes Name type( profile_config_t ), intent(in) :: profile Profile to be represented Return Value character(len=:), allocatable String representation of given profile Variables Type Visibility Attributes Name Initial integer, public :: i Source Code function info_profile ( profile ) result ( s ) !> Profile to be represented type ( profile_config_t ), intent ( in ) :: profile !> String representation of given profile character (:), allocatable :: s integer :: i s = \"profile_config_t(\" s = s // 'profile_name=\"' // profile % profile_name // '\"' s = s // ', compiler=\"' // profile % compiler // '\"' s = s // \", os_type=\" select case ( profile % os_type ) case ( OS_UNKNOWN ) s = s // \"OS_UNKNOWN\" case ( OS_LINUX ) s = s // \"OS_LINUX\" case ( OS_MACOS ) s = s // \"OS_MACOS\" case ( OS_WINDOWS ) s = s // \"OS_WINDOWS\" case ( OS_CYGWIN ) s = s // \"OS_CYGWIN\" case ( OS_SOLARIS ) s = s // \"OS_SOLARIS\" case ( OS_FREEBSD ) s = s // \"OS_FREEBSD\" case ( OS_OPENBSD ) s = s // \"OS_OPENBSD\" case ( OS_ALL ) s = s // \"OS_ALL\" case default s = s // \"INVALID\" end select if ( allocated ( profile % flags )) s = s // ', flags=\"' // profile % flags // '\"' if ( allocated ( profile % c_flags )) s = s // ', c_flags=\"' // profile % c_flags // '\"' if ( allocated ( profile % cxx_flags )) s = s // ', cxx_flags=\"' // profile % cxx_flags // '\"' if ( allocated ( profile % link_time_flags )) s = s // ', link_time_flags=\"' // profile % link_time_flags // '\"' if ( allocated ( profile % file_scope_flags )) then do i = 1 , size ( profile % file_scope_flags ) s = s // ', flags for ' // profile % file_scope_flags ( i )% file_name // & & ' =\"' // profile % file_scope_flags ( i )% flags // '\"' end do end if s = s // \")\" end function info_profile","tags":"","url":"proc/info_profile.html"},{"title":"new_profile – Fortran-lang/fpm","text":"public function new_profile(profile_name, compiler, os_type, flags, c_flags, cxx_flags, link_time_flags, file_scope_flags, is_built_in) result(profile) Construct a new profile configuration from a TOML data structure Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: profile_name Name of the profile character(len=*), intent(in) :: compiler Name of the compiler integer, intent(in) :: os_type Type of the OS character(len=*), intent(in), optional :: flags Fortran compiler flags character(len=*), intent(in), optional :: c_flags C compiler flags character(len=*), intent(in), optional :: cxx_flags C++ compiler flags character(len=*), intent(in), optional :: link_time_flags Link time compiler flags type( file_scope_flag ), intent(in), optional :: file_scope_flags (:) File scope flags logical, intent(in), optional :: is_built_in Is this profile one of the built-in ones? Return Value type( profile_config_t ) Source Code function new_profile ( profile_name , compiler , os_type , flags , c_flags , cxx_flags , & link_time_flags , file_scope_flags , is_built_in ) & & result ( profile ) !> Name of the profile character ( len =* ), intent ( in ) :: profile_name !> Name of the compiler character ( len =* ), intent ( in ) :: compiler !> Type of the OS integer , intent ( in ) :: os_type !> Fortran compiler flags character ( len =* ), optional , intent ( in ) :: flags !> C compiler flags character ( len =* ), optional , intent ( in ) :: c_flags !> C++ compiler flags character ( len =* ), optional , intent ( in ) :: cxx_flags !> Link time compiler flags character ( len =* ), optional , intent ( in ) :: link_time_flags !> File scope flags type ( file_scope_flag ), optional , intent ( in ) :: file_scope_flags (:) !> Is this profile one of the built-in ones? logical , optional , intent ( in ) :: is_built_in type ( profile_config_t ) :: profile profile % profile_name = profile_name profile % compiler = compiler profile % os_type = os_type if ( present ( flags )) then profile % flags = flags else profile % flags = \"\" end if if ( present ( c_flags )) then profile % c_flags = c_flags else profile % c_flags = \"\" end if if ( present ( cxx_flags )) then profile % cxx_flags = cxx_flags else profile % cxx_flags = \"\" end if if ( present ( link_time_flags )) then profile % link_time_flags = link_time_flags else profile % link_time_flags = \"\" end if if ( present ( file_scope_flags )) then profile % file_scope_flags = file_scope_flags end if if ( present ( is_built_in )) then profile % is_built_in = is_built_in else profile % is_built_in = . false . end if end function new_profile","tags":"","url":"proc/new_profile.html"},{"title":"os_type_name – Fortran-lang/fpm","text":"public function os_type_name(os_type) Match lowercase string with name of OS to os_type enum Arguments Type Intent Optional Attributes Name integer, intent(in) :: os_type Enum representing type of OS Return Value character(len=:), allocatable Name of operating system Source Code function os_type_name ( os_type ) !> Name of operating system character ( len = :), allocatable :: os_type_name !> Enum representing type of OS integer , intent ( in ) :: os_type select case ( os_type ) case ( OS_ALL ); os_type_name = \"all\" case default ; os_type_name = lower ( OS_NAME ( os_type )) end select end function os_type_name","tags":"","url":"proc/os_type_name.html"},{"title":"profile_same – Fortran-lang/fpm","text":"public function profile_same(this, that) All checks passed! Type Bound profile_config_t Arguments Type Intent Optional Attributes Name class( profile_config_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical Variables Type Visibility Attributes Name Initial integer, public :: ii Source Code logical function profile_same ( this , that ) class ( profile_config_t ), intent ( in ) :: this class ( serializable_t ), intent ( in ) :: that integer :: ii profile_same = . false . select type ( other => that ) type is ( profile_config_t ) if ( allocated ( this % profile_name ). neqv . allocated ( other % profile_name )) return if ( allocated ( this % profile_name )) then if (. not .( this % profile_name == other % profile_name )) return endif if ( allocated ( this % compiler ). neqv . allocated ( other % compiler )) return if ( allocated ( this % compiler )) then if (. not .( this % compiler == other % compiler )) return endif if ( this % os_type /= other % os_type ) return if ( allocated ( this % flags ). neqv . allocated ( other % flags )) return if ( allocated ( this % flags )) then if (. not .( this % flags == other % flags )) return endif if ( allocated ( this % c_flags ). neqv . allocated ( other % c_flags )) return if ( allocated ( this % c_flags )) then if (. not .( this % c_flags == other % c_flags )) return endif if ( allocated ( this % cxx_flags ). neqv . allocated ( other % cxx_flags )) return if ( allocated ( this % cxx_flags )) then if (. not .( this % cxx_flags == other % cxx_flags )) return endif if ( allocated ( this % link_time_flags ). neqv . allocated ( other % link_time_flags )) return if ( allocated ( this % link_time_flags )) then if (. not .( this % link_time_flags == other % link_time_flags )) return endif if ( allocated ( this % file_scope_flags ). neqv . allocated ( other % file_scope_flags )) return if ( allocated ( this % file_scope_flags )) then if (. not . size ( this % file_scope_flags ) == size ( other % file_scope_flags )) return do ii = 1 , size ( this % file_scope_flags ) print * , 'check ii-th file scope: ' , ii if (. not . this % file_scope_flags ( ii ) == other % file_scope_flags ( ii )) return end do endif if ( this % is_built_in . neqv . other % is_built_in ) return class default ! Not the same type return end select !> All checks passed! profile_same = . true . end function profile_same","tags":"","url":"proc/profile_same.html"},{"title":"file_scope_dump – Fortran-lang/fpm","text":"public subroutine file_scope_dump(self, table, error) Dump to toml table Type Bound file_scope_flag Arguments Type Intent Optional Attributes Name class( file_scope_flag ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling Source Code subroutine file_scope_dump ( self , table , error ) !> Instance of the serializable object class ( file_scope_flag ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error call set_string ( table , \"file-name\" , self % file_name , error ) if ( allocated ( error )) return call set_string ( table , \"flags\" , self % flags , error ) if ( allocated ( error )) return end subroutine file_scope_dump","tags":"","url":"proc/file_scope_dump.html"},{"title":"file_scope_load – Fortran-lang/fpm","text":"public subroutine file_scope_load(self, table, error) Read from toml table (no checks made at this stage) Type Bound file_scope_flag Arguments Type Intent Optional Attributes Name class( file_scope_flag ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling Source Code subroutine file_scope_load ( self , table , error ) !> Instance of the serializable object class ( file_scope_flag ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error call get_value ( table , \"file-name\" , self % file_name ) call get_value ( table , \"flags\" , self % flags ) end subroutine file_scope_load","tags":"","url":"proc/file_scope_load.html"},{"title":"find_profile – Fortran-lang/fpm","text":"public subroutine find_profile(profiles, profile_name, compiler, os_type, found_matching, chosen_profile) Look for profile with given configuration in array profiles Arguments Type Intent Optional Attributes Name type( profile_config_t ), intent(in), allocatable :: profiles (:) Array of profiles character(len=:), intent(in), allocatable :: profile_name Name of profile character(len=:), intent(in), allocatable :: compiler Name of compiler integer, intent(in) :: os_type Type of operating system (enum) logical, intent(out) :: found_matching Boolean value containing true if matching profile was found type( profile_config_t ), intent(out) :: chosen_profile Last matching profile in the profiles array Variables Type Visibility Attributes Name Initial character(len=:), public, allocatable :: curr_compiler integer, public :: curr_os integer, public :: curr_priority character(len=:), public, allocatable :: curr_profile_name integer, public :: i integer, public :: priority Source Code subroutine find_profile ( profiles , profile_name , compiler , os_type , found_matching , chosen_profile ) !> Array of profiles type ( profile_config_t ), allocatable , intent ( in ) :: profiles (:) !> Name of profile character (:), allocatable , intent ( in ) :: profile_name !> Name of compiler character (:), allocatable , intent ( in ) :: compiler !> Type of operating system (enum) integer , intent ( in ) :: os_type !> Boolean value containing true if matching profile was found logical , intent ( out ) :: found_matching !> Last matching profile in the profiles array type ( profile_config_t ), intent ( out ) :: chosen_profile character (:), allocatable :: curr_profile_name character (:), allocatable :: curr_compiler integer :: curr_os integer :: i , priority , curr_priority found_matching = . false . if ( size ( profiles ) < 1 ) return ! Try to find profile with matching OS type do i = 1 , size ( profiles ) curr_profile_name = profiles ( i )% profile_name curr_compiler = profiles ( i )% compiler curr_os = profiles ( i )% os_type if ( curr_profile_name . eq . profile_name ) then if ( curr_compiler . eq . compiler ) then if ( curr_os . eq . os_type ) then chosen_profile = profiles ( i ) found_matching = . true . end if end if end if end do ! Try to find profile with OS type 'all' if (. not . found_matching ) then do i = 1 , size ( profiles ) curr_profile_name = profiles ( i )% profile_name curr_compiler = profiles ( i )% compiler curr_os = profiles ( i )% os_type if ( curr_profile_name . eq . profile_name ) then if ( curr_compiler . eq . compiler ) then if ( curr_os . eq . OS_ALL ) then chosen_profile = profiles ( i ) found_matching = . true . end if end if end if end do end if end subroutine find_profile","tags":"","url":"proc/find_profile.html"},{"title":"get_flags – Fortran-lang/fpm","text":"public subroutine get_flags(profile_name, compiler_name, os_type, key_list, table, profiles, profindex, os_valid) Look for flags, c-flags, link-time-flags key-val pairs\nand files table in a given table and create new profiles Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: profile_name Name of profile character(len=:), intent(in), allocatable :: compiler_name Name of compiler integer, intent(in) :: os_type OS type type(toml_key), intent(in), allocatable :: key_list (:) List of keys in the table type(toml_table), intent(in), pointer :: table Table containing OS tables type( profile_config_t ), intent(inout), allocatable :: profiles (:) List of profiles integer, intent(inout) :: profindex Index in the list of profiles logical, intent(in) :: os_valid Was called with valid operating system Variables Type Visibility Attributes Name Initial character(len=:), public, allocatable :: c_flags character(len=:), public, allocatable :: cxx_flags character(len=:), public, allocatable :: err_message character(len=:), public, allocatable :: file_flags type(toml_key), public, allocatable :: file_list (:) character(len=:), public, allocatable :: file_name type( file_scope_flag ), public, allocatable :: file_scope_flags (:) type(toml_table), public, pointer :: files character(len=:), public, allocatable :: flags integer, public :: ifile integer, public :: ikey logical, public :: is_valid character(len=:), public, allocatable :: key_name character(len=:), public, allocatable :: link_time_flags integer, public :: stat Source Code subroutine get_flags ( profile_name , compiler_name , os_type , key_list , table , profiles , profindex , os_valid ) !> Name of profile character ( len = :), allocatable , intent ( in ) :: profile_name !> Name of compiler character ( len = :), allocatable , intent ( in ) :: compiler_name !> OS type integer , intent ( in ) :: os_type !> List of keys in the table type ( toml_key ), allocatable , intent ( in ) :: key_list (:) !> Table containing OS tables type ( toml_table ), pointer , intent ( in ) :: table !> List of profiles type ( profile_config_t ), allocatable , intent ( inout ) :: profiles (:) !> Index in the list of profiles integer , intent ( inout ) :: profindex !> Was called with valid operating system logical , intent ( in ) :: os_valid character ( len = :), allocatable :: flags , c_flags , cxx_flags , link_time_flags , key_name , file_name , file_flags , err_message type ( toml_table ), pointer :: files type ( toml_key ), allocatable :: file_list (:) type ( file_scope_flag ), allocatable :: file_scope_flags (:) integer :: ikey , ifile , stat logical :: is_valid call get_value ( table , 'flags' , flags ) call get_value ( table , 'c-flags' , c_flags ) call get_value ( table , 'cxx-flags' , cxx_flags ) call get_value ( table , 'link-time-flags' , link_time_flags ) call get_value ( table , 'files' , files ) if ( associated ( files )) then call files % get_keys ( file_list ) allocate ( file_scope_flags ( size ( file_list ))) do ifile = 1 , size ( file_list ) file_name = file_list ( ifile )% key call get_value ( files , file_name , file_flags ) associate ( cur_file => file_scope_flags ( ifile )) if (. not .( path . eq . \"\" )) file_name = join_path ( path , file_name ) cur_file % file_name = file_name cur_file % flags = file_flags end associate end do end if profiles ( profindex ) = new_profile ( profile_name , compiler_name , os_type , & & flags , c_flags , cxx_flags , link_time_flags , file_scope_flags ) profindex = profindex + 1 end subroutine get_flags","tags":"","url":"proc/get_flags.html"},{"title":"info – Fortran-lang/fpm","text":"public subroutine info(self, unit, verbosity) Write information on instance Type Bound profile_config_t Arguments Type Intent Optional Attributes Name class( profile_config_t ), intent(in) :: self Instance of the profile configuration integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout Variables Type Visibility Attributes Name Initial character(len=*), public, parameter :: fmt = '(\"#\", 1x, a, t30, a)' integer, public :: pr Source Code subroutine info ( self , unit , verbosity ) !> Instance of the profile configuration class ( profile_config_t ), intent ( in ) :: self !> Unit for IO integer , intent ( in ) :: unit !> Verbosity of the printout integer , intent ( in ), optional :: verbosity integer :: pr character ( len =* ), parameter :: fmt = '(\"#\", 1x, a, t30, a)' if ( present ( verbosity )) then pr = verbosity else pr = 1 end if write ( unit , fmt ) \"Profile\" if ( allocated ( self % profile_name )) then write ( unit , fmt ) \"- profile name\" , self % profile_name end if if ( allocated ( self % compiler )) then write ( unit , fmt ) \"- compiler\" , self % compiler end if write ( unit , fmt ) \"- os\" , os_type_name ( self % os_type ) if ( allocated ( self % flags )) then write ( unit , fmt ) \"- compiler flags\" , self % flags end if end subroutine info","tags":"","url":"proc/info~8.html"},{"title":"match_os_type – Fortran-lang/fpm","text":"public subroutine match_os_type(os_name, os_type) Match os_type enum to a lowercase string with name of OS Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: os_name Name of operating system integer, intent(out) :: os_type Enum representing type of OS Source Code subroutine match_os_type ( os_name , os_type ) !> Name of operating system character ( len = :), allocatable , intent ( in ) :: os_name !> Enum representing type of OS integer , intent ( out ) :: os_type select case ( os_name ) case ( \"linux\" ); os_type = OS_LINUX case ( \"macos\" ); os_type = OS_MACOS case ( \"windows\" ); os_type = OS_WINDOWS case ( \"cygwin\" ); os_type = OS_CYGWIN case ( \"solaris\" ); os_type = OS_SOLARIS case ( \"freebsd\" ); os_type = OS_FREEBSD case ( \"openbsd\" ); os_type = OS_OPENBSD case ( \"all\" ); os_type = OS_ALL case default ; os_type = OS_UNKNOWN end select end subroutine match_os_type","tags":"","url":"proc/match_os_type.html"},{"title":"new_profiles – Fortran-lang/fpm","text":"public subroutine new_profiles(profiles, table, error) Construct new profiles array from a TOML data structure Arguments Type Intent Optional Attributes Name type( profile_config_t ), intent(out), allocatable :: profiles (:) Instance of the dependency configuration type(toml_table), intent(inout), target :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling Variables Type Visibility Attributes Name Initial type(toml_key), public, allocatable :: comp_list (:) character(len=:), public, allocatable :: compiler_name type( profile_config_t ), public, allocatable :: default_profiles (:) integer, public :: iprof logical, public :: is_valid type(toml_key), public, allocatable :: os_list (:) type(toml_key), public, allocatable :: prof_list (:) type(toml_table), public, pointer :: prof_node character(len=:), public, allocatable :: profile_name integer, public :: profiles_size integer, public :: profindex integer, public :: stat Source Code subroutine new_profiles ( profiles , table , error ) !> Instance of the dependency configuration type ( profile_config_t ), allocatable , intent ( out ) :: profiles (:) !> Instance of the TOML data structure type ( toml_table ), target , intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_table ), pointer :: prof_node type ( toml_key ), allocatable :: prof_list (:) type ( toml_key ), allocatable :: comp_list (:) type ( toml_key ), allocatable :: os_list (:) character ( len = :), allocatable :: profile_name , compiler_name integer :: profiles_size , iprof , stat , profindex logical :: is_valid type ( profile_config_t ), allocatable :: default_profiles (:) path = '' default_profiles = get_default_profiles ( error ) if ( allocated ( error )) return call table % get_keys ( prof_list ) if ( size ( prof_list ) < 1 ) return profiles_size = 0 do iprof = 1 , size ( prof_list ) profile_name = prof_list ( iprof )% key call validate_compiler_name ( profile_name , is_valid ) if ( is_valid ) then profile_name = \"all\" comp_list = prof_list ( iprof : iprof ) prof_node => table call traverse_compilers ( profile_name , comp_list , prof_node , error , profiles_size = profiles_size ) if ( allocated ( error )) return else call validate_os_name ( profile_name , is_valid ) if ( is_valid ) then os_list = prof_list ( iprof : iprof ) profile_name = 'all' compiler_name = DEFAULT_COMPILER call traverse_oss_for_size ( profile_name , compiler_name , os_list , table , profiles_size , error ) if ( allocated ( error )) return else call get_value ( table , profile_name , prof_node , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"Profile \" // prof_list ( iprof )% key // \" must be a table entry\" ) exit end if call prof_node % get_keys ( comp_list ) call traverse_compilers ( profile_name , comp_list , prof_node , error , profiles_size = profiles_size ) if ( allocated ( error )) return end if end if end do profiles_size = profiles_size + size ( default_profiles ) allocate ( profiles ( profiles_size )) do profindex = 1 , size ( default_profiles ) profiles ( profindex ) = default_profiles ( profindex ) end do do iprof = 1 , size ( prof_list ) profile_name = prof_list ( iprof )% key call validate_compiler_name ( profile_name , is_valid ) if ( is_valid ) then profile_name = \"all\" comp_list = prof_list ( iprof : iprof ) prof_node => table call traverse_compilers ( profile_name , comp_list , prof_node , error , profiles = profiles , profindex = profindex ) if ( allocated ( error )) return else call validate_os_name ( profile_name , is_valid ) if ( is_valid ) then os_list = prof_list ( iprof : iprof ) profile_name = 'all' compiler_name = DEFAULT_COMPILER prof_node => table call traverse_oss ( profile_name , compiler_name , os_list , prof_node , profiles , profindex , error ) if ( allocated ( error )) return else call get_value ( table , profile_name , prof_node , stat = stat ) call prof_node % get_keys ( comp_list ) call traverse_compilers ( profile_name , comp_list , prof_node , error , profiles = profiles , profindex = profindex ) if ( allocated ( error )) return end if end if end do ! Apply profiles with profile name 'all' to matching profiles do iprof = 1 , size ( profiles ) if ( profiles ( iprof )% profile_name . eq . 'all' ) then do profindex = 1 , size ( profiles ) if (. not .( profiles ( profindex )% profile_name . eq . 'all' ) & & . and .( profiles ( profindex )% compiler . eq . profiles ( iprof )% compiler ) & & . and .( profiles ( profindex )% os_type . eq . profiles ( iprof )% os_type )) then profiles ( profindex )% flags = profiles ( profindex )% flags // & & \" \" // profiles ( iprof )% flags profiles ( profindex )% c_flags = profiles ( profindex )% c_flags // & & \" \" // profiles ( iprof )% c_flags profiles ( profindex )% cxx_flags = profiles ( profindex )% cxx_flags // & & \" \" // profiles ( iprof )% cxx_flags profiles ( profindex )% link_time_flags = profiles ( profindex )% link_time_flags // & & \" \" // profiles ( iprof )% link_time_flags end if end do end if end do end subroutine new_profiles","tags":"","url":"proc/new_profiles.html"},{"title":"profile_dump – Fortran-lang/fpm","text":"public subroutine profile_dump(self, table, error) Dump to toml table Because files need a name, fallback if this has no name Type Bound profile_config_t Arguments Type Intent Optional Attributes Name class( profile_config_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling Variables Type Visibility Attributes Name Initial integer, public :: ierr Local variables integer, public :: ii Local variables type(toml_table), public, pointer :: ptr type(toml_table), public, pointer :: ptr_deps character(len=30), public :: unnamed Source Code subroutine profile_dump ( self , table , error ) !> Instance of the serializable object class ( profile_config_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Local variables integer :: ierr , ii type ( toml_table ), pointer :: ptr_deps , ptr character ( len = 30 ) :: unnamed call set_string ( table , \"profile-name\" , self % profile_name , error ) if ( allocated ( error )) return call set_string ( table , \"compiler\" , self % compiler , error ) if ( allocated ( error )) return call set_string ( table , \"os-type\" , os_type_name ( self % os_type ), error , 'profile_config_t' ) if ( allocated ( error )) return call set_string ( table , \"flags\" , self % flags , error ) if ( allocated ( error )) return call set_string ( table , \"c-flags\" , self % c_flags , error ) if ( allocated ( error )) return call set_string ( table , \"cxx-flags\" , self % cxx_flags , error ) if ( allocated ( error )) return call set_string ( table , \"link-time-flags\" , self % link_time_flags , error ) if ( allocated ( error )) return if ( allocated ( self % file_scope_flags )) then ! Create dependency table call add_table ( table , \"file-scope-flags\" , ptr_deps ) if (. not . associated ( ptr_deps )) then call fatal_error ( error , \"profile_config_t cannot create file scope table \" ) return end if do ii = 1 , size ( self % file_scope_flags ) associate ( dep => self % file_scope_flags ( ii )) !> Because files need a name, fallback if this has no name if ( len_trim ( dep % file_name ) == 0 ) then write ( unnamed , 1 ) ii call add_table ( ptr_deps , trim ( unnamed ), ptr ) else call add_table ( ptr_deps , dep % file_name , ptr ) end if if (. not . associated ( ptr )) then call fatal_error ( error , \"profile_config_t cannot create entry for file \" // dep % file_name ) return end if call dep % dump_to_toml ( ptr , error ) if ( allocated ( error )) return end associate end do endif call set_value ( table , \"is-built-in\" , self % is_built_in , error , 'profile_config_t' ) if ( allocated ( error )) return 1 format ( 'UNNAMED_FILE_' , i0 ) end subroutine profile_dump","tags":"","url":"proc/profile_dump.html"},{"title":"profile_load – Fortran-lang/fpm","text":"public subroutine profile_load(self, table, error) Read from toml table (no checks made at this stage) Read all packages Type Bound profile_config_t Arguments Type Intent Optional Attributes Name class( profile_config_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling Variables Type Visibility Attributes Name Initial type(toml_key), public, allocatable :: dep_keys (:) character(len=:), public, allocatable :: flag Local variables integer, public :: ii integer, public :: jj type(toml_key), public, allocatable :: keys (:) type(toml_table), public, pointer :: ptr type(toml_table), public, pointer :: ptr_dep Source Code subroutine profile_load ( self , table , error ) !> Instance of the serializable object class ( profile_config_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Local variables character ( len = :), allocatable :: flag integer :: ii , jj type ( toml_table ), pointer :: ptr_dep , ptr type ( toml_key ), allocatable :: keys (:), dep_keys (:) call table % get_keys ( keys ) call get_value ( table , \"profile-name\" , self % profile_name ) call get_value ( table , \"compiler\" , self % compiler ) call get_value ( table , \"os-type\" , flag ) call match_os_type ( flag , self % os_type ) call get_value ( table , \"flags\" , self % flags ) call get_value ( table , \"c-flags\" , self % c_flags ) call get_value ( table , \"cxx-flags\" , self % cxx_flags ) call get_value ( table , \"link-time-flags\" , self % link_time_flags ) call get_value ( table , \"is-built-in\" , self % is_built_in , error , 'profile_config_t' ) if ( allocated ( error )) return if ( allocated ( self % file_scope_flags )) deallocate ( self % file_scope_flags ) sub_deps : do ii = 1 , size ( keys ) select case ( keys ( ii )% key ) case ( \"file-scope-flags\" ) call get_value ( table , keys ( ii ), ptr ) if (. not . associated ( ptr )) then call fatal_error ( error , 'profile_config_t: error retrieving file_scope_flags table' ) return end if !> Read all packages call ptr % get_keys ( dep_keys ) allocate ( self % file_scope_flags ( size ( dep_keys ))) do jj = 1 , size ( dep_keys ) call get_value ( ptr , dep_keys ( jj ), ptr_dep ) call self % file_scope_flags ( jj )% load_from_toml ( ptr_dep , error ) if ( allocated ( error )) return end do end select end do sub_deps end subroutine profile_load","tags":"","url":"proc/profile_load.html"},{"title":"traverse_compilers – Fortran-lang/fpm","text":"public subroutine traverse_compilers(profile_name, comp_list, table, error, profiles_size, profiles, profindex) Traverse compiler tables Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: profile_name Name of profile type(toml_key), intent(in), allocatable :: comp_list (:) List of OSs in table with profile name given type(toml_table), intent(in), pointer :: table Table containing compiler tables type( error_t ), intent(out), allocatable :: error Error handling integer, intent(inout), optional :: profiles_size Number of profiles in list of profiles type( profile_config_t ), intent(inout), optional, allocatable :: profiles (:) List of profiles integer, intent(inout), optional :: profindex Index in the list of profiles Variables Type Visibility Attributes Name Initial type(toml_table), public, pointer :: comp_node character(len=:), public, allocatable :: compiler_name integer, public :: icomp logical, public :: is_valid type(toml_key), public, allocatable :: os_list (:) integer, public :: stat Source Code subroutine traverse_compilers ( profile_name , comp_list , table , error , profiles_size , profiles , profindex ) !> Name of profile character ( len = :), allocatable , intent ( in ) :: profile_name !> List of OSs in table with profile name given type ( toml_key ), allocatable , intent ( in ) :: comp_list (:) !> Table containing compiler tables type ( toml_table ), pointer , intent ( in ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Number of profiles in list of profiles integer , intent ( inout ), optional :: profiles_size !> List of profiles type ( profile_config_t ), allocatable , intent ( inout ), optional :: profiles (:) !> Index in the list of profiles integer , intent ( inout ), optional :: profindex character ( len = :), allocatable :: compiler_name type ( toml_table ), pointer :: comp_node type ( toml_key ), allocatable :: os_list (:) integer :: icomp , stat logical :: is_valid if ( size ( comp_list ) < 1 ) return do icomp = 1 , size ( comp_list ) call validate_compiler_name ( comp_list ( icomp )% key , is_valid ) if ( is_valid ) then compiler_name = comp_list ( icomp )% key call get_value ( table , compiler_name , comp_node , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"Compiler \" // comp_list ( icomp )% key // \" must be a table entry\" ) exit end if call comp_node % get_keys ( os_list ) if ( present ( profiles_size )) then call traverse_oss_for_size ( profile_name , compiler_name , os_list , comp_node , profiles_size , error ) if ( allocated ( error )) return else if (. not .( present ( profiles ). and . present ( profindex ))) then call fatal_error ( error , \"Both profiles and profindex have to be present\" ) return end if call traverse_oss ( profile_name , compiler_name , os_list , comp_node , & & profiles , profindex , error ) if ( allocated ( error )) return end if else call fatal_error ( error , '*traverse_compilers*:Error: Compiler name not specified or invalid.' ) end if end do end subroutine traverse_compilers","tags":"","url":"proc/traverse_compilers.html"},{"title":"traverse_oss – Fortran-lang/fpm","text":"public subroutine traverse_oss(profile_name, compiler_name, os_list, table, profiles, profindex, error) Traverse operating system tables to obtain profiles Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: profile_name Name of profile character(len=:), intent(in), allocatable :: compiler_name Name of compiler type(toml_key), intent(in), allocatable :: os_list (:) List of OSs in table with profile name and compiler name given type(toml_table), intent(in), pointer :: table Table containing OS tables type( profile_config_t ), intent(inout), allocatable :: profiles (:) List of profiles integer, intent(inout) :: profindex Index in the list of profiles type( error_t ), intent(out), allocatable :: error Error handling Variables Type Visibility Attributes Name Initial integer, public :: ios logical, public :: is_key_val logical, public :: is_valid type(toml_key), public, allocatable :: key_list (:) character(len=:), public, allocatable :: l_os_name character(len=:), public, allocatable :: os_name type(toml_table), public, pointer :: os_node integer, public :: os_type integer, public :: stat Source Code subroutine traverse_oss ( profile_name , compiler_name , os_list , table , profiles , profindex , error ) !> Name of profile character ( len = :), allocatable , intent ( in ) :: profile_name !> Name of compiler character ( len = :), allocatable , intent ( in ) :: compiler_name !> List of OSs in table with profile name and compiler name given type ( toml_key ), allocatable , intent ( in ) :: os_list (:) !> Table containing OS tables type ( toml_table ), pointer , intent ( in ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> List of profiles type ( profile_config_t ), allocatable , intent ( inout ) :: profiles (:) !> Index in the list of profiles integer , intent ( inout ) :: profindex type ( toml_key ), allocatable :: key_list (:) character ( len = :), allocatable :: os_name , l_os_name type ( toml_table ), pointer :: os_node integer :: ios , stat , os_type logical :: is_valid , is_key_val if ( size ( os_list ) < 1 ) return do ios = 1 , size ( os_list ) os_name = os_list ( ios )% key call validate_os_name ( os_name , is_valid ) if ( is_valid ) then call get_value ( table , os_name , os_node , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"os \" // os_name // \" has to be a table\" ) return end if call os_node % get_keys ( key_list ) call match_os_type ( os_name , os_type ) call get_flags ( profile_name , compiler_name , os_type , key_list , os_node , profiles , profindex , . true .) else ! Not lowercase OS name l_os_name = lower ( os_name ) call validate_os_name ( l_os_name , is_valid ) if ( is_valid ) then call fatal_error ( error , '*traverse_oss*:Error: Name of the operating system must be a lowercase string.' ) end if if ( allocated ( error )) return ! Missing OS name is_key_val = . false . os_name = os_list ( ios )% key call get_value ( table , os_name , os_node , stat = stat ) if ( stat /= toml_stat % success ) then is_key_val = . true . end if os_node => table os_type = OS_ALL call get_flags ( profile_name , compiler_name , os_type , os_list , os_node , profiles , profindex , . false .) end if end do end subroutine traverse_oss","tags":"","url":"proc/traverse_oss.html"},{"title":"traverse_oss_for_size – Fortran-lang/fpm","text":"public subroutine traverse_oss_for_size(profile_name, compiler_name, os_list, table, profiles_size, error) Traverse operating system tables to obtain number of profiles Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: profile_name Name of profile character(len=:), intent(in), allocatable :: compiler_name Name of compiler type(toml_key), intent(in), allocatable :: os_list (:) List of OSs in table with profile name and compiler name given type(toml_table), intent(in), pointer :: table Table containing OS tables integer, intent(inout) :: profiles_size Number of profiles in list of profiles type( error_t ), intent(out), allocatable :: error Error handling Variables Type Visibility Attributes Name Initial integer, public :: ios logical, public :: is_key_val logical, public :: is_valid type(toml_key), public, allocatable :: key_list (:) logical, public :: key_val_added character(len=:), public, allocatable :: l_os_name character(len=:), public, allocatable :: os_name type(toml_table), public, pointer :: os_node integer, public :: stat Source Code subroutine traverse_oss_for_size ( profile_name , compiler_name , os_list , table , profiles_size , error ) !> Name of profile character ( len = :), allocatable , intent ( in ) :: profile_name !> Name of compiler character ( len = :), allocatable , intent ( in ) :: compiler_name !> List of OSs in table with profile name and compiler name given type ( toml_key ), allocatable , intent ( in ) :: os_list (:) !> Table containing OS tables type ( toml_table ), pointer , intent ( in ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Number of profiles in list of profiles integer , intent ( inout ) :: profiles_size type ( toml_key ), allocatable :: key_list (:) character ( len = :), allocatable :: os_name , l_os_name type ( toml_table ), pointer :: os_node integer :: ios , stat logical :: is_valid , key_val_added , is_key_val if ( size ( os_list ) < 1 ) return key_val_added = . false . do ios = 1 , size ( os_list ) os_name = os_list ( ios )% key call validate_os_name ( os_name , is_valid ) if ( is_valid ) then call get_value ( table , os_name , os_node , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"os \" // os_name // \" has to be a table\" ) return end if call os_node % get_keys ( key_list ) profiles_size = profiles_size + 1 call validate_profile_table ( profile_name , compiler_name , key_list , os_node , error , . true .) else ! Not lowercase OS name l_os_name = lower ( os_name ) call validate_os_name ( l_os_name , is_valid ) if ( is_valid ) then call fatal_error ( error , '*traverse_oss*:Error: Name of the operating system must be a lowercase string.' ) end if if ( allocated ( error )) return ! Missing OS name is_key_val = . false . os_name = os_list ( ios )% key call get_value ( table , os_name , os_node , stat = stat ) if ( stat /= toml_stat % success ) then is_key_val = . true . end if os_node => table if ( is_key_val . and .. not . key_val_added ) then key_val_added = . true . is_key_val = . false . profiles_size = profiles_size + 1 else if (. not . is_key_val ) then profiles_size = profiles_size + 1 end if call validate_profile_table ( profile_name , compiler_name , os_list , os_node , error , . false .) end if end do end subroutine traverse_oss_for_size","tags":"","url":"proc/traverse_oss_for_size.html"},{"title":"validate_compiler_name – Fortran-lang/fpm","text":"public subroutine validate_compiler_name(compiler_name, is_valid) Check if compiler name is a valid compiler name Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: compiler_name Name of a compiler logical, intent(out) :: is_valid Boolean value of whether compiler_name is valid or not Source Code subroutine validate_compiler_name ( compiler_name , is_valid ) !> Name of a compiler character ( len = :), allocatable , intent ( in ) :: compiler_name !> Boolean value of whether compiler_name is valid or not logical , intent ( out ) :: is_valid select case ( compiler_name ) case ( \"gfortran\" , \"ifort\" , \"ifx\" , \"pgfortran\" , \"nvfortran\" , \"flang\" , \"caf\" , & & \"f95\" , \"lfortran\" , \"lfc\" , \"nagfor\" , \"crayftn\" , \"xlf90\" , \"ftn95\" ) is_valid = . true . case default is_valid = . false . end select end subroutine validate_compiler_name","tags":"","url":"proc/validate_compiler_name.html"},{"title":"validate_os_name – Fortran-lang/fpm","text":"public subroutine validate_os_name(os_name, is_valid) Check if os_name is a valid name of a supported OS Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: os_name Name of an operating system logical, intent(out) :: is_valid Boolean value of whether os_name is valid or not Source Code subroutine validate_os_name ( os_name , is_valid ) !> Name of an operating system character ( len = :), allocatable , intent ( in ) :: os_name !> Boolean value of whether os_name is valid or not logical , intent ( out ) :: is_valid select case ( os_name ) case ( \"linux\" , \"macos\" , \"windows\" , \"cygwin\" , \"solaris\" , \"freebsd\" , & & \"openbsd\" , \"unknown\" ) is_valid = . true . case default is_valid = . false . end select end subroutine validate_os_name","tags":"","url":"proc/validate_os_name.html"},{"title":"validate_profile_table – Fortran-lang/fpm","text":"public subroutine validate_profile_table(profile_name, compiler_name, key_list, table, error, os_valid) Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: profile_name Name of profile character(len=:), intent(in), allocatable :: compiler_name Name of compiler type(toml_key), intent(in), allocatable :: key_list (:) List of keys in the table type(toml_table), intent(in), pointer :: table Table containing OS tables type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in) :: os_valid Was called with valid operating system Variables Type Visibility Attributes Name Initial character(len=:), public, allocatable :: c_flags character(len=:), public, allocatable :: cxx_flags character(len=:), public, allocatable :: err_message character(len=:), public, allocatable :: file_flags type(toml_key), public, allocatable :: file_list (:) character(len=:), public, allocatable :: file_name type(toml_table), public, pointer :: files character(len=:), public, allocatable :: flags integer, public :: ifile integer, public :: ikey logical, public :: is_valid character(len=:), public, allocatable :: key_name character(len=:), public, allocatable :: link_time_flags integer, public :: stat Source Code subroutine validate_profile_table ( profile_name , compiler_name , key_list , table , error , os_valid ) !> Name of profile character ( len = :), allocatable , intent ( in ) :: profile_name !> Name of compiler character ( len = :), allocatable , intent ( in ) :: compiler_name !> List of keys in the table type ( toml_key ), allocatable , intent ( in ) :: key_list (:) !> Table containing OS tables type ( toml_table ), pointer , intent ( in ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Was called with valid operating system logical , intent ( in ) :: os_valid character ( len = :), allocatable :: flags , c_flags , cxx_flags , link_time_flags , key_name , file_name , file_flags , err_message type ( toml_table ), pointer :: files type ( toml_key ), allocatable :: file_list (:) integer :: ikey , ifile , stat logical :: is_valid if ( size ( key_list ). ge . 1 ) then do ikey = 1 , size ( key_list ) key_name = key_list ( ikey )% key if ( key_name . eq . 'flags' ) then call get_value ( table , 'flags' , flags , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"flags has to be a key-value pair\" ) return end if else if ( key_name . eq . 'c-flags' ) then call get_value ( table , 'c-flags' , c_flags , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"c-flags has to be a key-value pair\" ) return end if else if ( key_name . eq . 'cxx-flags' ) then call get_value ( table , 'cxx-flags' , cxx_flags , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"cxx-flags has to be a key-value pair\" ) return end if else if ( key_name . eq . 'link-time-flags' ) then call get_value ( table , 'link-time-flags' , link_time_flags , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"link-time-flags has to be a key-value pair\" ) return end if else if ( key_name . eq . 'files' ) then call get_value ( table , 'files' , files , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"files has to be a table\" ) return end if call files % get_keys ( file_list ) do ifile = 1 , size ( file_list ) file_name = file_list ( ifile )% key call get_value ( files , file_name , file_flags , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"file scope flags has to be a key-value pair\" ) return end if end do else if (. not . os_valid ) then call validate_os_name ( key_name , is_valid ) err_message = \"Unexpected key \" // key_name // \" found in profile table \" // profile_name // \" \" // compiler_name // \".\" if (. not . is_valid ) call syntax_error ( error , err_message ) else err_message = \"Unexpected key \" // key_name // \" found in profile table \" // profile_name // \" \" // compiler_name // \".\" call syntax_error ( error , err_message ) end if end do end if if ( allocated ( error )) return end subroutine validate_profile_table","tags":"","url":"proc/validate_profile_table.html"},{"title":"add_pkg_config_compile_options – Fortran-lang/fpm","text":"public subroutine add_pkg_config_compile_options(this, name, include_flag, libdir, error) Add pkgconfig compile options to a metapackage\nGet version\nGet libraries\nGet compiler flags Arguments Type Intent Optional Attributes Name class( metapackage_t ), intent(inout) :: this character(len=*), intent(in) :: name character(len=*), intent(in) :: include_flag character(len=:), allocatable :: libdir type( error_t ), intent(out), allocatable :: error Source Code subroutine add_pkg_config_compile_options ( this , name , include_flag , libdir , error ) class ( metapackage_t ), intent ( inout ) :: this character ( len =* ), intent ( in ) :: name character ( len =* ), intent ( in ) :: include_flag type ( error_t ), allocatable , intent ( out ) :: error character ( len = :), allocatable :: libdir type ( string_t ) :: log , current_include_dir , current_lib type ( string_t ), allocatable :: libs (:), flags (:) integer :: i !> Get version if (. not . allocated ( this % version )) then log = pkgcfg_get_version ( name , error ) if ( allocated ( error )) return allocate ( this % version ) call new_version ( this % version , log % s , error ) if ( allocated ( error )) return end if !> Get libraries libs = pkgcfg_get_libs ( name , error ) if ( allocated ( error )) return libdir = \"\" do i = 1 , size ( libs ) if ( str_begins_with_str ( libs ( i )% s , '-l' )) then current_lib = string_t ( libs ( i )% s ( 3 :)) if ( len_trim ( current_lib % s ) == 0 ) cycle this % has_link_libraries = . true . this % link_libs = [ this % link_libs , current_lib ] else ! -L and others: concatenate this % has_link_flags = . true . this % link_flags = string_t ( trim ( this % link_flags % s ) // ' ' // libs ( i )% s ) ! Also save library dir if ( str_begins_with_str ( libs ( i )% s , '-L' )) then libdir = libs ( i )% s ( 3 :) elseif ( str_begins_with_str ( libs ( i )% s , '/LIBPATH' )) then libdir = libs ( i )% s ( 9 :) end if end if end do !> Get compiler flags flags = pkgcfg_get_build_flags ( name , . true ., error ) if ( allocated ( error )) return do i = 1 , size ( flags ) if ( str_begins_with_str ( flags ( i )% s , include_flag )) then current_include_dir = string_t ( flags ( i )% s ( len ( include_flag ) + 1 :)) if ( len_trim ( current_include_dir % s ) == 0 ) cycle this % has_include_dirs = . true . this % incl_dirs = [ this % incl_dirs , current_include_dir ] else this % has_build_flags = . true . this % flags = string_t ( trim ( this % flags % s ) // ' ' // flags ( i )% s ) end if end do end subroutine add_pkg_config_compile_options","tags":"","url":"proc/add_pkg_config_compile_options.html"},{"title":"lib_get_trailing – Fortran-lang/fpm","text":"public subroutine lib_get_trailing(lib_name, lib_dir, prefix, suffix, found) Given a library name and folder, find extension and prefix Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: lib_name character(len=*), intent(in) :: lib_dir character(len=:), intent(out), allocatable :: prefix character(len=:), intent(out), allocatable :: suffix logical, intent(out) :: found Source Code subroutine lib_get_trailing ( lib_name , lib_dir , prefix , suffix , found ) character ( * ), intent ( in ) :: lib_name , lib_dir character (:), allocatable , intent ( out ) :: prefix , suffix logical , intent ( out ) :: found character ( * ), parameter :: extensions ( * ) = [ character ( 11 ) :: '.dll.a' , '.a' , '.dylib' , '.dll' ] logical :: is_file character (:), allocatable :: noext , tokens (:), path integer :: l , k ! Extract name with no extension call split ( lib_name , tokens , '.' ) noext = trim ( tokens ( 1 )) ! Get library extension: find file name: NAME.a, NAME.dll.a, NAME.dylib, libNAME.a, etc. found = . false . suffix = \"\" prefix = \"\" with_pref : do l = 1 , 2 if ( l == 2 ) then prefix = \"lib\" else prefix = \"\" end if find_ext : do k = 1 , size ( extensions ) path = join_path ( lib_dir , prefix // noext // trim ( extensions ( k ))) inquire ( file = path , exist = is_file ) if ( is_file ) then suffix = trim ( extensions ( k )) found = . true . exit with_pref end if end do find_ext end do with_pref if (. not . found ) then prefix = \"\" suffix = \"\" end if end subroutine lib_get_trailing","tags":"","url":"proc/lib_get_trailing.html"},{"title":"build_package – Fortran-lang/fpm","text":"public subroutine build_package(targets, model, verbose, dry_run) Top-level routine to build package described by model Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(inout) :: targets (:) type( fpm_model_t ), intent(in) :: model logical, intent(in) :: verbose logical, intent(in) :: dry_run If dry_run, the build process is only mocked, but the list of compile_commands\nis still created Source Code subroutine build_package ( targets , model , verbose , dry_run ) type ( build_target_ptr ), intent ( inout ) :: targets (:) type ( fpm_model_t ), intent ( in ) :: model logical , intent ( in ) :: verbose !> If dry_run, the build process is only mocked, but the list of compile_commands !> is still created logical , intent ( in ) :: dry_run integer :: i , j type ( build_target_ptr ), allocatable :: queue (:) integer , allocatable :: schedule_ptr (:), stat (:) logical :: build_failed , skip_current type ( string_t ), allocatable :: build_dirs (:) type ( string_t ) :: temp type ( error_t ), allocatable :: error type ( build_progress_t ) :: progress logical :: plain_output ! Need to make output directory for include (mod) files allocate ( build_dirs ( 0 )) do i = 1 , size ( targets ) associate ( target => targets ( i )% ptr ) if ( target % output_dir . in . build_dirs ) cycle temp % s = target % output_dir build_dirs = [ build_dirs , temp ] end associate end do do i = 1 , size ( build_dirs ) if (. not . dry_run ) call mkdir ( build_dirs ( i )% s , verbose ) end do ! Perform depth-first topological sort of targets do i = 1 , size ( targets ) call sort_target ( targets ( i )% ptr , dry_run ) end do ! Construct build schedule queue call schedule_targets ( queue , schedule_ptr , targets ) ! Check if queue is empty if (. not . verbose . and . size ( queue ) < 1 . and . . not . dry_run ) then write ( stderr , '(a)' ) 'Project is up to date' return end if ! Initialise build status flags allocate ( stat ( size ( queue )), source = 0 ) build_failed = . false . ! Set output mode #ifndef FPM_BOOTSTRAP plain_output = (. not .( c_isatty () == 1 )) . or . verbose #else plain_output = . true . #endif progress = build_progress_t ( queue , plain_output ) ! Loop over parallel schedule regions do i = 1 , size ( schedule_ptr ) - 1 ! Build targets in schedule region i !$omp parallel do default(shared) private(skip_current) schedule(dynamic,1) do j = schedule_ptr ( i ),( schedule_ptr ( i + 1 ) - 1 ) ! Check if build already failed !$omp atomic read skip_current = build_failed if (. not . skip_current ) then if (. not . dry_run ) call progress % compiling_status ( j ) call build_target ( model , queue ( j )% ptr , verbose , dry_run , & progress % compile_commands , stat ( j )) if (. not . dry_run ) call progress % completed_status ( j , stat ( j )) end if ! Set global flag if this target failed to build if ( stat ( j ) /= 0 ) then !$omp atomic write build_failed = . true . end if end do ! Check if this schedule region failed: exit with message if failed if ( build_failed ) then write ( * , * ) do j = 1 , size ( stat ) if ( stat ( j ) /= 0 ) Then call print_build_log ( queue ( j )% ptr ) end if end do do j = 1 , size ( stat ) if ( stat ( j ) /= 0 ) then write ( stderr , '(*(g0:,1x))' ) ' Compilation failed for object \"' , basename ( queue ( j )% ptr % output_file ), '\"' end if end do call fpm_stop ( 1 , 'stopping due to failed compilation' ) end if end do if (. not . dry_run ) call progress % success () call progress % dump_commands ( error ) if ( allocated ( error )) call fpm_stop ( 1 , 'error writing compile_commands.json: ' // trim ( error % message )) end subroutine build_package","tags":"","url":"proc/build_package.html"},{"title":"schedule_targets – Fortran-lang/fpm","text":"public subroutine schedule_targets(queue, schedule_ptr, targets) Construct a build schedule from the sorted targets. The schedule is broken into regions, described by schedule_ptr ,\n where targets in each region can be compiled in parallel. Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(out), allocatable :: queue (:) integer, allocatable :: schedule_ptr (:) type( build_target_ptr ), intent(in) :: targets (:) Source Code subroutine schedule_targets ( queue , schedule_ptr , targets ) type ( build_target_ptr ), allocatable , intent ( out ) :: queue (:) integer , allocatable :: schedule_ptr (:) type ( build_target_ptr ), intent ( in ) :: targets (:) integer :: i , j integer :: n_schedule , n_sorted n_schedule = 0 ! Number of schedule regions n_sorted = 0 ! Total number of targets to build do i = 1 , size ( targets ) if ( targets ( i )% ptr % sorted ) then n_sorted = n_sorted + 1 end if n_schedule = max ( n_schedule , targets ( i )% ptr % schedule ) end do allocate ( queue ( n_sorted )) allocate ( schedule_ptr ( n_schedule + 1 )) ! Construct the target queue and schedule region pointer n_sorted = 1 schedule_ptr ( n_sorted ) = 1 do i = 1 , n_schedule do j = 1 , size ( targets ) if ( targets ( j )% ptr % sorted ) then if ( targets ( j )% ptr % schedule == i ) then queue ( n_sorted )% ptr => targets ( j )% ptr n_sorted = n_sorted + 1 end if end if end do schedule_ptr ( i + 1 ) = n_sorted end do end subroutine schedule_targets","tags":"","url":"proc/schedule_targets.html"},{"title":"sort_target – Fortran-lang/fpm","text":"public recursive subroutine sort_target(target, mock) Topologically sort a target for scheduling by\n recursing over its dependencies. Checks disk-cached source hashes to determine if objects are\n up-to-date. Up-to-date sources are tagged as skipped. On completion, target should either be marked as\nsorted ( target%sorted=.true. ) or skipped ( target%skip=.true. ) If target is marked as sorted, target%schedule should be an\ninteger greater than zero indicating the region for scheduling Arguments Type Intent Optional Attributes Name type( build_target_t ), intent(inout), target :: target logical, intent(in), optional :: mock Optionally sort ALL targets if this is a dry run Source Code recursive subroutine sort_target ( target , mock ) type ( build_target_t ), intent ( inout ), target :: target !> Optionally sort ALL targets if this is a dry run logical , optional , intent ( in ) :: mock integer :: i , fh , stat logical :: dry_run dry_run = . false . if ( present ( mock )) dry_run = mock ! Check if target has already been processed (as a dependency) if ( target % sorted . or . target % skip ) return ! Check for a circular dependency ! (If target has been touched but not processed) if ( target % touched ) then call fpm_stop ( 1 , '(!) Circular dependency found with: ' // target % output_file ) else target % touched = . true . ! Set touched flag end if ! Load cached source file digest if present if (. not . allocated ( target % digest_cached ) . and . & exists ( target % output_file ) . and . & exists ( target % output_file // '.digest' ) . and . & (. not . dry_run )) then allocate ( target % digest_cached ) open ( newunit = fh , file = target % output_file // '.digest' , status = 'old' ) read ( fh , * , iostat = stat ) target % digest_cached close ( fh ) ! Cached digest is not recognized if ( stat /= 0 ) deallocate ( target % digest_cached ) end if if ( dry_run ) then target % skip = . false . elseif ( allocated ( target % source )) then ! Skip if target is source-based and source file is unmodified if ( allocated ( target % digest_cached )) then if ( target % digest_cached == target % source % digest ) target % skip = . true . end if elseif ( exists ( target % output_file )) then ! Skip if target is not source-based and already exists target % skip = . true . end if ! Loop over target dependencies target % schedule = 1 do i = 1 , size ( target % dependencies ) ! Sort dependency call sort_target ( target % dependencies ( i )% ptr , dry_run ) if (. not . target % dependencies ( i )% ptr % skip ) then ! Can't skip target if any dependency is not skipped target % skip = . false . ! Set target schedule after all of its dependencies target % schedule = max ( target % schedule , target % dependencies ( i )% ptr % schedule + 1 ) end if end do ! Mark flag as processed: either sorted or skipped target % sorted = . not . target % skip end subroutine sort_target","tags":"","url":"proc/sort_target.html"},{"title":"dilate – Fortran-lang/fpm","text":"public function dilate(instr) result(outstr) NAME dilate(3f) - [M_strings:NONALPHA] expand tab characters\n(LICENSE:PD) SYNOPSIS function dilate(INSTR) result ( OUTSTR ) character ( len = * ), intent =( in ) :: INSTR character ( len =:), allocatable :: OUTSTR DESCRIPTION dilate() converts tabs in INSTR to spaces in OUTSTR. It assumes a\n tab is set every 8 characters. Trailing spaces are removed.\n\n In addition, trailing carriage returns and line feeds are removed\n (they are usually a problem created by going to and from MSWindows). OPTIONS instr Input line to remove tabs from RESULTS outstr Output string with tabs expanded. EXAMPLES Sample program: program demo_dilate use M_strings , only : dilate implicit none character ( len =:), allocatable :: in integer :: i in = ' this is my string ' ! change spaces to tabs to make a sample input do i = 1 , len ( in ) if ( in ( i : i ) == ' ' ) in ( i : i )= char ( 9 ) enddo write ( * , ' ( a ) ' ) in , dilate ( in ) end program demo_dilate Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: instr Return Value character(len=:), allocatable Source Code function dilate ( instr ) result ( outstr ) character ( len =* ), intent ( in ) :: instr ! input line to scan for tab characters character ( len = :), allocatable :: outstr ! tab-expanded version of INSTR produced integer :: i integer :: icount integer :: lgth icount = 0 do i = 1 , len ( instr ) if ( instr ( i : i ) == char ( 9 )) icount = icount + 1 end do allocate ( character ( len = ( len ( instr ) + 8 * icount )) :: outstr ) call notabs ( instr , outstr , lgth ) outstr = outstr (: lgth ) end function dilate","tags":"","url":"proc/dilate.html"},{"title":"f_string – Fortran-lang/fpm","text":"public function f_string(c_string) Uses iso_c_binding return Fortran character variable when given a C-like array of\nsingle characters terminated with a C_NULL_CHAR character Arguments Type Intent Optional Attributes Name character(len=1), intent(in) :: c_string (:) Return Value character(len=:), allocatable Source Code function f_string ( c_string ) use iso_c_binding character ( len = 1 ), intent ( in ) :: c_string (:) character (:), allocatable :: f_string integer :: i , n i = 0 do while ( c_string ( i + 1 ) /= C_NULL_CHAR ) i = i + 1 end do n = i allocate ( character ( n ) :: f_string ) do i = 1 , n f_string ( i : i ) = c_string ( i ) end do end function f_string","tags":"","url":"proc/f_string.html"},{"title":"glob – Fortran-lang/fpm","text":"public function glob(tame, wild) NAME glob(3f) - [fpm_strings:COMPARE] compare given string for match to\npattern which may contain wildcard characters\n(LICENSE:PD) SYNOPSIS logical function glob(string, pattern )\n\n character(len=*),intent(in) :: string\n character(len=*),intent(in) :: pattern DESCRIPTION glob(3f) compares given STRING for match to PATTERN which may\n contain wildcard characters. In this version to get a match the entire string must be described\n by PATTERN. Trailing whitespace is significant, so trim the input\n string to have trailing whitespace ignored. OPTIONS string the input string to test to see if it contains the pattern . pattern the following simple globbing options are available o \"?\" matching any one character o \"*\" matching zero or more characters . Do NOT use adjacent asterisks . o Both strings may have trailing spaces which are ignored . o There is no escape character , so matching strings with literal question mark and asterisk is problematic . EXAMPLES Example program program demo_glob implicit none ! This main () routine passes a bunch of test strings ! into the above code . In performance comparison mode , ! it does that over and over . Otherwise , it does it just ! once . Either way , it outputs a passed / failed result . ! integer :: nReps logical :: allpassed integer :: i allpassed = . true . nReps = 10000 ! Can choose as many repetitions as you ' re expecting ! in the real world . nReps = 1 do i = 1 , nReps ! Cases with repeating character sequences . allpassed = allpassed . and . test ( \"a*abab\" , \"a*b\" , . true .) !! cycle allpassed = allpassed . and . test ( \"ab\" , \"*?\" , . true .) allpassed = allpassed . and . test ( \"abc\" , \"*?\" , . true .) allpassed = allpassed . and . test ( \"abcccd\" , \"*ccd\" , . true .) allpassed = allpassed . and . test ( \"bLah\" , \"bLaH\" , . false .) allpassed = allpassed . and . test ( \"mississippi\" , \"*sip*\" , . true .) allpassed = allpassed . and . & & test ( \"xxxx*zzzzzzzzy*f\" , \"xxx*zzy*f\" , . true .) allpassed = allpassed . and . & & test ( \"xxxx*zzzzzzzzy*f\" , \"xxxx*zzy*fffff\" , . false .) allpassed = allpassed . and . & & test ( \"mississipissippi\" , \"*issip*ss*\" , . true .) allpassed = allpassed . and . & & test ( \"xxxxzzzzzzzzyf\" , \"xxxx*zzy*fffff\" , . false .) allpassed = allpassed . and . & & test ( \"xxxxzzzzzzzzyf\" , \"xxxx*zzy*f\" , . true .) allpassed = allpassed . and . test ( \"xyxyxyzyxyz\" , \"xy*z*xyz\" , . true .) allpassed = allpassed . and . test ( \"xyxyxyxyz\" , \"xy*xyz\" , . true .) allpassed = allpassed . and . test ( \"mississippi\" , \"mi*sip*\" , . true .) allpassed = allpassed . and . test ( \"ababac\" , \"*abac*\" , . true .) allpassed = allpassed . and . test ( \"aaazz\" , \"a*zz*\" , . true .) allpassed = allpassed . and . test ( \"a12b12\" , \"*12*23\" , . false .) allpassed = allpassed . and . test ( \"a12b12\" , \"a12b\" , . false .) allpassed = allpassed . and . test ( \"a12b12\" , \"*12*12*\" , . true .) ! Additional cases where the '*' char appears in the tame string . allpassed = allpassed . and . test ( \"*\" , \"*\" , . true .) allpassed = allpassed . and . test ( \"a*r\" , \"a*\" , . true .) allpassed = allpassed . and . test ( \"a*ar\" , \"a*aar\" , . false .) ! More double wildcard scenarios . allpassed = allpassed . and . test ( \"XYXYXYZYXYz\" , \"XY*Z*XYz\" , . true .) allpassed = allpassed . and . test ( \"missisSIPpi\" , \"*SIP*\" , . true .) allpassed = allpassed . and . test ( \"mississipPI\" , \"*issip*PI\" , . true .) allpassed = allpassed . and . test ( \"xyxyxyxyz\" , \"xy*xyz\" , . true .) allpassed = allpassed . and . test ( \"miSsissippi\" , \"mi*sip*\" , . true .) allpassed = allpassed . and . test ( \"miSsissippi\" , \"mi*Sip*\" , . false .) allpassed = allpassed . and . test ( \"abAbac\" , \"*Abac*\" , . true .) allpassed = allpassed . and . test ( \"aAazz\" , \"a*zz*\" , . true .) allpassed = allpassed . and . test ( \"A12b12\" , \"*12*23\" , . false .) allpassed = allpassed . and . test ( \"a12B12\" , \"*12*12*\" , . true .) allpassed = allpassed . and . test ( \"oWn\" , \"*oWn*\" , . true .) ! Completely tame ( no wildcards ) cases . allpassed = allpassed . and . test ( \"bLah\" , \"bLah\" , . true .) ! Simple mixed wildcard tests suggested by IBMer Marlin Deckert . allpassed = allpassed . and . test ( \"a\" , \"*?\" , . true .) ! More mixed wildcard tests including coverage for false positives . allpassed = allpassed . and . test ( \"a\" , \"??\" , . false .) allpassed = allpassed . and . test ( \"ab\" , \"?*?\" , . true .) allpassed = allpassed . and . test ( \"ab\" , \"*?*?*\" , . true .) allpassed = allpassed . and . test ( \"abc\" , \"?**?*?\" , . true .) allpassed = allpassed . and . test ( \"abc\" , \"?**?*&?\" , . false .) allpassed = allpassed . and . test ( \"abcd\" , \"?b*??\" , . true .) allpassed = allpassed . and . test ( \"abcd\" , \"?a*??\" , . false .) allpassed = allpassed . and . test ( \"abcd\" , \"?**?c?\" , . true .) allpassed = allpassed . and . test ( \"abcd\" , \"?**?d?\" , . false .) allpassed = allpassed . and . test ( \"abcde\" , \"?*b*?*d*?\" , . true .) ! Single - character - match cases . allpassed = allpassed . and . test ( \"bLah\" , \"bL?h\" , . true .) allpassed = allpassed . and . test ( \"bLaaa\" , \"bLa?\" , . false .) allpassed = allpassed . and . test ( \"bLah\" , \"bLa?\" , . true .) allpassed = allpassed . and . test ( \"bLaH\" , \"?Lah\" , . false .) allpassed = allpassed . and . test ( \"bLaH\" , \"?LaH\" , . true .) ! Many - wildcard scenarios . allpassed = allpassed . and . test ( & & \"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa& &aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab\" , & & \"a*a*a*a*a*a*aa*aaa*a*a*b\" , & & . true .) allpassed = allpassed . and . test ( & & \"abababababababababababababababababababaacacacacacacac& &adaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab\" , & & \"*a*b*ba*ca*a*aa*aaa*fa*ga*b*\" , & & . true .) allpassed = allpassed . and . test ( & & \"abababababababababababababababababababaacacacacacaca& &cadaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab\" , & & \"*a*b*ba*ca*a*x*aaa*fa*ga*b*\" , & & . false .) allpassed = allpassed . and . test ( & & \"abababababababababababababababababababaacacacacacacacad& &aeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab\" , & & \"*a*b*ba*ca*aaaa*fa*ga*gggg*b*\" , & & . false .) allpassed = allpassed . and . test ( & & \"abababababababababababababababababababaacacacacacacacad& &aeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab\" , & & \"*a*b*ba*ca*aaaa*fa*ga*ggg*b*\" , & & . true .) allpassed = allpassed . and . test ( \"aaabbaabbaab\" , \"*aabbaa*a*\" , . true .) allpassed = allpassed . and . & test ( \"a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*\" , & & \"a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*\" , . true .) allpassed = allpassed . and . test ( \"aaaaaaaaaaaaaaaaa\" , & & \"*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*\" , . true .) allpassed = allpassed . and . test ( \"aaaaaaaaaaaaaaaa\" , & & \"*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*\" , . false .) allpassed = allpassed . and . test ( & & \"abc*abcd*abcde*abcdef*abcdefg*abcdefgh*abcdefghi*abcdefghij& &*abcdefghijk*abcdefghijkl*abcdefghijklm*abcdefghijklmn\" , & & \"abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc& &*abc*abc*abc*\" , & & . false .) allpassed = allpassed . and . test ( & & \"abc*abcd*abcde*abcdef*abcdefg*abcdefgh*abcdefghi*abcdefghij& &*abcdefghijk*abcdefghijkl*abcdefghijklm*abcdefghijklmn\" , & & \"abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*\" , & & . true .) allpassed = allpassed . and . test ( \"abc*abcd*abcd*abc*abcd\" , & & \"abc*abc*abc*abc*abc\" , . false .) allpassed = allpassed . and . test ( \"abc*abcd*abcd*abc*abcd*abcd& &*abc*abcd*abc*abc*abcd\" , & & \"abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abcd\" , & & . true .) allpassed = allpassed . and . test ( \"abc\" , & & \"********a********b********c********\" , . true .) allpassed = allpassed . and . & & test ( \"********a********b********c********\" , \"abc\" , . false .) allpassed = allpassed . and . & & test ( \"abc\" , \"********a********b********b********\" , . false .) allpassed = allpassed . and . test ( \"*abc*\" , \"***a*b*c***\" , . true .) ! A case - insensitive algorithm test . ! allpassed = allpassed . and . test ( \"mississippi\" , \"*issip*PI\" , . true .) enddo if ( allpassed ) then write ( * , ' ( a ) ' ) \"Passed\" , nReps else write ( * , ' ( a ) ' ) \"Failed\" endif contains ! This is a test program for wildcard matching routines . ! It can be used either to test a single routine for correctness , ! or to compare the timings of two ( or more ) different wildcard ! matching routines . ! function test ( tame , wild , bExpectedResult ) result ( bpassed ) use fpm_strings , only : glob character ( len = * ) :: tame character ( len = * ) :: wild logical :: bExpectedResult logical :: bResult logical :: bPassed bResult = . true . ! We ' ll do \"&=\" cumulative checking . bPassed = . false . ! Assume the worst . write ( * , * ) repeat ( '=' , 79 ) bResult = glob ( tame , wild ) ! Call a wildcard matching routine . ! To assist correctness checking , output the two strings in any ! failing scenarios . if ( bExpectedResult . eqv . bResult ) then bPassed = . true . if ( nReps == 1 ) write ( * , * ) \"Passed match on \" , tame , \" vs. \" , wild else if ( nReps == 1 ) write ( * , * ) \"Failed match on \" , tame , \" vs. \" , wild endif end function test end program demo_glob Expected output REFERENCE The article “Matching Wildcards: An Empirical Way to Tame an Algorithm”\n in Dr Dobb’s Journal, By Kirk J. Krauss, October 07, 2014 Arguments Type Intent Optional Attributes Name character(len=*) :: tame A string without wildcards to compare to the globbing expression character(len=*) :: wild A (potentially) corresponding string with wildcards Return Value logical result of test Source Code function glob ( tame , wild ) ! @(#)fpm_strings::glob(3f): function compares text strings, one of which can have wildcards ('*' or '?'). logical :: glob !! result of test character ( len =* ) :: tame !! A string without wildcards to compare to the globbing expression character ( len =* ) :: wild !! A (potentially) corresponding string with wildcards character ( len = len ( tame ) + 1 ) :: tametext character ( len = len ( wild ) + 1 ) :: wildtext character ( len = 1 ), parameter :: NULL = char ( 0 ) integer :: wlen integer :: ti , wi integer :: i character ( len = :), allocatable :: tbookmark , wbookmark ! These two values are set when we observe a wildcard character. They ! represent the locations, in the two strings, from which we start once we've observed it. tametext = tame // NULL wildtext = wild // NULL tbookmark = NULL wbookmark = NULL wlen = len ( wild ) wi = 1 ti = 1 do ! Walk the text strings one character at a time. if ( wildtext ( wi : wi ) == '*' ) then ! How do you match a unique text string? do i = wi , wlen ! Easy: unique up on it! if ( wildtext ( wi : wi ) == '*' ) then wi = wi + 1 else exit endif enddo if ( wildtext ( wi : wi ) == NULL ) then ! \"x\" matches \"*\" glob = . true . return endif if ( wildtext ( wi : wi ) /= '?' ) then ! Fast-forward to next possible match. do while ( tametext ( ti : ti ) /= wildtext ( wi : wi )) ti = ti + 1 if ( tametext ( ti : ti ) == NULL ) then glob = . false . return ! \"x\" doesn't match \"*y*\" endif enddo endif wbookmark = wildtext ( wi :) tbookmark = tametext ( ti :) elseif ( tametext ( ti : ti ) /= wildtext ( wi : wi ) . and . wildtext ( wi : wi ) /= '?' ) then ! Got a non-match. If we've set our bookmarks, back up to one or both of them and retry. if ( wbookmark /= NULL ) then if ( wildtext ( wi :) /= wbookmark ) then wildtext = wbookmark ; wlen = len_trim ( wbookmark ) wi = 1 ! Don't go this far back again. if ( tametext ( ti : ti ) /= wildtext ( wi : wi )) then tbookmark = tbookmark ( 2 :) tametext = tbookmark ti = 1 cycle ! \"xy\" matches \"*y\" else wi = wi + 1 endif endif if ( tametext ( ti : ti ) /= NULL ) then ti = ti + 1 cycle ! \"mississippi\" matches \"*sip*\" endif endif glob = . false . return ! \"xy\" doesn't match \"x\" endif ti = ti + 1 wi = wi + 1 if ( tametext ( ti : ti ) == NULL ) then ! How do you match a tame text string? if ( wildtext ( wi : wi ) /= NULL ) then do while ( wildtext ( wi : wi ) == '*' ) ! The tame way: unique up on it! wi = wi + 1 ! \"x\" matches \"x*\" if ( wildtext ( wi : wi ) == NULL ) exit enddo endif if ( wildtext ( wi : wi ) == NULL ) then glob = . true . return ! \"x\" matches \"x\" endif glob = . false . return ! \"x\" doesn't match \"xy\" endif enddo end function glob","tags":"","url":"proc/glob.html"},{"title":"has_valid_custom_prefix – Fortran-lang/fpm","text":"public function has_valid_custom_prefix(module_name, custom_prefix) result(valid) Check that a module name is prefixed with a custom prefix:\n1) It must be a valid FORTRAN name subset (<=63 chars, begin with letter, only alphanumeric allowed)\n2) It must begin with the prefix\n3) If longer, package name must be followed by default separator (“_”) plus at least one char Basic check: check that both names are individually valid FPM package enforcing: check that the module name begins with the custom prefix Query string lengths\n2) It must begin with the package name.\n3) It can be equal to the package name, or, if longer, must be followed by the\n4) Package name must not end with an underscore Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: module_name type( string_t ), intent(in) :: custom_prefix Return Value logical Source Code logical function has_valid_custom_prefix ( module_name , custom_prefix ) result ( valid ) type ( string_t ), intent ( in ) :: module_name type ( string_t ), intent ( in ) :: custom_prefix !> custom_module separator: single underscore character ( * ), parameter :: SEP = \"_\" logical :: is_same , has_separator , same_beginning integer :: lpkg , lmod , lsep !> Basic check: check that both names are individually valid valid = is_fortran_name ( module_name % s ) . and . & is_valid_module_prefix ( custom_prefix ) !> FPM package enforcing: check that the module name begins with the custom prefix if ( valid ) then !> Query string lengths lpkg = len_trim ( custom_prefix ) lmod = len_trim ( module_name ) lsep = len_trim ( SEP ) same_beginning = str_begins_with_str ( module_name % s , custom_prefix % s , case_sensitive = . false .) is_same = lpkg == lmod . and . same_beginning if ( lmod >= lpkg + lsep ) then has_separator = str_begins_with_str ( module_name % s ( lpkg + 1 : lpkg + lsep ), SEP ) else has_separator = . false . endif !> 2) It must begin with the package name. !> 3) It can be equal to the package name, or, if longer, must be followed by the ! default separator plus at least one character !> 4) Package name must not end with an underscore valid = same_beginning . and . ( is_same . or . ( lmod > lpkg + lsep . and . has_separator )) end if end function has_valid_custom_prefix","tags":"","url":"proc/has_valid_custom_prefix.html"},{"title":"has_valid_standard_prefix – Fortran-lang/fpm","text":"public function has_valid_standard_prefix(module_name, package_name) result(valid) Check that a module name is prefixed with the default package prefix:\n1) It must be a valid FORTRAN name (<=63 chars, begin with letter, “_” is only allowed non-alphanumeric)\n2) It must begin with the package name\n3) If longer, package name must be followed by default separator plus at least one char Basic check: check the name is Fortran-compliant FPM package enforcing: check that the module name begins with the package name Query string lengths\n2) It must begin with the package name.\n3) It can be equal to the package name, or, if longer, must be followed by the\n4) Package name must not end with an underscore Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: module_name type( string_t ), intent(in) :: package_name Return Value logical Source Code logical function has_valid_standard_prefix ( module_name , package_name ) result ( valid ) type ( string_t ), intent ( in ) :: module_name type ( string_t ), intent ( in ) :: package_name !> Default package__module separator: two underscores character ( * ), parameter :: SEP = \"__\" character ( len = :), allocatable :: fortranized_pkg logical :: is_same , has_separator , same_beginning integer :: lpkg , lmod , lsep !> Basic check: check the name is Fortran-compliant valid = is_fortran_name ( module_name % s ) !> FPM package enforcing: check that the module name begins with the package name if ( valid ) then fortranized_pkg = to_fortran_name ( package_name % s ) !> Query string lengths lpkg = len_trim ( fortranized_pkg ) lmod = len_trim ( module_name ) lsep = len_trim ( SEP ) same_beginning = str_begins_with_str ( module_name % s , fortranized_pkg , case_sensitive = . false .) is_same = lpkg == lmod . and . same_beginning if ( lmod >= lpkg + lsep ) then has_separator = str_begins_with_str ( module_name % s ( lpkg + 1 : lpkg + lsep ), SEP ) else has_separator = . false . endif !> 2) It must begin with the package name. !> 3) It can be equal to the package name, or, if longer, must be followed by the ! default separator plus at least one character !> 4) Package name must not end with an underscore valid = is_fortran_name ( fortranized_pkg ) . and . & fortranized_pkg ( lpkg : lpkg ) /= '_' . and . & ( same_beginning . and . ( is_same . or . ( lmod > lpkg + lsep . and . has_separator ))) end if end function has_valid_standard_prefix","tags":"","url":"proc/has_valid_standard_prefix.html"},{"title":"is_fortran_name – Fortran-lang/fpm","text":"public elemental function is_fortran_name(line) result(lout) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: line Return Value logical Source Code elemental function is_fortran_name ( line ) result ( lout ) ! determine if a string is a valid Fortran name ignoring trailing spaces ! (but not leading spaces) character ( len =* ), parameter :: int = '0123456789' character ( len =* ), parameter :: lower = 'abcdefghijklmnopqrstuvwxyz' character ( len =* ), parameter :: upper = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' character ( len =* ), parameter :: allowed = upper // lower // int // '_' character ( len =* ), intent ( in ) :: line character ( len = :), allocatable :: name logical :: lout name = trim ( line ) if ( len ( name ) /= 0 ) then lout = . true . & & . and . verify ( name ( 1 : 1 ), lower // upper ) == 0 & & . and . verify ( name , allowed ) == 0 & & . and . len ( name ) <= 63 else lout = . false . endif end function is_fortran_name","tags":"","url":"proc/is_fortran_name.html"},{"title":"is_valid_module_name – Fortran-lang/fpm","text":"public function is_valid_module_name(module_name, package_name, custom_prefix, enforce_module_names) result(valid) Check that a module name fits the current naming rules:\n1) It must be a valid FORTRAN name (<=63 chars, begin with letter, “_” is only allowed non-alphanumeric)\n2) It must begin with the package name\n3) If longer, package name must be followed by default separator plus at least one char Basic check: check the name is Fortran-compliant FPM package enforcing: check that the module name begins with the package name Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: module_name type( string_t ), intent(in) :: package_name type( string_t ), intent(in) :: custom_prefix logical, intent(in) :: enforce_module_names Return Value logical Source Code logical function is_valid_module_name ( module_name , package_name , custom_prefix , enforce_module_names ) result ( valid ) type ( string_t ), intent ( in ) :: module_name type ( string_t ), intent ( in ) :: package_name type ( string_t ), intent ( in ) :: custom_prefix logical , intent ( in ) :: enforce_module_names !> Basic check: check the name is Fortran-compliant valid = is_fortran_name ( module_name % s ); if (. not . valid ) return !> FPM package enforcing: check that the module name begins with the package name if ( enforce_module_names ) then ! Default prefixing is always valid valid = has_valid_standard_prefix ( module_name , package_name ) ! If a custom prefix was validated, it provides additional naming options ! Because they never overlap with the default prefix, the former is always an option if ( len_trim ( custom_prefix ) > 0 . and . . not . valid ) & valid = has_valid_custom_prefix ( module_name , custom_prefix ) end if end function is_valid_module_name","tags":"","url":"proc/is_valid_module_name.html"},{"title":"is_valid_module_prefix – Fortran-lang/fpm","text":"public function is_valid_module_prefix(module_prefix) result(valid) Check that a custom module prefix fits the current naming rules:\n1) Only alphanumeric characters (no spaces, dashes, underscores or other characters)\n2) Does not begin with a number (Fortran-compatible syntax) Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: module_prefix Return Value logical Source Code logical function is_valid_module_prefix ( module_prefix ) result ( valid ) type ( string_t ), intent ( in ) :: module_prefix character ( len =* ), parameter :: num = '0123456789' character ( len =* ), parameter :: lower = 'abcdefghijklmnopqrstuvwxyz' character ( len =* ), parameter :: upper = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' character ( len =* ), parameter :: alpha = upper // lower character ( len =* ), parameter :: allowed = alpha // num character ( len = :), allocatable :: name name = trim ( module_prefix % s ) if ( len ( name ) > 0 . and . len ( name ) <= 63 ) then valid = verify ( name ( 1 : 1 ), alpha ) == 0 . and . & verify ( name , allowed ) == 0 else valid = . false . endif end function is_valid_module_prefix","tags":"","url":"proc/is_valid_module_prefix.html"},{"title":"join – Fortran-lang/fpm","text":"public pure function join(str, sep, trm, left, right, start, end) result(string) NAME join ( 3 f ) - [ M_strings : EDITING ] append CHARACTER variable array into a single CHARACTER variable with specified separator ( LICENSE : PD ) SYNOPSIS pure function join(str,sep,trm,left,right,start,end) result (string)\n\n character(len=*),intent(in) :: str(:)\n character(len=*),intent(in),optional :: sep\n logical,intent(in),optional :: trm\n character(len=*),intent(in),optional :: right\n character(len=*),intent(in),optional :: left\n character(len=*),intent(in),optional :: start\n character(len=*),intent(in),optional :: end\n character(len=:),allocatable :: string DESCRIPTION JOIN(3f) appends the elements of a CHARACTER array into a single\n CHARACTER variable, with elements 1 to N joined from left to right.\n By default each element is trimmed of trailing spaces and the\n default separator is a null string. OPTIONS STR (:) array of CHARACTER variables to be joined SEP separator string to place between each variable . defaults to a null string . LEFT string to place at left of each element RIGHT string to place at right of each element START prefix string END suffix string TRM option to trim each element of STR of trailing spaces . Defaults to . TRUE . RESULT STRING CHARACTER variable composed of all of the elements of STR () appended together with the optional separator SEP placed between the elements . EXAMPLE Sample program: program demo_join\n use M_strings, only: join\n implicit none\n character(len=:),allocatable :: s(:)\n character(len=:),allocatable :: out\n integer :: i\n s=[character(len=10) :: ‘United’,’ we’,’ stand,’, &\n & ’ divided’,’ we fall.’]\n out=join(s)\n write( ,’(a)’) out\n write( ,’(a)’) join(s,trm=.false.)\n write( ,’(a)’) (join(s,trm=.false.,sep=’|’),i=1,3)\n write( ,’(a)’) join(s,sep=’<>’)\n write( ,’(a)’) join(s,sep=’;’,left=’[‘,right=’]’)\n write( ,’(a)’) join(s,left=’[‘,right=’]’)\n write(*,’(a)’) join(s,left=’>>’)\n end program demo_join Expected output: United we stand, divided we fall.\n United we stand, divided we fall.\n United | we | stand, | divided | we fall.\n United | we | stand, | divided | we fall.\n United | we | stand, | divided | we fall.\n United<> we<> stand,<> divided<> we fall.\n [United];[ we];[ stand,];[ divided];[ we fall.]\n [United][ we][ stand,][ divided][ we fall.] United>> we>> stand,>> divided>> we fall. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: str (:) character(len=*), intent(in), optional :: sep logical, intent(in), optional :: trm character(len=*), intent(in), optional :: left character(len=*), intent(in), optional :: right character(len=*), intent(in), optional :: start character(len=*), intent(in), optional :: end Return Value character(len=:), allocatable Source Code pure function join ( str , sep , trm , left , right , start , end ) result ( string ) ! @(#)M_strings::join(3f): merge string array into a single CHARACTER value adding specified separators, caps, prefix and suffix character ( len =* ), intent ( in ) :: str (:) character ( len =* ), intent ( in ), optional :: sep , right , left , start , end logical , intent ( in ), optional :: trm character ( len = :), allocatable :: sep_local , left_local , right_local character ( len = :), allocatable :: string logical :: trm_local integer :: i if ( present ( sep )) then ; sep_local = sep ; else ; sep_local = '' ; endif if ( present ( trm )) then ; trm_local = trm ; else ; trm_local = . true . ; endif if ( present ( left )) then ; left_local = left ; else ; left_local = '' ; endif if ( present ( right )) then ; right_local = right ; else ; right_local = '' ; endif string = '' if ( size ( str ) == 0 ) then string = string // left_local // right_local else do i = 1 , size ( str ) - 1 if ( trm_local ) then string = string // left_local // trim ( str ( i )) // right_local // sep_local else string = string // left_local // str ( i ) // right_local // sep_local endif enddo if ( trm_local ) then string = string // left_local // trim ( str ( i )) // right_local else string = string // left_local // str ( i ) // right_local endif endif if ( present ( start )) string = start // string if ( present ( end )) string = string // end end function join","tags":"","url":"proc/join.html"},{"title":"lower – Fortran-lang/fpm","text":"public pure elemental function lower(str, begin, end) result(string) Changes a string to lowercase over optional specified column range Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: str integer, intent(in), optional :: begin integer, intent(in), optional :: end Return Value character(len=len(str)) Source Code elemental pure function lower ( str , begin , end ) result ( string ) character ( * ), intent ( In ) :: str character ( len ( str )) :: string integer , intent ( in ), optional :: begin , end integer :: i integer :: ibegin , iend string = str ibegin = 1 if ( present ( begin )) then ibegin = max ( ibegin , begin ) endif iend = len_trim ( str ) if ( present ( end )) then iend = min ( iend , end ) endif do i = ibegin , iend ! step thru each letter in the string in specified range select case ( str ( i : i )) case ( 'A' : 'Z' ) string ( i : i ) = char ( iachar ( str ( i : i )) + 32 ) ! change letter to miniscule case default end select end do end function lower","tags":"","url":"proc/lower.html"},{"title":"module_prefix_template – Fortran-lang/fpm","text":"public function module_prefix_template(project_name, custom_prefix) result(prefix) Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: project_name type( string_t ), intent(in) :: custom_prefix Return Value type( string_t ) Source Code type ( string_t ) function module_prefix_template ( project_name , custom_prefix ) result ( prefix ) type ( string_t ), intent ( in ) :: project_name type ( string_t ), intent ( in ) :: custom_prefix if ( is_valid_module_prefix ( custom_prefix )) then prefix = string_t ( trim ( custom_prefix % s ) // \"_\" ) else prefix = string_t ( to_fortran_name ( project_name % s ) // \"__\" ) end if end function module_prefix_template","tags":"","url":"proc/module_prefix_template.html"},{"title":"module_prefix_type – Fortran-lang/fpm","text":"public function module_prefix_type(project_name, custom_prefix) result(ptype) Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: project_name type( string_t ), intent(in) :: custom_prefix Return Value type( string_t ) Source Code type ( string_t ) function module_prefix_type ( project_name , custom_prefix ) result ( ptype ) type ( string_t ), intent ( in ) :: project_name type ( string_t ), intent ( in ) :: custom_prefix if ( is_valid_module_prefix ( custom_prefix )) then ptype = string_t ( \"custom\" ) else ptype = string_t ( \"default\" ) end if end function module_prefix_type","tags":"","url":"proc/module_prefix_type.html"},{"title":"replace – Fortran-lang/fpm","text":"public pure function replace(string, charset, target_char) result(res) Returns string with characters in charset replaced with target_char. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: string character(len=1), intent(in) :: charset (:) character(len=1), intent(in) :: target_char Return Value character(len=len(string)) Source Code pure function replace ( string , charset , target_char ) result ( res ) character ( * ), intent ( in ) :: string character , intent ( in ) :: charset (:), target_char character ( len ( string )) :: res integer :: n res = string do n = 1 , len ( string ) if ( any ( string ( n : n ) == charset )) then res ( n : n ) = target_char end if end do end function replace","tags":"","url":"proc/replace.html"},{"title":"str_begins_with_str – Fortran-lang/fpm","text":"public pure function str_begins_with_str(s, e, case_sensitive) result(r) test if a CHARACTER string begins with a specified prefix Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: s character(len=*), intent(in) :: e logical, intent(in), optional :: case_sensitive Return Value logical Source Code pure logical function str_begins_with_str ( s , e , case_sensitive ) result ( r ) character ( * ), intent ( in ) :: s , e logical , optional , intent ( in ) :: case_sensitive ! Default option: case sensitive integer :: n1 , n2 logical :: lower_case ! Check if case sensitive if ( present ( case_sensitive )) then lower_case = . not . case_sensitive else lower_case = . false . end if n1 = 1 n2 = 1 + len ( e ) - 1 if ( n2 > len ( s )) then r = . false . elseif ( lower_case ) then r = lower ( s ( n1 : n2 )) == lower ( e ) else r = ( s ( n1 : n2 ) == e ) end if end function str_begins_with_str","tags":"","url":"proc/str_begins_with_str.html"},{"title":"string_array_contains – Fortran-lang/fpm","text":"public function string_array_contains(search_string, array) Check if array of TYPE(STRING_T) matches a particular CHARACTER string Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: search_string type( string_t ), intent(in) :: array (:) Return Value logical Source Code logical function string_array_contains ( search_string , array ) character ( * ), intent ( in ) :: search_string type ( string_t ), intent ( in ) :: array (:) integer :: i string_array_contains = any ([( array ( i )% s == search_string , & i = 1 , size ( array ))]) end function string_array_contains","tags":"","url":"proc/string_array_contains.html"},{"title":"string_cat – Fortran-lang/fpm","text":"public function string_cat(strings, delim) result(cat) Concatenate an array of type(string_t) into\n a single CHARACTER variable Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: strings (:) character(len=*), intent(in), optional :: delim Return Value character(len=:), allocatable Source Code function string_cat ( strings , delim ) result ( cat ) type ( string_t ), intent ( in ) :: strings (:) character ( * ), intent ( in ), optional :: delim character (:), allocatable :: cat integer :: i character (:), allocatable :: delim_str if ( size ( strings ) < 1 ) then cat = '' return end if if ( present ( delim )) then delim_str = delim else delim_str = '' end if cat = strings ( 1 )% s do i = 2 , size ( strings ) cat = cat // delim_str // strings ( i )% s end do end function string_cat","tags":"","url":"proc/string_cat.html"},{"title":"to_fortran_name – Fortran-lang/fpm","text":"public pure function to_fortran_name(string) result(res) Returns string with special characters replaced with an underscore.\nFor now, only a hyphen is treated as a special character, but this can be\nexpanded to other characters if needed. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: string Return Value character(len=len(string)) Source Code pure function to_fortran_name ( string ) result ( res ) character ( * ), intent ( in ) :: string character ( len ( string )) :: res character , parameter :: SPECIAL_CHARACTERS ( * ) = [ '-' ] res = replace ( string , SPECIAL_CHARACTERS , '_' ) end function to_fortran_name","tags":"","url":"proc/to_fortran_name.html"},{"title":"upper – Fortran-lang/fpm","text":"public pure elemental function upper(str, begin, end) result(string) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: str integer, intent(in), optional :: begin integer, intent(in), optional :: end Return Value character(len=len(str)) Source Code elemental pure function upper ( str , begin , end ) result ( string ) character ( * ), intent ( In ) :: str character ( len ( str )) :: string integer , intent ( in ), optional :: begin , end integer :: i integer :: ibegin , iend string = str ibegin = 1 if ( present ( begin )) then ibegin = max ( ibegin , begin ) endif iend = len_trim ( str ) if ( present ( end )) then iend = min ( iend , end ) endif do i = ibegin , iend ! step thru each letter in the string in specified range select case ( str ( i : i )) case ( 'a' : 'z' ) string ( i : i ) = char ( iachar ( str ( i : i )) - 32 ) ! change letter to capitalized case default end select end do end function upper","tags":"","url":"proc/upper.html"},{"title":"notabs – Fortran-lang/fpm","text":"public impure elemental subroutine notabs(instr, outstr, ilen) NAME notabs(3f) - [fpm_strings:NONALPHA] expand tab characters\n (LICENSE:PD) SYNOPSIS subroutine notabs(INSTR,OUTSTR,ILEN)\n\n character(len=*),intent=(in) :: INSTR\n character(len=*),intent=(out) :: OUTSTR\n integer,intent=(out) :: ILEN DESCRIPTION NOTABS() converts tabs in INSTR to spaces in OUTSTR while maintaining\n columns. It assumes a tab is set every 8 characters. Trailing spaces\n are removed. In addition, trailing carriage returns and line feeds are removed\n (they are usually a problem created by going to and from MSWindows). What are some reasons for removing tab characters from an input line?\n Some Fortran compilers have problems with tabs, as tabs are not\n part of the Fortran character set. Some editors and printers will\n have problems with tabs. It is often useful to expand tabs in input\n files to simplify further processing such as tokenizing an input line. OPTIONS instr Input line to remove tabs from RESULTS outstr Output string with tabs expanded. Assumed to be of sufficient\n length\n ilen Significant length of returned string EXAMPLES Sample program: program demo_notabs\n\n! test filter to remove tabs and trailing white space from input\n! on files up to 1024 characters wide\nuse fpm_strings, only : notabs\ncharacter(len=1024) :: in,out\ninteger :: ios,iout\n do\n read(*,'(A)',iostat=ios)in\n if(ios /= 0) exit\n call notabs(in,out,iout)\n write(*,'(a)')out(:iout)\n enddo\nend program demo_notabs SEE ALSO GNU/Unix commands expand(1) and unexpand(1) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: instr character(len=*), intent(out) :: outstr integer, intent(out) :: ilen Source Code elemental impure subroutine notabs ( instr , outstr , ilen ) ! ident_31=\"@(#)fpm_strings::notabs(3f): convert tabs to spaces while maintaining columns, remove CRLF chars\" character ( len =* ), intent ( in ) :: instr ! input line to scan for tab characters character ( len =* ), intent ( out ) :: outstr ! tab-expanded version of INSTR produced integer , intent ( out ) :: ilen ! column position of last character put into output string ! that is, ILEN holds the position of the last non-blank character in OUTSTR integer , parameter :: tabsize = 8 ! assume a tab stop is set every 8th column integer :: ipos ! position in OUTSTR to put next character of INSTR integer :: lenin ! length of input string trimmed of trailing spaces integer :: lenout ! number of characters output string can hold integer :: istep ! counter that advances thru input string INSTR one character at a time character ( len = 1 ) :: c ! character in input line being processed integer :: iade ! ADE (ASCII Decimal Equivalent) of character being tested ipos = 1 ! where to put next character in output string OUTSTR lenin = len_trim ( instr ( 1 : len ( instr ) )) ! length of INSTR trimmed of trailing spaces lenout = len ( outstr ) ! number of characters output string OUTSTR can hold outstr = \" \" ! this SHOULD blank-fill string, a buggy machine required a loop to set all characters SCAN_LINE : do istep = 1 , lenin ! look through input string one character at a time c = instr ( istep : istep ) ! get next character iade = ichar ( c ) ! get ADE of the character EXPAND_TABS : select case ( iade ) ! take different actions depending on which character was found case ( 9 ) ! test if character is a tab and move pointer out to appropriate column ipos = ipos + ( tabsize - ( mod ( ipos - 1 , tabsize ))) case ( 10 , 13 ) ! convert carriage-return and new-line to space ,typically to handle DOS-format files ipos = ipos + 1 case default ! c is anything else other than a tab,newline,or return insert it in output string if ( ipos > lenout ) then write ( stderr , * ) \"*notabs* output string overflow\" exit else outstr ( ipos : ipos ) = c ipos = ipos + 1 endif end select EXPAND_TABS enddo SCAN_LINE ipos = min ( ipos , lenout ) ! tabs or newline or return characters or last character might have gone too far ilen = len_trim ( outstr (: ipos )) ! trim trailing spaces end subroutine notabs","tags":"","url":"proc/notabs.html"},{"title":"remove_characters_in_set – Fortran-lang/fpm","text":"public subroutine remove_characters_in_set(string, set, replace_with) Arguments Type Intent Optional Attributes Name character(len=:), intent(inout), allocatable :: string character(len=*), intent(in) :: set character(len=1), intent(in), optional :: replace_with Source Code subroutine remove_characters_in_set ( string , set , replace_with ) character ( len = :), allocatable , intent ( inout ) :: string character ( * ), intent ( in ) :: set character , optional , intent ( in ) :: replace_with ! Replace with this character instead of removing integer :: feed , length if (. not . allocated ( string )) return if ( len ( set ) <= 0 ) return length = len ( string ) feed = scan ( string , set ) do while ( length > 0 . and . feed > 0 ) ! Remove heading if ( length == 1 ) then string = \"\" elseif ( feed == 1 ) then string = string ( 2 : length ) ! Remove trailing elseif ( feed == length ) then string = string ( 1 : length - 1 ) ! In between: replace with given character elseif ( present ( replace_with )) then string ( feed : feed ) = replace_with ! Or just remove else string = string ( 1 : feed - 1 ) // string ( feed + 1 : length ) end if length = len ( string ) feed = scan ( string , set ) end do end subroutine remove_characters_in_set","tags":"","url":"proc/remove_characters_in_set.html"},{"title":"remove_newline_characters – Fortran-lang/fpm","text":"public subroutine remove_newline_characters(string) Arguments Type Intent Optional Attributes Name type( string_t ), intent(inout) :: string Source Code subroutine remove_newline_characters ( string ) type ( string_t ), intent ( inout ) :: string integer :: feed , length character ( * ), parameter :: CRLF = achar ( 13 ) // new_line ( 'a' ) character ( * ), parameter :: SPACE = ' ' call remove_characters_in_set ( string % s , set = CRLF , replace_with = SPACE ) end subroutine remove_newline_characters","tags":"","url":"proc/remove_newline_characters.html"},{"title":"split – Fortran-lang/fpm","text":"public subroutine split(input_line, array, delimiters, order, nulls) parse string on delimiter characters and store tokens into an allocatable array\ngiven a line of structure ” par1 par2 par3 … parn ” store each par(n) into a separate variable in array. by default adjacent delimiters in the input string do not create an empty string in the output array no quoting of delimiters is supported Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: input_line input string to tokenize character(len=:), intent(out), allocatable :: array (:) output array of tokens character(len=*), intent(in), optional :: delimiters list of delimiter characters character(len=*), intent(in), optional :: order order of output array sequential|[reverse|right] character(len=*), intent(in), optional :: nulls return strings composed of delimiters or not ignore|return|ignoreend Source Code subroutine split ( input_line , array , delimiters , order , nulls ) !! given a line of structure \" par1 par2 par3 ... parn \" store each par(n) into a separate variable in array. !! !! * by default adjacent delimiters in the input string do not create an empty string in the output array !! * no quoting of delimiters is supported character ( len =* ), intent ( in ) :: input_line !! input string to tokenize character ( len =* ), optional , intent ( in ) :: delimiters !! list of delimiter characters character ( len =* ), optional , intent ( in ) :: order !! order of output array sequential|[reverse|right] character ( len =* ), optional , intent ( in ) :: nulls !! return strings composed of delimiters or not ignore|return|ignoreend character ( len = :), allocatable , intent ( out ) :: array (:) !! output array of tokens integer :: n ! max number of strings INPUT_LINE could split into if all delimiter integer , allocatable :: ibegin (:) ! positions in input string where tokens start integer , allocatable :: iterm (:) ! positions in input string where tokens end character ( len = :), allocatable :: dlim ! string containing delimiter characters character ( len = :), allocatable :: ordr ! string containing order keyword character ( len = :), allocatable :: nlls ! string containing nulls keyword integer :: ii , iiii ! loop parameters used to control print order integer :: icount ! number of tokens found integer :: ilen ! length of input string with trailing spaces trimmed integer :: i10 , i20 , i30 ! loop counters integer :: icol ! pointer into input string as it is being parsed integer :: idlim ! number of delimiter characters integer :: ifound ! where next delimiter character is found in remaining input string data integer :: inotnull ! count strings not composed of delimiters integer :: ireturn ! number of tokens returned integer :: imax ! length of longest token ! decide on value for optional DELIMITERS parameter if ( present ( delimiters )) then ! optional delimiter list was present if ( delimiters /= '' ) then ! if DELIMITERS was specified and not null use it dlim = delimiters else ! DELIMITERS was specified on call as empty string dlim = ' ' // char ( 9 ) // char ( 10 ) // char ( 11 ) // char ( 12 ) // char ( 13 ) // char ( 0 ) ! use default delimiter when not specified endif else ! no delimiter value was specified dlim = ' ' // char ( 9 ) // char ( 10 ) // char ( 11 ) // char ( 12 ) // char ( 13 ) // char ( 0 ) ! use default delimiter when not specified endif idlim = len ( dlim ) ! dlim a lot of blanks on some machines if dlim is a big string if ( present ( order )) then ; ordr = lower ( adjustl ( order )); else ; ordr = 'sequential' ; endif ! decide on value for optional ORDER parameter if ( present ( nulls )) then ; nlls = lower ( adjustl ( nulls )); else ; nlls = 'ignore' ; endif ! optional parameter n = len ( input_line ) + 1 ! max number of strings INPUT_LINE could split into if all delimiter allocate ( ibegin ( n )) ! allocate enough space to hold starting location of tokens if string all tokens allocate ( iterm ( n )) ! allocate enough space to hold ending location of tokens if string all tokens ibegin (:) = 1 iterm (:) = 1 ilen = len ( input_line ) ! ILEN is the column position of the last non-blank character icount = 0 ! how many tokens found inotnull = 0 ! how many tokens found not composed of delimiters imax = 0 ! length of longest token found select case ( ilen ) case ( 0 ) ! command was totally blank case default ! there is at least one non-delimiter in INPUT_LINE if get here icol = 1 ! initialize pointer into input line INFINITE : do i30 = 1 , ilen , 1 ! store into each array element ibegin ( i30 ) = icol ! assume start new token on the character if ( index ( dlim ( 1 : idlim ), input_line ( icol : icol )) == 0 ) then ! if current character is not a delimiter iterm ( i30 ) = ilen ! initially assume no more tokens do i10 = 1 , idlim ! search for next delimiter ifound = index ( input_line ( ibegin ( i30 ): ilen ), dlim ( i10 : i10 )) IF ( ifound > 0 ) then iterm ( i30 ) = min ( iterm ( i30 ), ifound + ibegin ( i30 ) - 2 ) endif enddo icol = iterm ( i30 ) + 2 ! next place to look as found end of this token inotnull = inotnull + 1 ! increment count of number of tokens not composed of delimiters else ! character is a delimiter for a null string iterm ( i30 ) = icol - 1 ! record assumed end of string. Will be less than beginning icol = icol + 1 ! advance pointer into input string endif imax = max ( imax , iterm ( i30 ) - ibegin ( i30 ) + 1 ) icount = i30 ! increment count of number of tokens found if ( icol > ilen ) then ! no text left exit INFINITE endif enddo INFINITE end select select case ( trim ( adjustl ( nlls ))) case ( 'ignore' , '' , 'ignoreend' ) ireturn = inotnull case default ireturn = icount end select allocate ( character ( len = imax ) :: array ( ireturn )) ! allocate the array to return !allocate(array(ireturn)) ! allocate the array to turn select case ( trim ( adjustl ( ordr ))) ! decide which order to store tokens case ( 'reverse' , 'right' ) ; ii = ireturn ; iiii =- 1 ! last to first case default ; ii = 1 ; iiii = 1 ! first to last end select do i20 = 1 , icount ! fill the array with the tokens that were found if ( iterm ( i20 ) < ibegin ( i20 )) then select case ( trim ( adjustl ( nlls ))) case ( 'ignore' , '' , 'ignoreend' ) case default array ( ii ) = ' ' ii = ii + iiii end select else array ( ii ) = input_line ( ibegin ( i20 ): iterm ( i20 )) ii = ii + iiii endif enddo end subroutine split","tags":"","url":"proc/split.html"},{"title":"split_first_last – Fortran-lang/fpm","text":"public pure subroutine split_first_last(string, set, first, last) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: string character(len=*), intent(in) :: set integer, intent(out), allocatable :: first (:) integer, intent(out), allocatable :: last (:) Source Code pure subroutine split_first_last ( string , set , first , last ) character ( * ), intent ( in ) :: string character ( * ), intent ( in ) :: set integer , allocatable , intent ( out ) :: first (:) integer , allocatable , intent ( out ) :: last (:) integer , dimension ( len ( string ) + 1 ) :: istart , iend integer :: p , n , slen slen = len ( string ) n = 0 if ( slen > 0 ) then p = 0 do while ( p < slen ) n = n + 1 istart ( n ) = min ( p + 1 , slen ) call split_pos ( string , set , p ) iend ( n ) = p - 1 end do end if first = istart (: n ) last = iend (: n ) end subroutine split_first_last","tags":"","url":"proc/split_first_last.html"},{"title":"split_lines_first_last – Fortran-lang/fpm","text":"public pure subroutine split_lines_first_last(string, first, last) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: string integer, intent(out), allocatable :: first (:) integer, intent(out), allocatable :: last (:) Source Code pure subroutine split_lines_first_last ( string , first , last ) character ( * ), intent ( in ) :: string integer , allocatable , intent ( out ) :: first (:) integer , allocatable , intent ( out ) :: last (:) integer , dimension ( len ( string ) + 1 ) :: istart , iend integer :: p , n , slen character , parameter :: CR = achar ( 13 ) character , parameter :: LF = new_line ( 'A' ) slen = len ( string ) n = 0 if ( slen > 0 ) then p = 1 do while ( p <= slen ) if ( index ( CR // LF , string ( p : p )) == 0 ) then n = n + 1 istart ( n ) = p do while ( p <= slen ) if ( index ( CR // LF , string ( p : p )) /= 0 ) exit p = p + 1 end do iend ( n ) = p - 1 end if ! Handle Windows CRLF by skipping LF after CR if ( p < slen ) then if ( string ( p : p ) == CR . and . string ( p + 1 : p + 1 ) == LF ) p = p + 1 endif p = p + 1 end do end if first = istart (: n ) last = iend (: n ) end subroutine split_lines_first_last","tags":"","url":"proc/split_lines_first_last.html"},{"title":"fnv_1a – Fortran-lang/fpm","text":"public interface fnv_1a Module Procedures private pure function fnv_1a_char(input, seed) result(hash) Hash a character(*) string of default kind Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: input integer(kind=int64), intent(in), optional :: seed Return Value integer(kind=int64) private pure function fnv_1a_string_t(input, seed) result(hash) Hash a string_t array of default kind Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: input (:) integer(kind=int64), intent(in), optional :: seed Return Value integer(kind=int64)","tags":"","url":"interface/fnv_1a.html"},{"title":"len_trim – Fortran-lang/fpm","text":"public interface len_trim Module Procedures private elemental function string_len_trim(string) result(n) Determine total trimmed length of string_t array Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: string Return Value integer private pure function strings_len_trim(strings) result(n) Determine total trimmed length of string_t array Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: strings (:) Return Value integer","tags":"","url":"interface/len_trim.html"},{"title":"operator(.in.) – Fortran-lang/fpm","text":"public interface operator(.in.) Module Procedures public function string_array_contains (search_string, array) Check if array of TYPE(STRING_T) matches a particular CHARACTER string Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: search_string type( string_t ), intent(in) :: array (:) Return Value logical","tags":"","url":"interface/operator(.in.).html"},{"title":"operator(==) – Fortran-lang/fpm","text":"public interface operator(==) Module Procedures private pure function string_is_same(this, that) Check that two string objects are exactly identical Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: this two strings to be compared type( string_t ), intent(in) :: that two strings to be compared Return Value logical private pure function string_arrays_same(this, that) Check that two allocatable string object arrays are exactly identical Arguments Type Intent Optional Attributes Name type( string_t ), intent(in), allocatable :: this (:) two string arrays to be compared type( string_t ), intent(in), allocatable :: that (:) two string arrays to be compared Return Value logical","tags":"","url":"interface/operator(==).html"},{"title":"resize – Fortran-lang/fpm","text":"public interface resize Module Procedures private subroutine resize_string(list, n) increase the size of a TYPE(STRING_T) array by N elements Arguments Type Intent Optional Attributes Name type( string_t ), intent(inout), allocatable :: list (:) Instance of the array to be resized integer, intent(in), optional :: n Dimension of the final array size","tags":"","url":"interface/resize~3.html"},{"title":"str – Fortran-lang/fpm","text":"public interface str Module Procedures private pure function str_int(i) result(s) Converts integer “i” to string Arguments Type Intent Optional Attributes Name integer, intent(in) :: i Return Value character(len=str_int_len) private pure function str_int64(i) result(s) Converts integer “i” to string Arguments Type Intent Optional Attributes Name integer(kind=int64), intent(in) :: i Return Value character(len=str_int64_len) private pure function str_logical(l) result(s) Converts logical “l” to string Arguments Type Intent Optional Attributes Name logical, intent(in) :: l Return Value character(len=str_logical_len)","tags":"","url":"interface/str.html"},{"title":"str_ends_with – Fortran-lang/fpm","text":"public interface str_ends_with Module Procedures private pure function str_ends_with_str(s, e) result(r) test if a CHARACTER string ends with a specified suffix Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: s character(len=*), intent(in) :: e Return Value logical private pure function str_ends_with_any(s, e) result(r) test if a CHARACTER string ends with any of an array of suffixs Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: s character(len=*), intent(in) :: e (:) Return Value logical private pure function str_ends_with_any_string(s, e) result(r) Test if a CHARACTER string ends with any of an array of string suffixs Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: s type( string_t ), intent(in) :: e (:) Return Value logical","tags":"","url":"interface/str_ends_with.html"},{"title":"string_t – Fortran-lang/fpm","text":"public interface string_t Module Procedures private function new_string_t(s) result(string) Helper function to generate a new string_t instance\n (Required due to the allocatable component) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: s Return Value type( string_t )","tags":"","url":"interface/string_t.html"},{"title":"regex_version_from_text – Fortran-lang/fpm","text":"public function regex_version_from_text(text, what, error) result(ver) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: text character(len=*), intent(in) :: what type( error_t ), intent(out), allocatable :: error Return Value type( string_t ) Source Code type ( string_t ) function regex_version_from_text ( text , what , error ) result ( ver ) character ( * ), intent ( in ) :: text character ( * ), intent ( in ) :: what type ( error_t ), allocatable , intent ( out ) :: error integer :: ire , length if ( len_trim ( text ) <= 0 ) then call syntax_error ( error , 'cannot retrieve ' // what // ' version: empty input string' ) return end if ! Extract 3-sized version \"1.0.4\" ire = regex ( text , '\\d+\\.\\d+\\.\\d+' , length = length ) if ( ire > 0 . and . length > 0 ) then ! Parse version into the object (this should always work) ver = string_t ( text ( ire : ire + length - 1 )) else ! Try 2-sized version \"1.0\" ire = regex ( text , '\\d+\\.\\d+' , length = length ) if ( ire > 0 . and . length > 0 ) then ver = string_t ( text ( ire : ire + length - 1 )) else call syntax_error ( error , 'cannot retrieve ' // what // ' version.' ) end if end if end function regex_version_from_text","tags":"","url":"proc/regex_version_from_text.html"},{"title":"new_version – Fortran-lang/fpm","text":"public interface new_version Module Procedures private subroutine new_version_from_string(self, string, error) Create a new version from a string Arguments Type Intent Optional Attributes Name type( version_t ), intent(out) :: self Instance of the versioning data character(len=*), intent(in) :: string String describing the version information type( error_t ), intent(out), allocatable :: error Error handling private subroutine new_version_from_int(self, num) Create a new version from a string Arguments Type Intent Optional Attributes Name type( version_t ), intent(out) :: self Instance of the versioning data integer, intent(in) :: num (:) Subversion numbers to define version data","tags":"","url":"interface/new_version.html"},{"title":"has_manifest – Fortran-lang/fpm","text":"function has_manifest(dir) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: dir Return Value logical Source Code function has_manifest ( dir ) character ( len =* ), intent ( in ) :: dir logical :: has_manifest has_manifest = exists ( join_path ( dir , \"fpm.toml\" )) end function has_manifest","tags":"","url":"proc/has_manifest.html"},{"title":"get_working_dir – Fortran-lang/fpm","text":"subroutine get_working_dir(settings, working_dir_) Save access to working directory in settings, in case setting have not been allocated Arguments Type Intent Optional Attributes Name class( fpm_cmd_settings ), intent(in), optional :: settings character(len=:), intent(out), allocatable :: working_dir_ Source Code subroutine get_working_dir ( settings , working_dir_ ) class ( fpm_cmd_settings ), optional , intent ( in ) :: settings character ( len = :), allocatable , intent ( out ) :: working_dir_ if ( present ( settings )) then working_dir_ = settings % working_dir end if end subroutine get_working_dir","tags":"","url":"proc/get_working_dir.html"},{"title":"handle_error – Fortran-lang/fpm","text":"subroutine handle_error(error_) Arguments Type Intent Optional Attributes Name type( error_t ), intent(in), optional :: error_ Source Code subroutine handle_error ( error_ ) type ( error_t ), optional , intent ( in ) :: error_ if ( present ( error_ )) then write ( error_unit , '(\"[Error]\", 1x, a)' ) error_ % message stop 1 end if end subroutine handle_error","tags":"","url":"proc/handle_error~4.html"},{"title":"FPM_TARGET_NAME – Fortran-lang/fpm","text":"public pure function FPM_TARGET_NAME(type) result(msg) Target type name Arguments Type Intent Optional Attributes Name integer, intent(in) :: type Return Value character(len=:), allocatable Source Code pure function FPM_TARGET_NAME ( type ) result ( msg ) integer , intent ( in ) :: type character (:), allocatable :: msg select case ( type ) case ( FPM_TARGET_ARCHIVE ); msg = 'Archive' case ( FPM_TARGET_SHARED ); msg = 'Shared library' case ( FPM_TARGET_CPP_OBJECT ); msg = 'C++ object' case ( FPM_TARGET_C_OBJECT ); msg = 'C Object' case ( FPM_TARGET_EXECUTABLE ); msg = 'Executable' case ( FPM_TARGET_OBJECT ); msg = 'Object' case default ; msg = 'Unknown' end select end function FPM_TARGET_NAME","tags":"","url":"proc/fpm_target_name.html"},{"title":"new_target – Fortran-lang/fpm","text":"public function new_target(package, type, output_name, source, link_libraries, features, preprocess, version, output_dir) Allocate a new target Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: package integer, intent(in) :: type character(len=*), intent(in) :: output_name type( srcfile_t ), intent(in), optional :: source type( string_t ), intent(in), optional :: link_libraries (:) type( fortran_features_t ), intent(in), optional :: features type( preprocess_config_t ), intent(in), optional :: preprocess character(len=*), intent(in), optional :: version character(len=*), intent(in), optional :: output_dir Return Value type( build_target_ptr ) Source Code type ( build_target_ptr ) function new_target ( package , type , output_name , source , link_libraries , & & features , preprocess , version , output_dir ) character ( * ), intent ( in ) :: package integer , intent ( in ) :: type character ( * ), intent ( in ) :: output_name type ( srcfile_t ), intent ( in ), optional :: source type ( string_t ), intent ( in ), optional :: link_libraries (:) type ( fortran_features_t ), intent ( in ), optional :: features type ( preprocess_config_t ), intent ( in ), optional :: preprocess character ( * ), intent ( in ), optional :: version character ( * ), intent ( in ), optional :: output_dir allocate ( new_target % ptr ) associate ( target => new_target % ptr ) target % target_type = type target % output_name = output_name target % package_name = package if ( present ( source )) target % source = source if ( present ( link_libraries )) target % link_libraries = link_libraries if ( present ( features )) target % features = features if ( present ( preprocess )) then if ( allocated ( preprocess % macros )) target % macros = preprocess % macros endif if ( present ( version )) target % version = version allocate ( target % dependencies ( 0 )) call target % set_output_dir ( output_dir ) endassociate end function new_target","tags":"","url":"proc/new_target.html"},{"title":"add_dependency – Fortran-lang/fpm","text":"public subroutine add_dependency(target, dependency) Add pointer to dependeny in target%dependencies Arguments Type Intent Optional Attributes Name type( build_target_t ), intent(inout) :: target type( build_target_t ), intent(in), target :: dependency Source Code subroutine add_dependency ( target , dependency ) type ( build_target_t ), intent ( inout ) :: target type ( build_target_t ) , intent ( in ), target :: dependency target % dependencies = [ target % dependencies , build_target_ptr ( dependency )] end subroutine add_dependency","tags":"","url":"proc/add_dependency~2.html"},{"title":"filter_executable_targets – Fortran-lang/fpm","text":"public subroutine filter_executable_targets(targets, scope, list) Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(in) :: targets (:) integer, intent(in) :: scope type( string_t ), intent(out), allocatable :: list (:) Source Code subroutine filter_executable_targets ( targets , scope , list ) type ( build_target_ptr ), intent ( in ) :: targets (:) integer , intent ( in ) :: scope type ( string_t ), allocatable , intent ( out ) :: list (:) integer :: i , n n = 0 call resize ( list ) do i = 1 , size ( targets ) if ( is_executable_target ( targets ( i )% ptr , scope )) then if ( n >= size ( list )) call resize ( list ) n = n + 1 list ( n )% s = targets ( i )% ptr % output_file end if end do call resize ( list , n ) end subroutine filter_executable_targets","tags":"","url":"proc/filter_executable_targets.html"},{"title":"filter_library_targets – Fortran-lang/fpm","text":"public subroutine filter_library_targets(targets, list) Returns pointers to all library targets Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(in) :: targets (:) type( build_target_ptr ), intent(out), allocatable :: list (:) Source Code subroutine filter_library_targets ( targets , list ) type ( build_target_ptr ), intent ( in ) :: targets (:) type ( build_target_ptr ), allocatable , intent ( out ) :: list (:) integer :: i , n n = 0 do i = 1 , size ( targets ) if ( any ( targets ( i )% ptr % target_type == [ FPM_TARGET_ARCHIVE , FPM_TARGET_SHARED ])) then n = n + 1 end if end do allocate ( list ( n )) n = 0 do i = 1 , size ( targets ) if ( any ( targets ( i )% ptr % target_type == [ FPM_TARGET_ARCHIVE , FPM_TARGET_SHARED ])) then n = n + 1 list ( n )% ptr => targets ( i )% ptr end if end do end subroutine filter_library_targets","tags":"","url":"proc/filter_library_targets.html"},{"title":"filter_modules – Fortran-lang/fpm","text":"public subroutine filter_modules(targets, list) Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(in) :: targets (:) type( string_t ), intent(out), allocatable :: list (:) Source Code subroutine filter_modules ( targets , list ) type ( build_target_ptr ), intent ( in ) :: targets (:) type ( string_t ), allocatable , intent ( out ) :: list (:) integer :: i , j , n n = 0 call resize ( list ) do i = 1 , size ( targets ) associate ( target => targets ( i )% ptr ) if (. not . allocated ( target % source )) cycle if ( target % source % unit_type == FPM_UNIT_SUBMODULE ) cycle if ( n + size ( target % source % modules_provided ) >= size ( list )) call resize ( list ) do j = 1 , size ( target % source % modules_provided ) n = n + 1 list ( n )% s = join_path ( target % output_dir , & target % source % modules_provided ( j )% s ) end do end associate end do call resize ( list , n ) end subroutine filter_modules","tags":"","url":"proc/filter_modules.html"},{"title":"get_library_dirs – Fortran-lang/fpm","text":"public subroutine get_library_dirs(model, targets, shared_lib_dirs) Add link directories for all shared libraries in the dependency graph Arguments Type Intent Optional Attributes Name type( fpm_model_t ), intent(in) :: model type( build_target_ptr ), intent(inout), target :: targets (:) type( string_t ), intent(out), allocatable :: shared_lib_dirs (:) Source Code subroutine get_library_dirs ( model , targets , shared_lib_dirs ) type ( fpm_model_t ), intent ( in ) :: model type ( build_target_ptr ), intent ( inout ), target :: targets (:) type ( string_t ), allocatable , intent ( out ) :: shared_lib_dirs (:) integer :: i type ( string_t ) :: temp allocate ( shared_lib_dirs ( 0 )) do i = 1 , size ( targets ) associate ( target => targets ( i )% ptr ) if ( all ( target % target_type /= [ FPM_TARGET_SHARED , FPM_TARGET_ARCHIVE ])) cycle if ( target % output_dir . in . shared_lib_dirs ) cycle temp = string_t ( target % output_dir ) shared_lib_dirs = [ shared_lib_dirs , temp ] end associate end do end subroutine get_library_dirs","tags":"","url":"proc/get_library_dirs.html"},{"title":"resolve_module_dependencies – Fortran-lang/fpm","text":"public subroutine resolve_module_dependencies(targets, external_modules, error) Add dependencies to source-based targets ( FPM_TARGET_OBJECT )\n based on any modules used by the corresponding source file. Source file scoping Source files are assigned a scope of either FPM_SCOPE_LIB , FPM_SCOPE_APP or FPM_SCOPE_TEST . The scope controls which\n modules may be used by the source file: Library sources ( FPM_SCOPE_LIB ) may only use modules\n also with library scope. This includes library modules\n from dependencies. Executable sources ( FPM_SCOPE_APP , FPM_SCOPE_TEST ) may use\n library modules (including dependencies) as well as any modules\n corresponding to source files in the same directory or a\n subdirectory of the executable source file. @note Warning\n If a module used by a source file cannot be resolved to\n a source file in the package of the correct scope, then a fatal error is returned by the procedure and model construction fails. Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(inout), target :: targets (:) type( string_t ), intent(in) :: external_modules (:) type( error_t ), intent(out), allocatable :: error Source Code subroutine resolve_module_dependencies ( targets , external_modules , error ) type ( build_target_ptr ), intent ( inout ), target :: targets (:) type ( string_t ), intent ( in ) :: external_modules (:) type ( error_t ), allocatable , intent ( out ) :: error type ( build_target_ptr ) :: dep integer :: i , j do i = 1 , size ( targets ) if (. not . allocated ( targets ( i )% ptr % source )) cycle do j = 1 , size ( targets ( i )% ptr % source % modules_used ) if ( targets ( i )% ptr % source % modules_used ( j )% s . in . targets ( i )% ptr % source % modules_provided ) then ! Dependency satisfied in same file, skip cycle end if if ( targets ( i )% ptr % source % modules_used ( j )% s . in . external_modules ) then ! Dependency satisfied in system-installed module cycle end if if ( any ( targets ( i )% ptr % source % unit_scope == & [ FPM_SCOPE_APP , FPM_SCOPE_EXAMPLE , FPM_SCOPE_TEST ])) then dep % ptr => & find_module_dependency ( targets , targets ( i )% ptr % source % modules_used ( j )% s , & include_dir = dirname ( targets ( i )% ptr % source % file_name )) else dep % ptr => & find_module_dependency ( targets , targets ( i )% ptr % source % modules_used ( j )% s ) end if if (. not . associated ( dep % ptr )) then call fatal_error ( error , & 'Unable to find source for module dependency: \"' // & targets ( i )% ptr % source % modules_used ( j )% s // & '\" used by \"' // targets ( i )% ptr % source % file_name // '\"' ) return end if call add_dependency ( targets ( i )% ptr , dep % ptr ) end do end do end subroutine resolve_module_dependencies","tags":"","url":"proc/resolve_module_dependencies.html"},{"title":"targets_from_sources – Fortran-lang/fpm","text":"public subroutine targets_from_sources(targets, model, prune, library, error) High-level wrapper to generate build target information Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(out), allocatable :: targets (:) The generated list of build targets type( fpm_model_t ), intent(inout), target :: model The package model from which to construct the target list logical, intent(in) :: prune Enable tree-shaking/pruning of module dependencies type( library_config_t ), intent(in), optional :: library Library build configuration type( error_t ), intent(out), allocatable :: error Error structure Source Code subroutine targets_from_sources ( targets , model , prune , library , error ) !> The generated list of build targets type ( build_target_ptr ), intent ( out ), allocatable :: targets (:) !> The package model from which to construct the target list type ( fpm_model_t ), intent ( inout ), target :: model !> Library build configuration type ( library_config_t ), intent ( in ), optional :: library !> Enable tree-shaking/pruning of module dependencies logical , intent ( in ) :: prune !> Error structure type ( error_t ), intent ( out ), allocatable :: error logical :: should_prune call build_target_list ( targets , model , library ) call collect_exe_link_dependencies ( targets ) call resolve_module_dependencies ( targets , model % external_modules , error ) if ( allocated ( error )) return ! Prune unused source files, unless we're building shared libraries that need ! all sources to be distributable should_prune = prune if ( present ( library )) should_prune = should_prune . and . library % monolithic () call prune_build_targets ( targets , model % packages ( 1 ), should_prune ) call resolve_target_linking ( targets , model , library , error ) if ( allocated ( error )) return end subroutine targets_from_sources","tags":"","url":"proc/targets_from_sources.html"},{"title":"add_target – Fortran-lang/fpm","text":"public interface add_target Module Procedures private subroutine add_new_target(targets, package, type, output_name, source, link_libraries, features, preprocess, version, output_dir) Allocate a new target and append to target list Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(inout), allocatable :: targets (:) character(len=*), intent(in) :: package integer, intent(in) :: type character(len=*), intent(in) :: output_name type( srcfile_t ), intent(in), optional :: source type( string_t ), intent(in), optional :: link_libraries (:) type( fortran_features_t ), intent(in), optional :: features type( preprocess_config_t ), intent(in), optional :: preprocess character(len=*), intent(in), optional :: version character(len=*), intent(in), optional :: output_dir private subroutine add_old_target(targets, add_target) Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(inout), allocatable :: targets (:) type( build_target_ptr ), intent(in) :: add_target private subroutine add_old_targets(targets, add_targets) Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(inout), allocatable :: targets (:) type( build_target_ptr ), intent(in) :: add_targets (:)","tags":"","url":"interface/add_target.html"},{"title":"new_preprocessors – Fortran-lang/fpm","text":"public subroutine new_preprocessors(preprocessors, table, error) Construct new preprocess array from a TOML data structure. Arguments Type Intent Optional Attributes Name type( preprocess_config_t ), intent(out), allocatable :: preprocessors (:) Instance of the preprocess configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling Source Code subroutine new_preprocessors ( preprocessors , table , error ) !> Instance of the preprocess configuration type ( preprocess_config_t ), allocatable , intent ( out ) :: preprocessors (:) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_table ), pointer :: node type ( toml_key ), allocatable :: list (:) integer :: iprep , stat call table % get_keys ( list ) ! An empty table is not allowed if ( size ( list ) == 0 ) then call syntax_error ( error , \"No preprocessors defined\" ) end if allocate ( preprocessors ( size ( list ))) do iprep = 1 , size ( list ) call get_value ( table , list ( iprep )% key , node , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"Preprocessor \" // list ( iprep )% key // \" must be a table entry\" ) exit end if call preprocessors ( iprep )% new ( node , error ) if ( allocated ( error )) exit end do end subroutine new_preprocessors","tags":"","url":"proc/new_preprocessors.html"},{"title":"cct_is_same – Fortran-lang/fpm","text":"public function cct_is_same(this, that) Check that two compile_command_table_t objects are equal\nAll checks passed! Type Bound compile_command_table_t Arguments Type Intent Optional Attributes Name class( compile_command_table_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical Variables Type Visibility Attributes Name Initial integer, public :: i Source Code logical function cct_is_same ( this , that ) class ( compile_command_table_t ), intent ( in ) :: this class ( serializable_t ), intent ( in ) :: that integer :: i cct_is_same = . false . select type ( other => that ) type is ( compile_command_table_t ) if ( allocated ( this % command ). neqv . allocated ( other % command )) return if ( allocated ( this % command )) then if (. not .( size ( this % command ) == size ( other % command ))) return if (. not .( ubound ( this % command , 1 ) == ubound ( other % command , 1 ))) return if (. not .( lbound ( this % command , 1 ) == lbound ( other % command , 1 ))) return do i = lbound ( this % command , 1 ), ubound ( this % command , 1 ) if (. not . this % command ( i ) == other % command ( i )) return end do end if class default ! Not the same type return end select !> All checks passed! cct_is_same = . true . end function cct_is_same","tags":"","url":"proc/cct_is_same.html"},{"title":"cct_new – Fortran-lang/fpm","text":"public function cct_new(directory, arguments, file) result(cct) Override default initializer (GCC 15 bug) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: directory character(len=*), intent(in), optional :: arguments (:) character(len=*), intent(in) :: file Return Value type( compile_command_t ) Variables Type Visibility Attributes Name Initial integer, public :: i integer, public :: n Source Code type ( compile_command_t ) function cct_new ( directory , arguments , file ) result ( cct ) character ( len =* ), intent ( in ) :: directory , file character ( len =* ), optional , intent ( in ) :: arguments (:) integer :: i , n cct % directory = string_t ( trim ( directory )) cct % file = string_t ( trim ( file )) if ( present ( arguments )) then n = size ( arguments ) else n = 0 endif allocate ( cct % arguments ( n )) do i = 1 , n cct % arguments ( i ) = string_t ( trim ( arguments ( i ))) end do end function cct_new","tags":"","url":"proc/cct_new.html"},{"title":"compile_command_is_same – Fortran-lang/fpm","text":"public function compile_command_is_same(this, that) Check that two compile_command_t objects are equal\nAll checks passed! Type Bound compile_command_t Arguments Type Intent Optional Attributes Name class( compile_command_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical Source Code logical function compile_command_is_same ( this , that ) class ( compile_command_t ), intent ( in ) :: this class ( serializable_t ), intent ( in ) :: that compile_command_is_same = . false . select type ( other => that ) type is ( compile_command_t ) if (. not . this % directory == other % directory ) return if (. not . this % arguments == other % arguments ) return if (. not . this % file == other % file ) return class default ! Not the same type return end select !> All checks passed! compile_command_is_same = . true . end function compile_command_is_same","tags":"","url":"proc/compile_command_is_same.html"},{"title":"cct_destroy – Fortran-lang/fpm","text":"public elemental subroutine cct_destroy(self) Cleanup a compile command table Type Bound compile_command_table_t Arguments Type Intent Optional Attributes Name class( compile_command_table_t ), intent(inout) :: self Instance of the serializable object Source Code elemental subroutine cct_destroy ( self ) !> Instance of the serializable object class ( compile_command_table_t ), intent ( inout ) :: self if ( allocated ( self % command )) deallocate ( self % command ) end subroutine cct_destroy","tags":"","url":"proc/cct_destroy.html"},{"title":"cct_dump_array – Fortran-lang/fpm","text":"public subroutine cct_dump_array(self, array, error) Dump compile_command_table_t to a toml array Arguments Type Intent Optional Attributes Name class( compile_command_table_t ), intent(inout) :: self Instance of the serializable object type(toml_array), intent(inout) :: array Data structure type( error_t ), intent(out), allocatable :: error Error handling Variables Type Visibility Attributes Name Initial integer, public :: ii type(toml_table), public, pointer :: item integer, public :: stat Source Code subroutine cct_dump_array ( self , array , error ) !> Instance of the serializable object class ( compile_command_table_t ), intent ( inout ) :: self !> Data structure type ( toml_array ), intent ( inout ) :: array !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: ii , stat type ( toml_table ), pointer :: item if (. not . allocated ( self % command )) return do ii = 1 , size ( self % command ) associate ( cmd => self % command ( ii )) ! Set node for this command call add_table ( array , item , stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Cannot store entry in compile_command_table_t array\" ) return end if call cmd % dump_to_toml ( item , error ) if ( allocated ( error )) return endassociate end do end subroutine cct_dump_array","tags":"","url":"proc/cct_dump_array.html"},{"title":"cct_dump_toml – Fortran-lang/fpm","text":"public subroutine cct_dump_toml(self, table, error) Dump compile_command_table_t to toml table Type Bound compile_command_table_t Arguments Type Intent Optional Attributes Name class( compile_command_table_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling Variables Type Visibility Attributes Name Initial type(toml_array), public, pointer :: array integer, public :: ii integer, public :: stat Source Code subroutine cct_dump_toml ( self , table , error ) !> Instance of the serializable object class ( compile_command_table_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: stat , ii type ( toml_array ), pointer :: array ! Create array call add_array ( table , 'compile_commands' , array , stat = stat ) if ( stat /= toml_stat % success . or . . not . associated ( array )) then call fatal_error ( error , \"compile_command_table_t cannot create entry\" ) return end if ! Dump to it call cct_dump_array ( self , array , error ) end subroutine cct_dump_toml","tags":"","url":"proc/cct_dump_toml.html"},{"title":"cct_load_toml – Fortran-lang/fpm","text":"public subroutine cct_load_toml(self, table, error) Read compile_command_table_t from toml table (no checks made at this stage) Type Bound compile_command_table_t Arguments Type Intent Optional Attributes Name class( compile_command_table_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling Variables Type Visibility Attributes Name Initial type(toml_array), public, pointer :: array type(toml_table), public, pointer :: elem integer, public :: i integer, public :: n integer, public :: stat Source Code subroutine cct_load_toml ( self , table , error ) !> Instance of the serializable object class ( compile_command_table_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: stat , i , n type ( toml_array ), pointer :: array type ( toml_table ), pointer :: elem call self % destroy () call get_value ( table , key = 'compile_commands' , ptr = array , requested = . true ., stat = stat ) if ( stat /= toml_stat % success . or . . not . associated ( array )) then call fatal_error ( error , \"TOML table has no 'compile_commands' key\" ) return else n = len ( array ) if ( n <= 0 ) return allocate ( self % command ( n )) do i = 1 , n call get_value ( array , pos = i , ptr = elem , stat = stat ) if ( stat /= toml_stat % success . or . . not . associated ( elem )) then call fatal_error ( error , \"Entry in 'compile_commands' field cannot be read\" ) return end if call self % command ( i )% load ( elem , error ) if ( allocated ( error )) return end do end if end subroutine cct_load_toml","tags":"","url":"proc/cct_load_toml.html"},{"title":"cct_register – Fortran-lang/fpm","text":"public subroutine cct_register(self, command, target_os, error) Register a new compile command Type Bound compile_command_table_t Arguments Type Intent Optional Attributes Name class( compile_command_table_t ), intent(inout) :: self Instance of the serializable object character(len=*), intent(in) :: command Data structure integer, intent(in) :: target_os The target OS of the compile_commands.json (may be cross-compiling) type( error_t ), intent(out), allocatable :: error Error handling Variables Type Visibility Attributes Name Initial character(len=:), public, allocatable :: args (:) type( compile_command_t ), public :: cmd character(len=:), public, allocatable :: cwd integer, public :: i integer, public :: n logical, public :: sh_success character(len=:), public, allocatable :: source_file Source Code subroutine cct_register ( self , command , target_os , error ) !> Instance of the serializable object class ( compile_command_table_t ), intent ( inout ) :: self !> Data structure character ( len =* ), intent ( in ) :: command !> The target OS of the compile_commands.json (may be cross-compiling) integer , intent ( in ) :: target_os !> Error handling type ( error_t ), allocatable , intent ( out ) :: error ! Local variables type ( compile_command_t ) :: cmd character ( len = :), allocatable :: args (:), cwd , source_file logical :: sh_success integer :: i , n ! Early check if ( len_trim ( command ) <= 0 ) then call syntax_error ( error , \"compile_command_table_t trying to register an empty command\" ) return end if ! Tokenize the input command into args(:) if ( target_os == OS_WINDOWS ) then args = ms_split ( command , ucrt = . true ., success = sh_success ) else args = sh_split ( command , join_spaced = . false ., keep_quotes = . true ., success = sh_success ) end if n = size ( args ) if ( n == 0 . or . . not . sh_success ) then call syntax_error ( error , \"compile_command_table_t failed tokenizing: <\" // command // \">\" ) return end if ! Get current working directory call get_current_directory ( cwd , error ) if ( allocated ( error )) return ! Try to find the source file allocate ( character ( len = 0 ) :: source_file ) find_source_file : do i = 1 , n - 1 if ( args ( i ) == \"-c\" ) then source_file = trim ( args ( i + 1 )) exit find_source_file end if end do find_source_file ! Fallback: use last argument if not found if ( len_trim ( source_file ) == 0 ) source_file = trim ( args ( n )) ! Fill in the compile_command_t. ! Use non-default initializer due to gcc 15 bug cmd = compile_command_t ( cwd , args , source_file ) ! Add it to the structure !$omp critical (command_update) call cct_register_object ( self , cmd , error ) !$omp end critical (command_update) end subroutine cct_register","tags":"","url":"proc/cct_register.html"},{"title":"cct_register_object – Fortran-lang/fpm","text":"public pure subroutine cct_register_object(self, command, error) Type Bound compile_command_table_t Arguments Type Intent Optional Attributes Name class( compile_command_table_t ), intent(inout) :: self Instance of the serializable object type( compile_command_t ), intent(in) :: command Data structure type( error_t ), intent(out), allocatable :: error Error handling Source Code pure subroutine cct_register_object ( self , command , error ) !> Instance of the serializable object class ( compile_command_table_t ), intent ( inout ) :: self !> Data structure type ( compile_command_t ), intent ( in ) :: command !> Error handling type ( error_t ), allocatable , intent ( out ) :: error if ( allocated ( self % command )) then self % command = [ self % command , command ] else allocate ( self % command ( 1 ), source = command ) end if end subroutine cct_register_object","tags":"","url":"proc/cct_register_object.html"},{"title":"cct_write – Fortran-lang/fpm","text":"public subroutine cct_write(self, filename, error) Write compile_commands.json file. Because Jonquil does not support non-named arrays,\ncreate a custom json here. Type Bound compile_command_table_t Arguments Type Intent Optional Attributes Name class( compile_command_table_t ), intent(inout) :: self Instance of the serializable object character(len=*), intent(in) :: filename The file name type( error_t ), intent(out), allocatable :: error Error handling Variables Type Visibility Attributes Name Initial type(toml_array), public :: array type(json_ser_config), public :: cfg integer, public :: lun integer, public :: stat Source Code subroutine cct_write ( self , filename , error ) !> Instance of the serializable object class ( compile_command_table_t ), intent ( inout ) :: self !> The file name character ( * ), intent ( in ) :: filename !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_array ) :: array type ( json_ser_config ) :: cfg integer :: stat , lun ! Init array array = toml_array () ! Dump information to the array call cct_dump_array ( self , array , error ) if ( allocated ( error )) return ! Open file and write to it open ( newunit = lun , file = filename , form = 'formatted' , action = 'write' , status = 'replace' , iostat = stat ) if ( stat /= 0 ) then call fatal_error ( error , 'cannot open file ' // filename // ' for writing' ) return end if ! Ensure the array has no key if ( allocated ( array % key )) deallocate ( array % key ) cfg % indent = repeat ( ' ' , 3 ) write ( lun , '(A)' , iostat = stat , err = 1 ) json_serialize ( array , cfg ) close ( lun , iostat = stat ) 1 if ( stat /= 0 ) then call fatal_error ( error , 'cannot close file ' // filename // ' after writing' ) return end if end subroutine cct_write","tags":"","url":"proc/cct_write.html"},{"title":"compile_command_destroy – Fortran-lang/fpm","text":"public elemental subroutine compile_command_destroy(self) Cleanup compile command Type Bound compile_command_t Arguments Type Intent Optional Attributes Name class( compile_command_t ), intent(inout) :: self Instance of the serializable object Source Code elemental subroutine compile_command_destroy ( self ) !> Instance of the serializable object class ( compile_command_t ), intent ( inout ) :: self if ( allocated ( self % directory % s )) deallocate ( self % directory % s ) if ( allocated ( self % arguments )) deallocate ( self % arguments ) if ( allocated ( self % file % s )) deallocate ( self % file % s ) end subroutine compile_command_destroy","tags":"","url":"proc/compile_command_destroy.html"},{"title":"compile_command_dump_toml – Fortran-lang/fpm","text":"public subroutine compile_command_dump_toml(self, table, error) Dump compile_command_t to toml table Type Bound compile_command_t Arguments Type Intent Optional Attributes Name class( compile_command_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling Source Code subroutine compile_command_dump_toml ( self , table , error ) !> Instance of the serializable object class ( compile_command_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error call set_list ( table , \"arguments\" , self % arguments , error ) if ( allocated ( error )) return call set_string ( table , \"directory\" , self % directory , error , 'compile_command_t' ) if ( allocated ( error )) return call set_string ( table , \"file\" , self % file , error , 'compile_command_t' ) if ( allocated ( error )) return end subroutine compile_command_dump_toml","tags":"","url":"proc/compile_command_dump_toml.html"},{"title":"compile_command_load_toml – Fortran-lang/fpm","text":"public subroutine compile_command_load_toml(self, table, error) Read compile_command_t from toml table (no checks made at this stage) Type Bound compile_command_t Arguments Type Intent Optional Attributes Name class( compile_command_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling Source Code subroutine compile_command_load_toml ( self , table , error ) !> Instance of the serializable object class ( compile_command_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error call self % destroy () call get_list ( table , \"arguments\" , self % arguments , error ) if ( allocated ( error )) return ! Return unallocated value if not present call get_value ( table , \"directory\" , self % directory % s ) call get_value ( table , \"file\" , self % file % s ) end subroutine compile_command_load_toml","tags":"","url":"proc/compile_command_load_toml.html"},{"title":"compile_command_t – Fortran-lang/fpm","text":"public interface compile_command_t Module Procedures public function cct_new (directory, arguments, file) result(cct) Override default initializer (GCC 15 bug) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: directory character(len=*), intent(in), optional :: arguments (:) character(len=*), intent(in) :: file Return Value type( compile_command_t )","tags":"","url":"interface/compile_command_t.html"},{"title":"build_progress_t – Fortran-lang/fpm","text":"public interface build_progress_t Constructor for build_progress_t Module Procedures private function new_build_progress(target_queue, plain_mode) result(progress) Initialise a new build progress object Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(in), target :: target_queue (:) The queue of scheduled targets logical, intent(in), optional :: plain_mode Enable ‘plain’ output for progress object Return Value type( build_progress_t ) Progress object to initialise","tags":"","url":"interface/build_progress_t.html"},{"title":"fpm_version – Fortran-lang/fpm","text":"public function fpm_version() Return the current fpm version from fpm_version_ID as a version type Arguments None Return Value type( version_t ) Source Code type ( version_t ) function fpm_version () type ( error_t ), allocatable :: error ! Fallback to last known version in case of undefined macro #ifndef FPM_RELEASE_VERSION # define FPM_RELEASE_VERSION 0.12.0 #endif ! Accept solution from https://stackoverflow.com/questions/31649691/stringify-macro-with-gnu-gfortran ! which provides the \"easiest\" way to pass a macro to a string in Fortran complying with both ! gfortran's \"traditional\" cpp and the standard cpp syntaxes #ifdef __GFORTRAN__ /* traditional-cpp stringification */ # define STRINGIFY_START(X) \"& # define STRINGIFY_END(X) &X\" #else /* default stringification */ # define STRINGIFY_(X) #X # define STRINGIFY_START(X) & # define STRINGIFY_END(X) STRINGIFY_(X) #endif character ( len = :), allocatable :: ver_string ver_string = STRINGIFY_START ( FPM_RELEASE_VERSION ) STRINGIFY_END ( FPM_RELEASE_VERSION ) call new_version ( fpm_version , ver_string , error ) if ( allocated ( error )) call fpm_stop ( 1 , '*fpm*:internal error: cannot get version - ' // error % message ) end function fpm_version","tags":"","url":"proc/fpm_version.html"},{"title":"default_example – Fortran-lang/fpm","text":"public subroutine default_example(self, name) Populate test in case we find the default example/ directory Arguments Type Intent Optional Attributes Name type( example_config_t ), intent(out) :: self Instance of the executable meta data character(len=*), intent(in) :: name Name of the package Source Code subroutine default_example ( self , name ) !> Instance of the executable meta data type ( example_config_t ), intent ( out ) :: self !> Name of the package character ( len =* ), intent ( in ) :: name self % name = name // \"-demo\" self % source_dir = \"example\" self % main = \"main.f90\" end subroutine default_example","tags":"","url":"proc/default_example.html"},{"title":"default_executable – Fortran-lang/fpm","text":"public subroutine default_executable(self, name) Populate executable in case we find the default app directory Arguments Type Intent Optional Attributes Name type( executable_config_t ), intent(out) :: self Instance of the executable meta data character(len=*), intent(in) :: name Name of the package Source Code subroutine default_executable ( self , name ) !> Instance of the executable meta data type ( executable_config_t ), intent ( out ) :: self !> Name of the package character ( len =* ), intent ( in ) :: name self % name = name self % source_dir = \"app\" self % main = \"main.f90\" end subroutine default_executable","tags":"","url":"proc/default_executable.html"},{"title":"default_library – Fortran-lang/fpm","text":"public subroutine default_library(self) Populate library in case we find the default src directory Arguments Type Intent Optional Attributes Name type( library_config_t ), intent(out) :: self Instance of the library meta data Source Code subroutine default_library ( self ) !> Instance of the library meta data type ( library_config_t ), intent ( out ) :: self self % source_dir = \"src\" self % include_dir = [ string_t ( \"include\" )] end subroutine default_library","tags":"","url":"proc/default_library.html"},{"title":"default_test – Fortran-lang/fpm","text":"public subroutine default_test(self, name) Populate test in case we find the default test/ directory Arguments Type Intent Optional Attributes Name type( test_config_t ), intent(out) :: self Instance of the executable meta data character(len=*), intent(in) :: name Name of the package Source Code subroutine default_test ( self , name ) !> Instance of the executable meta data type ( test_config_t ), intent ( out ) :: self !> Name of the package character ( len =* ), intent ( in ) :: name self % name = name // \"-test\" self % source_dir = \"test\" self % main = \"main.f90\" end subroutine default_test","tags":"","url":"proc/default_test.html"},{"title":"get_package_data – Fortran-lang/fpm","text":"public subroutine get_package_data(package, file, error, apply_defaults) Obtain package meta data from a configuation file Arguments Type Intent Optional Attributes Name type( package_config_t ), intent(out) :: package Parsed package meta data character(len=*), intent(in) :: file Name of the package configuration file type( error_t ), intent(out), allocatable :: error Error status of the operation logical, intent(in), optional :: apply_defaults Apply package defaults (uses file system operations) Source Code subroutine get_package_data ( package , file , error , apply_defaults ) !> Parsed package meta data type ( package_config_t ), intent ( out ) :: package !> Name of the package configuration file character ( len =* ), intent ( in ) :: file !> Error status of the operation type ( error_t ), allocatable , intent ( out ) :: error !> Apply package defaults (uses file system operations) logical , intent ( in ), optional :: apply_defaults type ( toml_table ), allocatable :: table character ( len = :), allocatable :: root call read_package_file ( table , file , error ) if ( allocated ( error )) return if (. not . allocated ( table )) then call fatal_error ( error , \"Unclassified error while reading: '\" // file // \"'\" ) return end if call new_package ( package , table , dirname ( file ), error ) if ( allocated ( error )) return if ( present ( apply_defaults )) then if ( apply_defaults ) then root = dirname ( file ) if ( len_trim ( root ) == 0 ) root = \".\" call package_defaults ( package , root , error ) if ( allocated ( error )) return end if end if end subroutine get_package_data","tags":"","url":"proc/get_package_data.html"},{"title":"get_package_dependencies – Fortran-lang/fpm","text":"public subroutine get_package_dependencies(package, main, deps) Arguments Type Intent Optional Attributes Name type( package_config_t ), intent(in) :: package Parsed package meta data logical, intent(in) :: main Is the main project type( dependency_config_t ), intent(out), allocatable :: deps (:) Unprocessed list of all dependencies listed in this manifest Source Code subroutine get_package_dependencies ( package , main , deps ) !> Parsed package meta data type ( package_config_t ), intent ( in ) :: package !> Is the main project logical , intent ( in ) :: main !> Unprocessed list of all dependencies listed in this manifest type ( dependency_config_t ), allocatable , intent ( out ) :: deps (:) integer :: ndeps , k ndeps = 0 if ( allocated ( package % dependency )) & ndeps = ndeps + size ( package % dependency ) if ( main ) then if ( allocated ( package % dev_dependency )) & ndeps = ndeps + size ( package % dev_dependency ) if ( allocated ( package % example )) then do k = 1 , size ( package % example ) if ( allocated ( package % example ( k )% dependency )) & ndeps = ndeps + size ( package % example ( k )% dependency ) end do end if if ( allocated ( package % executable )) then do k = 1 , size ( package % executable ) if ( allocated ( package % executable ( k )% dependency )) & ndeps = ndeps + size ( package % executable ( k )% dependency ) end do end if if ( allocated ( package % test )) then do k = 1 , size ( package % test ) if ( allocated ( package % test ( k )% dependency )) & ndeps = ndeps + size ( package % test ( k )% dependency ) end do end if endif allocate ( deps ( ndeps )) if ( ndeps > 0 ) then ndeps = 0 if ( allocated ( package % dependency )) & call collect ( deps , ndeps , package % dependency ) if ( main ) then if ( allocated ( package % dev_dependency )) & call collect ( deps , ndeps , package % dev_dependency ) if ( allocated ( package % example )) then do k = 1 , size ( package % example ) if ( allocated ( package % example ( k )% dependency )) & call collect ( deps , ndeps , package % example ( k )% dependency ) end do end if if ( allocated ( package % executable )) then do k = 1 , size ( package % executable ) if ( allocated ( package % executable ( k )% dependency )) & call collect ( deps , ndeps , package % executable ( k )% dependency ) end do end if if ( allocated ( package % test )) then do k = 1 , size ( package % test ) if ( allocated ( package % test ( k )% dependency )) & call collect ( deps , ndeps , package % test ( k )% dependency ) end do end if endif endif contains ! Add dependencies to the list pure subroutine collect ( list , nreq , new_deps ) type ( dependency_config_t ), intent ( inout ) :: list (:) integer , intent ( inout ) :: nreq type ( dependency_config_t ), intent ( in ) :: new_deps (:) integer :: i do i = 1 , size ( new_deps ) nreq = nreq + 1 list ( nreq ) = new_deps ( i ) end do end subroutine collect end subroutine get_package_dependencies","tags":"","url":"proc/get_package_dependencies.html"},{"title":"basename – Fortran-lang/fpm","text":"public function basename(path, suffix) result(base) Extract filename from path with/without suffix Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path logical, intent(in), optional :: suffix Return Value character(len=:), allocatable Source Code function basename ( path , suffix ) result ( base ) character ( * ), intent ( In ) :: path logical , intent ( in ), optional :: suffix character (:), allocatable :: base character (:), allocatable :: file_parts (:) logical :: with_suffix if (. not . present ( suffix )) then with_suffix = . true . else with_suffix = suffix end if call split ( path , file_parts , delimiters = '\\/' ) if ( size ( file_parts ) > 0 ) then base = trim ( file_parts ( size ( file_parts ))) else base = '' endif if (. not . with_suffix ) then call split ( base , file_parts , delimiters = '.' ) if ( size ( file_parts ) >= 2 ) then base = trim ( file_parts ( size ( file_parts ) - 1 )) endif endif end function basename","tags":"","url":"proc/basename.html"},{"title":"canon_path – Fortran-lang/fpm","text":"public function canon_path(path) Canonicalize path for comparison\n* Handles path string redundancies\n* Does not test existence of path To be replaced by realpath/_fullname in stdlib_os FIXME: Lot’s of ugly hacks following here Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path Return Value character(len=:), allocatable Source Code function canon_path ( path ) character ( len =* ), intent ( in ) :: path character ( len = :), allocatable :: canon_path character ( len = :), allocatable :: nixpath integer :: istart , iend , nn , last logical :: is_path , absolute nixpath = unix_path ( path ) istart = 0 nn = 0 iend = 0 absolute = nixpath ( 1 : 1 ) == \"/\" if ( absolute ) then canon_path = \"/\" else canon_path = \"\" end if do while ( iend < len ( nixpath )) call next ( nixpath , istart , iend , is_path ) if ( is_path ) then select case ( nixpath ( istart : iend )) case ( \".\" , \"\" ) ! always drop empty paths case ( \"..\" ) if ( nn > 0 ) then last = scan ( canon_path (: len ( canon_path ) - 1 ), \"/\" , back = . true .) canon_path = canon_path (: last ) nn = nn - 1 else if (. not . absolute ) then canon_path = canon_path // nixpath ( istart : iend ) // \"/\" end if end if case default nn = nn + 1 canon_path = canon_path // nixpath ( istart : iend ) // \"/\" end select end if end do if ( len ( canon_path ) == 0 ) canon_path = \".\" if ( len ( canon_path ) > 1 . and . canon_path ( len ( canon_path ):) == \"/\" ) then canon_path = canon_path (: len ( canon_path ) - 1 ) end if contains subroutine next ( string , istart , iend , is_path ) character ( len =* ), intent ( in ) :: string integer , intent ( inout ) :: istart integer , intent ( inout ) :: iend logical , intent ( inout ) :: is_path integer :: ii , nn character :: tok nn = len ( string ) if ( iend >= nn ) then istart = nn iend = nn return end if ii = min ( iend + 1 , nn ) tok = string ( ii : ii ) is_path = tok /= '/' if (. not . is_path ) then is_path = . false . istart = ii iend = ii return end if istart = ii do ii = min ( iend + 1 , nn ), nn tok = string ( ii : ii ) select case ( tok ) case ( '/' ) exit case default iend = ii cycle end select end do end subroutine next end function canon_path","tags":"","url":"proc/canon_path.html"},{"title":"dirname – Fortran-lang/fpm","text":"public function dirname(path) result(dir) Extract dirname from path Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path Return Value character(len=:), allocatable Source Code function dirname ( path ) result ( dir ) character ( * ), intent ( in ) :: path character (:), allocatable :: dir dir = path ( 1 : scan ( path , ' / \\' , back = . true .)) end function dirname","tags":"","url":"proc/dirname.html"},{"title":"exists – Fortran-lang/fpm","text":"public function exists(filename) result(r) test if pathname already exists Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: filename Return Value logical","tags":"","url":"proc/exists.html"},{"title":"get_dos_path – Fortran-lang/fpm","text":"public function get_dos_path(path, error) Ensure a windows path is converted to an 8.3 DOS path if it contains spaces\nNo need to convert if there are no spaces Read screen output Ensure there are no trailing slashes Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path type( error_t ), intent(out), allocatable :: error Return Value character(len=:), allocatable Source Code function get_dos_path ( path , error ) character ( len =* ), intent ( in ) :: path type ( error_t ), allocatable , intent ( out ) :: error character ( len = :), allocatable :: get_dos_path character (:), allocatable :: redirect , screen_output , line integer :: stat , cmdstat , iunit , last ! Non-Windows OS if ( get_os_type () /= OS_WINDOWS ) then get_dos_path = path return end if ! Trim path first get_dos_path = trim ( path ) !> No need to convert if there are no spaces has_spaces : if ( scan ( get_dos_path , ' ' ) > 0 ) then redirect = get_temp_filename () call execute_command_line ( 'cmd /c for %A in (\"' // path // '\") do @echo %~sA >' // redirect // ' 2>&1' ,& exitstat = stat , cmdstat = cmdstat ) !> Read screen output command_OK : if ( cmdstat == 0 . and . stat == 0 ) then allocate ( character ( len = 0 ) :: screen_output ) open ( newunit = iunit , file = redirect , status = 'old' , iostat = stat ) if ( stat == 0 ) then do call getline ( iunit , line , stat ) if ( stat /= 0 ) exit screen_output = screen_output // line // ' ' end do ! Close and delete file close ( iunit , status = 'delete' ) else call fatal_error ( error , 'cannot read temporary file from successful DOS path evaluation' ) return endif else command_OK call fatal_error ( error , 'unsuccessful Windows->DOS path command' ) return end if command_OK get_dos_path = trim ( adjustl ( screen_output )) endif has_spaces !> Ensure there are no trailing slashes last = len_trim ( get_dos_path ) if ( last > 1 . and . get_dos_path ( last : last ) == '/' . or . get_dos_path ( last : last ) == '\\' ) get_dos_path = get_dos_path ( 1 : last - 1 ) end function get_dos_path","tags":"","url":"proc/get_dos_path.html"},{"title":"get_local_prefix – Fortran-lang/fpm","text":"public function get_local_prefix(os) result(prefix) Determine the path prefix to the local folder. Used for installation, registry etc. Arguments Type Intent Optional Attributes Name integer, intent(in), optional :: os Platform identifier Return Value character(len=:), allocatable Installation prefix Source Code function get_local_prefix ( os ) result ( prefix ) !> Installation prefix character ( len = :), allocatable :: prefix !> Platform identifier integer , intent ( in ), optional :: os !> Default installation prefix on Unix platforms character ( len =* ), parameter :: default_prefix_unix = \"/usr/local\" !> Default installation prefix on Windows platforms character ( len =* ), parameter :: default_prefix_win = \"C:\\\" character(len=:), allocatable :: home if (os_is_unix(os)) then home=get_env('HOME','') if (home /= '' ) then prefix = join_path(home, \" . local \") else prefix = default_prefix_unix end if else home=get_env('APPDATA','') if (home /= '' ) then prefix = join_path(home, \" local \" ) else prefix = default_prefix_win end if end if end function get_local_prefix","tags":"","url":"proc/get_local_prefix.html"},{"title":"get_temp_filename – Fortran-lang/fpm","text":"public function get_temp_filename() result(tempfile) Uses iso_c_binding Get a unused temporary filename\n Calls posix ‘tempnam’ - not recommended, but\n we have no security concerns for this application\n and use here is temporary.\nWorks with MinGW Arguments None Return Value character(len=:), allocatable Source Code function get_temp_filename () result ( tempfile ) ! use iso_c_binding , only : c_ptr , C_NULL_PTR , c_f_pointer integer , parameter :: MAX_FILENAME_LENGTH = 32768 character (:), allocatable :: tempfile type ( c_ptr ) :: c_tempfile_ptr character ( len = 1 ), pointer :: c_tempfile (:) interface function c_tempnam ( dir , pfx ) result ( tmp ) bind ( c , name = \"tempnam\" ) import type ( c_ptr ), intent ( in ), value :: dir type ( c_ptr ), intent ( in ), value :: pfx type ( c_ptr ) :: tmp end function c_tempnam subroutine c_free ( ptr ) BIND ( C , name = \"free\" ) import type ( c_ptr ), value :: ptr end subroutine c_free end interface c_tempfile_ptr = c_tempnam ( C_NULL_PTR , C_NULL_PTR ) call c_f_pointer ( c_tempfile_ptr , c_tempfile ,[ MAX_FILENAME_LENGTH ]) tempfile = f_string ( c_tempfile ) call c_free ( c_tempfile_ptr ) end function get_temp_filename","tags":"","url":"proc/get_temp_filename.html"},{"title":"is_absolute_path – Fortran-lang/fpm","text":"public function is_absolute_path(path, is_unix) Returns .true. if provided path is absolute. ~ not treated as absolute. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path logical, intent(in), optional :: is_unix Return Value logical Source Code logical function is_absolute_path ( path , is_unix ) character ( len =* ), intent ( in ) :: path logical , optional , intent ( in ) :: is_unix character ( len =* ), parameter :: letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' logical :: is_unix_os if ( present ( is_unix )) then is_unix_os = is_unix else is_unix_os = os_is_unix () end if if ( is_unix_os ) then is_absolute_path = path ( 1 : 1 ) == '/' else if ( len ( path ) < 2 ) then is_absolute_path = . false . return end if is_absolute_path = index ( letters , path ( 1 : 1 )) /= 0 . and . path ( 2 : 2 ) == ':' end if end function is_absolute_path","tags":"","url":"proc/is_absolute_path.html"},{"title":"is_dir – Fortran-lang/fpm","text":"public function is_dir(dir) test if a name matches an existing directory path Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: dir Return Value logical Source Code logical function is_dir ( dir ) character ( * ), intent ( in ) :: dir integer :: stat select case ( get_os_type ()) case ( OS_UNKNOWN , OS_LINUX , OS_MACOS , OS_CYGWIN , OS_SOLARIS , OS_FREEBSD , OS_OPENBSD ) call run ( \"test -d \" // dir , & & exitstat = stat , echo = . false ., verbose = . false .) case ( OS_WINDOWS ) call run ( 'cmd /c \"if not exist ' // windows_path ( dir ) // '\\ exit /B 1\"' , & & exitstat = stat , echo = . false ., verbose = . false .) end select is_dir = ( stat == 0 ) end function is_dir","tags":"","url":"proc/is_dir.html"},{"title":"is_hidden_file – Fortran-lang/fpm","text":"public function is_hidden_file(file_basename) result(r) test if a file is hidden Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: file_basename Return Value logical Source Code logical function is_hidden_file ( file_basename ) result ( r ) character ( * ), intent ( in ) :: file_basename if ( len ( file_basename ) <= 2 ) then r = . false . else r = str_begins_with_str ( file_basename , '.' ) end if end function is_hidden_file","tags":"","url":"proc/is_hidden_file.html"},{"title":"join_path – Fortran-lang/fpm","text":"public function join_path(a1, a2, a3, a4, a5) result(path) Construct path by joining strings with os file separator Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: a1 character(len=*), intent(in) :: a2 character(len=*), intent(in), optional :: a3 character(len=*), intent(in), optional :: a4 character(len=*), intent(in), optional :: a5 Return Value character(len=:), allocatable Source Code function join_path ( a1 , a2 , a3 , a4 , a5 ) result ( path ) character ( len =* ), intent ( in ) :: a1 , a2 character ( len =* ), intent ( in ), optional :: a3 , a4 , a5 character ( len = :), allocatable :: path character ( len = 1 ) :: filesep logical , save :: has_cache = . false . character ( len = 1 ), save :: cache = '/' !$omp threadprivate(has_cache, cache) if ( has_cache ) then filesep = cache else select case ( get_os_type ()) case default filesep = '/' case ( OS_WINDOWS ) filesep = '\\' end select cache = filesep has_cache = . true . end if if ( a1 == \"\" ) then path = a2 else path = a1 // filesep // a2 end if if ( present ( a3 )) then path = path // filesep // a3 else return end if if ( present ( a4 )) then path = path // filesep // a4 else return end if if ( present ( a5 )) then path = path // filesep // a5 else return end if end function join_path","tags":"","url":"proc/join_path.html"},{"title":"number_of_rows – Fortran-lang/fpm","text":"public function number_of_rows(s) result(nrows) Determine number or rows in a file given a LUN Arguments Type Intent Optional Attributes Name integer, intent(in) :: s Return Value integer Source Code integer function number_of_rows ( s ) result ( nrows ) integer , intent ( in ) :: s integer :: ios rewind ( s ) nrows = 0 do read ( s , * , iostat = ios ) if ( ios /= 0 ) exit nrows = nrows + 1 end do rewind ( s ) end function number_of_rows","tags":"","url":"proc/number_of_rows.html"},{"title":"parent_dir – Fortran-lang/fpm","text":"public function parent_dir(path) result(dir) Extract dirname from path Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path Return Value character(len=:), allocatable Source Code function parent_dir ( path ) result ( dir ) character ( * ), intent ( in ) :: path character (:), allocatable :: dir dir = path ( 1 : scan ( path , ' / \\' , back = . true .) - 1 ) end function parent_dir","tags":"","url":"proc/parent_dir.html"},{"title":"read_lines – Fortran-lang/fpm","text":"public function read_lines(filename) result(lines) read lines into an array of TYPE(STRING_T) variables Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: filename Return Value type( string_t ), allocatable, (:) Source Code function read_lines ( filename ) result ( lines ) character ( len =* ), intent ( in ) :: filename type ( string_t ), allocatable :: lines (:) integer :: i character ( len = :), allocatable :: content integer , allocatable :: first (:), last (:) content = read_text_file ( filename ) if ( len ( content ) == 0 ) then allocate ( lines ( 0 )) return end if call split_lines_first_last ( content , first , last ) ! allocate lines from file content string allocate ( lines ( size ( first ))) do i = 1 , size ( first ) allocate ( lines ( i )% s , source = content ( first ( i ): last ( i ))) end do end function read_lines","tags":"","url":"proc/read_lines.html"},{"title":"read_lines_expanded – Fortran-lang/fpm","text":"public function read_lines_expanded(filename) result(lines) read lines into an array of TYPE(STRING_T) variables expanding tabs Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: filename Return Value type( string_t ), allocatable, (:) Source Code function read_lines_expanded ( filename ) result ( lines ) character ( len =* ), intent ( in ) :: filename type ( string_t ), allocatable :: lines (:) integer :: i character ( len = :), allocatable :: content integer , allocatable :: first (:), last (:) content = read_text_file ( filename ) if ( len ( content ) == 0 ) then allocate ( lines ( 0 )) return end if call split_lines_first_last ( content , first , last ) ! allocate lines from file content string allocate ( lines ( size ( first ))) do i = 1 , size ( first ) allocate ( lines ( i )% s , source = dilate ( content ( first ( i ): last ( i )))) end do end function read_lines_expanded","tags":"","url":"proc/read_lines_expanded.html"},{"title":"unix_path – Fortran-lang/fpm","text":"public function unix_path(path) result(nixpath) Replace file system separators for unix Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path Return Value character(len=:), allocatable Source Code function unix_path ( path ) result ( nixpath ) character ( * ), intent ( in ) :: path character (:), allocatable :: nixpath integer :: idx nixpath = path idx = index ( nixpath , '\\') do while(idx > 0) nixpath(idx:idx) = ' / ' idx = index(nixpath,' \\' ) end do end function unix_path","tags":"","url":"proc/unix_path.html"},{"title":"which – Fortran-lang/fpm","text":"public function which(command) result(pathname) Name which ( 3 f ) - [ M_io : ENVIRONMENT ] given a command name find the pathname by searching the directories in the environment variable $ PATH ( LICENSE : PD ) Syntax function which(command) result(pathname) character(len=*),intent(in) :: command\ncharacter(len=:),allocatable :: pathname Description Given a command name find the first file with that name in the directories specified by the environment variable $ PATH . options COMMAND the command to search for Returns PATHNAME the first pathname found in the current user path . Returns blank if the command is not found . Example Sample program: Checking the error message and counting lines: program demo_which use M_io , only : which implicit none write ( * , * ) ' ls is ' , which ( ' ls ' ) write ( * , * ) ' dir is ' , which ( ' dir ' ) write ( * , * ) ' install is ' , which ( ' install ' ) end program demo_which Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: command Return Value character(len=:), allocatable Source Code function which ( command ) result ( pathname ) character ( len =* ), intent ( in ) :: command character ( len = :), allocatable :: pathname , checkon , paths (:), exts (:) integer :: i , j pathname = '' call split ( get_env ( 'PATH' ), paths , delimiters = merge ( ';' , ':' , separator () == '\\')) SEARCH: do i=1,size(paths) checkon=trim(join_path(trim(paths(i)),command)) select case(separator()) case(' / ') if(exists(checkon))then pathname=checkon exit SEARCH endif case(' \\ ') if(exists(checkon))then pathname=checkon exit SEARCH endif if(exists(checkon//' . bat '))then pathname=checkon//' . bat ' exit SEARCH endif if(exists(checkon//' . exe '))then pathname=checkon//' . exe ' exit SEARCH endif call split(get_env(' PATHEXT '),exts,delimiters=' ; ') do j=1,size(exts) if(exists(checkon//' . '//trim(exts(j))))then pathname=checkon//' . ' // trim ( exts ( j )) exit SEARCH endif enddo end select enddo SEARCH end function which","tags":"","url":"proc/which.html"},{"title":"windows_path – Fortran-lang/fpm","text":"public function windows_path(path) result(winpath) Replace file system separators for windows Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path Return Value character(len=:), allocatable Source Code function windows_path ( path ) result ( winpath ) character ( * ), intent ( in ) :: path character (:), allocatable :: winpath integer :: idx winpath = path idx = index ( winpath , '/' ) do while ( idx > 0 ) winpath ( idx : idx ) = '\\' idx = index(winpath,' / ' ) end do end function windows_path","tags":"","url":"proc/windows_path.html"},{"title":"delete_file – Fortran-lang/fpm","text":"public subroutine delete_file(file) delete a file by filename Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: file Source Code subroutine delete_file ( file ) character ( len =* ), intent ( in ) :: file logical :: exist integer :: unit inquire ( file = file , exist = exist ) if ( exist ) then open ( file = file , newunit = unit ) close ( unit , status = \"delete\" ) end if end subroutine delete_file","tags":"","url":"proc/delete_file.html"},{"title":"execute_and_read_output – Fortran-lang/fpm","text":"public subroutine execute_and_read_output(cmd, output, error, verbose) Execute command line and return output as a string. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: cmd Command to execute. character(len=:), intent(out), allocatable :: output Command line output. type( error_t ), intent(out), allocatable :: error Error to handle. logical, intent(in), optional :: verbose Print additional information if true.","tags":"","url":"proc/execute_and_read_output.html"},{"title":"fileclose – Fortran-lang/fpm","text":"public subroutine fileclose(lun, ier) simple close of a LUN. On error show message and stop (by default) Arguments Type Intent Optional Attributes Name integer, intent(in) :: lun integer, intent(out), optional :: ier Source Code subroutine fileclose ( lun , ier ) integer , intent ( in ) :: lun integer , intent ( out ), optional :: ier character ( len = 256 ) :: message integer :: ios if ( lun /=- 1 ) then close ( unit = lun , iostat = ios , iomsg = message ) if ( ios /= 0 ) then if ( present ( ier )) then ier = ios else call fpm_stop ( 4 , '*fileclose*:' // trim ( message )) endif endif endif end subroutine fileclose","tags":"","url":"proc/fileclose.html"},{"title":"fileopen – Fortran-lang/fpm","text":"public subroutine fileopen(filename, lun, ier) procedure to open filename as a sequential “text” file Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: filename integer, intent(out) :: lun integer, intent(out), optional :: ier Source Code subroutine fileopen ( filename , lun , ier ) character ( len =* ), intent ( in ) :: filename integer , intent ( out ) :: lun integer , intent ( out ), optional :: ier integer :: ios character ( len = 256 ) :: message message = ' ' ios = 0 if ( filename /= ' ' ) then open ( file = filename , & & newunit = lun , & & form = 'formatted' , & ! FORM = FORMATTED | UNFORMATTED & access = 'sequential' , & ! ACCESS = SEQUENTIAL| DIRECT | STREAM & action = 'write' , & ! ACTION = READ|WRITE| READWRITE & position = 'rewind' , & ! POSITION= ASIS | REWIND | APPEND & status = 'new' , & ! STATUS = NEW| REPLACE| OLD| SCRATCH| UNKNOWN & iostat = ios , & & iomsg = message ) else lun = stdout ios = 0 endif if ( ios /= 0 ) then lun =- 1 if ( present ( ier )) then ier = ios else call fpm_stop ( 3 , '*fileopen*:' // filename // ':' // trim ( message )) endif endif end subroutine fileopen","tags":"","url":"proc/fileopen.html"},{"title":"filewrite – Fortran-lang/fpm","text":"public subroutine filewrite(filename, filedata) procedure to write filedata to file filename Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: filename character(len=*), intent(in) :: filedata (:) Source Code subroutine filewrite ( filename , filedata ) character ( len =* ), intent ( in ) :: filename character ( len =* ), intent ( in ) :: filedata (:) integer :: lun , i , ios character ( len = 256 ) :: message call fileopen ( filename , lun ) if ( lun /=- 1 ) then ! program currently stops on error on open, but might ! want it to continue so -1 (unallowed LUN) indicates error ! write file do i = 1 , size ( filedata ) write ( lun , '(a)' , iostat = ios , iomsg = message ) trim ( filedata ( i )) if ( ios /= 0 ) then call fpm_stop ( 5 , '*filewrite*:' // filename // ':' // trim ( message )) endif enddo endif ! close file call fileclose ( lun ) end subroutine filewrite","tags":"","url":"proc/filewrite.html"},{"title":"get_home – Fortran-lang/fpm","text":"public subroutine get_home(home, error) Get the HOME directory on Unix and the %USERPROFILE% directory on Windows. Arguments Type Intent Optional Attributes Name character(len=:), intent(out), allocatable :: home type( error_t ), intent(out), allocatable :: error Source Code subroutine get_home ( home , error ) character ( len = :), allocatable , intent ( out ) :: home type ( error_t ), allocatable , intent ( out ) :: error if ( os_is_unix ()) then home = get_env ( 'HOME' , '' ) if ( home == '' ) then call fatal_error ( error , \"Couldn't retrieve 'HOME' variable\" ) return end if else home = get_env ( 'USERPROFILE' , '' ) if ( home == '' ) then call fatal_error ( error , \"Couldn't retrieve '%USERPROFILE%' variable\" ) return end if end if end subroutine get_home","tags":"","url":"proc/get_home.html"},{"title":"getline – Fortran-lang/fpm","text":"public subroutine getline(unit, line, iostat, iomsg) NAME getline(3f) - [M_io:READ] read a line of arbintrary length from specified\n LUN into allocatable string (up to system line length limit)\n(LICENSE:PD) SYNTAX subroutine getline(unit,line,iostat,iomsg) integer,intent(in) :: unit\ncharacter(len=:),allocatable,intent(out) :: line\ninteger,intent(out) :: iostat\ncharacter(len=:), allocatable, optional :: iomsg DESCRIPTION Read a line of any length up to programming environment maximum line length . Requires Fortran 2003 +. It is primarily expected to be used when reading input which will then be parsed or echoed . The input file must have a PAD attribute of YES for the function to work properly , which is typically true . The simple use of a loop that repeatedly re - allocates a character variable in addition to reading the input file one buffer at a time could ( depending on the programming environment used ) be inefficient , as it could reallocate and allocate memory used for the output string with each buffer read . OPTIONS LINE The line read when IOSTAT returns as zero . LUN LUN ( Fortran logical I / O unit ) number of file open and ready to read . IOSTAT status returned by READ ( IOSTAT = IOS ) . If not zero , an error occurred or an end - of - file or end - of - record was encountered . IOMSG error message returned by system when IOSTAT is not zero . EXAMPLE Sample program: program demo_getline use , intrinsic :: iso_fortran_env , only : stdin => input_unit use , intrinsic :: iso_fortran_env , only : iostat_end use FPM_filesystem , only : getline implicit none integer :: iostat character ( len =:), allocatable :: line , iomsg open ( unit = stdin , pad = ' yes ' ) INFINITE : do call getline ( stdin , line , iostat , iomsg ) if ( iostat /= 0 ) exit INFINITE write ( * , ' ( a ) ')' [ ' //line//']' enddo INFINITE if ( iostat /= iostat_end ) then write ( * , * ) ' error reading input : ' , iomsg endif end program demo_getline Arguments Type Intent Optional Attributes Name integer, intent(in) :: unit Formatted IO unit character(len=:), intent(out), allocatable :: line Line to read integer, intent(out) :: iostat Status of operation character(len=:), optional, allocatable :: iomsg Error message Source Code subroutine getline ( unit , line , iostat , iomsg ) !> Formatted IO unit integer , intent ( in ) :: unit !> Line to read character ( len = :), allocatable , intent ( out ) :: line !> Status of operation integer , intent ( out ) :: iostat !> Error message character ( len = :), allocatable , optional :: iomsg integer , parameter :: BUFFER_SIZE = 1024 character ( len = BUFFER_SIZE ) :: buffer character ( len = 256 ) :: msg integer :: size integer :: stat allocate ( character ( len = 0 ) :: line ) do read ( unit , '(a)' , advance = 'no' , iostat = stat , iomsg = msg , size = size ) & & buffer if ( stat > 0 ) exit line = line // buffer (: size ) if ( stat < 0 ) then if ( is_iostat_eor ( stat )) then stat = 0 end if exit end if end do if ( stat /= 0 ) then if ( present ( iomsg )) iomsg = trim ( msg ) end if iostat = stat end subroutine getline","tags":"","url":"proc/getline.html"},{"title":"list_files – Fortran-lang/fpm","text":"public recursive subroutine list_files(dir, files, recurse) Get file & directory names in directory dir using iso_c_binding. File/directory names return are relative to cwd, ie. preprended with dir Includes files starting with . except current directory and parent directory Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: dir type( string_t ), intent(out), allocatable :: files (:) logical, intent(in), optional :: recurse Source Code recursive subroutine list_files ( dir , files , recurse ) character ( len =* ), intent ( in ) :: dir type ( string_t ), allocatable , intent ( out ) :: files (:) logical , intent ( in ), optional :: recurse integer :: i type ( string_t ), allocatable :: dir_files (:) type ( string_t ), allocatable :: sub_dir_files (:) type ( c_ptr ) :: dir_handle type ( c_ptr ) :: dir_entry_c character ( len = :, kind = c_char ), allocatable :: fortran_name character ( len = :), allocatable :: string_fortran integer , parameter :: N_MAX = 256 type ( string_t ) :: files_tmp ( N_MAX ) integer ( kind = c_int ) :: r if ( c_is_dir ( dir ( 1 : len_trim ( dir )) // c_null_char ) == 0 ) then allocate ( files ( 0 )) return end if dir_handle = c_opendir ( dir ( 1 : len_trim ( dir )) // c_null_char ) if (. not . c_associated ( dir_handle )) then print * , 'c_opendir() failed' error stop end if i = 0 allocate ( files ( 0 )) do dir_entry_c = c_readdir ( dir_handle ) if (. not . c_associated ( dir_entry_c )) then exit else string_fortran = f_string ( c_get_d_name ( dir_entry_c )) if (( string_fortran == '.' . or . string_fortran == '..' )) then cycle end if i = i + 1 if ( i > N_MAX ) then files = [ files , files_tmp ] i = 1 end if files_tmp ( i )% s = join_path ( dir , string_fortran ) end if end do r = c_closedir ( dir_handle ) if ( r /= 0 ) then print * , 'c_closedir() failed' error stop end if if ( i > 0 ) then files = [ files , files_tmp ( 1 : i )] end if if ( present ( recurse )) then if ( recurse ) then allocate ( sub_dir_files ( 0 )) do i = 1 , size ( files ) if ( c_is_dir ( files ( i )% s // c_null_char ) /= 0 ) then call list_files ( files ( i )% s , dir_files , recurse = . true .) sub_dir_files = [ sub_dir_files , dir_files ] end if end do files = [ files , sub_dir_files ] end if end if end subroutine list_files","tags":"","url":"proc/list_files.html"},{"title":"mkdir – Fortran-lang/fpm","text":"public subroutine mkdir(dir, echo) Create a directory. Create subdirectories as needed Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: dir logical, intent(in), optional :: echo Source Code subroutine mkdir ( dir , echo ) character ( len =* ), intent ( in ) :: dir logical , intent ( in ), optional :: echo integer :: stat if ( is_dir ( dir )) return select case ( get_os_type ()) case ( OS_UNKNOWN , OS_LINUX , OS_MACOS , OS_CYGWIN , OS_SOLARIS , OS_FREEBSD , OS_OPENBSD ) call run ( 'mkdir -p ' // dir , exitstat = stat , echo = echo , verbose = . false .) case ( OS_WINDOWS ) call run ( \"mkdir \" // windows_path ( dir ), & & echo = echo , exitstat = stat , verbose = . false .) end select if ( stat /= 0 ) then call fpm_stop ( 1 , '*mkdir*:directory creation failed' ) end if end subroutine mkdir","tags":"","url":"proc/mkdir.html"},{"title":"os_delete_dir – Fortran-lang/fpm","text":"public subroutine os_delete_dir(is_unix, dir, echo) Delete directory using system OS remove directory commands Arguments Type Intent Optional Attributes Name logical, intent(in) :: is_unix character(len=*), intent(in) :: dir logical, intent(in), optional :: echo Source Code subroutine os_delete_dir ( is_unix , dir , echo ) logical , intent ( in ) :: is_unix character ( len =* ), intent ( in ) :: dir logical , intent ( in ), optional :: echo if ( is_unix ) then call run ( 'rm -rf ' // dir , echo = echo , verbose = . false .) else call run ( 'rmdir /s/q ' // dir , echo = echo , verbose = . false .) end if end subroutine os_delete_dir","tags":"","url":"proc/os_delete_dir.html"},{"title":"run – Fortran-lang/fpm","text":"public subroutine run(cmd, echo, exitstat, verbose, redirect) Name run(3f) - execute specified system command and selectively echo\ncommand and output to a file and/or stdout.\n(LICENSE:MIT) Syntax subroutine run(cmd,echo,exitstat,verbose,redirect)\n\n character(len=*), intent(in) :: cmd\n logical,intent(in),optional :: echo\n integer, intent(out),optional :: exitstat\n logical, intent(in), optional :: verbose\n character(*), intent(in), optional :: redirect Description Execute the specified system command. Optionally echo the command before execution return the system exit status of the command. redirect the output of the command to a file. echo command output to stdout Calling run(3f) is preferred to direct calls to\n execute_command_line(3f) in the fpm(1) source to provide a standard\n interface where output modes can be specified. Options CMD System command to execute ECHO Whether to echo the command being executed or not Defaults to . TRUE . . VERBOSE Whether to redirect the command output to a null device or not Defaults to . TRUE . . REDIRECT Filename to redirect stdout and stderr of the command into . If generated it is closed before run ( 3 f ) returns . EXITSTAT The system exit status of the command when supported by the system . If not present and a non - zero status is generated program termination occurs . Example Sample program: Checking the error message and counting lines: program demo_run use fpm_filesystem , only : run implicit none logical , parameter :: T =. true ., F =. false . integer :: exitstat character ( len =:), allocatable :: cmd cmd = ' ls - ltrasd * . md ' call run ( cmd ) call run ( cmd , exitstat = exitstat ) call run ( cmd , echo = F ) call run ( cmd , verbose = F ) end program demo_run Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: cmd logical, intent(in), optional :: echo integer, intent(out), optional :: exitstat logical, intent(in), optional :: verbose character(len=*), intent(in), optional :: redirect Source Code subroutine run ( cmd , echo , exitstat , verbose , redirect ) character ( len =* ), intent ( in ) :: cmd logical , intent ( in ), optional :: echo integer , intent ( out ), optional :: exitstat logical , intent ( in ), optional :: verbose character ( * ), intent ( in ), optional :: redirect integer :: cmdstat character ( len = 256 ) :: cmdmsg , iomsg logical :: echo_local , verbose_local character (:), allocatable :: redirect_str character (:), allocatable :: line integer :: stat , fh , iostat if ( present ( echo )) then echo_local = echo else echo_local = . true . end if if ( present ( verbose )) then verbose_local = verbose else verbose_local = . true . end if if ( present ( redirect )) then if ( redirect /= '' ) then redirect_str = \">\" // redirect // \" 2>&1\" else redirect_str = \"\" endif else if ( verbose_local ) then ! No redirection but verbose output redirect_str = \"\" else ! No redirection and non-verbose output if ( os_is_unix ()) then redirect_str = \" >/dev/null 2>&1\" else redirect_str = \" >NUL 2>&1\" end if end if end if if ( echo_local ) print * , '+ ' , cmd !//redirect_str call execute_command_line ( cmd // redirect_str , exitstat = stat , cmdstat = cmdstat , cmdmsg = cmdmsg ) if ( cmdstat /= 0 ) then write ( * , '(a)' ) ':failed command ' // cmd // redirect_str call fpm_stop ( 1 , '*run*:' // trim ( cmdmsg )) endif if ( verbose_local . and . present ( redirect )) then open ( newunit = fh , file = redirect , status = 'old' , iostat = iostat , iomsg = iomsg ) if ( iostat == 0 ) then do call getline ( fh , line , iostat ) if ( iostat /= 0 ) exit write ( * , '(A)' ) trim ( line ) end do else write ( * , '(A)' ) trim ( iomsg ) endif close ( fh ) end if if ( present ( exitstat )) then exitstat = stat elseif ( stat /= 0 ) then call fpm_stop ( stat , '*run*: Command ' // cmd // redirect_str // ' returned a non-zero status code' ) end if end subroutine run","tags":"","url":"proc/run~2.html"},{"title":"warnwrite – Fortran-lang/fpm","text":"public subroutine warnwrite(fname, data) write trimmed character data to a file if it does not exist Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: fname character(len=*), intent(in) :: data (:) Source Code subroutine warnwrite ( fname , data ) character ( len =* ), intent ( in ) :: fname character ( len =* ), intent ( in ) :: data (:) if (. not . exists ( fname )) then call filewrite ( fname , data ) else write ( stderr , '(*(g0,1x))' ) ' ' , fname ,& & 'already exists. Not overwriting' endif end subroutine warnwrite","tags":"","url":"proc/warnwrite.html"},{"title":"new_example – Fortran-lang/fpm","text":"public subroutine new_example(self, table, error) Construct a new example configuration from a TOML data structure Arguments Type Intent Optional Attributes Name type( example_config_t ), intent(out) :: self Instance of the example configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling Source Code subroutine new_example ( self , table , error ) !> Instance of the example configuration type ( example_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_table ), pointer :: child call check ( table , error ) if ( allocated ( error )) return call get_value ( table , \"name\" , self % name ) if (. not . allocated ( self % name )) then call syntax_error ( error , \"Could not retrieve example name\" ) return end if if ( bad_name_error ( error , 'example' , self % name )) then return endif call get_value ( table , \"source-dir\" , self % source_dir , \"example\" ) call get_value ( table , \"main\" , self % main , \"main.f90\" ) call get_value ( table , \"dependencies\" , child , requested = . false .) if ( associated ( child )) then call new_dependencies ( self % dependency , child , error = error ) if ( allocated ( error )) return end if call get_list ( table , \"link\" , self % link , error ) if ( allocated ( error )) return end subroutine new_example","tags":"","url":"proc/new_example.html"},{"title":"ar_is_same – Fortran-lang/fpm","text":"public function ar_is_same(this, that) Check that two archiver_t objects are equal\nAll checks passed! Type Bound archiver_t Arguments Type Intent Optional Attributes Name class( archiver_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical Source Code logical function ar_is_same ( this , that ) class ( archiver_t ), intent ( in ) :: this class ( serializable_t ), intent ( in ) :: that ar_is_same = . false . select type ( other => that ) type is ( archiver_t ) if ( allocated ( this % ar ). neqv . allocated ( other % ar )) return if ( allocated ( this % ar )) then if (. not .( this % ar == other % ar )) return end if if (. not .( this % use_response_file . eqv . other % use_response_file )) return if (. not .( this % echo . eqv . other % echo )) return if (. not .( this % verbose . eqv . other % verbose )) return class default ! Not the same type return end select !> All checks passed! ar_is_same = . true . end function ar_is_same","tags":"","url":"proc/ar_is_same.html"},{"title":"check_compiler – Fortran-lang/fpm","text":"public function check_compiler(compiler, expected) result(match) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: compiler character(len=*), intent(in) :: expected Return Value logical Source Code function check_compiler ( compiler , expected ) result ( match ) character ( len =* ), intent ( in ) :: compiler character ( len =* ), intent ( in ) :: expected logical :: match match = compiler == expected if (. not . match ) then match = index ( basename ( compiler ), expected ) > 0 end if end function check_compiler","tags":"","url":"proc/check_compiler.html"},{"title":"check_flags_supported – Fortran-lang/fpm","text":"public function check_flags_supported(self, compile_flags, link_flags) Check if the given compile and/or link flags are accepted by the compiler Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in), optional :: compile_flags character(len=*), intent(in), optional :: link_flags Return Value logical Variables Type Visibility Attributes Name Initial character(len=*), public, parameter :: hello_world = \"print *, 'Hello, World!'; end\" Source Code logical function check_flags_supported ( self , compile_flags , link_flags ) class ( compiler_t ), intent ( in ) :: self character ( len =* ), optional , intent ( in ) :: compile_flags , link_flags ! Minimal program that always compiles character ( len =* ), parameter :: hello_world = \"print *, 'Hello, World!'; end\" check_flags_supported = self % check_fortran_source_runs ( hello_world , compile_flags , link_flags ) end function check_flags_supported","tags":"","url":"proc/check_flags_supported.html"},{"title":"check_fortran_source_runs – Fortran-lang/fpm","text":"public function check_fortran_source_runs(self, input, compile_flags, link_flags) result(success) Run a single-source Fortran program using the current compiler\nCompile a Fortran object\nCreate temporary source file\nWrite contents\nGet flags\nIntel: Needs -warn last for error on unknown command line arguments to work\nCompile and link program\nRun and retrieve exit code Successful exit on 0 exit code Delete files Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object character(len=*), intent(in) :: input Program Source character(len=*), intent(in), optional :: compile_flags Optional build and link flags character(len=*), intent(in), optional :: link_flags Optional build and link flags Return Value logical Variables Type Visibility Attributes Name Initial character(len=:), public, allocatable :: exe character(len=:), public, allocatable :: flags character(len=:), public, allocatable :: ldflags character(len=:), public, allocatable :: logf character(len=:), public, allocatable :: object character(len=:), public, allocatable :: source integer, public :: stat integer, public :: unit Source Code logical function check_fortran_source_runs ( self , input , compile_flags , link_flags ) result ( success ) !> Instance of the compiler object class ( compiler_t ), intent ( in ) :: self !> Program Source character ( len =* ), intent ( in ) :: input !> Optional build and link flags character ( len =* ), optional , intent ( in ) :: compile_flags , link_flags integer :: stat , unit character (:), allocatable :: source , object , logf , exe , flags , ldflags success = . false . !> Create temporary source file exe = get_temp_filename () source = exe // '.f90' object = exe // '.o' logf = exe // '.log' open ( newunit = unit , file = source , action = 'readwrite' , iostat = stat ) if ( stat /= 0 ) return !> Write contents write ( unit , * ) input close ( unit ) !> Get flags flags = self % get_default_flags ( release = . false .) ldflags = self % get_default_flags ( release = . false .) if ( present ( compile_flags )) flags = flags // \" \" // compile_flags if ( present ( link_flags )) ldflags = ldflags // \" \" // link_flags !> Intel: Needs -warn last for error on unknown command line arguments to work if ( self % id == id_intel_llvm_nix ) then flags = flags // \" \" // flag_intel_warn ldflags = ldflags // \" \" // flag_intel_warn elseif ( self % id == id_intel_llvm_windows ) then flags = flags // \" \" // flag_intel_warn_win ldflags = ldflags // \" \" // flag_intel_warn_win end if !> Compile and link program call self % compile_fortran ( source , object , flags , logf , stat ) if ( stat == 0 ) & call self % link ( exe , ldflags // \" \" // object , logf , stat ) !> Run and retrieve exit code if ( stat == 0 ) & call run ( exe , echo = . false ., exitstat = stat , verbose = . false ., redirect = logf ) !> Successful exit on 0 exit code success = stat == 0 !> Delete files open ( newunit = unit , file = source , action = 'readwrite' , iostat = stat ) close ( unit , status = 'delete' ) open ( newunit = unit , file = object , action = 'readwrite' , iostat = stat ) close ( unit , status = 'delete' ) open ( newunit = unit , file = logf , action = 'readwrite' , iostat = stat ) close ( unit , status = 'delete' ) open ( newunit = unit , file = exe , action = 'readwrite' , iostat = stat ) close ( unit , status = 'delete' ) end function check_fortran_source_runs","tags":"","url":"proc/check_fortran_source_runs.html"},{"title":"compiler_is_same – Fortran-lang/fpm","text":"public function compiler_is_same(this, that) Check that two compiler_t objects are equal\nAll checks passed! Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical Source Code logical function compiler_is_same ( this , that ) class ( compiler_t ), intent ( in ) :: this class ( serializable_t ), intent ( in ) :: that compiler_is_same = . false . select type ( other => that ) type is ( compiler_t ) if (. not .( this % id == other % id )) return if ( allocated ( this % fc ). neqv . allocated ( other % fc )) return if ( allocated ( this % fc )) then if (. not .( this % fc == other % fc )) return end if if ( allocated ( this % cc ). neqv . allocated ( other % cc )) return if ( allocated ( this % cc )) then if (. not .( this % cc == other % cc )) return end if if ( allocated ( this % cxx ). neqv . allocated ( other % cxx )) return if ( allocated ( this % cxx )) then if (. not .( this % cxx == other % cxx )) return end if if (. not .( this % echo . eqv . other % echo )) return if (. not .( this % verbose . eqv . other % verbose )) return class default ! Not the same type return end select !> All checks passed! compiler_is_same = . true . end function compiler_is_same","tags":"","url":"proc/compiler_is_same.html"},{"title":"compiler_name – Fortran-lang/fpm","text":"public pure function compiler_name(self) result(name) Return a compiler name string Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object Return Value character(len=:), allocatable Representation as string Source Code pure function compiler_name ( self ) result ( name ) !> Instance of the compiler object class ( compiler_t ), intent ( in ) :: self !> Representation as string character ( len = :), allocatable :: name select case ( self % id ) case ( id_gcc ); name = \"gfortran\" case ( id_f95 ); name = \"f95\" case ( id_caf ); name = \"caf\" case ( id_intel_classic_nix ); name = \"ifort\" case ( id_intel_classic_mac ); name = \"ifort\" case ( id_intel_classic_windows ); name = \"ifort\" case ( id_intel_llvm_nix ); name = \"ifx\" case ( id_intel_llvm_windows ); name = \"ifx\" case ( id_intel_llvm_unknown ); name = \"ifx\" case ( id_pgi ); name = \"pgfortran\" case ( id_nvhpc ); name = \"nvfortran\" case ( id_nag ); name = \"nagfor\" case ( id_flang ); name = \"flang\" case ( id_flang_new ); name = \"flang-new\" case ( id_f18 ); name = \"f18\" case ( id_ibmxl ); name = \"xlf90\" case ( id_cray ); name = \"crayftn\" case ( id_lahey ); name = \"lfc\" case ( id_lfortran ); name = \"lFortran\" case default ; name = \"invalid/unknown\" end select end function compiler_name","tags":"","url":"proc/compiler_name.html"},{"title":"debug_archiver – Fortran-lang/fpm","text":"public pure function debug_archiver(self) result(repr) String representation of an archiver object Arguments Type Intent Optional Attributes Name type( archiver_t ), intent(in) :: self Instance of the archiver object Return Value character(len=:), allocatable Representation as string Source Code pure function debug_archiver ( self ) result ( repr ) !> Instance of the archiver object type ( archiver_t ), intent ( in ) :: self !> Representation as string character ( len = :), allocatable :: repr repr = 'ar=\"' // self % ar // '\"' end function debug_archiver","tags":"","url":"proc/debug_archiver.html"},{"title":"debug_compiler – Fortran-lang/fpm","text":"public pure function debug_compiler(self) result(repr) String representation of a compiler object Arguments Type Intent Optional Attributes Name type( compiler_t ), intent(in) :: self Instance of the compiler object Return Value character(len=:), allocatable Representation as string Source Code pure function debug_compiler ( self ) result ( repr ) !> Instance of the compiler object type ( compiler_t ), intent ( in ) :: self !> Representation as string character ( len = :), allocatable :: repr repr = 'fc=\"' // self % fc // '\", cc=\"' // self % cc // '\"' end function debug_compiler","tags":"","url":"proc/debug_compiler.html"},{"title":"enumerate_libraries – Fortran-lang/fpm","text":"public function enumerate_libraries(self, prefix, libs) result(r) Enumerate libraries, based on compiler and platform Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: prefix type( string_t ), intent(in) :: libs (:) Return Value character(len=:), allocatable Variables Type Visibility Attributes Name Initial character(len=:), public, allocatable :: joined Source Code function enumerate_libraries ( self , prefix , libs ) result ( r ) class ( compiler_t ), intent ( in ) :: self character ( len =* ), intent ( in ) :: prefix type ( string_t ), intent ( in ) :: libs (:) character ( len = :), allocatable :: r character ( len = :), allocatable :: joined if ( size ( libs ) == 0 ) then r = prefix return end if select case ( self % id ) case ( id_intel_classic_windows , id_intel_llvm_windows ) ! Windows Intel uses `.lib` files directly joined = string_cat ( libs , \".lib \" ) // \".lib\" r = trim ( prefix ) // \" \" // trim ( joined ) case ( id_nag , id_ibmxl ) ! NAG and IBMXL need -Wl, wrapper around linker flags joined = string_cat ( libs , \" -Wl,\" ) r = trim ( prefix ) // \" -Wl,\" // trim ( joined ) case default ! Generic Unix-style linker flags: use `-lfoo` joined = string_cat ( libs , \" -l\" ) r = trim ( prefix ) // \" -l\" // trim ( joined ) end select end function enumerate_libraries","tags":"","url":"proc/enumerate_libraries.html"},{"title":"get_compiler_id – Fortran-lang/fpm","text":"public function get_compiler_id(compiler) result(id) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: compiler Return Value integer(kind=compiler_enum) Variables Type Visibility Attributes Name Initial character(len=:), public, allocatable :: command character(len=:), public, allocatable :: full_command character(len=:), public, allocatable :: full_command_parts (:) integer, public :: io character(len=:), public, allocatable :: output integer, public :: stat Source Code function get_compiler_id ( compiler ) result ( id ) character ( len =* ), intent ( in ) :: compiler integer ( kind = compiler_enum ) :: id character ( len = :), allocatable :: full_command , full_command_parts (:), command , output integer :: stat , io ! Check whether we are dealing with an MPI compiler wrapper first if ( check_compiler ( compiler , \"mpifort\" ) & & . or . check_compiler ( compiler , \"mpif90\" ) & & . or . check_compiler ( compiler , \"mpif77\" )) then output = get_temp_filename () call run ( compiler // \" -show > \" // output // \" 2>&1\" , & & echo = . false ., exitstat = stat ) if ( stat == 0 ) then open ( file = output , newunit = io , iostat = stat ) if ( stat == 0 ) call getline ( io , full_command , stat ) close ( io , iostat = stat ) ! If we get a command from the wrapper, we will try to identify it call split ( full_command , full_command_parts , delimiters = ' ' ) if ( size ( full_command_parts ) > 0 ) then command = trim ( full_command_parts ( 1 )) endif if ( allocated ( command )) then id = get_id ( command ) if ( id /= id_unknown ) return end if end if end if id = get_id ( compiler ) end function get_compiler_id","tags":"","url":"proc/get_compiler_id.html"},{"title":"get_default_flags – Fortran-lang/fpm","text":"public function get_default_flags(self, release) result(flags) Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self logical, intent(in) :: release Return Value character(len=:), allocatable Variables Type Visibility Attributes Name Initial character(len=:), public, allocatable :: pic_flag Source Code function get_default_flags ( self , release ) result ( flags ) class ( compiler_t ), intent ( in ) :: self logical , intent ( in ) :: release character ( len = :), allocatable :: flags character ( len = :), allocatable :: pic_flag if ( release ) then call get_release_compile_flags ( self % id , flags ) else call get_debug_compile_flags ( self % id , flags ) end if ! Append position-independent code (PIC) flag, that is necessary ! building shared libraries select case ( self % id ) case ( id_gcc , id_f95 , id_caf , id_flang , id_flang_new , id_f18 , id_lfortran , & id_intel_classic_nix , id_intel_classic_mac , id_intel_llvm_nix , & id_pgi , id_nvhpc , id_nag , id_cray , id_ibmxl ) pic_flag = \" -fPIC\" case ( id_intel_classic_windows , id_intel_llvm_windows ) pic_flag = \"\" ! Windows does not use -fPIC case default pic_flag = \" -fPIC\" ! Conservative fallback end select flags = flags // pic_flag end function get_default_flags","tags":"","url":"proc/get_default_flags.html"},{"title":"get_export_flags – Fortran-lang/fpm","text":"public function get_export_flags(self, target_dir, target_name) result(export_flags) Generate library export flags for a shared library build Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler character(len=*), intent(in) :: target_dir Path and package name character(len=*), intent(in) :: target_name Path and package name Return Value character(len=:), allocatable Variables Type Visibility Attributes Name Initial character(len=:), public, allocatable :: def_path character(len=:), public, allocatable :: implib_path Source Code function get_export_flags ( self , target_dir , target_name ) result ( export_flags ) !> Instance of the compiler class ( compiler_t ), intent ( in ) :: self !> Path and package name character ( len =* ), intent ( in ) :: target_dir , target_name character ( len = :), allocatable :: export_flags character ( len = :), allocatable :: implib_path , def_path ! Only apply on Windows if ( get_os_type () /= OS_WINDOWS ) then export_flags = \"\" return end if select case ( self % id ) case ( id_gcc , id_caf , id_f95 ) ! GNU-based: emit both import library and def file implib_path = quote ( join_path ( target_dir , target_name // \".dll.a\" ) , for_cmd = . true .) def_path = quote ( join_path ( target_dir , target_name // \".def\" ) , for_cmd = . true .) export_flags = \" -Wl,--out-implib,\" // implib_path // & \" -Wl,--output-def,\" // def_path case ( id_intel_classic_windows , id_intel_llvm_windows ) ! Intel/MSVC-style implib_path = quote ( join_path ( target_dir , target_name // \".lib\" ) , for_cmd = . true .) def_path = quote ( join_path ( target_dir , target_name // \".def\" ) , for_cmd = . true .) export_flags = \" /IMPLIB:\" // implib_path // & \" /DEF:\" // def_path case default export_flags = \"\" ! Do nothing elsewhere end select end function get_export_flags","tags":"","url":"proc/get_export_flags.html"},{"title":"get_feature_flag – Fortran-lang/fpm","text":"public function get_feature_flag(self, feature) result(flags) Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: feature Return Value character(len=:), allocatable Source Code function get_feature_flag ( self , feature ) result ( flags ) class ( compiler_t ), intent ( in ) :: self character ( len =* ), intent ( in ) :: feature character ( len = :), allocatable :: flags flags = \"\" select case ( feature ) case ( \"no-implicit-typing\" ) select case ( self % id ) case ( id_caf , id_gcc , id_f95 ) flags = flag_gnu_no_implicit_typing case ( id_nag ) flags = flag_nag_no_implicit_typing case ( id_cray ) flags = flag_cray_no_implicit_typing end select case ( \"implicit-typing\" ) select case ( self % id ) case ( id_cray ) flags = flag_cray_implicit_typing case ( id_lfortran ) flags = flag_lfortran_implicit_typing end select case ( \"no-implicit-external\" ) select case ( self % id ) case ( id_caf , id_gcc , id_f95 ) flags = flag_gnu_no_implicit_external end select case ( \"implicit-external\" ) select case ( self % id ) case ( id_lfortran ) flags = flag_lfortran_implicit_external end select case ( \"free-form\" ) select case ( self % id ) case ( id_caf , id_gcc , id_f95 ) flags = flag_gnu_free_form case ( id_pgi , id_nvhpc , id_flang ) flags = flag_pgi_free_form case ( id_nag ) flags = flag_nag_free_form case ( id_intel_classic_nix , id_intel_classic_mac , id_intel_llvm_nix , & & id_intel_llvm_unknown ) flags = flag_intel_free_form case ( id_intel_classic_windows , id_intel_llvm_windows ) flags = flag_intel_free_form_win case ( id_cray ) flags = flag_cray_free_form end select case ( \"fixed-form\" ) select case ( self % id ) case ( id_caf , id_gcc , id_f95 ) flags = flag_gnu_fixed_form case ( id_pgi , id_nvhpc , id_flang ) flags = flag_pgi_fixed_form case ( id_nag ) flags = flag_nag_fixed_form case ( id_intel_classic_nix , id_intel_classic_mac , id_intel_llvm_nix , & & id_intel_llvm_unknown ) flags = flag_intel_fixed_form case ( id_intel_classic_windows , id_intel_llvm_windows ) flags = flag_intel_fixed_form_win case ( id_cray ) flags = flag_cray_fixed_form case ( id_lfortran ) flags = flag_lfortran_fixed_form end select case ( \"default-form\" ) continue case default error stop \"Unknown feature '\" // feature // \"'\" end select end function get_feature_flag","tags":"","url":"proc/get_feature_flag.html"},{"title":"get_headerpad_flags – Fortran-lang/fpm","text":"public function get_headerpad_flags(self) result(flags) Generate header padding flags for install_name_tool compatibility on macOS Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Return Value character(len=:), allocatable Source Code function get_headerpad_flags ( self ) result ( flags ) class ( compiler_t ), intent ( in ) :: self character ( len = :), allocatable :: flags if ( get_os_type () /= OS_MACOS ) then flags = \"\" return end if ! Reserve enough space in the Mach-O header to safely add two install_name or rpath later flags = \" -Wl,-headerpad,0x200\" end function get_headerpad_flags","tags":"","url":"proc/get_headerpad_flags.html"},{"title":"get_id – Fortran-lang/fpm","text":"public function get_id(compiler) result(id) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: compiler Return Value integer(kind=compiler_enum) Source Code function get_id ( compiler ) result ( id ) character ( len =* ), intent ( in ) :: compiler integer ( kind = compiler_enum ) :: id if ( check_compiler ( compiler , \"gfortran\" )) then id = id_gcc return end if if ( check_compiler ( compiler , \"f95\" )) then id = id_f95 return end if if ( check_compiler ( compiler , \"caf\" )) then id = id_caf return end if if ( check_compiler ( compiler , \"ifort\" )) then select case ( get_os_type ()) case default id = id_intel_classic_nix case ( OS_MACOS ) id = id_intel_classic_mac case ( OS_WINDOWS , OS_CYGWIN ) id = id_intel_classic_windows end select return end if if ( check_compiler ( compiler , \"ifx\" )) then select case ( get_os_type ()) case default id = id_intel_llvm_nix case ( OS_WINDOWS , OS_CYGWIN ) id = id_intel_llvm_windows end select return end if if ( check_compiler ( compiler , \"nvfortran\" )) then id = id_nvhpc return end if if ( check_compiler ( compiler , \"pgfortran\" ) & & . or . check_compiler ( compiler , \"pgf90\" ) & & . or . check_compiler ( compiler , \"pgf95\" )) then id = id_pgi return end if if ( check_compiler ( compiler , \"nagfor\" )) then id = id_nag return end if if ( check_compiler ( compiler , \"flang-new\" )) then id = id_flang_new return end if if ( check_compiler ( compiler , \"f18\" )) then id = id_f18 return end if if ( check_compiler ( compiler , \"flang\" )) then id = id_flang return end if if ( check_compiler ( compiler , \"xlf90\" )) then id = id_ibmxl return end if if ( check_compiler ( compiler , \"crayftn\" )) then id = id_cray return end if if ( check_compiler ( compiler , \"lfc\" )) then id = id_lahey return end if if ( check_compiler ( compiler , \"lfortran\" )) then id = id_lfortran return end if id = id_unknown end function get_id","tags":"","url":"proc/get_id.html"},{"title":"get_include_flag – Fortran-lang/fpm","text":"public function get_include_flag(self, path) result(flags) Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: path Return Value character(len=:), allocatable Source Code function get_include_flag ( self , path ) result ( flags ) class ( compiler_t ), intent ( in ) :: self character ( len =* ), intent ( in ) :: path character ( len = :), allocatable :: flags select case ( self % id ) case default flags = \"-I \" // path case ( id_caf , id_gcc , id_f95 , id_cray , id_nvhpc , id_pgi , & & id_flang , id_flang_new , id_f18 , & & id_intel_classic_nix , id_intel_classic_mac , & & id_intel_llvm_nix , id_lahey , id_nag , id_ibmxl , & & id_lfortran ) flags = \"-I \" // path case ( id_intel_classic_windows , id_intel_llvm_windows ) flags = \"/I\" // path end select end function get_include_flag","tags":"","url":"proc/get_include_flag.html"},{"title":"get_install_name_flags – Fortran-lang/fpm","text":"public function get_install_name_flags(self, target_dir, target_name) result(flags) Generate install_name flag for a shared library build on macOS Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: target_dir character(len=*), intent(in) :: target_name Return Value character(len=:), allocatable Variables Type Visibility Attributes Name Initial character(len=:), public, allocatable :: library_file Source Code function get_install_name_flags ( self , target_dir , target_name ) result ( flags ) class ( compiler_t ), intent ( in ) :: self character ( len =* ), intent ( in ) :: target_dir , target_name character ( len = :), allocatable :: flags character ( len = :), allocatable :: library_file if ( get_os_type () /= OS_MACOS ) then flags = \"\" return end if ! Shared library basename (e.g., libfoo.dylib) if ( str_ends_with ( target_name , \".dylib\" )) then library_file = target_name else library_file = library_filename ( target_name ,. true .,. false ., OS_MACOS ) end if flags = \" -Wl,-install_name,@rpath/\" // library_file end function get_install_name_flags","tags":"","url":"proc/get_install_name_flags.html"},{"title":"get_macros – Fortran-lang/fpm","text":"public function get_macros(id, macros_list, version) result(macros) This function will parse and read the macros list and\nreturn them as defined flags.\nSet macro defintion symbol on the basis of compiler used\nCheck if macros are not allocated.\nSplit the macro name and value. Check if the value of macro starts with ‘{’ character. Check if the value of macro ends with ‘}’ character. Check if the string contains “version” as substring. These conditions are placed in order to ensure proper spacing between the macros. Arguments Type Intent Optional Attributes Name integer(kind=compiler_enum), intent(in) :: id type( string_t ), intent(in), allocatable :: macros_list (:) character(len=:), intent(in), allocatable :: version Return Value character(len=:), allocatable Variables Type Visibility Attributes Name Initial integer, public :: i character(len=:), public, allocatable :: macro_definition_symbol character(len=:), public, allocatable :: valued_macros (:) Source Code function get_macros ( id , macros_list , version ) result ( macros ) integer ( compiler_enum ), intent ( in ) :: id character ( len = :), allocatable , intent ( in ) :: version type ( string_t ), allocatable , intent ( in ) :: macros_list (:) character ( len = :), allocatable :: macros character ( len = :), allocatable :: macro_definition_symbol character (:), allocatable :: valued_macros (:) integer :: i if (. not . allocated ( macros_list )) then macros = \"\" return end if !> Set macro defintion symbol on the basis of compiler used select case ( id ) case default macro_definition_symbol = \" -D\" case ( id_intel_classic_windows , id_intel_llvm_windows ) macro_definition_symbol = \" /D\" end select !> Check if macros are not allocated. if (. not . allocated ( macros )) then macros = \"\" end if do i = 1 , size ( macros_list ) !> Split the macro name and value. call split ( macros_list ( i )% s , valued_macros , delimiters = \"=\" ) if ( size ( valued_macros ) > 1 ) then !> Check if the value of macro starts with '{' character. if ( str_begins_with_str ( trim ( valued_macros ( size ( valued_macros ))), \"{\" )) then !> Check if the value of macro ends with '}' character. if ( str_ends_with ( trim ( valued_macros ( size ( valued_macros ))), \"}\" )) then !> Check if the string contains \"version\" as substring. if ( index ( valued_macros ( size ( valued_macros )), \"version\" ) /= 0 ) then !> These conditions are placed in order to ensure proper spacing between the macros. macros = macros // macro_definition_symbol // trim ( valued_macros ( 1 )) // '=' // version cycle end if end if end if end if macros = macros // macro_definition_symbol // macros_list ( i )% s end do end function get_macros","tags":"","url":"proc/get_macros.html"},{"title":"get_module_flag – Fortran-lang/fpm","text":"public function get_module_flag(self, path) result(flags) Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: path Return Value character(len=:), allocatable Source Code function get_module_flag ( self , path ) result ( flags ) class ( compiler_t ), intent ( in ) :: self character ( len =* ), intent ( in ) :: path character ( len = :), allocatable :: flags select case ( self % id ) case default flags = \"-module \" // path case ( id_caf , id_gcc , id_f95 , id_cray , id_lfortran ) flags = \"-J \" // path case ( id_nvhpc , id_pgi , id_flang ) flags = \"-module \" // path case ( id_flang_new , id_f18 ) flags = \"-module-dir \" // path case ( id_intel_classic_nix , id_intel_classic_mac , & & id_intel_llvm_nix ) flags = \"-module \" // path case ( id_intel_classic_windows , id_intel_llvm_windows ) flags = \"/module:\" // path case ( id_lahey ) flags = \"-M \" // path case ( id_nag ) flags = \"-mdir \" // path case ( id_ibmxl ) flags = \"-qmoddir \" // path end select end function get_module_flag","tags":"","url":"proc/get_module_flag.html"},{"title":"get_shared_flag – Fortran-lang/fpm","text":"public function get_shared_flag(self) result(shared_flag) Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Return Value character(len=:), allocatable Source Code function get_shared_flag ( self ) result ( shared_flag ) class ( compiler_t ), intent ( in ) :: self character ( len = :), allocatable :: shared_flag select case ( self % id ) case default shared_flag = \"-shared\" case ( id_gcc , id_f95 , id_flang , id_flang_new , id_lfortran ) shared_flag = \"-shared\" case ( id_intel_classic_nix , id_intel_llvm_nix , id_pgi , id_nvhpc ) shared_flag = \"-shared\" case ( id_intel_classic_windows , id_intel_llvm_windows ) shared_flag = \"/DLL\" case ( id_nag ) shared_flag = \"-Wl,-shared\" case ( id_ibmxl ) shared_flag = \"-qmkshrobj\" case ( id_cray , id_lahey ) shared_flag = \"\" ! Needs special handling end select end function get_shared_flag","tags":"","url":"proc/get_shared_flag.html"},{"title":"is_gnu – Fortran-lang/fpm","text":"public pure function is_gnu(self) Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Return Value logical Source Code pure logical function is_gnu ( self ) class ( compiler_t ), intent ( in ) :: self is_gnu = any ( self % id == [ id_f95 , id_gcc , id_caf ]) end function is_gnu","tags":"","url":"proc/is_gnu.html"},{"title":"is_intel – Fortran-lang/fpm","text":"public pure function is_intel(self) Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Return Value logical Source Code pure logical function is_intel ( self ) class ( compiler_t ), intent ( in ) :: self is_intel = any ( self % id == [ id_intel_classic_nix , id_intel_classic_mac , id_intel_classic_windows , & id_intel_llvm_nix , id_intel_llvm_windows , id_intel_llvm_unknown ]) end function is_intel","tags":"","url":"proc/is_intel.html"},{"title":"is_unknown – Fortran-lang/fpm","text":"public pure function is_unknown(self) Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Return Value logical Source Code pure function is_unknown ( self ) class ( compiler_t ), intent ( in ) :: self logical :: is_unknown is_unknown = self % id == id_unknown end function is_unknown","tags":"","url":"proc/is_unknown.html"},{"title":"with_qp – Fortran-lang/fpm","text":"public function with_qp(self) Check if the current compiler supports 128-bit real precision Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object Return Value logical Source Code logical function with_qp ( self ) !> Instance of the compiler object class ( compiler_t ), intent ( in ) :: self with_qp = self % check_fortran_source_runs & ( 'if (selected_real_kind(33) == -1) stop 1; end' ) end function with_qp","tags":"","url":"proc/with_qp.html"},{"title":"with_xdp – Fortran-lang/fpm","text":"public function with_xdp(self) Check if the current compiler supports 80-bit “extended” real precision Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object Return Value logical Source Code logical function with_xdp ( self ) !> Instance of the compiler object class ( compiler_t ), intent ( in ) :: self with_xdp = self % check_fortran_source_runs & ( 'if (any(selected_real_kind(18) == [-1, selected_real_kind(33)])) stop 1; end' ) end function with_xdp","tags":"","url":"proc/with_xdp.html"},{"title":"append_clean_flags – Fortran-lang/fpm","text":"public subroutine append_clean_flags(flags, new_flags) Append new flags to existing flags, removing duplicates and empty flags (string version) Arguments Type Intent Optional Attributes Name character(len=:), intent(inout), allocatable :: flags character(len=*), intent(in) :: new_flags Variables Type Visibility Attributes Name Initial type( string_t ), public, allocatable :: flags_array (:) integer, public :: i type( string_t ), public, allocatable :: new_flags_array (:) Source Code subroutine append_clean_flags ( flags , new_flags ) character (:), intent ( inout ), allocatable :: flags character ( * ), intent ( in ) :: new_flags type ( string_t ), allocatable :: flags_array (:), new_flags_array (:) integer :: i call tokenize_flags ( flags , flags_array ) call tokenize_flags ( new_flags , new_flags_array ) call append_clean_flags_array ( flags_array , new_flags_array ) do i = 1 , size ( flags_array ) flags = flags // \" \" // flags_array ( i )% s end do end subroutine append_clean_flags","tags":"","url":"proc/append_clean_flags.html"},{"title":"append_clean_flags_array – Fortran-lang/fpm","text":"public subroutine append_clean_flags_array(flags_array, new_flags_array) Append new flags to existing flags, removing duplicates and empty flags (array version) Arguments Type Intent Optional Attributes Name type( string_t ), intent(inout), allocatable :: flags_array (:) type( string_t ), intent(in) :: new_flags_array (:) Variables Type Visibility Attributes Name Initial integer, public :: i Source Code subroutine append_clean_flags_array ( flags_array , new_flags_array ) type ( string_t ), allocatable , intent ( inout ) :: flags_array (:) type ( string_t ), intent ( in ) :: new_flags_array (:) integer :: i do i = 1 , size ( new_flags_array ) if ( string_array_contains ( new_flags_array ( i )% s , flags_array )) cycle ! Filter out empty flags and arguments if ( new_flags_array ( i )% s == \"\" ) cycle if ( trim ( new_flags_array ( i )% s ) == \"-l\" ) cycle if ( trim ( new_flags_array ( i )% s ) == \"-L\" ) cycle if ( trim ( new_flags_array ( i )% s ) == \"-I\" ) cycle if ( trim ( new_flags_array ( i )% s ) == \"-J\" ) cycle if ( trim ( new_flags_array ( i )% s ) == \"-M\" ) cycle flags_array = [ flags_array , new_flags_array ( i )] end do end subroutine append_clean_flags_array","tags":"","url":"proc/append_clean_flags_array.html"},{"title":"compile_c – Fortran-lang/fpm","text":"public subroutine compile_c(self, input, output, args, log_file, stat, table, dry_run) Compile a C object Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object character(len=*), intent(in) :: input Source file input character(len=*), intent(in) :: output Output file of object character(len=*), intent(in) :: args Arguments for compiler character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag type( compile_command_table_t ), intent(inout), optional :: table Optional compile_commands table logical, intent(in), optional :: dry_run Optional mocking Variables Type Visibility Attributes Name Initial character(len=:), public, allocatable :: command type( error_t ), public, allocatable :: error logical, public :: mock Source Code subroutine compile_c ( self , input , output , args , log_file , stat , table , dry_run ) !> Instance of the compiler object class ( compiler_t ), intent ( in ) :: self !> Source file input character ( len =* ), intent ( in ) :: input !> Output file of object character ( len =* ), intent ( in ) :: output !> Arguments for compiler character ( len =* ), intent ( in ) :: args !> Compiler output log file character ( len =* ), intent ( in ) :: log_file !> Status flag integer , intent ( out ) :: stat !> Optional compile_commands table type ( compile_command_table_t ), optional , intent ( inout ) :: table !> Optional mocking logical , optional , intent ( in ) :: dry_run character ( len = :), allocatable :: command type ( error_t ), allocatable :: error logical :: mock ! Check if we're actually building this file mock = . false . if ( present ( dry_run )) mock = dry_run ! Set command command = self % cc // \" -c \" // input // \" \" // args // \" -o \" // output ! Execute command if (. not . mock ) then call run ( command , echo = self % echo , verbose = self % verbose , redirect = log_file , exitstat = stat ) if ( stat /= 0 ) return endif ! Optionally register compile command if ( present ( table )) then call table % register ( command , get_os_type (), error ) stat = merge ( - 1 , 0 , allocated ( error )) endif end subroutine compile_c","tags":"","url":"proc/compile_c.html"},{"title":"compile_cpp – Fortran-lang/fpm","text":"public subroutine compile_cpp(self, input, output, args, log_file, stat, table, dry_run) Compile a CPP object Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object character(len=*), intent(in) :: input Source file input character(len=*), intent(in) :: output Output file of object character(len=*), intent(in) :: args Arguments for compiler character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag type( compile_command_table_t ), intent(inout), optional :: table Optional compile_commands table logical, intent(in), optional :: dry_run Optional mocking Variables Type Visibility Attributes Name Initial character(len=:), public, allocatable :: command type( error_t ), public, allocatable :: error logical, public :: mock Source Code subroutine compile_cpp ( self , input , output , args , log_file , stat , table , dry_run ) !> Instance of the compiler object class ( compiler_t ), intent ( in ) :: self !> Source file input character ( len =* ), intent ( in ) :: input !> Output file of object character ( len =* ), intent ( in ) :: output !> Arguments for compiler character ( len =* ), intent ( in ) :: args !> Compiler output log file character ( len =* ), intent ( in ) :: log_file !> Status flag integer , intent ( out ) :: stat !> Optional compile_commands table type ( compile_command_table_t ), optional , intent ( inout ) :: table !> Optional mocking logical , optional , intent ( in ) :: dry_run character ( len = :), allocatable :: command type ( error_t ), allocatable :: error logical :: mock ! Check if we're actually building this file mock = . false . if ( present ( dry_run )) mock = dry_run ! Set command command = self % cxx // \" -c \" // input // \" \" // args // \" -o \" // output ! Execute command if (. not . mock ) then call run ( command , echo = self % echo , verbose = self % verbose , redirect = log_file , exitstat = stat ) if ( stat /= 0 ) return endif ! Optionally register compile command if ( present ( table )) then call table % register ( command , get_os_type (), error ) stat = merge ( - 1 , 0 , allocated ( error )) endif end subroutine compile_cpp","tags":"","url":"proc/compile_cpp.html"},{"title":"compile_fortran – Fortran-lang/fpm","text":"public subroutine compile_fortran(self, input, output, args, log_file, stat, table, dry_run) Compile a Fortran object Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object character(len=*), intent(in) :: input Source file input character(len=*), intent(in) :: output Output file of object character(len=*), intent(in) :: args Arguments for compiler character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag type( compile_command_table_t ), intent(inout), optional :: table Optional compile_commands table logical, intent(in), optional :: dry_run Optional mocking Variables Type Visibility Attributes Name Initial character(len=:), public, allocatable :: command type( error_t ), public, allocatable :: error logical, public :: mock Source Code subroutine compile_fortran ( self , input , output , args , log_file , stat , table , dry_run ) !> Instance of the compiler object class ( compiler_t ), intent ( in ) :: self !> Source file input character ( len =* ), intent ( in ) :: input !> Output file of object character ( len =* ), intent ( in ) :: output !> Arguments for compiler character ( len =* ), intent ( in ) :: args !> Compiler output log file character ( len =* ), intent ( in ) :: log_file !> Status flag integer , intent ( out ) :: stat !> Optional compile_commands table type ( compile_command_table_t ), optional , intent ( inout ) :: table !> Optional mocking logical , optional , intent ( in ) :: dry_run character ( len = :), allocatable :: command type ( error_t ), allocatable :: error logical :: mock ! Check if we're actually building this file mock = . false . if ( present ( dry_run )) mock = dry_run ! Set command command = self % fc // \" -c \" // input // \" \" // args // \" -o \" // output ! Execute command if (. not . mock ) then call run ( command , echo = self % echo , verbose = self % verbose , redirect = log_file , exitstat = stat ) if ( stat /= 0 ) return endif ! Optionally register compile command if ( present ( table )) then call table % register ( command , get_os_type (), error ) stat = merge ( - 1 , 0 , allocated ( error )) endif end subroutine compile_fortran","tags":"","url":"proc/compile_fortran.html"},{"title":"compiler_dump – Fortran-lang/fpm","text":"public subroutine compiler_dump(self, table, error) Dump dependency to toml table Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling Variables Type Visibility Attributes Name Initial integer, public :: ierr Source Code subroutine compiler_dump ( self , table , error ) !> Instance of the serializable object class ( compiler_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: ierr call set_value ( table , \"id\" , self % id , error , 'compiler_t' ) if ( allocated ( error )) return call set_string ( table , \"fc\" , self % fc , error , 'compiler_t' ) if ( allocated ( error )) return call set_string ( table , \"cc\" , self % cc , error , 'compiler_t' ) if ( allocated ( error )) return call set_string ( table , \"cxx\" , self % cxx , error , 'compiler_t' ) if ( allocated ( error )) return call set_value ( table , \"echo\" , self % echo , error , 'compiler_t' ) if ( allocated ( error )) return call set_value ( table , \"verbose\" , self % verbose , error , 'compiler_t' ) if ( allocated ( error )) return end subroutine compiler_dump","tags":"","url":"proc/compiler_dump.html"},{"title":"compiler_load – Fortran-lang/fpm","text":"public subroutine compiler_load(self, table, error) Read dependency from toml table (no checks made at this stage) Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling Source Code subroutine compiler_load ( self , table , error ) !> Instance of the serializable object class ( compiler_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error call get_value ( table , \"id\" , self % id , error , 'compiler_t' ) if ( allocated ( error )) return call get_value ( table , \"fc\" , self % fc ) call get_value ( table , \"cc\" , self % cc ) call get_value ( table , \"cxx\" , self % cxx ) call get_value ( table , \"echo\" , self % echo , error , 'compiler_t' ) if ( allocated ( error )) return call get_value ( table , \"verbose\" , self % verbose , error , 'compiler_t' ) if ( allocated ( error )) return end subroutine compiler_load","tags":"","url":"proc/compiler_load.html"},{"title":"dump_to_toml – Fortran-lang/fpm","text":"public subroutine dump_to_toml(self, table, error) Dump dependency to toml table Path to archiver Type Bound archiver_t Arguments Type Intent Optional Attributes Name class( archiver_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling Source Code subroutine dump_to_toml ( self , table , error ) !> Instance of the serializable object class ( archiver_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Path to archiver call set_string ( table , \"ar\" , self % ar , error , 'archiver_t' ) if ( allocated ( error )) return call set_value ( table , \"use-response-file\" , self % use_response_file , error , 'archiver_t' ) if ( allocated ( error )) return call set_value ( table , \"echo\" , self % echo , error , 'archiver_t' ) if ( allocated ( error )) return call set_value ( table , \"verbose\" , self % verbose , error , 'archiver_t' ) if ( allocated ( error )) return end subroutine dump_to_toml","tags":"","url":"proc/dump_to_toml~8.html"},{"title":"get_debug_compile_flags – Fortran-lang/fpm","text":"public subroutine get_debug_compile_flags(id, flags) Arguments Type Intent Optional Attributes Name integer(kind=compiler_enum), intent(in) :: id character(len=:), intent(out), allocatable :: flags Source Code subroutine get_debug_compile_flags ( id , flags ) integer ( compiler_enum ), intent ( in ) :: id character ( len = :), allocatable , intent ( out ) :: flags select case ( id ) case default flags = \"\" case ( id_caf ) flags = & flag_gnu_warn // & flag_gnu_pic // & flag_gnu_limit // & flag_gnu_debug // & flag_gnu_check // & flag_gnu_backtrace case ( id_gcc ) flags = & flag_gnu_warn // & flag_gnu_pic // & flag_gnu_limit // & flag_gnu_debug // & flag_gnu_check // & flag_gnu_backtrace // & flag_gnu_coarray case ( id_f95 ) flags = & flag_gnu_warn // & flag_gnu_pic // & flag_gnu_limit // & flag_gnu_debug // & flag_gnu_check // & ' -Wno-maybe-uninitialized -Wno-uninitialized' // & flag_gnu_backtrace case ( id_nvhpc ) flags = & flag_pgi_warn // & flag_pgi_backslash // & flag_pgi_check // & flag_pgi_traceback case ( id_ibmxl ) flags = & flag_ibmxl_backslash case ( id_intel_classic_nix ) flags = & flag_intel_warn // & flag_intel_check // & flag_intel_limit // & flag_intel_debug // & flag_intel_byterecl // & flag_intel_backtrace case ( id_intel_classic_mac ) flags = & flag_intel_warn // & flag_intel_check // & flag_intel_limit // & flag_intel_debug // & flag_intel_byterecl // & flag_intel_backtrace case ( id_intel_classic_windows ) flags = & flag_intel_warn_win // & flag_intel_check_win // & flag_intel_limit_win // & flag_intel_debug_win // & flag_intel_byterecl_win // & flag_intel_backtrace_win case ( id_intel_llvm_nix ) flags = & flag_intel_unknown_cmd_err // & flag_intel_llvm_check // & flag_intel_limit // & flag_intel_debug // & flag_intel_byterecl // & flag_intel_backtrace case ( id_intel_llvm_windows ) flags = & flag_intel_unknown_cmd_err_win // & flag_intel_check_win // & flag_intel_limit_win // & flag_intel_debug_win // & flag_intel_byterecl_win case ( id_nag ) flags = & flag_nag_debug // & flag_nag_check // & flag_nag_backtrace // & flag_nag_coarray // & flag_nag_pic case ( id_lfortran ) flags = \"\" end select end subroutine get_debug_compile_flags","tags":"","url":"proc/get_debug_compile_flags.html"},{"title":"get_default_c_compiler – Fortran-lang/fpm","text":"public subroutine get_default_c_compiler(f_compiler, c_compiler) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: f_compiler character(len=:), intent(out), allocatable :: c_compiler Variables Type Visibility Attributes Name Initial integer(kind=compiler_enum), public :: id Source Code subroutine get_default_c_compiler ( f_compiler , c_compiler ) character ( len =* ), intent ( in ) :: f_compiler character ( len = :), allocatable , intent ( out ) :: c_compiler integer ( compiler_enum ) :: id id = get_compiler_id ( f_compiler ) select case ( id ) case ( id_intel_classic_nix , id_intel_classic_mac , id_intel_classic_windows ) c_compiler = 'icc' case ( id_intel_llvm_nix , id_intel_llvm_windows ) c_compiler = 'icx' case ( id_flang , id_flang_new , id_f18 ) c_compiler = 'clang' case ( id_ibmxl ) c_compiler = 'xlc' case ( id_lfortran ) c_compiler = 'cc' case ( id_gcc ) c_compiler = 'gcc' case default ! Fall-back to using Fortran compiler c_compiler = f_compiler end select end subroutine get_default_c_compiler","tags":"","url":"proc/get_default_c_compiler.html"},{"title":"get_default_cxx_compiler – Fortran-lang/fpm","text":"public subroutine get_default_cxx_compiler(f_compiler, cxx_compiler) Get C++ Compiler. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: f_compiler character(len=:), intent(out), allocatable :: cxx_compiler Variables Type Visibility Attributes Name Initial integer(kind=compiler_enum), public :: id Source Code subroutine get_default_cxx_compiler ( f_compiler , cxx_compiler ) character ( len =* ), intent ( in ) :: f_compiler character ( len = :), allocatable , intent ( out ) :: cxx_compiler integer ( compiler_enum ) :: id id = get_compiler_id ( f_compiler ) select case ( id ) case ( id_intel_classic_nix , id_intel_classic_mac , id_intel_classic_windows ) cxx_compiler = 'icpc' case ( id_intel_llvm_nix , id_intel_llvm_windows ) cxx_compiler = 'icpx' case ( id_flang , id_flang_new , id_f18 ) cxx_compiler = 'clang++' case ( id_ibmxl ) cxx_compiler = 'xlc++' case ( id_lfortran ) cxx_compiler = 'cc' case ( id_gcc ) cxx_compiler = 'g++' case default ! Fall-back to using Fortran compiler cxx_compiler = f_compiler end select end subroutine get_default_cxx_compiler","tags":"","url":"proc/get_default_cxx_compiler.html"},{"title":"get_main_flags – Fortran-lang/fpm","text":"public subroutine get_main_flags(self, language, flags) Get special flags for the main linker Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: language character(len=:), intent(out), allocatable :: flags Source Code subroutine get_main_flags ( self , language , flags ) class ( compiler_t ), intent ( in ) :: self character ( len =* ), intent ( in ) :: language character ( len = :), allocatable , intent ( out ) :: flags flags = \"\" select case ( language ) case ( \"fortran\" ) flags = \"\" case ( \"c\" ) ! If the main program is on a C/C++ source, the Intel Fortran compiler requires option ! -nofor-main to avoid \"duplicate main\" errors. ! https://stackoverflow.com/questions/36221612/p3dfft-compilation-ifort-compiler-error-multiple-definiton-of-main select case ( self % id ) case ( id_intel_classic_nix , id_intel_classic_mac , id_intel_llvm_nix ) flags = '-nofor-main' case ( id_intel_classic_windows , id_intel_llvm_windows ) flags = '/nofor-main' case ( id_pgi , id_nvhpc ) flags = '-Mnomain' end select case ( \"c++\" , \"cpp\" , \"cxx\" ) select case ( self % id ) case ( id_intel_classic_nix , id_intel_classic_mac , id_intel_llvm_nix ) flags = '-nofor-main' case ( id_intel_classic_windows , id_intel_llvm_windows ) flags = '/nofor-main' case ( id_pgi , id_nvhpc ) flags = '-Mnomain' end select case default error stop \"Unknown language '\" // language // '\", try \"fortran\", \"c\", \"c++\"' end select end subroutine get_main_flags","tags":"","url":"proc/get_main_flags.html"},{"title":"get_release_compile_flags – Fortran-lang/fpm","text":"public subroutine get_release_compile_flags(id, flags) Arguments Type Intent Optional Attributes Name integer(kind=compiler_enum), intent(in) :: id character(len=:), intent(out), allocatable :: flags Source Code subroutine get_release_compile_flags ( id , flags ) integer ( compiler_enum ), intent ( in ) :: id character ( len = :), allocatable , intent ( out ) :: flags select case ( id ) case default flags = \"\" case ( id_caf ) flags = & flag_gnu_opt // & flag_gnu_external // & flag_gnu_pic // & flag_gnu_limit case ( id_gcc ) flags = & flag_gnu_opt // & flag_gnu_external // & flag_gnu_pic // & flag_gnu_limit // & flag_gnu_coarray case ( id_f95 ) flags = & flag_gnu_opt // & flag_gnu_external // & flag_gnu_pic // & flag_gnu_limit case ( id_nvhpc ) flags = & flag_pgi_backslash case ( id_ibmxl ) flags = & flag_ibmxl_backslash case ( id_intel_classic_nix ) flags = & flag_intel_opt // & flag_intel_fp // & flag_intel_align // & flag_intel_limit // & flag_intel_pthread // & flag_intel_nogen // & flag_intel_byterecl case ( id_intel_classic_mac ) flags = & flag_intel_opt // & flag_intel_fp // & flag_intel_align // & flag_intel_limit // & flag_intel_pthread // & flag_intel_nogen // & flag_intel_byterecl case ( id_intel_classic_windows ) flags = & flag_intel_opt_win // & flag_intel_fp_win // & flag_intel_align_win // & flag_intel_limit_win // & flag_intel_pthread_win // & flag_intel_nogen_win // & flag_intel_byterecl_win case ( id_intel_llvm_nix ) flags = & flag_intel_opt // & flag_intel_fp // & flag_intel_align // & flag_intel_limit // & flag_intel_pthread // & flag_intel_nogen // & flag_intel_byterecl case ( id_intel_llvm_windows ) flags = & flag_intel_opt_win // & flag_intel_fp_win // & flag_intel_align_win // & flag_intel_limit_win // & flag_intel_pthread_win // & flag_intel_nogen_win // & flag_intel_byterecl_win case ( id_nag ) flags = & flag_nag_opt // & flag_nag_coarray // & flag_nag_pic case ( id_lfortran ) flags = & flag_lfortran_opt end select end subroutine get_release_compile_flags","tags":"","url":"proc/get_release_compile_flags.html"},{"title":"link_executable – Fortran-lang/fpm","text":"public subroutine link_executable(self, output, args, log_file, stat, dry_run) Link an executable Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object character(len=*), intent(in) :: output Output file of object character(len=*), intent(in) :: args Arguments for compiler character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag logical, intent(in), optional :: dry_run Optional mocking Variables Type Visibility Attributes Name Initial character(len=:), public, allocatable :: command logical, public :: mock Source Code subroutine link_executable ( self , output , args , log_file , stat , dry_run ) !> Instance of the compiler object class ( compiler_t ), intent ( in ) :: self !> Output file of object character ( len =* ), intent ( in ) :: output !> Arguments for compiler character ( len =* ), intent ( in ) :: args !> Compiler output log file character ( len =* ), intent ( in ) :: log_file !> Status flag integer , intent ( out ) :: stat !> Optional mocking logical , optional , intent ( in ) :: dry_run character ( len = :), allocatable :: command logical :: mock ! Check if we're actually linking mock = . false . if ( present ( dry_run )) mock = dry_run ! Set command command = self % fc // \" \" // args // \" -o \" // output ! Execute command if (. not . mock ) & call run ( command , echo = self % echo , verbose = self % verbose , redirect = log_file , exitstat = stat ) end subroutine link_executable","tags":"","url":"proc/link_executable.html"},{"title":"link_shared – Fortran-lang/fpm","text":"public subroutine link_shared(self, output, args, log_file, stat, dry_run) Link a shared library Type Bound compiler_t Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object character(len=*), intent(in) :: output Output file of shared library object character(len=*), intent(in) :: args Arguments for the compiler character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag logical, intent(in), optional :: dry_run Optional mocking Variables Type Visibility Attributes Name Initial character(len=:), public, allocatable :: command logical, public :: mock character(len=:), public, allocatable :: shared_flag Source Code subroutine link_shared ( self , output , args , log_file , stat , dry_run ) !> Instance of the compiler object class ( compiler_t ), intent ( in ) :: self !> Output file of shared library object character ( len =* ), intent ( in ) :: output !> Arguments for the compiler character ( len =* ), intent ( in ) :: args !> Compiler output log file character ( len =* ), intent ( in ) :: log_file !> Status flag integer , intent ( out ) :: stat !> Optional mocking logical , optional , intent ( in ) :: dry_run character ( len = :), allocatable :: command logical :: mock character ( len = :), allocatable :: shared_flag mock = . false . if ( present ( dry_run )) mock = dry_run shared_flag = get_shared_flag ( self ) command = self % fc // \" \" // shared_flag // \" \" // args // \" -o \" // output if (. not . mock ) & call run ( command , echo = self % echo , verbose = self % verbose , redirect = log_file , exitstat = stat ) end subroutine link_shared","tags":"","url":"proc/link_shared.html"},{"title":"load_from_toml – Fortran-lang/fpm","text":"public subroutine load_from_toml(self, table, error) Read dependency from toml table (no checks made at this stage) Type Bound archiver_t Arguments Type Intent Optional Attributes Name class( archiver_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling Source Code subroutine load_from_toml ( self , table , error ) !> Instance of the serializable object class ( archiver_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error call get_value ( table , \"ar\" , self % ar ) call get_value ( table , \"use-response-file\" , self % use_response_file , error , 'archiver_t' ) if ( allocated ( error )) return call get_value ( table , \"echo\" , self % echo , error , 'archiver_t' ) if ( allocated ( error )) return call get_value ( table , \"verbose\" , self % verbose , error , 'archiver_t' ) if ( allocated ( error )) return end subroutine load_from_toml","tags":"","url":"proc/load_from_toml~8.html"},{"title":"make_archive – Fortran-lang/fpm","text":"public subroutine make_archive(self, output, args, log_file, stat, dry_run) Create an archive Todo For Windows OS, use the local delete_file_win32 in stead of delete_file .\nThis may be related to a bug in Mingw64-openmp and is expected to be resolved in the future,\nsee issue #707, #708 and #808. Type Bound archiver_t Arguments Type Intent Optional Attributes Name class( archiver_t ), intent(in) :: self Instance of the archiver object character(len=*), intent(in) :: output Name of the archive to generate type( string_t ), intent(in) :: args (:) Object files to include into the archive character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag logical, intent(in), optional :: dry_run Optional mocking Variables Type Visibility Attributes Name Initial logical, public :: mock Subroutines subroutine delete_file_win32 (file) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: file Source Code subroutine make_archive ( self , output , args , log_file , stat , dry_run ) !> Instance of the archiver object class ( archiver_t ), intent ( in ) :: self !> Name of the archive to generate character ( len =* ), intent ( in ) :: output !> Object files to include into the archive type ( string_t ), intent ( in ) :: args (:) !> Compiler output log file character ( len =* ), intent ( in ) :: log_file !> Status flag integer , intent ( out ) :: stat !> Optional mocking logical , optional , intent ( in ) :: dry_run logical :: mock ! Check if we're actually linking mock = . false . if ( present ( dry_run )) mock = dry_run if ( mock ) return if ( self % use_response_file ) then call write_response_file ( output // \".resp\" , args ) call run ( self % ar // output // \" @\" // output // \".resp\" , echo = self % echo , & & verbose = self % verbose , redirect = log_file , exitstat = stat ) call delete_file_win32 ( output // \".resp\" ) else call run ( self % ar // output // \" \" // string_cat ( args , \" \" ), & & echo = self % echo , verbose = self % verbose , redirect = log_file , exitstat = stat ) end if contains subroutine delete_file_win32 ( file ) character ( len =* ), intent ( in ) :: file logical :: exist integer :: unit , iostat inquire ( file = file , exist = exist ) if ( exist ) then open ( file = file , newunit = unit ) close ( unit , status = 'delete' , iostat = iostat ) end if end subroutine delete_file_win32 end subroutine make_archive","tags":"","url":"proc/make_archive.html"},{"title":"new_archiver – Fortran-lang/fpm","text":"public subroutine new_archiver(self, ar, echo, verbose) Create new archiver instance Arguments Type Intent Optional Attributes Name type( archiver_t ), intent(out) :: self New instance of the archiver character(len=*), intent(in) :: ar User provided archiver command logical, intent(in) :: echo Echo compiler command logical, intent(in) :: verbose Verbose mode: dump compiler output Variables Type Visibility Attributes Name Initial character(len=*), public, parameter :: arflags = \" -rs \" integer, public :: estat character(len=*), public, parameter :: libflags = \" /OUT:\" integer, public :: os_type Source Code subroutine new_archiver ( self , ar , echo , verbose ) !> New instance of the archiver type ( archiver_t ), intent ( out ) :: self !> User provided archiver command character ( len =* ), intent ( in ) :: ar !> Echo compiler command logical , intent ( in ) :: echo !> Verbose mode: dump compiler output logical , intent ( in ) :: verbose integer :: estat , os_type character ( len =* ), parameter :: arflags = \" -rs \" , libflags = \" /OUT:\" if ( len_trim ( ar ) > 0 ) then ! Check first for ar-like commands if ( check_compiler ( ar , \"ar\" )) then self % ar = ar // arflags end if ! Check for lib-like commands if ( check_compiler ( ar , \"lib\" )) then self % ar = ar // libflags end if ! Fallback and assume ar-like behaviour self % ar = ar // arflags else os_type = get_os_type () if ( os_type /= OS_WINDOWS . and . os_type /= OS_UNKNOWN ) then self % ar = \"ar\" // arflags else ! Attempt \"ar\" call execute_command_line ( \"ar --version > \" // get_temp_filename () // \" 2>&1\" , & & exitstat = estat ) if ( estat == 0 ) then self % ar = \"ar\" // arflags else ! Then \"gcc-ar\" call execute_command_line ( \"gcc-ar --version > \" // get_temp_filename () // \" 2>&1\" , & & exitstat = estat ) if ( estat /= 0 ) then self % ar = \"lib\" // libflags else self % ar = \"gcc-ar\" // arflags end if endif end if end if self % use_response_file = os_type == OS_WINDOWS self % echo = echo self % verbose = verbose end subroutine new_archiver","tags":"","url":"proc/new_archiver.html"},{"title":"new_compiler – Fortran-lang/fpm","text":"public subroutine new_compiler(self, fc, cc, cxx, echo, verbose) Create new compiler instance Arguments Type Intent Optional Attributes Name type( compiler_t ), intent(out) :: self New instance of the compiler character(len=*), intent(in) :: fc Fortran compiler name or path character(len=*), intent(in) :: cc C compiler name or path character(len=*), intent(in) :: cxx C++ Compiler name or path logical, intent(in) :: echo Echo compiler command logical, intent(in) :: verbose Verbose mode: dump compiler output Source Code subroutine new_compiler ( self , fc , cc , cxx , echo , verbose ) !> New instance of the compiler type ( compiler_t ), intent ( out ) :: self !> Fortran compiler name or path character ( len =* ), intent ( in ) :: fc !> C compiler name or path character ( len =* ), intent ( in ) :: cc !> C++ Compiler name or path character ( len =* ), intent ( in ) :: cxx !> Echo compiler command logical , intent ( in ) :: echo !> Verbose mode: dump compiler output logical , intent ( in ) :: verbose self % id = get_compiler_id ( fc ) self % echo = echo self % verbose = verbose self % fc = fc if ( len_trim ( cc ) > 0 ) then self % cc = cc else call get_default_c_compiler ( self % fc , self % cc ) end if if ( len_trim ( cxx ) > 0 ) then self % cxx = cxx else call get_default_cxx_compiler ( self % fc , self % cxx ) end if end subroutine new_compiler","tags":"","url":"proc/new_compiler.html"},{"title":"set_cpp_preprocessor_flags – Fortran-lang/fpm","text":"public pure subroutine set_cpp_preprocessor_flags(id, flags) Modify the flag_cpp_preprocessor on the basis of the compiler. Arguments Type Intent Optional Attributes Name integer(kind=compiler_enum), intent(in) :: id character(len=:), intent(inout), allocatable :: flags Variables Type Visibility Attributes Name Initial character(len=:), public, allocatable :: flag_cpp_preprocessor Source Code pure subroutine set_cpp_preprocessor_flags ( id , flags ) integer ( compiler_enum ), intent ( in ) :: id character ( len = :), allocatable , intent ( inout ) :: flags character ( len = :), allocatable :: flag_cpp_preprocessor !> Modify the flag_cpp_preprocessor on the basis of the compiler. select case ( id ) case default flag_cpp_preprocessor = \"\" case ( id_caf , id_gcc , id_f95 , id_nvhpc ) flag_cpp_preprocessor = \"-cpp\" case ( id_intel_classic_windows , id_intel_llvm_windows ) flag_cpp_preprocessor = \"/fpp\" case ( id_intel_classic_nix , id_intel_classic_mac , id_intel_llvm_nix , id_nag ) flag_cpp_preprocessor = \"-fpp\" case ( id_lfortran ) flag_cpp_preprocessor = \"--cpp\" end select flags = flag_cpp_preprocessor // flags end subroutine set_cpp_preprocessor_flags","tags":"","url":"proc/set_cpp_preprocessor_flags.html"},{"title":"tokenize_flags – Fortran-lang/fpm","text":"public subroutine tokenize_flags(flags, flags_array) Tokenize a string into an array of compiler flags Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: flags type( string_t ), intent(out), allocatable :: flags_array (:) Variables Type Visibility Attributes Name Initial character(len=:), public, allocatable :: flags_char_array (:) integer, public :: i logical, public :: success Source Code subroutine tokenize_flags ( flags , flags_array ) character ( * ), intent ( in ) :: flags type ( string_t ), allocatable , intent ( out ) :: flags_array (:) character ( len = :), allocatable :: flags_char_array (:) integer :: i logical :: success flags_char_array = sh_split ( flags , join_spaced = . true ., keep_quotes = . true ., success = success ) if (. not . success ) then allocate ( flags_array ( 0 )) return end if allocate ( flags_array ( size ( flags_char_array ))) do i = 1 , size ( flags_char_array ) flags_array ( i )% s = trim ( adjustl ( flags_char_array ( i ))) end do end subroutine tokenize_flags","tags":"","url":"proc/tokenize_flags.html"},{"title":"write_response_file – Fortran-lang/fpm","text":"public subroutine write_response_file(name, argv) Response files allow to read command line options from files.\nWhitespace is used to separate the arguments, we will use newlines\nas separator to create readable response files which can be inspected\nin case of errors. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: name type( string_t ), intent(in) :: argv (:) Variables Type Visibility Attributes Name Initial integer, public :: iarg integer, public :: io Source Code subroutine write_response_file ( name , argv ) character ( len =* ), intent ( in ) :: name type ( string_t ), intent ( in ) :: argv (:) integer :: iarg , io open ( file = name , newunit = io , status = 'replace' ) do iarg = 1 , size ( argv ) write ( io , '(a)' ) unix_path ( argv ( iarg )% s ) end do close ( io ) end subroutine write_response_file","tags":"","url":"proc/write_response_file.html"},{"title":"debug – Fortran-lang/fpm","text":"public interface debug Create debug printout Module Procedures public pure function debug_compiler (self) result(repr) String representation of a compiler object Arguments Type Intent Optional Attributes Name type( compiler_t ), intent(in) :: self Instance of the compiler object Return Value character(len=:), allocatable Representation as string public pure function debug_archiver (self) result(repr) String representation of an archiver object Arguments Type Intent Optional Attributes Name type( archiver_t ), intent(in) :: self Instance of the archiver object Return Value character(len=:), allocatable Representation as string","tags":"","url":"interface/debug.html"},{"title":"get_exe_name_with_suffix – Fortran-lang/fpm","text":"public function get_exe_name_with_suffix(source) result(suffixed) Build an executable name with suffix. Safe routine that always returns an allocated string Arguments Type Intent Optional Attributes Name type( srcfile_t ), intent(in) :: source Return Value character(len=:), allocatable Source Code function get_exe_name_with_suffix ( source ) result ( suffixed ) type ( srcfile_t ), intent ( in ) :: source character ( len = :), allocatable :: suffixed if ( allocated ( source % exe_name )) then if ( get_os_type () == OS_WINDOWS ) then suffixed = source % exe_name // '.exe' else suffixed = source % exe_name end if else suffixed = \"\" endif end function get_exe_name_with_suffix","tags":"","url":"proc/get_exe_name_with_suffix.html"},{"title":"add_executable_sources – Fortran-lang/fpm","text":"public subroutine add_executable_sources(sources, executables, scope, auto_discover, with_f_ext, error) Add to sources using the executable and test entries in the manifest and\napplies any executable-specific overrides such as executable%name .\nAdds all sources (including modules) from each executable%source_dir Compare lowercase strings to allow auto-discovery of pre-processed extensions Arguments Type Intent Optional Attributes Name type( srcfile_t ), intent(inout), allocatable, target :: sources (:) List of [[srcfile_t]] objects to append to. Allocated if not allocated class( executable_config_t ), intent(in) :: executables (:) List of [[executable_config_t]] entries from manifest integer, intent(in) :: scope Scope to apply to the discovered sources: either FPM_SCOPE_APP or FPM_SCOPE_TEST , see fpm_model logical, intent(in) :: auto_discover If .false. only executables and tests specified in the manifest are added to sources type( string_t ), intent(in), optional :: with_f_ext (:) Additional user-defined (preprocessor) extensions that should be treated as Fortran sources type( error_t ), intent(out), allocatable :: error Error handling Source Code subroutine add_executable_sources ( sources , executables , scope , auto_discover , with_f_ext , error ) !> List of `[[srcfile_t]]` objects to append to. Allocated if not allocated type ( srcfile_t ), allocatable , intent ( inout ), target :: sources (:) !> List of `[[executable_config_t]]` entries from manifest class ( executable_config_t ), intent ( in ) :: executables (:) !> Scope to apply to the discovered sources: either `FPM_SCOPE_APP` or `FPM_SCOPE_TEST`, see [[fpm_model]] integer , intent ( in ) :: scope !> If `.false.` only executables and tests specified in the manifest are added to `sources` logical , intent ( in ) :: auto_discover !> Additional user-defined (preprocessor) extensions that should be treated as Fortran sources type ( string_t ), intent ( in ), optional :: with_f_ext (:) !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: i , j type ( string_t ), allocatable :: exe_dirs (:) type ( srcfile_t ) :: exe_source call get_executable_source_dirs ( exe_dirs , executables ) do i = 1 , size ( exe_dirs ) call add_sources_from_dir ( sources , exe_dirs ( i )% s , scope , & with_executables = auto_discover , with_f_ext = with_f_ext , recurse = . false ., error = error ) if ( allocated ( error )) then return end if end do exe_loop : do i = 1 , size ( executables ) ! Check if executable already discovered automatically ! and apply any overrides do j = 1 , size ( sources ) !> Compare lowercase strings to allow auto-discovery of pre-processed extensions if ( lower ( basename ( sources ( j )% file_name , suffix = . true .)) == lower ( executables ( i )% main ) . and .& canon_path ( dirname ( sources ( j )% file_name )) == & canon_path ( executables ( i )% source_dir ) ) then sources ( j )% exe_name = executables ( i )% name if ( allocated ( executables ( i )% link )) then sources ( j )% link_libraries = executables ( i )% link end if sources ( j )% unit_type = FPM_UNIT_PROGRAM cycle exe_loop end if end do ! Add if not already discovered (auto_discovery off) associate ( exe => executables ( i )) exe_source = parse_source ( join_path ( exe % source_dir , exe % main ), with_f_ext , error ) exe_source % exe_name = exe % name if ( allocated ( exe % link )) then exe_source % link_libraries = exe % link end if exe_source % unit_type = FPM_UNIT_PROGRAM exe_source % unit_scope = scope end associate if ( allocated ( error )) return if (. not . allocated ( sources )) then sources = [ exe_source ] else sources = [ sources , exe_source ] end if end do exe_loop end subroutine add_executable_sources","tags":"","url":"proc/add_executable_sources.html"},{"title":"add_sources_from_dir – Fortran-lang/fpm","text":"public subroutine add_sources_from_dir(sources, directory, scope, with_executables, with_f_ext, recurse, error) Add to sources by looking for source files in directory Arguments Type Intent Optional Attributes Name type( srcfile_t ), intent(inout), allocatable, target :: sources (:) List of [[srcfile_t]] objects to append to. Allocated if not allocated character(len=*), intent(in) :: directory Directory in which to search for source files integer, intent(in) :: scope Scope to apply to the discovered sources, see fpm_model for enumeration logical, intent(in), optional :: with_executables Executable sources (fortran program s) are ignored unless with_executables=.true. type( string_t ), intent(in), optional :: with_f_ext (:) Additional user-defined (preprocessor) extensions that should be treated as Fortran sources logical, intent(in), optional :: recurse Whether to recursively search subdirectories, default is .true. type( error_t ), intent(out), allocatable :: error Error handling Source Code subroutine add_sources_from_dir ( sources , directory , scope , with_executables , with_f_ext , recurse , error ) !> List of `[[srcfile_t]]` objects to append to. Allocated if not allocated type ( srcfile_t ), allocatable , intent ( inout ), target :: sources (:) !> Directory in which to search for source files character ( * ), intent ( in ) :: directory !> Scope to apply to the discovered sources, see [[fpm_model]] for enumeration integer , intent ( in ) :: scope !> Executable sources (fortran `program`s) are ignored unless `with_executables=.true.` logical , intent ( in ), optional :: with_executables !> Additional user-defined (preprocessor) extensions that should be treated as Fortran sources type ( string_t ), intent ( in ), optional :: with_f_ext (:) !> Whether to recursively search subdirectories, default is `.true.` logical , intent ( in ), optional :: recurse !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: i logical , allocatable :: is_source (:), exclude_source (:) logical :: recurse_ type ( string_t ), allocatable :: file_names (:) type ( string_t ), allocatable :: src_file_names (:), f_ext (:) type ( string_t ), allocatable :: existing_src_files (:) type ( srcfile_t ), allocatable :: dir_sources (:) recurse_ = . true . if ( present ( recurse )) recurse_ = recurse ! Scan directory for sources call list_files ( directory , file_names , recurse = recurse_ ) if ( allocated ( sources )) then allocate ( existing_src_files ( size ( sources ))) do i = 1 , size ( sources ) existing_src_files ( i )% s = canon_path ( sources ( i )% file_name ) end do else allocate ( existing_src_files ( 0 )) end if ! Get legal fortran suffixes call list_fortran_suffixes ( f_ext , with_f_ext ) is_source = [(. not .( is_hidden_file ( basename ( file_names ( i )% s ))) . and . & . not .( canon_path ( file_names ( i )% s ) . in . existing_src_files ) . and . & ( str_ends_with ( lower ( file_names ( i )% s ), f_ext ) . or . & str_ends_with ( lower ( file_names ( i )% s ), c_suffixes ) ), i = 1 , size ( file_names ))] src_file_names = pack ( file_names , is_source ) allocate ( dir_sources ( size ( src_file_names ))) allocate ( exclude_source ( size ( src_file_names ))) do i = 1 , size ( src_file_names ) dir_sources ( i ) = parse_source ( src_file_names ( i )% s , with_f_ext , error ) if ( allocated ( error )) return dir_sources ( i )% unit_scope = scope allocate ( dir_sources ( i )% link_libraries ( 0 )) ! Exclude executables unless specified otherwise exclude_source ( i ) = ( dir_sources ( i )% unit_type == FPM_UNIT_PROGRAM ) if ( dir_sources ( i )% unit_type == FPM_UNIT_PROGRAM . and . & & present ( with_executables )) then if ( with_executables ) then exclude_source ( i ) = . false . end if end if end do if (. not . allocated ( sources )) then sources = pack ( dir_sources ,. not . exclude_source ) else sources = [ sources , pack ( dir_sources ,. not . exclude_source )] end if end subroutine add_sources_from_dir","tags":"","url":"proc/add_sources_from_dir.html"},{"title":"destroy – Fortran-lang/fpm","text":"public elemental subroutine destroy(this) Type Bound metapackage_t Arguments Type Intent Optional Attributes Name class( metapackage_t ), intent(inout) :: this Source Code elemental subroutine destroy ( this ) class ( metapackage_t ), intent ( inout ) :: this this % has_link_libraries = . false . this % has_link_flags = . false . this % has_build_flags = . false . this % has_fortran_flags = . false . this % has_c_flags = . false . this % has_cxx_flags = . false . this % has_include_dirs = . false . this % has_dependencies = . false . this % has_run_command = . false . this % has_external_modules = . false . if ( allocated ( this % fortran )) deallocate ( this % fortran ) if ( allocated ( this % preprocess )) deallocate ( this % preprocess ) if ( allocated ( this % name )) deallocate ( this % name ) if ( allocated ( this % version )) deallocate ( this % version ) if ( allocated ( this % flags % s )) deallocate ( this % flags % s ) if ( allocated ( this % link_libs )) deallocate ( this % link_libs ) if ( allocated ( this % incl_dirs )) deallocate ( this % incl_dirs ) if ( allocated ( this % external_modules )) deallocate ( this % external_modules ) end subroutine destroy","tags":"","url":"proc/destroy~2.html"},{"title":"parse_c_source – Fortran-lang/fpm","text":"public function parse_c_source(c_filename, error) result(c_source) Parsing of c, cpp source files The following statements are recognised and parsed: #include preprocessor statement Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: c_filename type( error_t ), intent(out), allocatable :: error Return Value type( srcfile_t ) Source Code function parse_c_source ( c_filename , error ) result ( c_source ) character ( * ), intent ( in ) :: c_filename type ( srcfile_t ) :: c_source type ( error_t ), allocatable , intent ( out ) :: error integer :: fh , n_include , i , pass , stat type ( string_t ), allocatable :: file_lines (:) c_source % file_name = c_filename if ( str_ends_with ( lower ( c_filename ), \".c\" )) then c_source % unit_type = FPM_UNIT_CSOURCE else if ( str_ends_with ( lower ( c_filename ), \".h\" )) then c_source % unit_type = FPM_UNIT_CHEADER else if ( str_ends_with ( lower ( c_filename ), \".cpp\" )) then c_source % unit_type = FPM_UNIT_CPPSOURCE end if allocate ( c_source % modules_used ( 0 )) allocate ( c_source % modules_provided ( 0 )) allocate ( c_source % parent_modules ( 0 )) file_lines = read_lines ( c_filename ) ! Ignore empty files, returned as FPM_UNIT_UNKNOWN if ( len_trim ( file_lines ) < 1 ) then c_source % unit_type = FPM_UNIT_UNKNOWN return end if c_source % digest = fnv_1a ( file_lines ) do pass = 1 , 2 n_include = 0 file_loop : do i = 1 , size ( file_lines ) ! Process 'INCLUDE' statements if ( index ( adjustl ( lower ( file_lines ( i )% s )), '#include' ) == 1 . and . & index ( file_lines ( i )% s , '\"' ) > 0 ) then n_include = n_include + 1 if ( pass == 2 ) then c_source % include_dependencies ( n_include )% s = & & split_n ( file_lines ( i )% s , n = 2 , delims = '\"' , stat = stat ) if ( stat /= 0 ) then call file_parse_error ( error , c_filename , & 'unable to get c include file' , i , & file_lines ( i )% s , index ( file_lines ( i )% s , '\"' )) return end if end if end if end do file_loop if ( pass == 1 ) then allocate ( c_source % include_dependencies ( n_include )) end if end do end function parse_c_source","tags":"","url":"proc/parse_c_source.html"},{"title":"parse_f_source – Fortran-lang/fpm","text":"public function parse_f_source(f_filename, error) result(f_source) Parsing of free-form fortran source files The following statements are recognised and parsed: Module / submodule / program declaration Module use statement include statement @note Note\n Intrinsic modules used by sources are not listed in\n the modules_used field of source objects. @note Note\n Submodules are treated as normal modules which use their\n corresponding parent modules. Parsing limitations Statements must not continued onto another line\n except for an only: list in the use statement. This is supported: use my_module , only : & my_var , my_function , my_subroutine This is NOT supported: use & my_module Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: f_filename type( error_t ), intent(out), allocatable :: error Return Value type( srcfile_t ) Source Code function parse_f_source ( f_filename , error ) result ( f_source ) character ( * ), intent ( in ) :: f_filename type ( srcfile_t ) :: f_source type ( error_t ), allocatable , intent ( out ) :: error logical :: inside_module , inside_interface , using , intrinsic_module integer :: stat integer :: fh , n_use , n_include , n_mod , n_parent , i , j , ic , pass type ( string_t ), allocatable :: file_lines (:), file_lines_lower (:) character (:), allocatable :: temp_string , mod_name , string_parts (:) if (. not . exists ( f_filename )) then call file_not_found_error ( error , f_filename ) return end if f_source % file_name = f_filename file_lines = read_lines_expanded ( f_filename ) ! for efficiency in parsing make a lowercase left-adjusted copy of the file ! Need a copy because INCLUDE (and #include) file arguments are case-sensitive file_lines_lower = file_lines do i = 1 , size ( file_lines_lower ) file_lines_lower ( i )% s = adjustl ( lower ( file_lines_lower ( i )% s )) enddo ! fnv_1a can only be applied to non-zero-length arrays if ( len_trim ( file_lines_lower ) > 0 ) f_source % digest = fnv_1a ( file_lines ) do pass = 1 , 2 n_use = 0 n_include = 0 n_mod = 0 n_parent = 0 inside_module = . false . inside_interface = . false . file_loop : do i = 1 , size ( file_lines_lower ) ! Skip comment lines and preprocessor directives if ( index ( file_lines_lower ( i )% s , '!' ) == 1 . or . & index ( file_lines_lower ( i )% s , '#' ) == 1 . or . & len_trim ( file_lines_lower ( i )% s ) < 1 ) then cycle end if ! Detect exported C-API via bind(C) if (. not . inside_interface . and . & parse_subsequence ( file_lines_lower ( i )% s , 'bind' , '(' , 'c' )) then do j = i , 1 , - 1 if ( index ( file_lines_lower ( j )% s , 'function' ) > 0 . or . & index ( file_lines_lower ( j )% s , 'subroutine' ) > 0 ) then f_source % unit_type = FPM_UNIT_SUBPROGRAM exit end if if ( j > 1 ) then ic = index ( file_lines_lower ( j - 1 )% s , '!' ) if ( ic < 1 ) then ic = len ( file_lines_lower ( j - 1 )% s ) end if temp_string = trim ( file_lines_lower ( j - 1 )% s ( 1 : ic )) if ( index ( temp_string , '&' ) /= len ( temp_string )) then exit end if end if end do end if ! Skip lines that are continued: not statements if ( i > 1 ) then ic = index ( file_lines_lower ( i - 1 )% s , '!' ) if ( ic < 1 ) then ic = len ( file_lines_lower ( i - 1 )% s ) end if temp_string = trim ( file_lines_lower ( i - 1 )% s ( 1 : ic )) if ( len ( temp_string ) > 0 . and . index ( temp_string , '&' ) == len ( temp_string )) then cycle end if end if ! Detect beginning of interface block if ( index ( file_lines_lower ( i )% s , 'interface' ) == 1 & . or . parse_sequence ( file_lines_lower ( i )% s , 'abstract' , 'interface' )) then inside_interface = . true . cycle end if ! Detect end of interface block if ( parse_sequence ( file_lines_lower ( i )% s , 'end' , 'interface' )) then inside_interface = . false . cycle end if ! Process 'USE' statements call parse_use_statement ( f_filename , i , file_lines_lower ( i )% s , using , intrinsic_module , mod_name , error ) if ( allocated ( error )) return if ( using ) then ! Not a valid module name? if (. not . is_fortran_name ( mod_name )) cycle ! Valid intrinsic module: not a dependency if ( intrinsic_module ) cycle n_use = n_use + 1 if ( pass == 2 ) f_source % modules_used ( n_use )% s = mod_name cycle endif ! Process 'INCLUDE' statements ic = index ( file_lines_lower ( i )% s , 'include' ) if ( ic == 1 ) then ic = index ( lower ( file_lines ( i )% s ), 'include' ) if ( index ( adjustl ( file_lines ( i )% s ( ic + 7 :)), '\"' ) == 1 . or . & index ( adjustl ( file_lines ( i )% s ( ic + 7 :)), \"'\" ) == 1 ) then n_include = n_include + 1 if ( pass == 2 ) then f_source % include_dependencies ( n_include )% s = & & split_n ( file_lines ( i )% s , n = 2 , delims = \"'\" // '\"' , stat = stat ) if ( stat /= 0 ) then call file_parse_error ( error , f_filename , & 'unable to find include file name' , i , & file_lines ( i )% s ) return end if end if cycle end if end if ! Extract name of module if is module if ( index ( file_lines_lower ( i )% s , 'module ' ) == 1 ) then ! Remove any trailing comments ic = index ( file_lines_lower ( i )% s , '!' ) - 1 if ( ic < 1 ) then ic = len ( file_lines_lower ( i )% s ) end if temp_string = trim ( file_lines_lower ( i )% s ( 1 : ic )) ! R1405 module-stmt := \"MODULE\" module-name ! module-stmt has two space-delimited parts only ! (no line continuations) call split ( temp_string , string_parts , ' ' ) if ( size ( string_parts ) /= 2 ) then cycle end if mod_name = trim ( adjustl ( string_parts ( 2 ))) if ( scan ( mod_name , '=(&' ) > 0 ) then ! Ignore these cases: ! module & ! module =* ! module (i) cycle end if if (. not . is_fortran_name ( mod_name )) then call file_parse_error ( error , f_filename , & 'empty or invalid name for module' , i , & file_lines_lower ( i )% s , index ( file_lines_lower ( i )% s , mod_name )) return end if n_mod = n_mod + 1 if ( pass == 2 ) then f_source % modules_provided ( n_mod ) = string_t ( mod_name ) end if if ( f_source % unit_type == FPM_UNIT_UNKNOWN ) then f_source % unit_type = FPM_UNIT_MODULE end if if (. not . inside_module ) then inside_module = . true . else ! Must have missed an end module statement (can't assume a pure module) if ( f_source % unit_type /= FPM_UNIT_PROGRAM ) then f_source % unit_type = FPM_UNIT_SUBPROGRAM end if end if cycle end if ! Extract name of submodule if is submodule if ( index ( file_lines_lower ( i )% s , 'submodule' ) == 1 ) then mod_name = split_n ( file_lines_lower ( i )% s , n = 3 , delims = '()' , stat = stat ) if ( stat /= 0 ) then call file_parse_error ( error , f_filename , & 'unable to get submodule name' , i , & file_lines_lower ( i )% s ) return end if if (. not . is_fortran_name ( mod_name )) then call file_parse_error ( error , f_filename , & 'empty or invalid name for submodule' , i , & file_lines_lower ( i )% s , index ( file_lines_lower ( i )% s , mod_name )) return end if n_mod = n_mod + 1 temp_string = split_n ( file_lines_lower ( i )% s , n = 2 , delims = '()' , stat = stat ) if ( stat /= 0 ) then call file_parse_error ( error , f_filename , & 'unable to get submodule ancestry' , i , & file_lines_lower ( i )% s ) return end if if ( f_source % unit_type /= FPM_UNIT_PROGRAM ) then f_source % unit_type = FPM_UNIT_SUBMODULE end if n_use = n_use + 1 inside_module = . true . n_parent = n_parent + 1 if ( pass == 2 ) then if ( index ( temp_string , ':' ) > 0 ) then temp_string = temp_string ( index ( temp_string , ':' ) + 1 :) end if if (. not . is_fortran_name ( temp_string )) then call file_parse_error ( error , f_filename , & 'empty or invalid name for submodule parent' , i , & file_lines_lower ( i )% s , index ( file_lines_lower ( i )% s , temp_string )) return end if f_source % modules_used ( n_use )% s = temp_string f_source % parent_modules ( n_parent )% s = temp_string f_source % modules_provided ( n_mod )% s = mod_name end if cycle end if ! Detect if contains a program ! - no modules allowed after program def ! - program header may be missing (only \"end program\" statement present) if ( index ( file_lines_lower ( i )% s , 'program ' ) == 1 . or . & parse_sequence ( file_lines_lower ( i )% s , 'end' , 'program' )) then temp_string = split_n ( file_lines_lower ( i )% s , n = 2 , delims = ' ' , stat = stat ) if ( stat == 0 ) then if ( scan ( temp_string , '=(' ) > 0 ) then ! Ignore: ! program =* ! program (i) =* cycle end if end if f_source % unit_type = FPM_UNIT_PROGRAM cycle end if ! Parse end module statement ! (to check for code outside of modules) if ( parse_sequence ( file_lines_lower ( i )% s , 'end' , 'module' ) . or . & parse_sequence ( file_lines_lower ( i )% s , 'end' , 'submodule' )) then inside_module = . false . cycle end if ! Any statements not yet parsed are assumed to be other code statements if (. not . inside_module . and . f_source % unit_type /= FPM_UNIT_PROGRAM ) then f_source % unit_type = FPM_UNIT_SUBPROGRAM end if end do file_loop ! If unable to parse end of module statement, then can't assume pure module ! (there could be non-module subprograms present) if ( inside_module . and . f_source % unit_type == FPM_UNIT_MODULE ) then f_source % unit_type = FPM_UNIT_SUBPROGRAM end if if ( pass == 1 ) then allocate ( f_source % modules_used ( n_use )) allocate ( f_source % include_dependencies ( n_include )) allocate ( f_source % modules_provided ( n_mod )) allocate ( f_source % parent_modules ( n_parent )) end if end do end function parse_f_source","tags":"","url":"proc/parse_f_source.html"},{"title":"parse_use_statement – Fortran-lang/fpm","text":"public subroutine parse_use_statement(f_filename, i, line, use_stmt, is_intrinsic, module_name, error) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: f_filename Current file name and line number (for error messaging) integer, intent(in) :: i character(len=*), intent(in) :: line The line being parsed. MUST BE preprocessed with trim(adjustl() logical, intent(out) :: use_stmt Does this line contain a use statement? logical, intent(out) :: is_intrinsic Is the module in this statement intrinsic? character(len=:), intent(out), allocatable :: module_name used module name type( error_t ), intent(out), allocatable :: error Error handling Source Code subroutine parse_use_statement ( f_filename , i , line , use_stmt , is_intrinsic , module_name , error ) !> Current file name and line number (for error messaging) character ( * ), intent ( in ) :: f_filename integer , intent ( in ) :: i !> The line being parsed. MUST BE preprocessed with trim(adjustl() character ( * ), intent ( in ) :: line !> Does this line contain a `use` statement? logical , intent ( out ) :: use_stmt !> Is the module in this statement intrinsic? logical , intent ( out ) :: is_intrinsic !> used module name character (:), allocatable , intent ( out ) :: module_name !> Error handling type ( error_t ), allocatable , intent ( out ) :: error character ( 15 ), parameter :: INTRINSIC_NAMES ( * ) = & [ 'iso_c_binding ' , & 'iso_fortran_env' , & 'ieee_arithmetic' , & 'ieee_exceptions' , & 'ieee_features ' , & 'omp_lib ' ] character ( len = :), allocatable :: temp_string integer :: colons , intr , nonintr , j , stat logical :: has_intrinsic_name use_stmt = . false . is_intrinsic = . false . if ( len_trim ( line ) <= 0 ) return ! Quick check that the line is preprocessed if ( line ( 1 : 1 ) == ' ' ) then call fatal_error ( error , 'internal_error: source file line is not trim(adjustl()) on input to parse_use_statement' ) return end if ! 'use' should be the first string in the adjustl line use_stmt = index ( line , 'use ' ) == 1 . or . index ( line , 'use::' ) == 1 . or . index ( line , 'use,' ) == 1 if (. not . use_stmt ) return colons = index ( line , '::' ) nonintr = 0 intr = 0 have_colons : if ( colons > 3 ) then ! there may be an intrinsic/non-intrinsic spec nonintr = index ( line ( 1 : colons - 1 ), 'non_intrinsic' ) if ( nonintr == 0 ) intr = index ( line ( 1 : colons - 1 ), 'intrinsic' ) temp_string = split_n ( line , delims = ':' , n = 2 , stat = stat ) if ( stat /= 0 ) then call file_parse_error ( error , f_filename , & 'unable to find used module name' , i , & line , colons ) return end if module_name = split_n ( temp_string , delims = ' ,' , n = 1 , stat = stat ) if ( stat /= 0 ) then call file_parse_error ( error , f_filename , & 'unable to find used module name' , i , & line ) return end if else module_name = split_n ( line , n = 2 , delims = ' ,' , stat = stat ) if ( stat /= 0 ) then call file_parse_error ( error , f_filename , & 'unable to find used module name' , i , & line ) return end if end if have_colons ! If declared intrinsic, check that it is true has_intrinsic_name = any ([( index ( module_name , trim ( INTRINSIC_NAMES ( j ))) > 0 , & j = 1 , size ( INTRINSIC_NAMES ))]) if ( intr > 0 . and . . not . has_intrinsic_name ) then ! An intrinsic module was not found. Its name could be in the next line, ! in which case, we just skip this check. The compiler will do the job if the name is invalid. ! Module name was not read: it's in the next line if ( index ( module_name , '&' ) <= 0 ) then call file_parse_error ( error , f_filename , & 'module ' // module_name // ' is declared intrinsic but it is not ' , i , & line ) return endif endif ! Should we treat this as an intrinsic module is_intrinsic = nonintr == 0 . and . & ! not declared non-intrinsic ( intr > 0 . or . has_intrinsic_name ) end subroutine parse_use_statement","tags":"","url":"proc/parse_use_statement.html"},{"title":"new_executable – Fortran-lang/fpm","text":"public subroutine new_executable(self, table, error) Construct a new executable configuration from a TOML data structure Arguments Type Intent Optional Attributes Name type( executable_config_t ), intent(out) :: self Instance of the executable configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling Source Code subroutine new_executable ( self , table , error ) !> Instance of the executable configuration type ( executable_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_table ), pointer :: child call check ( table , error ) if ( allocated ( error )) return call get_value ( table , \"name\" , self % name ) if (. not . allocated ( self % name )) then call syntax_error ( error , \"Could not retrieve executable name\" ) return end if if ( bad_name_error ( error , 'executable' , self % name )) then return endif call get_value ( table , \"source-dir\" , self % source_dir , \"app\" ) call get_value ( table , \"main\" , self % main , \"main.f90\" ) call get_value ( table , \"dependencies\" , child , requested = . false .) if ( associated ( child )) then call new_dependencies ( self % dependency , child , error = error ) if ( allocated ( error )) return end if call get_list ( table , \"link\" , self % link , error ) if ( allocated ( error )) return end subroutine new_executable","tags":"","url":"proc/new_executable.html"},{"title":"init_hdf5 – Fortran-lang/fpm","text":"public subroutine init_hdf5(this, compiler, all_meta, error) Initialize HDF5 metapackage for the current system\nCleanup\nSet name Assert pkg-config is installed\nFind pkg-config package file by priority\nsome distros put hdf5-1.2.3.pc with version number in .pc filename.\nAdd HDF5 modules as external Arguments Type Intent Optional Attributes Name class( metapackage_t ), intent(inout) :: this type( compiler_t ), intent(in) :: compiler type( metapackage_request_t ), intent(in) :: all_meta (:) type( error_t ), intent(out), allocatable :: error Source Code subroutine init_hdf5 ( this , compiler , all_meta , error ) class ( metapackage_t ), intent ( inout ) :: this type ( compiler_t ), intent ( in ) :: compiler type ( metapackage_request_t ), intent ( in ) :: all_meta (:) type ( error_t ), allocatable , intent ( out ) :: error character ( * ), parameter :: find_hl ( * ) = & [ character ( 11 ) :: '_hl_fortran' , 'hl_fortran' , '_fortran' , '_hl' ] character ( * ), parameter :: candidates ( * ) = & [ character ( 15 ) :: 'hdf5_hl_fortran' , 'hdf5-hl-fortran' , 'hdf5_fortran' , 'hdf5-fortran' ,& 'hdf5_hl' , 'hdf5' , 'hdf5-serial' ] integer :: i , j , k , l logical :: s , found_hl ( size ( find_hl )), found type ( string_t ) :: log , this_lib type ( string_t ), allocatable :: libs (:), flags (:), modules (:), non_fortran (:) character ( len = :), allocatable :: name , include_flag , libdir , ext , pref include_flag = get_include_flag ( compiler , \"\" ) !> Cleanup call destroy ( this ) allocate ( this % link_libs ( 0 ), this % incl_dirs ( 0 ), this % external_modules ( 0 ), non_fortran ( 0 )) this % link_flags = string_t ( \"\" ) this % flags = string_t ( \"\" ) !> Set name this % name = \"hdf5\" !> Assert pkg-config is installed if (. not . assert_pkg_config ()) then call fatal_error ( error , 'hdf5 metapackage requires pkg-config' ) return end if !> Find pkg-config package file by priority name = 'NOT_FOUND' find_package : do i = 1 , size ( candidates ) if ( pkgcfg_has_package ( trim ( candidates ( i )))) then name = trim ( candidates ( i )) exit find_package end if end do find_package !> some distros put hdf5-1.2.3.pc with version number in .pc filename. if ( name == 'NOT_FOUND' ) then modules = pkgcfg_list_all ( error ) find_global_package : do i = 1 , size ( modules ) if ( str_begins_with_str ( modules ( i )% s , 'hdf5' )) then name = modules ( i )% s exit find_global_package end if end do find_global_package end if if ( name == 'NOT_FOUND' ) then call fatal_error ( error , 'pkg-config could not find a suitable hdf5 package.' ) return end if call add_pkg_config_compile_options ( this , name , include_flag , libdir , error ) if ( allocated ( error )) return ! Some pkg-config hdf5.pc (e.g. Ubuntu) don't include the commonly-used HL HDF5 libraries, ! so let's add them if they exist if ( len_trim ( libdir ) > 0 ) then do i = 1 , size ( this % link_libs ) found_hl = . false . if (. not . str_ends_with ( this % link_libs ( i )% s , find_hl )) then ! Extract name with no extension call lib_get_trailing ( this % link_libs ( i )% s , libdir , pref , ext , found ) ! Search how many versions with the Fortran endings there are finals : do k = 1 , size ( find_hl ) do j = 1 , size ( this % link_libs ) if ( str_begins_with_str ( this % link_libs ( j )% s , this % link_libs ( i )% s ) . and . & str_ends_with ( this % link_libs ( j )% s , trim ( find_hl ( k )))) then found_hl ( k ) = . true . cycle finals end if end do end do finals ! For each of the missing ones, if there is a file, add it add_missing : do k = 1 , size ( find_hl ) if ( found_hl ( k )) cycle add_missing ! Build file name this_lib % s = join_path ( libdir , pref // this % link_libs ( i )% s // trim ( find_hl ( k )) // ext ) inquire ( file = this_lib % s , exist = found ) ! File exists, but it is not linked against if ( found ) this % link_libs = [ this % link_libs , & string_t ( this % link_libs ( i )% s // trim ( find_hl ( k )))] end do add_missing end if end do endif !> Add HDF5 modules as external this % has_external_modules = . true . this % external_modules = [ string_t ( 'h5a' ), & string_t ( 'h5d' ), & string_t ( 'h5es' ), & string_t ( 'h5e' ), & string_t ( 'h5f' ), & string_t ( 'h5g' ), & string_t ( 'h5i' ), & string_t ( 'h5l' ), & string_t ( 'h5o' ), & string_t ( 'h5p' ), & string_t ( 'h5r' ), & string_t ( 'h5s' ), & string_t ( 'h5t' ), & string_t ( 'h5vl' ), & string_t ( 'h5z' ), & string_t ( 'h5lt' ), & string_t ( 'h5lib' ), & string_t ( 'h5global' ), & string_t ( 'h5_gen' ), & string_t ( 'h5fortkit' ), & string_t ( 'hdf5' )] end subroutine init_hdf5","tags":"","url":"proc/init_hdf5.html"},{"title":"cmd_new – Fortran-lang/fpm","text":"public subroutine cmd_new(settings) TOP DIRECTORY NAME PROCESSING\nsee if requested new directory already exists and process appropriately\ntemporarily change to new directory as a test. NB: System dependent Arguments Type Intent Optional Attributes Name type( fpm_new_settings ), intent(in) :: settings Source Code subroutine cmd_new ( settings ) type ( fpm_new_settings ), intent ( in ) :: settings integer , parameter :: tfc = selected_char_kind ( 'DEFAULT' ) character ( len = :, kind = tfc ), allocatable :: bname ! baeename of NAME character ( len = :, kind = tfc ), allocatable :: tomlfile (:) character ( len = :, kind = tfc ), allocatable :: littlefile (:) !> TOP DIRECTORY NAME PROCESSING !> see if requested new directory already exists and process appropriately if ( exists ( settings % name ) . and . . not . settings % backfill ) then write ( stderr , '(*(g0,1x))' )& & '' , settings % name , 'already exists.' write ( stderr , '(*(g0,1x))' )& & ' perhaps you wanted to add --backfill ?' return elseif ( is_dir ( settings % name ) . and . settings % backfill ) then write ( * , '(*(g0))' ) 'backfilling ' , settings % name elseif ( exists ( settings % name ) ) then write ( stderr , '(*(g0,1x))' )& & '' , settings % name , 'already exists and is not a directory.' return else ! make new directory call mkdir ( settings % name ) endif !> temporarily change to new directory as a test. NB: System dependent call run ( 'cd ' // settings % name ) ! NOTE: need some system routines to handle filenames like \".\" ! like realpath() or getcwd(). bname = basename ( settings % name ) littlefile = [ character ( len = 80 ) :: '# ' // bname , 'My cool new project!' ] ! create NAME/README.md call warnwrite ( join_path ( settings % name , 'README.md' ), littlefile ) ! start building NAME/fpm.toml if ( settings % with_full ) then tomlfile = [ character ( len = 80 ) :: & & ' # This is your fpm(Fortran Package Manager) manifest file ' ,& & ' # (\"fpm.toml\"). It is heavily annotated to help guide you though ' ,& & ' # customizing a package build, although the defaults are sufficient ' ,& & ' # for many basic packages. ' ,& & ' # ' ,& & ' # The manifest file is not only used to provide metadata identifying ' ,& & ' # your project (so it can be used by others as a dependency). It can ' ,& & ' # specify where your library and program sources live, what the name ' ,& & ' # of the executable(s) will be, what files to build, dependencies on ' ,& & ' # other fpm packages, and what external libraries are required. ' ,& & ' # ' ,& & ' # The manifest format must conform to the TOML configuration file ' ,& & ' # standard. ' ,& & ' # ' ,& & ' # TOML files support flexible use of white-space and commenting of the ' ,& & ' # configuration data, but for clarity in this sample active directives ' ,& & ' # begin in column one. Inactive example directives are commented ' ,& & ' # out with a pound character (\"#\") but begin in column one as well. ' ,& & ' # Commentary begins with a pound character in column three. ' ,& & ' # ' ,& & ' # This file draws heavily upon the following references: ' ,& & ' # ' ,& & ' # The fpm home page at ' ,& & ' # https://github.com/fortran-lang/fpm ' ,& & ' # A complete list of keys and their attributes at ' ,& & ' # https://github.com/fortran-lang/fpm/blob/main/manifest-reference.md ' ,& & ' # examples of fpm project packaging at ' ,& & ' # https://github.com/fortran-lang/fpm/blob/main/PACKAGING.md ' ,& & ' # The Fortran TOML file interface and it''s references at ' ,& & ' # https://github.com/toml-f/toml-f ' ,& & ' # ' ,& & ' #----------------------- ' ,& & ' # project Identification ' ,& & ' #----------------------- ' ,& & ' # We begin with project metadata at the manifest root. This data is designed ' ,& & ' # to aid others when searching for the project in a repository and to ' ,& & ' # identify how and when to contact the package supporters. ' ,& & ' ' ,& & 'name = \"' // bname // '\"' ,& & ' # The project name (required) is how the project will be referred to. ' ,& & ' # The name is used by other packages using it as a dependency. It also ' ,& & ' # is used as the default name of any library built and the optional ' ,& & ' # default executable built from app/main.f90. It must conform to the rules ' ,& & ' # for a Fortran variable name. ' ,& & ' ' ,& & 'version = \"0.1.0\" ' ,& & ' # The project version number is a string. A recommended scheme for ' ,& & ' # specifying versions is the Semantic Versioning scheme. ' ,& & ' ' ,& & 'license = \"license\" ' ,& & ' # Licensing information specified using SPDX identifiers is preferred ' ,& & ' # (eg. \"Apache-2.0 OR MIT\" or \"LGPL-3.0-or-later\"). ' ,& & ' ' ,& & 'maintainer = \"jane.doe@example.com\" ' ,& & ' # Information on the project maintainer and means to reach out to them. ' ,& & ' ' ,& & 'author = \"Jane Doe\" ' ,& & ' # Information on the project author. ' ,& & ' ' ,& & 'copyright = \"Copyright 2020 Jane Doe\" ' ,& & ' # A statement clarifying the Copyright status of the project. ' ,& & ' ' ,& & '#description = \"A short project summary in plain text\" ' ,& & ' # The description provides a short summary on the project. It should be ' ,& & ' # plain text and not use any markup formatting. ' ,& & ' ' ,& & '#categories = [\"fortran\", \"graphics\"] ' ,& & ' # Categories associated with the project. Listing only one is preferred. ' ,& & ' ' ,& & '#keywords = [\"hdf5\", \"mpi\"] ' ,& & ' # The keywords field is an array of strings describing the project. ' ,& & ' ' ,& & '#homepage = \"https://stdlib.fortran-lang.org\" ' ,& & ' # URL to the webpage of the project. ' ,& & ' ' ,& & ' # ----------------------------------------- ' ,& & ' # We are done with identifying the project. ' ,& & ' # ----------------------------------------- ' ,& & ' # ' ,& & ' # Now lets start describing how the project should be built. ' ,& & ' # ' ,& & ' # Note tables would go here but we will not be talking about them (much)!!' ,& & ' # ' ,& & ' # Tables are a way to explicitly specify large numbers of programs in ' ,& & ' # a compact format instead of individual per-program entries in the ' ,& & ' # [[executable]], [[test]], and [[example]] sections to follow but ' ,& & ' # will not be discussed further except for the following notes: ' ,& & ' # ' ,& & ' # + Tables must appear (here) before any sections are declared. Once a ' ,& & ' # section is specified in a TOML file everything afterwards must be ' ,& & ' # values for that section or the beginning of a new section. A simple ' ,& & ' # example looks like: ' ,& & ' ' ,& & '#executable = [ ' ,& & '# { name = \"a-prog\" }, ' ,& & '# { name = \"app-tool\", source-dir = \"tool\" }, ' ,& & '# { name = \"fpm-man\", source-dir = \"tool\", main=\"fman.f90\" } ' ,& & '#] ' ,& & ' ' ,& & ' # This would be in lieue of the [[executable]] section found later in this ' ,& & ' # configuration file. ' ,& & ' # + See the reference documents (at the beginning of this document) ' ,& & ' # for more information on tables if you have long lists of programs ' ,& & ' # to build and are not simply depending on auto-detection. ' ,& & ' # ' ,& & ' # Now lets begin the TOML sections (lines beginning with \"[\") ... ' ,& & ' # ' ,& & ' ' ,& & '[install] # Options for the \"install\" subcommand ' ,& & ' ' ,& & ' # When you run the \"install\" subcommand only executables are installed by ' ,& & ' # default on the local system. Library projects that will be used outside of ' ,& & ' # \"fpm\" can set the \"library\" boolean to also allow installing the module ' ,& & ' # files and library archive. Without this being set to \"true\" an \"install\" ' ,& & ' # subcommand ignores parameters that specify library installation. ' ,& & ' ' ,& & ' # If your project sets `[library] type = \"shared\"`, enabling this option ' ,& & ' # will install the compiled `.so`, `.dylib`, or `.dll` files into the ' ,& & ' # appropriate `lib/` folder. This applies equally to static archives. ' ,& & ' # ' ,& & ' # For shared libraries, installing is typically required for runtime usage. ' ,& & ' ' ,& & 'library = false ' ,& & ' ' ,& & '[build] # General Build Options ' ,& & ' ' ,& & ' ### Automatic target discovery ' ,& & ' # ' ,& & ' # Normally fpm recursively searches the app/, example/, and test/ directories ' ,& & ' # for program sources and builds them. To disable this automatic discovery of ' ,& & ' # program targets set the following to \"false\": ' ,& & ' ' ,& & '#auto-executables = true ' ,& & '#auto-examples = true ' ,& & '#auto-tests = true ' ,& & ' ' ,& & ' ### Package-level External Library Links ' ,& & ' # ' ,& & ' # To declare link-time dependencies on external libraries a list of ' ,& & ' # native libraries can be specified with the \"link\" entry. You may ' ,& & ' # have one library name or a list of strings in case several ' ,& & ' # libraries should be linked. This list of library dependencies is ' ,& & ' # exported to dependent packages. You may have to alter your library ' ,& & ' # search-path to ensure the libraries can be accessed. Typically, ' ,& & ' # this is done with the LD_LIBRARY_PATH environment variable on ULS ' ,& & ' # (Unix-Like Systems). You only specify the core name of the library ' ,& & ' # (as is typical with most programming environments, where you ' ,& & ' # would specify \"-lz\" on your load command to link against the zlib ' ,& & ' # compression library even though the library file would typically be ' ,& & ' # a file called \"libz.a\" \"or libz.so\"). So to link against that library ' ,& & ' # you would specify: ' ,& & ' ' ,& & '#link = \"z\" ' ,& & ' ' ,& & ' # Note that in some cases the order of the libraries matters: ' ,& & ' ' ,& & '#link = [\"blas\", \"lapack\"] ' ,& & '' ] endif if ( settings % with_bare ) then elseif ( settings % with_lib ) then call mkdir ( join_path ( settings % name , 'src' ) ) ! create next section of fpm.toml if ( settings % with_full ) then tomlfile = [ character ( len = 80 ) :: tomlfile , & & '[library] ' ,& & ' ' ,& & ' # You can change the name of the directory to search for your library ' ,& & ' # source from the default of \"src/\". Library targets are exported ' ,& & ' # and usable by other projects. ' ,& & ' ' ,& & 'source-dir=\"src\" ' ,& & ' ' ,& & ' # this can be a list: ' ,& & ' ' ,& & '#source-dir=[\"src\", \"src2\"] ' ,& & ' ' ,& & ' # More complex libraries may organize their modules in subdirectories. ' ,& & ' # For modules in a top-level directory fpm requires (but does not ' ,& & ' # enforce) that: ' ,& & ' # ' ,& & ' # + The module has the same name as the source file. This is important. ' ,& & ' # + There should be only one module per file. ' ,& & ' # ' ,& & ' # These two requirements simplify the build process for fpm. As Fortran ' ,& & ' # compilers emit module files (.mod) with the same name as the module ' ,& & ' # itself (but not the source file, .f90), naming the module the same ' ,& & ' # as the source file allows fpm to: ' ,& & ' # ' ,& & ' # + Uniquely and exactly map a source file (.f90) to its object (.o) ' ,& & ' # and module (.mod) files. ' ,& & ' # + Avoid conflicts with modules of the same name that could appear ' ,& & ' # in dependency packages. ' ,& & ' # ' ,& & ' ### Multi-level library source ' ,& & ' # You can place your module source files in any number of levels of ' ,& & ' # subdirectories inside your source directory, but there are certain naming ' ,& & ' # conventions to be followed -- module names must contain the path components ' ,& & ' # of the directory that its source file is in. ' ,& & ' # ' ,& & ' # This rule applies generally to any number of nested directories and ' ,& & ' # modules. For example, src/a/b/c/d.f90 must define a module called a_b_c_d. ' ,& & ' # Again, this is not enforced but may be required in future releases. ' ,& & ' ' ,& & ' ### Library type ' ,& & ' # Set `type = \"shared\"` to build dynamic libraries (.so/.dylib/.dll) ' ,& & ' # instead of a static archive. You can also set `type = \"static\"` to ' ,& & ' # generate per-package archives, or use `type = \"monolithic\"` (default) ' ,& & ' # to bundle all sources and dependencies into a single archive. ' ,& & ' # ' ,& & ' # Supported types: ' ,& & ' # ' ,& & ' # + \"monolithic\": Single archive with used sources and dependencies. ' ,& & ' # + \"static\": One full archive per package (for external integration). ' ,& & ' # + \"shared\": One shared library per package, for dynamic linking. ' ,& & ' # ' ,& & ' # Shared libraries are useful for plugin systems, dynamic linking, or ' ,& & ' # language bindings. Static per-package archives may aid external reuse. ' ,& & ' # ' ,& & ' # When running with `fpm run`, shared library paths are automatically ' ,& & ' # added to the environment (e.g. `LD_LIBRARY_PATH`, `PATH`) at runtime. ' ,& & ' # ' ,& & ' # Note: library files are not installed unless `[install] library=true` ' ,& & ' # is also enabled. ' ,& & ' # ' ,& & ' # Example: ' ,& & ' ' ,& & 'type = \"shared\" ' ,& & ' ' ,& & '' ] endif ! create placeholder module src/bname.f90 littlefile = [ character ( len = 80 ) :: & & 'module ' // to_fortran_name ( bname ), & & ' implicit none' , & & ' private' , & & '' , & & ' public :: say_hello' , & & 'contains' , & & ' subroutine say_hello' , & & ' print *, \"Hello, ' // bname // '!\"' , & & ' end subroutine say_hello' , & & 'end module ' // to_fortran_name ( bname )] ! create NAME/src/NAME.f90 call warnwrite ( join_path ( settings % name , 'src' , bname // '.f90' ),& & littlefile ) endif if ( settings % with_full ) then tomlfile = [ character ( len = 80 ) :: tomlfile ,& & '[dependencies] ' ,& & ' ' ,& & ' # Inevitably, you will want to be able to include other packages in ' ,& & ' # a project. Fpm makes this incredibly simple, by taking care of ' ,& & ' # fetching and compiling your dependencies for you. You just tell it ' ,& & ' # what your dependencies names are, and where to find them. ' ,& & ' # ' ,& & ' # If you are going to distribute your package only place dependencies ' ,& & ' # here someone using your package as a remote dependency needs built. ' ,& & ' # You can define dependencies just for developer executables in the ' ,& & ' # next section, or even for specific executables as we will see below ' ,& & ' # (Then fpm will still fetch and compile it when building your ' ,& & ' # developer executables, but users of your library will not have to). ' ,& & ' # ' ,& & ' ## GLOBAL DEPENDENCIES (exported with your project) ' ,& & ' # ' ,& & ' # Typically, dependencies are defined by specifying the project''s ' ,& & ' # git repository. ' ,& & ' # ' ,& & ' # You can be specific about which version of a dependency you would ' ,& & ' # like. By default the latest default branch is used. You can ' ,& & ' # optionally specify a branch, a tag or a commit value. ' ,& & ' # ' ,& & ' # So here are several alternates for specifying a remote dependency (you ' ,& & ' # can have at most one of \"branch\", \"rev\" or \"tag\" present): ' ,& & ' ' ,& & '#stdlib = { git = \"https://github.com/LKedward/stdlib-fpm.git\" } ' ,& & '#stdlib = {git=\"https://github.com/LKedward/stdlib-fpm.git\",branch = \"master\" },' ,& & '#stdlib = {git=\"https://github.com/LKedward/stdlib-fpm.git\", tag = \"v0.1.0\" }, ' ,& & '#stdlib = {git=\"https://github.com/LKedward/stdlib-fpm.git\", rev = \"5a9b7a8\" }. ' ,& & ' ' ,& & ' # There may be multiple packages listed: ' ,& & ' ' ,& & '#M_strings = { git = \"https://github.com/urbanjost/M_strings.git\" } ' ,& & '#M_time = { git = \"https://github.com/urbanjost/M_time.git\" } ' ,& & ' ' ,& & ' # ' ,& & ' # You can even specify the local path to another project if it is in ' ,& & ' # a sub-folder (If for example you have got another fpm package **in ' ,& & ' # the same repository**) like this: ' ,& & ' ' ,& & '#M_strings = { path = \"M_strings\" } ' ,& & ' ' ,& & ' # This tells fpm that we depend on a crate called M_strings which is found ' ,& & ' # in the M_strings folder (relative to the fpm.toml it’s written in). ' ,& & ' # ' ,& & ' # For a more verbose layout use normal tables rather than inline tables ' ,& & ' # to specify dependencies: ' ,& & ' ' ,& & '#[dependencies.toml-f] ' ,& & '#git = \"https://github.com/toml-f/toml-f\" ' ,& & '#rev = \"2f5eaba864ff630ba0c3791126a3f811b6e437f3\" ' ,& & ' ' ,& & ' # Now you can use any modules from these libraries anywhere in your ' ,& & ' # code -- whether is in your library source or a program source. ' ,& & ' ' ,& & '[dev-dependencies] ' ,& & ' ' ,& & ' ## Dependencies Only for Development ' ,& & ' # ' ,& & ' # You can specify dependencies your library or application does not ' ,& & ' # depend on in a similar way. The difference is that these will not ' ,& & ' # be exported as part of your project to those using it as a remote ' ,& & ' # dependency. ' ,& & ' # ' ,& & ' # Currently, like a global dependency it will still be available for ' ,& & ' # all codes. It is up to the developer to ensure that nothing except ' ,& & ' # developer test programs rely upon it. ' ,& & ' ' ,& & '#M_msg = { git = \"https://github.com/urbanjost/M_msg.git\" } ' ,& & '#M_verify = { git = \"https://github.com/urbanjost/M_verify.git\" } ' ,& & '' ] endif if ( settings % with_bare ) then elseif ( settings % with_executable ) then ! create next section of fpm.toml call mkdir ( join_path ( settings % name , 'app' )) ! create NAME/app or stop if ( settings % with_full ) then tomlfile = [ character ( len = 80 ) :: tomlfile , & & ' #----------------------------------- ' ,& & ' ## Application-specific declarations ' ,& & ' #----------------------------------- ' ,& & ' # Now lets begin entries for the TOML tables (lines beginning with \"[[\") ' ,& & ' # that describe the program sources -- applications, tests, and examples. ' ,& & ' # ' ,& & ' # First we will configuration individual applications run with \"fpm run\". ' ,& & ' # ' ,& & ' # + the \"name\" entry for the executable to be built must always ' ,& & ' # be specified. The name must satisfy the rules for a Fortran ' ,& & ' # variable name. This will be the name of the binary installed by ' ,& & ' # the \"install\" subcommand and used on the \"run\" subcommand. ' ,& & ' # + The source directory for each executable can be adjusted by the ' ,& & ' # \"source-dir\" entry. ' ,& & ' # + The basename of the source file containing the program body can ' ,& & ' # be specified with the \"main\" entry. ' ,& & ' # + Executables can also specify their own external package and ' ,& & ' # library link dependencies. ' ,& & ' # ' ,& & ' # Currently, like a global dependency any external package dependency ' ,& & ' # will be available for all codes. It is up to the developer to ensure ' ,& & ' # that nothing except the application programs specified rely upon it. ' ,& & ' # ' ,& & ' # Note if your application needs to use a module internally, but you do not ' ,& & ' # intend to build it as a library to be used in other projects, you can ' ,& & ' # include the module in your program source file or directory as well. ' ,& & ' ' ,& & '[[executable]] ' ,& & 'name=\"' // bname // '\"' ,& & 'source-dir=\"app\" ' ,& & 'main=\"main.f90\" ' ,& & ' ' ,& & ' # You may repeat this pattern to define additional applications. For instance,' ,& & ' # the following sample illustrates all accepted options, where \"link\" and ' ,& & ' # \"executable.dependencies\" keys are the same as the global external library ' ,& & ' # links and package dependencies described previously except they apply ' ,& & ' # only to this executable: ' ,& & ' ' ,& & '#[[ executable ]] ' ,& & '#name = \"app-name\" ' ,& & '#source-dir = \"prog\" ' ,& & '#main = \"program.f90\" ' ,& & '#link = \"z\" ' ,& & '#[executable.dependencies] ' ,& & '#M_CLI = { git = \"https://github.com/urbanjost/M_CLI.git\" } ' ,& & '#helloff = { git = \"https://gitlab.com/everythingfunctional/helloff.git\" } ' ,& & '#M_path = { git = \"https://github.com/urbanjost/M_path.git\" } ' ,& & '' ] endif if ( exists ( bname // '/src/' )) then littlefile = [ character ( len = 80 ) :: & & 'program main' , & & ' use ' // to_fortran_name ( bname ) // ', only: say_hello' , & & ' implicit none' , & & '' , & & ' call say_hello()' , & & 'end program main' ] else littlefile = [ character ( len = 80 ) :: & & 'program main' , & & ' implicit none' , & & '' , & & ' print *, \"hello from project ' // bname // '\"' , & & 'end program main' ] endif call warnwrite ( join_path ( settings % name , 'app/main.f90' ), littlefile ) endif if ( settings % with_bare ) then elseif ( settings % with_test ) then ! create NAME/test or stop call mkdir ( join_path ( settings % name , 'test' )) ! create next section of fpm.toml if ( settings % with_full ) then tomlfile = [ character ( len = 80 ) :: tomlfile ,& & '[[test]] ' ,& & ' ' ,& & ' # The same declarations can be made for test programs, which are ' ,& & ' # executed with the \"fpm test\" command and are not build when your ' ,& & ' # package is used as a dependency by other packages. These are ' ,& & ' # typically unit tests of the package only used during package ' ,& & ' # development. ' ,& & ' ' ,& & 'name=\"runTests\" ' ,& & 'source-dir=\"test\" ' ,& & 'main=\"check.f90\" ' ,& & ' ' ,& & ' # you may repeat this pattern to add additional explicit test program ' ,& & ' # parameters. The following example contains a sample of all accepted ' ,& & ' # options. ' ,& & ' ' ,& & '#[[ test ]] ' ,& & '#name = \"tester\" ' ,& & '#source-dir=\"test\" ' ,& & '#main=\"tester.f90\" ' ,& & '#link = [\"blas\", \"lapack\"] ' ,& & '#[test.dependencies] ' ,& & '#M_CLI2 = { git = \"https://github.com/urbanjost/M_CLI2.git\" } ' ,& & '#M_io = { git = \"https://github.com/urbanjost/M_io.git\" } ' ,& & '#M_system= { git = \"https://github.com/urbanjost/M_system.git\" } ' ,& & '' ] endif littlefile = [ character ( len = 80 ) :: & & 'program check' , & & 'implicit none' , & & '' , & & 'print *, \"Put some tests in here!\"' , & & 'end program check' ] ! create NAME/test/check.f90 call warnwrite ( join_path ( settings % name , 'test/check.f90' ), littlefile ) endif if ( settings % with_bare ) then elseif ( settings % with_example ) then ! create NAME/example or stop call mkdir ( join_path ( settings % name , 'example' )) ! create next section of fpm.toml if ( settings % with_full ) then tomlfile = [ character ( len = 80 ) :: tomlfile , & & '[[example]] ' ,& & ' ' ,& & ' # Example applications for a project are defined here. ' ,& & ' # These are run via \"fpm run --example NAME\" and like the ' ,& & ' # test applications, are not built when this package is used as a ' ,& & ' # dependency by other packages. ' ,& & ' ' ,& & 'name=\"demo\" ' ,& & 'source-dir=\"example\" ' ,& & 'main=\"demo.f90\" ' ,& & ' ' ,& & ' # ' ,& & ' # you may add additional programs to the example table. The following ' ,& & ' # example contains a sample of all accepted options ' ,& & ' ' ,& & '#[[ example ]] ' ,& & '#name = \"example-tool\" ' ,& & '#source-dir=\"example\" ' ,& & '#main=\"tool.f90\" ' ,& & '#link = \"z\" ' ,& & '#[example.dependencies] ' ,& & '#M_kracken95 = { git = \"https://github.com/urbanjost/M_kracken95.git\" } ' ,& & '#datetime = {git = \"https://github.com/wavebitscientific/datetime-fortran.git\" }' ,& & '' ] endif littlefile = [ character ( len = 80 ) :: & & 'program demo' , & & 'implicit none' , & & '' , & & 'print *, \"Put some examples in here!\"' , & & 'end program demo' ] ! create NAME/example/demo.f90 call warnwrite ( join_path ( settings % name , 'example/demo.f90' ), littlefile ) endif ! now that built it write NAME/fpm.toml if ( allocated ( tomlfile ) ) then call validate_toml_data ( tomlfile ) call warnwrite ( join_path ( settings % name , 'fpm.toml' ), tomlfile ) else call create_verified_basic_manifest ( join_path ( settings % name , 'fpm.toml' )) endif ! assumes git(1) is installed and in path if ( which ( 'git' ) /= '' ) then call run ( 'git init ' // settings % name ) endif contains function git_metadata ( what ) result ( returned ) !> get metadata values such as email address and git name from git(1) or return appropriate default use fpm_filesystem , only : get_temp_filename , getline character ( len =* ), intent ( in ) :: what ! keyword designating what git metatdata to query character ( len = :), allocatable :: returned ! value to return for requested keyword character ( len = :), allocatable :: command character ( len = :), allocatable :: temp_filename character ( len = :), allocatable :: iomsg character ( len = :), allocatable :: temp_value integer :: stat , unit temp_filename = get_temp_filename () ! for known keywords set default value for RETURNED and associated git(1) command for query select case ( what ) case ( 'uname' ) returned = \"Jane Doe\" command = \"git config --get user.name > \" // temp_filename case ( 'email' ) returned = \"jane.doe@example.com\" command = \"git config --get user.email > \" // temp_filename case default write ( stderr , '(*(g0,1x))' )& & ' *git_metadata* unknown metadata name ' , trim ( what ) returned = '' return end select ! Execute command if git(1) is in command path if ( which ( 'git' ) /= '' ) then call run ( command , exitstat = stat ) if ( stat /= 0 ) then ! If command failed just return default return else ! Command did not return an error so try to read expected output file open ( file = temp_filename , newunit = unit , iostat = stat ) if ( stat == 0 ) then ! Read file into a scratch variable until status of doing so is checked call getline ( unit , temp_value , stat , iomsg ) if ( stat == 0 . and . temp_value /= '' ) then ! Return output from successful command returned = temp_value endif endif ! Always do the CLOSE because a failed open has unpredictable results. ! Add IOSTAT so a failed close does not cause program to stop close ( unit , status = \"delete\" , iostat = stat ) endif endif end function git_metadata subroutine create_verified_basic_manifest ( filename ) !> create a basic but verified default manifest file use tomlf , only : toml_table , toml_serialize use fpm_toml , only : set_value use fpm_manifest_package , only : package_config_t , new_package use fpm_error , only : error_t implicit none character ( len =* ), intent ( in ) :: filename type ( toml_table ) :: table type ( package_config_t ) :: package type ( error_t ), allocatable :: error integer :: lun character ( len = 8 ) :: date character (:), allocatable :: output if ( exists ( filename )) then write ( stderr , '(*(g0,1x))' ) ' ' , filename ,& & 'already exists. Not overwriting' return endif !> get date to put into metadata in manifest file \"fpm.toml\" call date_and_time ( DATE = date ) table = toml_table () call fileopen ( filename , lun ) ! fileopen stops on error call set_value ( table , \"name\" , BNAME ) call set_value ( table , \"version\" , \"0.1.0\" ) call set_value ( table , \"license\" , \"license\" ) call set_value ( table , \"author\" , git_metadata ( 'uname' )) call set_value ( table , \"maintainer\" , git_metadata ( 'email' )) call set_value ( table , \"copyright\" , 'Copyright ' // date ( 1 : 4 ) // ', ' // git_metadata ( 'uname' )) ! continue building of manifest ! ... call new_package ( package , table , error = error ) if ( allocated ( error )) call fpm_stop ( 3 , '' ) output = toml_serialize ( table ) if ( settings % verbose ) then print '(a)' , output endif write ( lun , '(a)' ) output call fileclose ( lun ) ! fileopen stops on error end subroutine create_verified_basic_manifest subroutine validate_toml_data ( input ) !> verify a string array is a valid fpm.toml file ! use tomlf , only : toml_table , toml_load , toml_serialize implicit none character ( kind = tfc , len = :), intent ( in ), allocatable :: input (:) character ( len = 1 ), parameter :: nl = new_line ( 'a' ) type ( toml_table ), allocatable :: table character ( kind = tfc , len = :), allocatable :: joined_string ! you have to add a newline character by using the intrinsic ! function `new_line(\"a\")` to get the lines processed correctly. joined_string = join ( input , right = nl ) if ( allocated ( table )) deallocate ( table ) call toml_load ( table , joined_string ) if ( allocated ( table )) then if ( settings % verbose ) then ! If the TOML file is successfully parsed the table will be allocated and ! can be written by `toml_serialize` to the standard output print '(a)' , toml_serialize ( table ) endif call table % destroy endif end subroutine validate_toml_data end subroutine cmd_new","tags":"","url":"proc/cmd_new.html"},{"title":"new_library – Fortran-lang/fpm","text":"public subroutine new_library(self, table, error) Construct a new library configuration from a TOML data structure Arguments Type Intent Optional Attributes Name type( library_config_t ), intent(out) :: self Instance of the library configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling Source Code subroutine new_library ( self , table , error ) !> Instance of the library configuration type ( library_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: stat call check ( table , error ) if ( allocated ( error )) return if ( has_list ( table , \"source-dir\" )) then call syntax_error ( error , \"Manifest key [library.source-dir] does not allow list input\" ) return end if if ( has_list ( table , \"type\" )) then call syntax_error ( error , \"Manifest key [library.type] does not allow list input\" ) return end if call get_value ( table , \"source-dir\" , self % source_dir , \"src\" ) call get_value ( table , \"build-script\" , self % build_script ) call get_list ( table , \"include-dir\" , self % include_dir , error ) if ( allocated ( error )) return call get_value ( table , \"type\" , self % lib_type , \"monolithic\" ) select case ( self % lib_type ) case ( \"shared\" , \"static\" , \"monolithic\" ) ! OK case default call fatal_error ( error , \"Value of library.type cannot be '\" // self % lib_type & // \"', choose shared/static/monolithic (default)\" ) return end select ! Set default value of include-dir if not found in manifest if (. not . allocated ( self % include_dir )) then self % include_dir = [ string_t ( \"include\" )] end if if (. not . allocated ( self % lib_type )) then self % lib_type = \"monolithic\" end if end subroutine new_library","tags":"","url":"proc/new_library.html"},{"title":"fpm_model – Fortran-lang/fpm","text":"The fpm package model Defines the fpm model data types which encapsulate all information\n required to correctly build a package and its dependencies. The process (see [[build_model(subroutine)]] ) for generating a valid [[fpm_model]] involves\n source files discovery ( fpm_sources ) and parsing ( fpm_source_parsing ). Once a valid [[fpm_model]] has been constructed, it may be passed to [[fpm_targets:targets_from_sources]] to\n generate a list of build targets for the backend. Enumerations Source type: FPM_UNIT_* Describes the type of source file — determines build target generation The logical order of precedence for assigning unit_type is as follows: if source - file contains program then unit_type = FPM_UNIT_PROGRAM else if source - file contains non - module subroutine / function then unit_type = FPM_UNIT_SUBPROGRAM else if source - file contains submodule then unit_type = FPM_UNIT_SUBMODULE else if source - file contains module then unit_type = FPM_UNIT_MODULE end if @note Note\n A source file is only designated FPM_UNIT_MODULE if it only contains modules - no non-module subprograms.\n (This allows tree-shaking/pruning of build targets based on unused module dependencies.) Source scope: FPM_SCOPE_* Describes the scoping rules for using modules — controls module dependency resolution Uses fpm_toml fpm_dependency tomlf fpm_error fpm_manifest_preprocess fpm_strings fpm_compiler iso_fortran_env fpm_environment Variables Type Visibility Attributes Name Initial integer, public, parameter :: FPM_SCOPE_APP = 3 Module-use scope is library/dependency and app modules integer, public, parameter :: FPM_SCOPE_DEP = 2 Module-use scope is library/dependency modules only integer, public, parameter :: FPM_SCOPE_EXAMPLE = 5 integer, public, parameter :: FPM_SCOPE_LIB = 1 Module-use scope is library/dependency modules only integer, public, parameter :: FPM_SCOPE_TEST = 4 Module-use scope is library/dependency and test modules integer, public, parameter :: FPM_SCOPE_UNKNOWN = -1 Source has no module-use scope integer, public, parameter :: FPM_UNIT_CHEADER = 6 Source type is c header file integer, public, parameter :: FPM_UNIT_CPPSOURCE = 7 Souce type is c++ source file. integer, public, parameter :: FPM_UNIT_CSOURCE = 5 Source type is c source file integer, public, parameter :: FPM_UNIT_MODULE = 2 Source only contains one or more fortran modules integer, public, parameter :: FPM_UNIT_PROGRAM = 1 Source contains a fortran program integer, public, parameter :: FPM_UNIT_SUBMODULE = 3 Source contains one or more fortran submodules integer, public, parameter :: FPM_UNIT_SUBPROGRAM = 4 Source contains one or more fortran subprogram not within modules integer, public, parameter :: FPM_UNIT_UNKNOWN = -1 Source type unknown Derived Types type, public, extends( serializable_t ) :: fortran_features_t Enabled Fortran language features Components Type Visibility Attributes Name Initial logical, public :: implicit_external = .false. Use implicit external interface logical, public :: implicit_typing = .false. Use default implicit typing character(len=:), public, allocatable :: source_form Form to use for all Fortran sources Type-Bound Procedures generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit procedure, public :: dump_to_toml => fft_dump_to_toml generic, public :: load => load_from_toml , load_from_file, load_from_unit procedure, public :: load_from_toml => fft_load_from_toml generic, public :: operator(==) => serializable_is_same procedure, public :: serializable_is_same => fft_is_same Serialization interface procedure, public, non_overridable :: test_serialization Test load/write roundtrip type, public, extends( serializable_t ) :: fpm_model_t Type describing everything required to build\n the root package and its dependencies. Components Type Visibility Attributes Name Initial type( archiver_t ), public :: archiver Archiver object character(len=:), public, allocatable :: build_prefix Base directory for build character(len=:), public, allocatable :: c_compile_flags Command line flags passed to C for compilation type( compiler_t ), public :: compiler Compiler object character(len=:), public, allocatable :: cxx_compile_flags Command line flags passed to C++ for compilation type( dependency_tree_t ), public :: deps Project dependencies logical, public :: enforce_module_names = .false. Whether module names should be prefixed with the package name type( string_t ), public, allocatable :: external_modules (:) External modules used character(len=:), public, allocatable :: fortran_compile_flags Command line flags passed to fortran for compilation type( string_t ), public, allocatable :: include_dirs (:) Include directories logical, public :: include_tests = .true. Whether tests should be added to the build list character(len=:), public, allocatable :: link_flags Command line flags passed to the linker type( string_t ), public, allocatable :: link_libraries (:) Native libraries to link against type( string_t ), public :: module_prefix Prefix for all module names character(len=:), public, allocatable :: package_name Name of root package type( package_t ), public, allocatable :: packages (:) Array of packages (including the root package) Type-Bound Procedures generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit procedure, public :: dump_to_toml => model_dump_to_toml procedure, public :: get_package_libraries_link Get target link flags generic, public :: load => load_from_toml , load_from_file, load_from_unit procedure, public :: load_from_toml => model_load_from_toml generic, public :: operator(==) => serializable_is_same procedure, public :: serializable_is_same => model_is_same Serialization interface procedure, public, non_overridable :: test_serialization Test load/write roundtrip type, public, extends( serializable_t ) :: package_t Type for describing a single package Components Type Visibility Attributes Name Initial logical, public :: enforce_module_names = .false. Module naming conventions type( fortran_features_t ), public :: features Language features type( string_t ), public :: module_prefix Prefix for all module names character(len=:), public, allocatable :: name Name of package type( preprocess_config_t ), public :: preprocess List of macros. type( srcfile_t ), public, allocatable :: sources (:) Array of sources character(len=:), public, allocatable :: version Package version number. Type-Bound Procedures generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit procedure, public :: dump_to_toml => package_dump_to_toml procedure, public :: has_library => package_has_library Check if a package will create a library generic, public :: load => load_from_toml , load_from_file, load_from_unit procedure, public :: load_from_toml => package_load_from_toml generic, public :: operator(==) => serializable_is_same procedure, public :: serializable_is_same => package_is_same Serialization interface procedure, public, non_overridable :: test_serialization Test load/write roundtrip type, public, extends( serializable_t ) :: srcfile_t Type for describing a source file Components Type Visibility Attributes Name Initial integer(kind=int64), public :: digest Current hash character(len=:), public, allocatable :: exe_name Name of executable for FPM_UNIT_PROGRAM character(len=:), public, allocatable :: file_name File path relative to cwd type( string_t ), public, allocatable :: include_dependencies (:) Files INCLUDEd by this source file type( string_t ), public, allocatable :: link_libraries (:) Native libraries to link against type( string_t ), public, allocatable :: modules_provided (:) Modules provided by this source file (lowerstring) type( string_t ), public, allocatable :: modules_used (:) Modules USEd by this source file (lowerstring) type( string_t ), public, allocatable :: parent_modules (:) Parent modules (submodules only) integer, public :: unit_scope = FPM_SCOPE_UNKNOWN Target module-use scope integer, public :: unit_type = FPM_UNIT_UNKNOWN Type of source unit Type-Bound Procedures generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit procedure, public :: dump_to_toml => srcfile_dump_to_toml generic, public :: load => load_from_toml , load_from_file, load_from_unit procedure, public :: load_from_toml => srcfile_load_from_toml generic, public :: operator(==) => serializable_is_same procedure, public :: serializable_is_same => srcfile_is_same Serialization interface procedure, public, non_overridable :: test_serialization Test load/write roundtrip Functions public function FPM_SCOPE_NAME (flag) result(name) Return the character name of a scope flag Arguments Type Intent Optional Attributes Name integer, intent(in) :: flag Return Value character(len=:), allocatable public function FPM_UNIT_NAME (flag) result(name) Return the character name of a unit flag Arguments Type Intent Optional Attributes Name integer, intent(in) :: flag Return Value character(len=:), allocatable Subroutines public subroutine show_model (model) Arguments Type Intent Optional Attributes Name type( fpm_model_t ), intent(in) :: model","tags":"","url":"module/fpm_model.html"},{"title":"fpm_environment – Fortran-lang/fpm","text":"This module contains procedures that interact with the programming environment. [get_os_type] – Determine the OS type [get_env] – return the value of an environment variable Uses iso_c_binding fpm_error iso_fortran_env Variables Type Visibility Attributes Name Initial integer, public, parameter :: OS_CYGWIN = 4 integer, public, parameter :: OS_FREEBSD = 6 integer, public, parameter :: OS_LINUX = 1 integer, public, parameter :: OS_MACOS = 2 integer, public, parameter :: OS_OPENBSD = 7 integer, public, parameter :: OS_SOLARIS = 5 integer, public, parameter :: OS_UNKNOWN = 0 integer, public, parameter :: OS_WINDOWS = 3 Functions public pure function OS_NAME (os) Return string describing the OS type flag Arguments Type Intent Optional Attributes Name integer, intent(in) :: os Return Value character(len=:), allocatable public function delete_env (name) result(success) Deletes an environment variable for the current environment using the C standard library\nReturns an error if the variable did not exist in the first place Read more… Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: name Variable name Return Value logical public function get_command_arguments_quoted () result(args) Arguments None Return Value character(len=:), allocatable public function get_env (NAME, DEFAULT) result(VALUE) get named environment variable value. It it is blank or\n not set return the optional default value\n!print , NAME, ” is not defined in the environment. Strange…”\n!print , “This processor doesn’t support environment variables. Boooh!” Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: NAME name of environment variable to get the value of character(len=*), intent(in), optional :: DEFAULT default value to return if the requested value is undefined or blank Return Value character(len=:), allocatable the returned value public function get_os_type () result(r) Determine the OS type Read more… Arguments None Return Value integer public pure function library_filename (package_name, shared, import, target_os) result(name) Utility function: return library filename Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: package_name logical, intent(in) :: shared Whether it’s a shared library logical, intent(in) :: import Whether it’s for linking (import library) or actual library integer, intent(in) :: target_os Build target OS: one of OS_WINDOWS, OS_MACOS, … Return Value character(len=:), allocatable public function os_is_unix (os) Compare the output of get_os_type or the optional\npassed INTEGER value to the value for OS_WINDOWS\nand return .TRUE. if they match and .FALSE. otherwise Arguments Type Intent Optional Attributes Name integer, intent(in), optional :: os Return Value logical public function separator () result(sep) sample usage Read more… Arguments None Return Value character(len=1) ifort_bug*!character(len=1),save :: sep_cache=’ ‘ public function set_env (name, value, overwrite) Set an environment variable for the current environment using the C standard library Read more… Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: name Variable name character(len=*), intent(in) :: value Variable value logical, intent(in), optional :: overwrite Should a former value be overwritten? default = .true. Return Value logical","tags":"","url":"module/fpm_environment.html"},{"title":"fpm_meta_blas – Fortran-lang/fpm","text":"Uses fpm_pkg_config fpm_error fpm_meta_util fpm_environment fpm_compiler fpm_strings fpm_meta_base fpm_manifest_metapackages Subroutines public subroutine init_blas (this, compiler, all_meta, error) Initialize blas metapackage for the current system\nCleanup\nSet name Read more… Arguments Type Intent Optional Attributes Name class( metapackage_t ), intent(inout) :: this type( compiler_t ), intent(in) :: compiler type( metapackage_request_t ), intent(in) :: all_meta (:) type( error_t ), intent(out), allocatable :: error","tags":"","url":"module/fpm_meta_blas.html"},{"title":"fpm_pkg_config – Fortran-lang/fpm","text":"The fpm interface to pkg-config This module contains wrapper functions to interface with a pkg-config installation. Uses fpm_error fpm_environment fpm_strings shlex_module fpm_filesystem Functions public function assert_pkg_config () Check whether pkg-config is available on the local system Arguments None Return Value logical public function pkgcfg_get_build_flags (name, allow_system, error) result(flags) Get build flags (option to include flags from system directories, that \ngfortran does not look into by default) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: name Package name logical, intent(in) :: allow_system Should pkg-config look in system paths? This is necessary for gfortran \nthat doesn’t otherwise look into them type( error_t ), intent(out), allocatable :: error Error flag Return Value type( string_t ), allocatable, (:) List of compile flags public function pkgcfg_get_libs (package, error) result(libraries) Get package libraries from pkg-config Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: package Package name type( error_t ), intent(out), allocatable :: error Error handler Return Value type( string_t ), allocatable, (:) A list of libraries public function pkgcfg_get_version (package, error) result(screen) Get package version from pkg-config Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: package Package name type( error_t ), intent(out), allocatable :: error Error handler Return Value type( string_t ) public function pkgcfg_has_package (name) result(success) Check if pkgcfg has package Read more… Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: name Package name Return Value logical public function pkgcfg_list_all (error, descriptions) result(modules) Return whole list of available pkg-cfg packages Read more… Arguments Type Intent Optional Attributes Name type( error_t ), intent(out), allocatable :: error Error handler type( string_t ), intent(out), optional, allocatable :: descriptions (:) An optional list of package descriptions Return Value type( string_t ), allocatable, (:) A list of all available packages Subroutines public subroutine run_wrapper (wrapper, args, verbose, exitcode, cmd_success, screen_output) Simple call to execute_command_line involving one mpi* wrapper Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: wrapper type( string_t ), intent(in), optional :: args (:) logical, intent(in), optional :: verbose integer, intent(out), optional :: exitcode logical, intent(out), optional :: cmd_success type( string_t ), intent(out), optional :: screen_output","tags":"","url":"module/fpm_pkg_config.html"},{"title":"fpm_backend_console – Fortran-lang/fpm","text":"Build Backend Console This module provides a lightweight implementation for printing to the console\n and updating previously-printed console lines. It used by [[fpm_backend_output]] for pretty-printing build status and progress. @note Note\n The implementation for updating previous lines relies on no other output\n going to stdout / stderr except through the console_t object provided. @note Note\n All write statements to stdout are enclosed within OpenMP critical regions Uses iso_fortran_env Variables Type Visibility Attributes Name Initial character(len=*), public, parameter :: COLOR_GREEN = ESC//\"[32m\" Escape code for green foreground color character(len=*), public, parameter :: COLOR_RED = ESC//\"[31m\" Escape code for red foreground color character(len=*), public, parameter :: COLOR_RESET = ESC//\"[0m\" Escape code to reset foreground color character(len=*), public, parameter :: COLOR_YELLOW = ESC//\"[93m\" Escape code for yellow foreground color character(len=*), public, parameter :: LINE_RESET = ESC//\"[2K\"//ESC//\"[1G\" Escape code for erasing current line Derived Types type, public :: console_t Console object Components Type Visibility Attributes Name Initial integer, public :: n_line = 1 Number of lines printed Type-Bound Procedures procedure, public :: update_line => console_update_line Update a previously-written console line procedure, public :: write_line => console_write_line Write a single line to the console","tags":"","url":"module/fpm_backend_console.html"},{"title":"fpm_meta_mpi – Fortran-lang/fpm","text":"Uses fpm_versioning fpm_pkg_config fpm_os fpm_error fpm_compiler fpm_strings fpm_environment shlex_module fpm_manifest_metapackages fpm_filesystem fpm_meta_base Functions public pure function MPI_TYPE_NAME (mpilib) result(name) Return a name for the MPI library Arguments Type Intent Optional Attributes Name integer, intent(in) :: mpilib Return Value character(len=:), allocatable Subroutines public subroutine init_mpi (this, compiler, all_meta, error) Initialize MPI metapackage for the current system\nCleanup Read more… Arguments Type Intent Optional Attributes Name class( metapackage_t ), intent(inout) :: this type( compiler_t ), intent(in) :: compiler type( metapackage_request_t ), intent(in) :: all_meta (:) type( error_t ), intent(out), allocatable :: error","tags":"","url":"module/fpm_meta_mpi.html"},{"title":"fpm_manifest_package – Fortran-lang/fpm","text":"Define the package data containing the meta data from the configuration file. The package data defines a Fortran type corresponding to the respective\n TOML document, after creating it from a package file no more interaction\n with the TOML document is required. Every configuration type provides it custom constructor (prefixed with new_ )\n and knows how to deserialize itself from a TOML document.\n To ensure we find no untracked content in the package file all keywords are\n checked and possible entries have to be explicitly allowed in the check function.\n If entries are mutally exclusive or interdependent inside the current table\n the check function is required to enforce this schema on the data structure. The package file root allows the following keywords name = \"string\" version = \"string\" license = \"string\" author = \"string\" maintainer = \"string\" copyright = \"string\" [library] [dependencies] [dev-dependencies] [profiles] [build] [install] [fortran] [[ executable ]] [[ example ]] [[ test ]] [extra] Uses fpm_toml fpm_versioning fpm_manifest_install tomlf fpm_manifest_dependency fpm_manifest_profile fpm_manifest_example fpm_manifest_executable fpm_manifest_fortran fpm_manifest_library fpm_manifest_test fpm_manifest_build fpm_manifest_preprocess fpm_error fpm_manifest_metapackages fpm_filesystem Derived Types type, public, extends( serializable_t ) :: package_config_t Package meta data Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: author Author meta data type( build_config_t ), public :: build Build configuration data character(len=:), public, allocatable :: copyright Copyright meta data type( dependency_config_t ), public, allocatable :: dependency (:) Dependency meta data type( dependency_config_t ), public, allocatable :: dev_dependency (:) Development dependency meta data type( example_config_t ), public, allocatable :: example (:) Example meta data type( executable_config_t ), public, allocatable :: executable (:) Executable meta data type( fortran_config_t ), public :: fortran Fortran meta data type( install_config_t ), public :: install Installation configuration data type( library_config_t ), public, allocatable :: library Library meta data character(len=:), public, allocatable :: license License meta data character(len=:), public, allocatable :: maintainer Maintainer meta data type( metapackage_config_t ), public :: meta Metapackage data character(len=:), public, allocatable :: name Name of the package type( preprocess_config_t ), public, allocatable :: preprocess (:) Preprocess meta data type( profile_config_t ), public, allocatable :: profiles (:) Profiles meta data type( test_config_t ), public, allocatable :: test (:) Test meta data type( version_t ), public :: version Package version Type-Bound Procedures generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit procedure, public :: dump_to_toml procedure, public :: info Print information on this instance generic, public :: load => load_from_toml , load_from_file, load_from_unit procedure, public :: load_from_toml generic, public :: operator(==) => serializable_is_same procedure, public :: serializable_is_same => manifest_is_same Serialization interface procedure, public, non_overridable :: test_serialization Test load/write roundtrip Subroutines public subroutine new_package (self, table, root, error) Construct a new package configuration from a TOML data structure Arguments Type Intent Optional Attributes Name type( package_config_t ), intent(out) :: self Instance of the package configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in), optional :: root Root directory of the manifest type( error_t ), intent(out), allocatable :: error Error handling","tags":"","url":"module/fpm_manifest_package.html"},{"title":"fpm_error – Fortran-lang/fpm","text":"Implementation of basic error handling. Uses fpm_strings iso_fortran_env Derived Types type, public :: error_t Data type defining an error Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: message Error message Functions public function bad_name_error (error, label, name) Arguments Type Intent Optional Attributes Name type( error_t ), intent(out), allocatable :: error Instance of the error data character(len=*), intent(in) :: label Error message label to add to message character(len=*), intent(in) :: name name value to check Return Value logical Subroutines public subroutine fatal_error (error, message) Generic fatal runtime error Arguments Type Intent Optional Attributes Name type( error_t ), intent(out), allocatable :: error Instance of the error data character(len=*), intent(in) :: message Error message public subroutine file_not_found_error (error, file_name) Error created when a file is missing or not found Arguments Type Intent Optional Attributes Name type( error_t ), intent(out), allocatable :: error Instance of the error data character(len=*), intent(in) :: file_name Name of the missing file public subroutine file_parse_error (error, file_name, message, line_num, line_string, line_col) Error created when file parsing fails Arguments Type Intent Optional Attributes Name type( error_t ), intent(out), allocatable :: error Instance of the error data character(len=*), intent(in) :: file_name Name of file character(len=*), intent(in) :: message Parse error message integer, intent(in), optional :: line_num Line number of parse error character(len=*), intent(in), optional :: line_string Line context string integer, intent(in), optional :: line_col Line context column public subroutine fpm_stop (value, message) Arguments Type Intent Optional Attributes Name integer, intent(in) :: value value to use on STOP character(len=*), intent(in) :: message Error message public subroutine syntax_error (error, message) Arguments Type Intent Optional Attributes Name type( error_t ), intent(out), allocatable :: error Instance of the error data character(len=*), intent(in) :: message Error message","tags":"","url":"module/fpm_error.html"},{"title":"fpm_meta_openmp – Fortran-lang/fpm","text":"Uses fpm_error fpm_strings fpm_compiler fpm_manifest_metapackages fpm_meta_base Subroutines public subroutine init_openmp (this, compiler, all_meta, error) Initialize OpenMP metapackage for the current system\nCleanup Read more… Arguments Type Intent Optional Attributes Name class( metapackage_t ), intent(inout) :: this type( compiler_t ), intent(in) :: compiler type( metapackage_request_t ), intent(in) :: all_meta (:) type( error_t ), intent(out), allocatable :: error","tags":"","url":"module/fpm_meta_openmp.html"},{"title":"fpm_manifest_build – Fortran-lang/fpm","text":"Implementation of the build configuration data. A build table can currently have the following fields [build] auto-executables = bool auto-examples = bool auto-tests = bool link = [ \"lib\" ] Uses fpm_strings fpm_toml fpm_error tomlf Derived Types type, public, extends( serializable_t ) :: build_config_t Configuration data for build Components Type Visibility Attributes Name Initial logical, public :: auto_examples = .true. Automatic discovery of examples logical, public :: auto_executables = .true. Automatic discovery of executables logical, public :: auto_tests = .true. Automatic discovery of tests type( string_t ), public, allocatable :: external_modules (:) External modules to use type( string_t ), public, allocatable :: link (:) Libraries to link against logical, public :: module_naming = .false. Enforcing of package module names type( string_t ), public :: module_prefix Type-Bound Procedures generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit procedure, public :: dump_to_toml procedure, public :: info Print information on this instance generic, public :: load => load_from_toml , load_from_file, load_from_unit procedure, public :: load_from_toml generic, public :: operator(==) => serializable_is_same procedure, public :: serializable_is_same => build_conf_is_same Serialization interface procedure, public, non_overridable :: test_serialization Test load/write roundtrip Subroutines public subroutine new_build_config (self, table, package_name, error) Construct a new build configuration from a TOML data structure Read more… Arguments Type Intent Optional Attributes Name type( build_config_t ), intent(out) :: self Instance of the build configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in) :: package_name Package name type( error_t ), intent(out), allocatable :: error Error handling","tags":"","url":"module/fpm_manifest_build.html"},{"title":"fpm_settings – Fortran-lang/fpm","text":"Manages global settings which are defined in the global config file. Uses fpm_toml tomlf fpm_os fpm_error fpm_environment fpm_filesystem Variables Type Visibility Attributes Name Initial character(len=*), public, parameter :: official_registry_base_url = 'https://fpm-registry.vercel.app' Derived Types type, public :: fpm_global_settings Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: config_file_name Name of the global config file. The default is config.toml . character(len=:), public, allocatable :: path_to_config_folder Path to the global config file excluding the file name. type(fpm_registry_settings), public, allocatable :: registry_settings Registry configs. Type-Bound Procedures procedure, public :: full_path procedure, public :: has_custom_location procedure, public :: path_to_config_folder_or_empty Subroutines public subroutine get_global_settings (global_settings, error) Obtain global settings from the global config file. Arguments Type Intent Optional Attributes Name type( fpm_global_settings ), intent(inout) :: global_settings Global settings to be obtained. type( error_t ), intent(out), allocatable :: error Error reading config file. public subroutine get_registry_settings (table, global_settings, error) Read registry settings from the global config file. Arguments Type Intent Optional Attributes Name type(toml_table), intent(inout), target :: table The [registry] subtable from the global config file. type( fpm_global_settings ), intent(inout) :: global_settings The global settings which can be filled with the registry settings. type( error_t ), intent(out), allocatable :: error Error handling.","tags":"","url":"module/fpm_settings.html"},{"title":"fpm_dependency – Fortran-lang/fpm","text":"Dependency management Fetching dependencies and creating a dependency tree Dependencies on the top-level can be specified from: package%dependencies package%dev_dependencies package%executable(:)%dependencies package%test(:)%dependencies Each dependency is fetched in some way and provides a path to its package\nmanifest.\nThe package%dependencies of the dependencies are resolved recursively. To initialize the dependency tree all dependencies are recursively fetched\nand stored in a flat data structure to avoid retrieving a package twice.\nThe data structure used to store this information should describe the current\nstatus of the dependency tree. Important information are: name of the package version of the package path to the package root Additionally, for version controlled dependencies the following should be\nstored along with the package: the upstream url the current checked out revision Fetching a remote (version controlled) dependency turns it for our purpose\ninto a local path dependency which is handled by the same means. Updating dependencies For a given dependency tree all top-level dependencies can be updated.\nWe have two cases to consider, a remote dependency and a local dependency,\nagain, remote dependencies turn into local dependencies by fetching.\nTherefore we will update remote dependencies by simply refetching them. For remote dependencies we have to refetch if the revision in the manifest\nchanges or the upstream HEAD has changed (for branches and tags). Note For our purpose a tag is just a fancy branch name. Tags can be delete and\n modified afterwards, therefore they do not differ too much from branches\n from our perspective. For the latter case we only know if we actually fetch from the upstream URL. In case of local (and fetched remote) dependencies we have to read the package\nmanifest and compare its dependencies against our dependency tree, any change\nrequires updating the respective dependencies as well. Handling dependency compatibilties Currenly ignored. First come, first serve. Uses fpm_toml fpm_versioning tomlf fpm_settings fpm_manifest fpm_manifest_dependency fpm_downloader fpm_error fpm_manifest_preprocess fpm_git fpm_environment iso_fortran_env fpm_strings jonquil fpm_filesystem Interfaces public interface resize Overloaded reallocation interface private pure subroutine resize_dependency_node(var, n) Reallocate a list of dependencies Arguments Type Intent Optional Attributes Name type( dependency_node_t ), intent(inout), allocatable :: var (:) Instance of the array to be resized integer, intent(in), optional :: n Dimension of the final array size Derived Types type, public, extends( dependency_config_t ) :: dependency_node_t Dependency node in the projects dependency tree Components Type Visibility Attributes Name Initial logical, public :: cached = .false. Dependency was loaded from a cache logical, public :: done = .false. Dependency is handled type( git_target_t ), public, allocatable :: git Git descriptor character(len=:), public, allocatable :: name Name of the dependency character(len=:), public, allocatable :: namespace Namespace which the dependency belongs to.\nEnables multiple dependencies with the same name.\nRequired for dependencies that are obtained via the official registry. type( string_t ), public, allocatable :: package_dep (:) Package dependencies of this node character(len=:), public, allocatable :: path Local target type( preprocess_config_t ), public, allocatable :: preprocess (:) Requested macros for the dependency character(len=:), public, allocatable :: proj_dir Installation prefix of this dependencies type( version_t ), public, allocatable :: requested_version The requested version of the dependency.\nThe latest version is used if not specified. character(len=:), public, allocatable :: revision Checked out revision of the version control system logical, public :: update = .false. Dependency should be updated type( version_t ), public, allocatable :: version Actual version of this dependency Type-Bound Procedures procedure, public :: add_preprocess Add a preprocessor configuration generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit procedure, public :: dump_to_toml => node_dump_to_toml procedure, public :: get_from_registry Get dependency from the registry. procedure, public :: info Print information on this instance generic, public :: load => load_from_toml , load_from_file, load_from_unit procedure, public :: load_from_toml => node_load_from_toml generic, public :: operator(==) => serializable_is_same procedure, public :: register Update dependency from project manifest. procedure, public :: serializable_is_same => dependency_node_is_same Serialization interface procedure, public, non_overridable :: test_serialization Test load/write roundtrip type, public, extends( serializable_t ) :: dependency_tree_t Respresentation of a projects dependencies Read more… Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: cache Cache file type( dependency_node_t ), public, allocatable :: dep (:) Flattend list of all dependencies character(len=:), public, allocatable :: dep_dir Installation prefix for dependencies integer, public :: ndep = 0 Number of currently registered dependencies character(len=:), public, allocatable :: path_to_config Custom path to the global config file integer, public :: unit = output_unit Unit for IO integer, public :: verbosity = 1 Verbosity of printout Type-Bound Procedures generic, public :: add => add_project, add_project_dependencies, add_dependencies, add_dependency, add_dependency_node Overload procedure to add new dependencies to the tree generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit generic, public :: dump_cache => dump_cache_to_file, dump_cache_to_unit, dump_cache_to_toml Writing of dependency tree procedure, public :: dump_to_toml => tree_dump_to_toml generic, public :: find => find_name Find a dependency in the tree procedure, public :: finished Depedendncy resolution finished generic, public :: has => has_dependency True if entity can be found generic, public :: load => load_from_toml , load_from_file, load_from_unit generic, public :: load_cache => load_cache_from_file, load_cache_from_unit, load_cache_from_toml Reading of dependency tree procedure, public :: load_from_toml => tree_load_from_toml procedure, public :: local_link_order Establish local link order for a node’s package dependencies generic, public :: operator(==) => serializable_is_same generic, public :: resolve => resolve_dependencies, resolve_dependency Resolve dependencies procedure, public :: serializable_is_same => dependency_tree_is_same Serialization interface procedure, public, non_overridable :: test_serialization Test load/write roundtrip generic, public :: update => update_dependency, update_tree Update dependency tree Subroutines public subroutine check_and_read_pkg_data (json, node, download_url, version, error) Arguments Type Intent Optional Attributes Name type(json_object), intent(inout) :: json class( dependency_node_t ), intent(in) :: node character(len=:), intent(out), allocatable :: download_url type( version_t ), intent(out) :: version type( error_t ), intent(out), allocatable :: error public elemental subroutine destroy_dependency_node (self) Destructor Arguments Type Intent Optional Attributes Name class( dependency_node_t ), intent(inout) :: self public subroutine new_dependency_node (self, dependency, version, proj_dir, update) Create a new dependency node from a configuration Arguments Type Intent Optional Attributes Name type( dependency_node_t ), intent(out) :: self Instance of the dependency node type( dependency_config_t ), intent(in) :: dependency Dependency configuration data type( version_t ), intent(in), optional :: version Version of the dependency character(len=*), intent(in), optional :: proj_dir Installation prefix of the dependency logical, intent(in), optional :: update Dependency should be updated public subroutine new_dependency_tree (self, verbosity, cache, path_to_config) Create a new dependency tree Arguments Type Intent Optional Attributes Name type( dependency_tree_t ), intent(out) :: self Instance of the dependency tree integer, intent(in), optional :: verbosity Verbosity of printout character(len=*), intent(in), optional :: cache Name of the cache file character(len=*), intent(in), optional :: path_to_config Path to the global config file.","tags":"","url":"module/fpm_dependency.html"},{"title":"fpm_git – Fortran-lang/fpm","text":"Implementation for interacting with git repositories. Uses fpm_toml fpm_error tomlf fpm_filesystem Variables Type Visibility Attributes Name Initial character(len=*), public, parameter :: compressed_package_name = 'compressed_package' Name of the compressed package that is generated temporarily. type( enum_descriptor ), public, parameter :: git_descriptor = enum_descriptor() Actual enumerator for descriptors character(len=*), public, parameter :: out_fmt = '(\"#\", *(1x, g0))' Common output format for writing to the command line Derived Types type, public :: enum_descriptor Possible git target Components Type Visibility Attributes Name Initial integer, public :: branch = 201 Branch in git repository integer, public :: default = 200 Default target integer, public :: error = -999 Invalid descriptor integer, public :: revision = 203 Commit hash integer, public :: tag = 202 Tag in git repository type, public, extends( serializable_t ) :: git_target_t Description of an git target Components Type Visibility Attributes Name Initial integer, public :: descriptor = git_descriptor%default Kind of the git target character(len=:), public, allocatable :: object Additional descriptor of the git object character(len=:), public, allocatable :: url Target URL of the git repository Type-Bound Procedures procedure, public :: checkout Fetch and checkout in local directory generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit procedure, public :: dump_to_toml procedure, public :: info Show information on instance generic, public :: load => load_from_toml , load_from_file, load_from_unit procedure, public :: load_from_toml generic, public :: operator(==) => serializable_is_same procedure, public :: serializable_is_same => git_is_same Serialization interface procedure, public, non_overridable :: test_serialization Test load/write roundtrip Functions public pure function descriptor_name (descriptor) result(name) Code git descriptor to a string Arguments Type Intent Optional Attributes Name integer, intent(in) :: descriptor Return Value character(len=:), allocatable public function git_is_same (this, that) Check that two git targets are equal\nAll checks passed! Arguments Type Intent Optional Attributes Name class( git_target_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical public function git_matches_manifest (cached, manifest, verbosity, iunit) Check that a cached dependency matches a manifest request Read more… Arguments Type Intent Optional Attributes Name type( git_target_t ), intent(in) :: cached Two input git targets type( git_target_t ), intent(in) :: manifest Two input git targets integer, intent(in) :: verbosity integer, intent(in) :: iunit Return Value logical public function git_target_branch (url, branch) result(self) Target a branch in the git repository Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: url Target URL of the git repository character(len=*), intent(in) :: branch Name of the branch of interest Return Value type( git_target_t ) New git target public function git_target_default (url) result(self) Default target Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: url Target URL of the git repository Return Value type( git_target_t ) New git target public function git_target_revision (url, sha1) result(self) Target a specific git revision Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: url Target URL of the git repository character(len=*), intent(in) :: sha1 Commit hash of interest Return Value type( git_target_t ) New git target public function git_target_tag (url, tag) result(self) Target a git tag Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: url Target URL of the git repository character(len=*), intent(in) :: tag Tag name of interest Return Value type( git_target_t ) New git target public pure function parse_descriptor (name) Parse git descriptor identifier from a string Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: name Return Value integer Subroutines public subroutine checkout (self, local_path, error) Arguments Type Intent Optional Attributes Name class( git_target_t ), intent(in) :: self Instance of the git target character(len=*), intent(in) :: local_path Local path to checkout in type( error_t ), intent(out), allocatable :: error Error public subroutine dump_to_toml (self, table, error) Dump dependency to toml table Arguments Type Intent Optional Attributes Name class( git_target_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling public subroutine git_archive (source, destination, ref, additional_files, verbose, error) Archive a folder using git archive . Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: source Directory to archive. character(len=*), intent(in) :: destination Destination of the archive. character(len=*), intent(in) :: ref (Symbolic) Reference to be archived. character(len=*), intent(in), optional :: additional_files (:) (Optional) list of additional untracked files to be added to the archive. logical, intent(in) :: verbose Print additional information if true. type( error_t ), intent(out), allocatable :: error Error handling. public subroutine git_revision (local_path, object, error) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: local_path Local path to checkout in character(len=:), intent(out), allocatable :: object Git object reference type( error_t ), intent(out), allocatable :: error Error public subroutine info (self, unit, verbosity) Show information on git target Arguments Type Intent Optional Attributes Name class( git_target_t ), intent(in) :: self Instance of the git target integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout public subroutine load_from_toml (self, table, error) Read dependency from toml table (no checks made at this stage) Read more… Arguments Type Intent Optional Attributes Name class( git_target_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling","tags":"","url":"module/fpm_git.html"},{"title":"fpm_manifest_metapackages – Fortran-lang/fpm","text":"Implementation of the metapackage configuration data. A metapackage table can currently have the following fields [metapackages] fpm = \"0.1.0\" openmp = bool stdlib = bool Uses fpm_toml fpm_environment fpm_error tomlf Derived Types type, public :: metapackage_config_t Configuration data for metapackages Components Type Visibility Attributes Name Initial type( metapackage_request_t ), public :: blas BLAS type( metapackage_request_t ), public :: hdf5 HDF5 type( metapackage_request_t ), public :: minpack fortran-lang minpack type( metapackage_request_t ), public :: mpi Request MPI support type( metapackage_request_t ), public :: netcdf NetCDF type( metapackage_request_t ), public :: openmp Request OpenMP support type( metapackage_request_t ), public :: stdlib Request stdlib support Type-Bound Procedures procedure, public :: get_requests type, public :: metapackage_request_t Configuration data for a single metapackage request Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: name Metapackage name logical, public :: on = .false. Request flag character(len=:), public, allocatable :: version Version Specification string Functions public function is_meta_package (key) Check local schema for allowed entries Read more… Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: key Instance of the TOML data structure Return Value logical Subroutines public subroutine new_meta_config (self, table, meta_allowed, error) Construct a new build configuration from a TOML data structure Read more… Arguments Type Intent Optional Attributes Name type( metapackage_config_t ), intent(out) :: self Instance of the build configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure logical, intent(in) :: meta_allowed (:) List of keys allowed to be metapackages type( error_t ), intent(out), allocatable :: error Error handling public subroutine new_meta_request (self, key, table, meta_allowed, error) Construct a new metapackage request from the dependencies table Read more… Arguments Type Intent Optional Attributes Name type( metapackage_request_t ), intent(out) :: self character(len=*), intent(in) :: key The package name type(toml_table), intent(inout) :: table Instance of the TOML data structure logical, intent(in), optional :: meta_allowed (:) List of keys allowed to be metapackages type( error_t ), intent(out), allocatable :: error Error handling","tags":"","url":"module/fpm_manifest_metapackages.html"},{"title":"fpm_os – Fortran-lang/fpm","text":"Uses fpm_error fpm_environment fpm_filesystem iso_c_binding Subroutines public subroutine change_directory (path, error) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path type( error_t ), intent(out), allocatable :: error public subroutine convert_to_absolute_path (path, error) Converts a path to an absolute, canonical path. Arguments Type Intent Optional Attributes Name character(len=:), intent(inout), allocatable :: path type( error_t ), intent(out), allocatable :: error public subroutine get_absolute_path (path, absolute_path, error) Determine the canonical, absolute path for the given path.\nExpands home folder (~) on both Unix and Windows. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path character(len=:), intent(out), allocatable :: absolute_path type( error_t ), intent(out), allocatable :: error public subroutine get_absolute_path_by_cd (path, absolute_path, error) Alternative to get_absolute_path that uses chdir / _chdir to determine the absolute path. Read more… Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path character(len=:), intent(out), allocatable :: absolute_path type( error_t ), intent(out), allocatable :: error public subroutine get_current_directory (path, error) Arguments Type Intent Optional Attributes Name character(len=:), intent(out), allocatable :: path type( error_t ), intent(out), allocatable :: error","tags":"","url":"module/fpm_os.html"},{"title":"fpm_manifest_fortran – Fortran-lang/fpm","text":"Uses fpm_toml fpm_error tomlf Derived Types type, public, extends( serializable_t ) :: fortran_config_t Configuration data for Fortran Components Type Visibility Attributes Name Initial logical, public :: implicit_external = .false. Enable implicit external interfaces logical, public :: implicit_typing = .false. Enable default implicit typing character(len=:), public, allocatable :: source_form Form to use for all Fortran sources Type-Bound Procedures generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit procedure, public :: dump_to_toml generic, public :: load => load_from_toml , load_from_file, load_from_unit procedure, public :: load_from_toml generic, public :: operator(==) => serializable_is_same procedure, public :: serializable_is_same => fortran_is_same Serialization interface procedure, public, non_overridable :: test_serialization Test load/write roundtrip Subroutines public subroutine new_fortran_config (self, table, error) Construct a new build configuration from a TOML data structure Arguments Type Intent Optional Attributes Name type( fortran_config_t ), intent(out) :: self Instance of the fortran configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling","tags":"","url":"module/fpm_manifest_fortran.html"},{"title":"fpm_manifest_test – Fortran-lang/fpm","text":"Implementation of the meta data for a test. The test data structure is effectively a decorated version of an executable\n and shares most of its properties, except for the defaults and can be\n handled under most circumstances just like any other executable. A test table can currently have the following fields [[ test ]] name = \"string\" source-dir = \"path\" main = \"file\" link = [ \"lib\" ] [test.dependencies] Uses fpm_toml tomlf fpm_manifest_dependency fpm_error fpm_manifest_executable Derived Types type, public, extends( executable_config_t ) :: test_config_t Configuation meta data for an test Components Type Visibility Attributes Name Initial type( dependency_config_t ), public, allocatable :: dependency (:) Dependency meta data for this executable type( string_t ), public, allocatable :: link (:) Libraries to link against character(len=:), public, allocatable :: main Name of the source file declaring the main program character(len=:), public, allocatable :: name Name of the resulting executable character(len=:), public, allocatable :: source_dir Source directory for collecting the executable Type-Bound Procedures generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit procedure, public :: dump_to_toml procedure, public :: info Print information on this instance generic, public :: load => load_from_toml , load_from_file, load_from_unit procedure, public :: load_from_toml generic, public :: operator(==) => serializable_is_same procedure, public :: serializable_is_same => exe_is_same Serialization interface procedure, public, non_overridable :: test_serialization Test load/write roundtrip Subroutines public subroutine new_test (self, table, error) Construct a new test configuration from a TOML data structure Arguments Type Intent Optional Attributes Name type( test_config_t ), intent(out) :: self Instance of the test configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling","tags":"","url":"module/fpm_manifest_test.html"},{"title":"fpm_manifest_install – Fortran-lang/fpm","text":"Implementation of the installation configuration. An install table can currently have the following fields library = bool Uses fpm_toml fpm_error tomlf Derived Types type, public, extends( serializable_t ) :: install_config_t Configuration data for installation Components Type Visibility Attributes Name Initial logical, public :: library = .false. Install library with this project logical, public :: test = .false. Install tests with this project Type-Bound Procedures generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit procedure, public :: dump_to_toml procedure, public :: info Print information on this instance generic, public :: load => load_from_toml , load_from_file, load_from_unit procedure, public :: load_from_toml generic, public :: operator(==) => serializable_is_same procedure, public :: serializable_is_same => install_conf_same Serialization interface procedure, public, non_overridable :: test_serialization Test load/write roundtrip Subroutines public subroutine new_install_config (self, table, error) Create a new installation configuration from a TOML data structure Arguments Type Intent Optional Attributes Name type( install_config_t ), intent(out) :: self Instance of the install configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling","tags":"","url":"module/fpm_manifest_install.html"},{"title":"fpm_meta – Fortran-lang/fpm","text":"The fpm meta-package model This is a wrapper data type that encapsulate all pre-processing information\n (compiler flags, linker libraries, etc.) required to correctly enable a package\n to use a core library. Available core libraries OpenMP MPI HDF5 fortran-lang stdlib fortran-lang minpack @note Note\n Core libraries are enabled in the [build] section of the fpm.toml manifest Uses fpm_meta_openmp fpm_meta_minpack fpm_command_line fpm_manifest fpm_meta_mpi fpm_meta_blas fpm_error fpm_meta_stdlib fpm_meta_netcdf regex_module fpm_compiler shlex_module iso_fortran_env fpm_meta_hdf5 fpm_model fpm_meta_base fpm_manifest_metapackages Interfaces public interface resolve_metapackages private subroutine resolve_metapackage_model(model, package, settings, error) Resolve all metapackages into the package config Arguments Type Intent Optional Attributes Name type( fpm_model_t ), intent(inout) :: model type( package_config_t ), intent(inout) :: package class( fpm_build_settings ), intent(inout) :: settings type( error_t ), intent(out), allocatable :: error","tags":"","url":"module/fpm_meta.html"},{"title":"fpm_cmd_install – Fortran-lang/fpm","text":"Uses fpm_backend fpm_installer fpm_command_line fpm_manifest fpm_error fpm_targets fpm fpm_strings iso_fortran_env fpm_model fpm_filesystem Subroutines public subroutine cmd_install (settings) Entry point for the fpm-install subcommand Arguments Type Intent Optional Attributes Name type( fpm_install_settings ), intent(inout) :: settings Representation of the command line settings","tags":"","url":"module/fpm_cmd_install.html"},{"title":"fpm_command_line – Fortran-lang/fpm","text":"Definition of the command line interface This module uses M_CLI2 to define\n the command line interface.\n To define a command line interface create a new command settings type\n from the fpm_cmd_settings base class or the respective parent command\n settings. The subcommand is selected by the first non-option argument in the command\n line. In the subcase block the actual command line is defined and transferred\n to an instance of the fpm_cmd_settings , the actual type is used by the fpm main program to determine which command entry point is chosen. To add a new subcommand add a new case to select construct and specify the\n wanted command line and the expected default values.\n Some of the following points also apply if you add a new option or argument\n to an existing fpm subcommand.\n At this point you should create a help page for the new command in a simple\n catman-like format as well in the set_help procedure.\n Make sure to register new subcommands in the fpm-manual command by adding\n them to the manual character array and in the help/manual case as well.\n You should add the new command to the synopsis section of the fpm-list , fpm-help and fpm --list help pages below to make sure the help output\n is complete and consistent as well. Uses fpm_os fpm_error fpm_release fpm_strings fpm_environment iso_fortran_env M_CLI2 fpm_filesystem Derived Types type, public, extends( fpm_cmd_settings ) :: fpm_build_settings Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: archiver logical, public :: build_tests = .false. character(len=:), public, allocatable :: c_compiler character(len=:), public, allocatable :: cflag character(len=:), public, allocatable :: compiler character(len=:), public, allocatable :: cxx_compiler character(len=:), public, allocatable :: cxxflag character(len=:), public, allocatable :: dump character(len=:), public, allocatable :: flag character(len=:), public, allocatable :: ldflag logical, public :: list = .false. character(len=:), public, allocatable :: path_to_config character(len=:), public, allocatable :: profile logical, public :: prune = .true. logical, public :: show_model = .false. logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir type, public, extends( fpm_cmd_settings ) :: fpm_clean_settings Components Type Visibility Attributes Name Initial logical, public :: clean_all = .false. logical, public :: clean_skip = .false. character(len=:), public, allocatable :: path_to_config logical, public :: registry_cache = .false. logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir type, public, abstract :: fpm_cmd_settings Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: path_to_config logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir type, public, extends( fpm_build_settings ) :: fpm_export_settings Settings for exporting model data Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: archiver logical, public :: build_tests = .false. character(len=:), public, allocatable :: c_compiler character(len=:), public, allocatable :: cflag character(len=:), public, allocatable :: compiler character(len=:), public, allocatable :: cxx_compiler character(len=:), public, allocatable :: cxxflag character(len=:), public, allocatable :: dump character(len=:), public, allocatable :: dump_dependencies character(len=:), public, allocatable :: dump_manifest character(len=:), public, allocatable :: dump_model character(len=:), public, allocatable :: flag character(len=:), public, allocatable :: ldflag logical, public :: list = .false. character(len=:), public, allocatable :: path_to_config character(len=:), public, allocatable :: profile logical, public :: prune = .true. logical, public :: show_model = .false. logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir type, public, extends( fpm_build_settings ) :: fpm_install_settings Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: archiver character(len=:), public, allocatable :: bindir logical, public :: build_tests = .false. character(len=:), public, allocatable :: c_compiler character(len=:), public, allocatable :: cflag character(len=:), public, allocatable :: compiler character(len=:), public, allocatable :: cxx_compiler character(len=:), public, allocatable :: cxxflag character(len=:), public, allocatable :: dump character(len=:), public, allocatable :: flag character(len=:), public, allocatable :: includedir character(len=:), public, allocatable :: ldflag character(len=:), public, allocatable :: libdir logical, public :: list = .false. logical, public :: no_rebuild character(len=:), public, allocatable :: path_to_config character(len=:), public, allocatable :: prefix character(len=:), public, allocatable :: profile logical, public :: prune = .true. logical, public :: show_model = .false. character(len=:), public, allocatable :: testdir logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir type, public, extends( fpm_cmd_settings ) :: fpm_new_settings Components Type Visibility Attributes Name Initial logical, public :: backfill = .true. character(len=:), public, allocatable :: name character(len=:), public, allocatable :: path_to_config logical, public :: verbose = .true. logical, public :: with_bare = .false. logical, public :: with_example = .false. logical, public :: with_executable = .false. logical, public :: with_full = .false. logical, public :: with_lib = .true. logical, public :: with_test = .false. character(len=:), public, allocatable :: working_dir type, public, extends( fpm_build_settings ) :: fpm_publish_settings Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: archiver logical, public :: build_tests = .false. character(len=:), public, allocatable :: c_compiler character(len=:), public, allocatable :: cflag character(len=:), public, allocatable :: compiler character(len=:), public, allocatable :: cxx_compiler character(len=:), public, allocatable :: cxxflag character(len=:), public, allocatable :: dump character(len=:), public, allocatable :: flag logical, public :: is_dry_run = .false. character(len=:), public, allocatable :: ldflag logical, public :: list = .false. character(len=:), public, allocatable :: path_to_config character(len=:), public, allocatable :: profile logical, public :: prune = .true. logical, public :: show_model = .false. logical, public :: show_package_version = .false. logical, public :: show_upload_data = .false. character(len=:), public, allocatable :: token logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir type, public, extends( fpm_build_settings ) :: fpm_run_settings Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: archiver character(len=:), public, allocatable :: args logical, public :: build_tests = .false. character(len=:), public, allocatable :: c_compiler character(len=:), public, allocatable :: cflag character(len=:), public, allocatable :: compiler character(len=:), public, allocatable :: cxx_compiler character(len=:), public, allocatable :: cxxflag character(len=:), public, allocatable :: dump logical, public :: example character(len=:), public, allocatable :: flag character(len=:), public, allocatable :: ldflag logical, public :: list = .false. character(len=ibug), public, allocatable :: name (:) character(len=:), public, allocatable :: path_to_config character(len=:), public, allocatable :: profile logical, public :: prune = .true. character(len=:), public, allocatable :: runner character(len=:), public, allocatable :: runner_args logical, public :: show_model = .false. logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir Type-Bound Procedures procedure, public :: name_ID procedure, public :: runner_command type, public, extends( fpm_run_settings ) :: fpm_test_settings Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: archiver character(len=:), public, allocatable :: args logical, public :: build_tests = .false. character(len=:), public, allocatable :: c_compiler character(len=:), public, allocatable :: cflag character(len=:), public, allocatable :: compiler character(len=:), public, allocatable :: cxx_compiler character(len=:), public, allocatable :: cxxflag character(len=:), public, allocatable :: dump logical, public :: example character(len=:), public, allocatable :: flag character(len=:), public, allocatable :: ldflag logical, public :: list = .false. character(len=ibug), public, allocatable :: name (:) character(len=:), public, allocatable :: path_to_config character(len=:), public, allocatable :: profile logical, public :: prune = .true. character(len=:), public, allocatable :: runner character(len=:), public, allocatable :: runner_args logical, public :: show_model = .false. logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir Type-Bound Procedures procedure, public :: name_ID procedure, public :: runner_command type, public, extends( fpm_cmd_settings ) :: fpm_update_settings Settings for interacting and updating with project dependencies Components Type Visibility Attributes Name Initial logical, public :: clean character(len=:), public, allocatable :: dump logical, public :: fetch_only character(len=ibug), public, allocatable :: name (:) character(len=:), public, allocatable :: path_to_config logical, public :: verbose = .true. character(len=:), public, allocatable :: working_dir Functions public function get_fpm_env (env, default) result(val) Get an environment variable for fpm, this routine ensures that every variable\nused by fpm is prefixed with FPM_. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: env character(len=*), intent(in) :: default Return Value character(len=:), allocatable Subroutines public subroutine get_command_line_settings (cmd_settings) ! canon_path is not converting “.”, etc.\n& ‘ unknown help topic “’//trim(unnamed(i)).’not found in:’,manual] Arguments Type Intent Optional Attributes Name class( fpm_cmd_settings ), intent(out), allocatable :: cmd_settings","tags":"","url":"module/fpm_command_line.html"},{"title":"fpm_cmd_update – Fortran-lang/fpm","text":"Uses fpm_toml fpm_dependency fpm_command_line fpm_manifest fpm_error fpm_filesystem Subroutines public subroutine cmd_update (settings) Entry point for the update subcommand Arguments Type Intent Optional Attributes Name type( fpm_update_settings ), intent(in) :: settings Representation of the command line arguments","tags":"","url":"module/fpm_cmd_update.html"},{"title":"fpm_meta_stdlib – Fortran-lang/fpm","text":"Uses fpm_error fpm_git fpm_compiler fpm_strings iso_fortran_env fpm_manifest_metapackages fpm_meta_base Subroutines public subroutine init_stdlib (this, compiler, all_meta, error) Initialize stdlib metapackage for the current system\nCleanup Read more… Arguments Type Intent Optional Attributes Name class( metapackage_t ), intent(inout) :: this type( compiler_t ), intent(in) :: compiler type( metapackage_request_t ), intent(in) :: all_meta (:) type( error_t ), intent(out), allocatable :: error","tags":"","url":"module/fpm_meta_stdlib.html"},{"title":"fpm – Fortran-lang/fpm","text":"Uses fpm_backend fpm_toml fpm_dependency fpm_settings iso_c_binding fpm_command_line fpm_manifest fpm_error fpm_targets fpm_strings fpm_compiler fpm_sources fpm_meta fpm_environment iso_fortran_env fpm_model fpm_filesystem Subroutines public subroutine build_model (model, settings, package, error) Constructs a valid fpm model from command line settings and the toml manifest.\nAdd this dependency’s manifest macros\nAdd this dependency’s package-level macros Arguments Type Intent Optional Attributes Name type( fpm_model_t ), intent(out) :: model class( fpm_build_settings ), intent(inout) :: settings type( package_config_t ), intent(inout), target :: package type( error_t ), intent(out), allocatable :: error public subroutine check_modules_for_duplicates (model, duplicates_found) Arguments Type Intent Optional Attributes Name type( fpm_model_t ), intent(in) :: model logical :: duplicates_found public subroutine cmd_build (settings) Dump model to file Arguments Type Intent Optional Attributes Name type( fpm_build_settings ), intent(inout) :: settings public subroutine cmd_clean (settings) Delete the build directory including or excluding dependencies. Can be used\nto clear the registry cache. Arguments Type Intent Optional Attributes Name class( fpm_clean_settings ), intent(in) :: settings Settings for the clean command. public subroutine cmd_run (settings, test) Arguments Type Intent Optional Attributes Name class( fpm_run_settings ), intent(inout) :: settings logical, intent(in) :: test","tags":"","url":"module/fpm.html"},{"title":"fpm_cmd_publish – Fortran-lang/fpm","text":"Upload a package to the registry using the publish command. To upload a package you need to provide a token that will be linked to your username and created for a namespace.\nThe token can be obtained from the registry website. It can be used as fpm publish --token . Uses fpm_versioning fpm_settings fpm_command_line fpm_manifest fpm_downloader fpm_error fpm_git fpm_strings fpm fpm_model fpm_filesystem Subroutines public subroutine cmd_publish (settings) The publish command first builds the root package to obtain all the relevant information such as the\npackage version. It then creates a tarball of the package and uploads it to the registry.\nChecks before uploading the package. Arguments Type Intent Optional Attributes Name type( fpm_publish_settings ), intent(inout) :: settings","tags":"","url":"module/fpm_cmd_publish.html"},{"title":"fpm_meta_minpack – Fortran-lang/fpm","text":"Uses fpm_error fpm_git fpm_compiler fpm_manifest_metapackages fpm_meta_base Subroutines public subroutine init_minpack (this, compiler, all_meta, error) Initialize minpack metapackage for the current system\nCleanup Read more… Arguments Type Intent Optional Attributes Name class( metapackage_t ), intent(inout) :: this type( compiler_t ), intent(in) :: compiler type( metapackage_request_t ), intent(in) :: all_meta (:) type( error_t ), intent(out), allocatable :: error","tags":"","url":"module/fpm_meta_minpack.html"},{"title":"fpm_toml – Fortran-lang/fpm","text":"Interface to TOML processing library This module acts as a proxy to the toml-f public Fortran API and allows\n to selectively expose components from the library to fpm .\n The interaction with toml-f data types outside of this module should be\n limited to tables, arrays and key-lists, most of the necessary interactions\n are implemented in the building interface with the get_value and set_value procedures. This module allows to implement features necessary for fpm , which are\n not yet available in upstream toml-f . For more details on the library used see the TOML-Fortran developer pages. Uses tomlf fpm_error tomlf_de_parser fpm_strings jonquil iso_fortran_env Interfaces public interface add_table add_table: fpm interface private subroutine add_table_fpm(table, key, ptr, error, whereAt) Function wrapper to add a toml table and return an fpm error Nullify pointer Arguments Type Intent Optional Attributes Name type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in) :: key Table key type(toml_table), intent(out), pointer :: ptr The character variable type( error_t ), intent(out), allocatable :: error Error handling character(len=*), intent(in), optional :: whereAt Optional description public interface get_value get_value: fpm interface private subroutine get_logical(table, key, var, error, whereAt) Function wrapper to get a logical variable from a toml table, returning an fpm error Arguments Type Intent Optional Attributes Name type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in) :: key The key logical, intent(inout) :: var The variable type( error_t ), intent(out), allocatable :: error Error handling character(len=*), intent(in), optional :: whereAt Optional description private subroutine get_integer(table, key, var, error, whereAt) Function wrapper to get a default integer variable from a toml table, returning an fpm error Arguments Type Intent Optional Attributes Name type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in) :: key The key integer, intent(inout) :: var The variable type( error_t ), intent(out), allocatable :: error Error handling character(len=*), intent(in), optional :: whereAt Optional description private subroutine get_integer_64(table, key, var, error, whereAt) Function wrapper to get a integer(int64) variable from a toml table, returning an fpm error Arguments Type Intent Optional Attributes Name type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in) :: key The key integer(kind=int64), intent(inout) :: var The variable type( error_t ), intent(out), allocatable :: error Error handling character(len=*), intent(in), optional :: whereAt Optional description private subroutine get_char(table, key, var, error, whereAt) Function wrapper to get a default character variable from a toml table, returning an fpm error Arguments Type Intent Optional Attributes Name type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in) :: key The key character(len=:), intent(inout), allocatable :: var The variable type( error_t ), intent(out), allocatable :: error Error handling character(len=*), intent(in), optional :: whereAt Optional description private subroutine get_string(table, key, var, error, whereAt) Function wrapper to get a default string variable from a toml table, returning an fpm error Arguments Type Intent Optional Attributes Name type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in) :: key The key type( string_t ), intent(inout) :: var The variable type( error_t ), intent(out), allocatable :: error Error handling character(len=*), intent(in), optional :: whereAt Optional description public interface set_string private subroutine set_character(table, key, var, error, whereAt) Function wrapper to set a character(len=:), allocatable variable to a toml table Check the key is not empty Arguments Type Intent Optional Attributes Name type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in) :: key List of keys to check. character(len=*), intent(in), optional :: var The character variable type( error_t ), intent(out), allocatable :: error Error handling character(len=*), intent(in), optional :: whereAt Optional description private subroutine set_string_type(table, key, var, error, whereAt) Function wrapper to set a character(len=:), allocatable variable to a toml table Arguments Type Intent Optional Attributes Name type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in) :: key List of keys to check. type( string_t ), intent(in) :: var The character variable type( error_t ), intent(out), allocatable :: error Error handling character(len=*), intent(in), optional :: whereAt Optional description public interface set_value set_value: fpm interface private subroutine set_logical(table, key, var, error, whereAt) Function wrapper to set a logical variable to a toml table, returning an fpm error Arguments Type Intent Optional Attributes Name type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in) :: key The key logical, intent(in) :: var The variable type( error_t ), intent(out), allocatable :: error Error handling character(len=*), intent(in), optional :: whereAt Optional description private subroutine set_integer(table, key, var, error, whereAt) Function wrapper to set a default integer variable to a toml table, returning an fpm error Arguments Type Intent Optional Attributes Name type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in) :: key The key integer, intent(in) :: var The variable type( error_t ), intent(out), allocatable :: error Error handling character(len=*), intent(in), optional :: whereAt Optional description private subroutine set_integer_64(table, key, var, error, whereAt) Function wrapper to set a default integer variable to a toml table, returning an fpm error Arguments Type Intent Optional Attributes Name type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in) :: key The key integer(kind=int64), intent(in) :: var The variable type( error_t ), intent(out), allocatable :: error Error handling character(len=*), intent(in), optional :: whereAt Optional description Derived Types type, public, abstract :: serializable_t An abstract interface for any fpm class that should be fully serializable to/from TOML/JSON Type-Bound Procedures generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit procedure(to_toml), public, deferred :: dump_to_toml Dump to TOML table, unit, file generic, public :: load => load_from_toml , load_from_file, load_from_unit procedure(from_toml), public, deferred :: load_from_toml Load from TOML table, unit, file generic, public :: operator(==) => serializable_is_same procedure(is_equal), public, deferred :: serializable_is_same Serializable entities need a way to check that they’re equal procedure, public, non_overridable :: test_serialization Test load/write roundtrip Functions public function has_list (table, key) Check if an instance of the TOML data structure contains a list Arguments Type Intent Optional Attributes Name type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in) :: key Key to read from Return Value logical public function name_is_json (filename) Choose between JSON or TOML based on a file name Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: filename Return Value logical Subroutines public subroutine check_keys (table, valid_keys, error) Check if table contains only keys that are part of the list. If a key is\nfound that is not part of the list, an error is allocated. Arguments Type Intent Optional Attributes Name type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in) :: valid_keys (:) List of keys to check. type( error_t ), intent(out), allocatable :: error Error handling public subroutine get_list (table, key, list, error) Arguments Type Intent Optional Attributes Name type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in) :: key Key to read from type( string_t ), intent(out), allocatable :: list (:) List of strings to read type( error_t ), intent(out), allocatable :: error Error handling public subroutine read_package_file (table, manifest, error) Process the configuration file to a TOML data structure Arguments Type Intent Optional Attributes Name type(toml_table), intent(out), allocatable :: table TOML data structure character(len=*), intent(in) :: manifest Name of the package configuration file type( error_t ), intent(out), allocatable :: error Error status of the operation public subroutine set_list (table, key, list, error) Set no key if array is not present Read more… Arguments Type Intent Optional Attributes Name type(toml_table), intent(inout) :: table Instance of the toml table character(len=*), intent(in) :: key Key to save to type( string_t ), intent(in), allocatable :: list (:) Instance of the string array type( error_t ), intent(out), allocatable :: error Error handling","tags":"","url":"module/fpm_toml.html"},{"title":"fpm_cmd_export – Fortran-lang/fpm","text":"Uses fpm_toml fpm_dependency fpm_command_line fpm_manifest fpm_error fpm fpm_model fpm_filesystem Subroutines public subroutine cmd_export (settings) Entry point for the export subcommand\nRead in manifest\nExport manifest\nExport dependency tree Read more… Arguments Type Intent Optional Attributes Name type( fpm_export_settings ), intent(inout) :: settings Representation of the command line arguments","tags":"","url":"module/fpm_cmd_export.html"},{"title":"fpm_manifest_dependency – Fortran-lang/fpm","text":"Implementation of the meta data for dependencies. A dependency table can currently have the following fields [dependencies] \"dep1\" = { git = \"url\" } \"dep2\" = { git = \"url\" , branch = \"name\" } \"dep3\" = { git = \"url\" , tag = \"name\" } \"dep4\" = { git = \"url\" , rev = \"sha1\" } \"dep0\" = { path = \"path\" } To reduce the amount of boilerplate code this module provides two constructors\n for dependency types, one basic for an actual dependency (inline) table\n and another to collect all dependency objects from a dependencies table,\n which is handling the allocation of the objects and is forwarding the\n individual dependency tables to their respective constructors.\n The usual entry point should be the constructor for the super table. This objects contains a target to retrieve required fpm projects to\n build the target declaring the dependency.\n Resolving a dependency will result in obtaining a new package configuration\n data for the respective project. Uses fpm_toml fpm_versioning tomlf fpm_error fpm_manifest_preprocess fpm_git fpm_environment fpm_strings fpm_filesystem fpm_manifest_metapackages Interfaces public interface resize private pure subroutine resize_dependency_config(var, n) Reallocate a list of dependencies Arguments Type Intent Optional Attributes Name type( dependency_config_t ), intent(inout), allocatable :: var (:) Instance of the array to be resized integer, intent(in), optional :: n Dimension of the final array size Derived Types type, public, extends( serializable_t ) :: dependency_config_t Configuration meta data for a dependency Components Type Visibility Attributes Name Initial type( git_target_t ), public, allocatable :: git Git descriptor character(len=:), public, allocatable :: name Name of the dependency character(len=:), public, allocatable :: namespace Namespace which the dependency belongs to.\nEnables multiple dependencies with the same name.\nRequired for dependencies that are obtained via the official registry. character(len=:), public, allocatable :: path Local target type( preprocess_config_t ), public, allocatable :: preprocess (:) Requested macros for the dependency type( version_t ), public, allocatable :: requested_version The requested version of the dependency.\nThe latest version is used if not specified. Type-Bound Procedures procedure, public :: add_preprocess Add a preprocessor configuration generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit procedure, public :: dump_to_toml procedure, public :: info Print information on this instance generic, public :: load => load_from_toml , load_from_file, load_from_unit procedure, public :: load_from_toml generic, public :: operator(==) => serializable_is_same procedure, public :: serializable_is_same => dependency_is_same Serialization interface procedure, public, non_overridable :: test_serialization Test load/write roundtrip Functions public function manifest_has_changed (cached, manifest, verbosity, iunit) result(has_changed) Check if two dependency configurations are different Read more… Arguments Type Intent Optional Attributes Name class( dependency_config_t ), intent(in) :: cached Two instances of the dependency configuration class( dependency_config_t ), intent(in) :: manifest Two instances of the dependency configuration integer, intent(in) :: verbosity Log verbosity integer, intent(in) :: iunit Log verbosity Return Value logical Subroutines public elemental subroutine dependency_destroy (self) Clean memory Arguments Type Intent Optional Attributes Name class( dependency_config_t ), intent(inout) :: self public subroutine new_dependencies (deps, table, root, meta, error) Construct new dependency array from a TOML data structure Read more… Arguments Type Intent Optional Attributes Name type( dependency_config_t ), intent(out), allocatable :: deps (:) Instance of the dependency configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in), optional :: root Root directory of the manifest type( metapackage_config_t ), intent(out), optional :: meta (optional) metapackages type( error_t ), intent(out), allocatable :: error Error handling public subroutine new_dependency (self, table, root, error) Construct a new dependency configuration from a TOML data structure Read more… Arguments Type Intent Optional Attributes Name type( dependency_config_t ), intent(out) :: self Instance of the dependency configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure character(len=*), intent(in), optional :: root Root directory of the manifest type( error_t ), intent(out), allocatable :: error Error handling","tags":"","url":"module/fpm_manifest_dependency.html"},{"title":"fpm_meta_netcdf – Fortran-lang/fpm","text":"Uses fpm_pkg_config fpm_error fpm_meta_util fpm_compiler fpm_strings fpm_meta_base fpm_manifest_metapackages Subroutines public subroutine init_netcdf (this, compiler, all_meta, error) Initialize NetCDF metapackage for the current system\nCleanup\nSet name Read more… Arguments Type Intent Optional Attributes Name class( metapackage_t ), intent(inout) :: this type( compiler_t ), intent(in) :: compiler type( metapackage_request_t ), intent(in) :: all_meta (:) type( error_t ), intent(out), allocatable :: error","tags":"","url":"module/fpm_meta_netcdf.html"},{"title":"fpm_installer – Fortran-lang/fpm","text":"Implementation of an installer object. The installer provides a way to install objects to their respective directories\nin the installation prefix, a generic install command allows to install\nto any directory within the prefix. Uses fpm_error fpm_targets fpm_environment iso_fortran_env fpm_filesystem Derived Types type, public :: installer_t Declaration of the installer type Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: bindir Binary dir relative to the installation prefix character(len=:), public, allocatable :: copy Command to copy objects into the installation prefix character(len=:), public, allocatable :: includedir Include directory relative to the installation prefix character(len=:), public, allocatable :: libdir Library directory relative to the installation prefix character(len=:), public, allocatable :: move Command to move objects into the installation prefix integer, public :: os Cached operating system character(len=:), public, allocatable :: prefix Path to installation directory character(len=:), public, allocatable :: testdir Test program directory relative to the installation prefix integer, public :: unit = output_unit Output unit for informative printout integer, public :: verbosity = 1 Verbosity of the installer Type-Bound Procedures procedure, public :: install Install a generic file into a subdirectory in the installation prefix procedure, public :: install_destination Evaluate the installation path procedure, public :: install_executable Install an executable in its correct subdirectory procedure, public :: install_header Install a header/module in its correct subdirectory procedure, public :: install_library Install a library in its correct subdirectory procedure, public :: install_test Install a test program in its correct subdirectory procedure, public :: make_dir Create a new directory in the prefix, type-bound for unit testing purposes procedure, public :: run Run an installation command, type-bound for unit testing purposes Subroutines public subroutine new_installer (self, prefix, bindir, libdir, includedir, testdir, verbosity, copy, move) Create a new instance of an installer Arguments Type Intent Optional Attributes Name type( installer_t ), intent(out) :: self Instance of the installer character(len=*), intent(in), optional :: prefix Path to installation directory character(len=*), intent(in), optional :: bindir Binary dir relative to the installation prefix character(len=*), intent(in), optional :: libdir Library directory relative to the installation prefix character(len=*), intent(in), optional :: includedir Include directory relative to the installation prefix character(len=*), intent(in), optional :: testdir Test directory relative to the installation prefix integer, intent(in), optional :: verbosity Verbosity of the installer character(len=*), intent(in), optional :: copy Copy command character(len=*), intent(in), optional :: move Move command","tags":"","url":"module/fpm_installer.html"},{"title":"fpm_manifest_profile – Fortran-lang/fpm","text":"Implementation of the meta data for compiler flag profiles. A profiles table can currently have the following subtables:\n Profile names - any string, if omitted, flags are appended to all matching profiles\n Compiler - any from the following list, omitting it yields an error “gfortran” “ifort” “ifx” “pgfortran” “nvfortran” “flang” “caf” “f95” “lfortran” “lfc” “nagfor” “crayftn” “xlf90” “ftn95” OS - any from the following list, if omitted, the profile is used if and only\n if there is no profile perfectly matching the current configuration “linux” “macos” “windows” “cygwin” “solaris” “freebsd” “openbsd” “unknown” Each of the subtables currently supports the following fields: [profiles.debug.gfortran.linux] flags = \"-Wall -g -Og\" c-flags = \"-g O1\" cxx-flags = \"-g O1\" link-time-flags = \"-xlinkopt\" files = { \"hello_world.f90\" = \"-Wall -O3\" } Uses fpm_toml tomlf fpm_error fpm_strings fpm_environment fpm_filesystem Variables Type Visibility Attributes Name Initial character(len=*), public, parameter :: DEFAULT_COMPILER = 'gfortran' Name of the default compiler integer, public, parameter :: OS_ALL = -1 character(len=:), public, allocatable :: path Derived Types type, public, extends( serializable_t ) :: file_scope_flag Type storing file name - file scope compiler flags pairs Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: file_name Name of the file character(len=:), public, allocatable :: flags File scope flags Type-Bound Procedures generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit procedure, public :: dump_to_toml => file_scope_dump generic, public :: load => load_from_toml , load_from_file, load_from_unit procedure, public :: load_from_toml => file_scope_load generic, public :: operator(==) => serializable_is_same procedure, public :: serializable_is_same => file_scope_same Serialization interface procedure, public, non_overridable :: test_serialization Test load/write roundtrip type, public, extends( serializable_t ) :: profile_config_t Configuration meta data for a profile Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: c_flags C compiler flags character(len=:), public, allocatable :: compiler Name of the compiler character(len=:), public, allocatable :: cxx_flags C++ compiler flags type( file_scope_flag ), public, allocatable :: file_scope_flags (:) File scope flags character(len=:), public, allocatable :: flags Fortran compiler flags logical, public :: is_built_in = .false. Is this profile one of the built-in ones? character(len=:), public, allocatable :: link_time_flags Link time compiler flags integer, public :: os_type = OS_ALL Value repesenting OS character(len=:), public, allocatable :: profile_name Name of the profile Type-Bound Procedures generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit procedure, public :: dump_to_toml => profile_dump procedure, public :: info Print information on this instance generic, public :: load => load_from_toml , load_from_file, load_from_unit procedure, public :: load_from_toml => profile_load generic, public :: operator(==) => serializable_is_same procedure, public :: serializable_is_same => profile_same Serialization interface procedure, public, non_overridable :: test_serialization Test load/write roundtrip Functions public function file_scope_same (this, that) All checks passed! Arguments Type Intent Optional Attributes Name class( file_scope_flag ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical public function get_default_profiles (error) result(default_profiles) Construct an array of built-in profiles Arguments Type Intent Optional Attributes Name type( error_t ), intent(out), allocatable :: error Error handling Return Value type( profile_config_t ), allocatable, (:) public function info_profile (profile) result(s) Print a representation of profile_config_t Arguments Type Intent Optional Attributes Name type( profile_config_t ), intent(in) :: profile Profile to be represented Return Value character(len=:), allocatable String representation of given profile public function new_profile (profile_name, compiler, os_type, flags, c_flags, cxx_flags, link_time_flags, file_scope_flags, is_built_in) result(profile) Construct a new profile configuration from a TOML data structure Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: profile_name Name of the profile character(len=*), intent(in) :: compiler Name of the compiler integer, intent(in) :: os_type Type of the OS character(len=*), intent(in), optional :: flags Fortran compiler flags character(len=*), intent(in), optional :: c_flags C compiler flags character(len=*), intent(in), optional :: cxx_flags C++ compiler flags character(len=*), intent(in), optional :: link_time_flags Link time compiler flags type( file_scope_flag ), intent(in), optional :: file_scope_flags (:) File scope flags logical, intent(in), optional :: is_built_in Is this profile one of the built-in ones? Return Value type( profile_config_t ) public function os_type_name (os_type) Match lowercase string with name of OS to os_type enum Arguments Type Intent Optional Attributes Name integer, intent(in) :: os_type Enum representing type of OS Return Value character(len=:), allocatable Name of operating system public function profile_same (this, that) All checks passed! Arguments Type Intent Optional Attributes Name class( profile_config_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical Subroutines public subroutine file_scope_dump (self, table, error) Dump to toml table Arguments Type Intent Optional Attributes Name class( file_scope_flag ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling public subroutine file_scope_load (self, table, error) Read from toml table (no checks made at this stage) Arguments Type Intent Optional Attributes Name class( file_scope_flag ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling public subroutine find_profile (profiles, profile_name, compiler, os_type, found_matching, chosen_profile) Look for profile with given configuration in array profiles Arguments Type Intent Optional Attributes Name type( profile_config_t ), intent(in), allocatable :: profiles (:) Array of profiles character(len=:), intent(in), allocatable :: profile_name Name of profile character(len=:), intent(in), allocatable :: compiler Name of compiler integer, intent(in) :: os_type Type of operating system (enum) logical, intent(out) :: found_matching Boolean value containing true if matching profile was found type( profile_config_t ), intent(out) :: chosen_profile Last matching profile in the profiles array public subroutine get_flags (profile_name, compiler_name, os_type, key_list, table, profiles, profindex, os_valid) Look for flags, c-flags, link-time-flags key-val pairs\nand files table in a given table and create new profiles Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: profile_name Name of profile character(len=:), intent(in), allocatable :: compiler_name Name of compiler integer, intent(in) :: os_type OS type type(toml_key), intent(in), allocatable :: key_list (:) List of keys in the table type(toml_table), intent(in), pointer :: table Table containing OS tables type( profile_config_t ), intent(inout), allocatable :: profiles (:) List of profiles integer, intent(inout) :: profindex Index in the list of profiles logical, intent(in) :: os_valid Was called with valid operating system public subroutine info (self, unit, verbosity) Write information on instance Arguments Type Intent Optional Attributes Name class( profile_config_t ), intent(in) :: self Instance of the profile configuration integer, intent(in) :: unit Unit for IO integer, intent(in), optional :: verbosity Verbosity of the printout public subroutine match_os_type (os_name, os_type) Match os_type enum to a lowercase string with name of OS Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: os_name Name of operating system integer, intent(out) :: os_type Enum representing type of OS public subroutine new_profiles (profiles, table, error) Construct new profiles array from a TOML data structure Arguments Type Intent Optional Attributes Name type( profile_config_t ), intent(out), allocatable :: profiles (:) Instance of the dependency configuration type(toml_table), intent(inout), target :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling public subroutine profile_dump (self, table, error) Dump to toml table Read more… Arguments Type Intent Optional Attributes Name class( profile_config_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling public subroutine profile_load (self, table, error) Read from toml table (no checks made at this stage) Read more… Arguments Type Intent Optional Attributes Name class( profile_config_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling public subroutine traverse_compilers (profile_name, comp_list, table, error, profiles_size, profiles, profindex) Traverse compiler tables Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: profile_name Name of profile type(toml_key), intent(in), allocatable :: comp_list (:) List of OSs in table with profile name given type(toml_table), intent(in), pointer :: table Table containing compiler tables type( error_t ), intent(out), allocatable :: error Error handling integer, intent(inout), optional :: profiles_size Number of profiles in list of profiles type( profile_config_t ), intent(inout), optional, allocatable :: profiles (:) List of profiles integer, intent(inout), optional :: profindex Index in the list of profiles public subroutine traverse_oss (profile_name, compiler_name, os_list, table, profiles, profindex, error) Traverse operating system tables to obtain profiles Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: profile_name Name of profile character(len=:), intent(in), allocatable :: compiler_name Name of compiler type(toml_key), intent(in), allocatable :: os_list (:) List of OSs in table with profile name and compiler name given type(toml_table), intent(in), pointer :: table Table containing OS tables type( profile_config_t ), intent(inout), allocatable :: profiles (:) List of profiles integer, intent(inout) :: profindex Index in the list of profiles type( error_t ), intent(out), allocatable :: error Error handling public subroutine traverse_oss_for_size (profile_name, compiler_name, os_list, table, profiles_size, error) Traverse operating system tables to obtain number of profiles Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: profile_name Name of profile character(len=:), intent(in), allocatable :: compiler_name Name of compiler type(toml_key), intent(in), allocatable :: os_list (:) List of OSs in table with profile name and compiler name given type(toml_table), intent(in), pointer :: table Table containing OS tables integer, intent(inout) :: profiles_size Number of profiles in list of profiles type( error_t ), intent(out), allocatable :: error Error handling public subroutine validate_compiler_name (compiler_name, is_valid) Check if compiler name is a valid compiler name Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: compiler_name Name of a compiler logical, intent(out) :: is_valid Boolean value of whether compiler_name is valid or not public subroutine validate_os_name (os_name, is_valid) Check if os_name is a valid name of a supported OS Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: os_name Name of an operating system logical, intent(out) :: is_valid Boolean value of whether os_name is valid or not public subroutine validate_profile_table (profile_name, compiler_name, key_list, table, error, os_valid) Arguments Type Intent Optional Attributes Name character(len=:), intent(in), allocatable :: profile_name Name of profile character(len=:), intent(in), allocatable :: compiler_name Name of compiler type(toml_key), intent(in), allocatable :: key_list (:) List of keys in the table type(toml_table), intent(in), pointer :: table Table containing OS tables type( error_t ), intent(out), allocatable :: error Error handling logical, intent(in) :: os_valid Was called with valid operating system","tags":"","url":"module/fpm_manifest_profile.html"},{"title":"fpm_meta_util – Fortran-lang/fpm","text":"Uses fpm_versioning fpm_pkg_config fpm_error fpm_strings fpm_meta_base fpm_filesystem Subroutines public subroutine add_pkg_config_compile_options (this, name, include_flag, libdir, error) Add pkgconfig compile options to a metapackage\nGet version\nGet libraries\nGet compiler flags Arguments Type Intent Optional Attributes Name class( metapackage_t ), intent(inout) :: this character(len=*), intent(in) :: name character(len=*), intent(in) :: include_flag character(len=:), allocatable :: libdir type( error_t ), intent(out), allocatable :: error public subroutine lib_get_trailing (lib_name, lib_dir, prefix, suffix, found) Given a library name and folder, find extension and prefix Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: lib_name character(len=*), intent(in) :: lib_dir character(len=:), intent(out), allocatable :: prefix character(len=:), intent(out), allocatable :: suffix logical, intent(out) :: found","tags":"","url":"module/fpm_meta_util.html"},{"title":"fpm_backend – Fortran-lang/fpm","text":"Build backend Uses a list of [[build_target_ptr]] and a valid [[fpm_model]] instance\n to schedule and execute the compilation and linking of package targets. The package build process ( [[build_package]] ) comprises three steps: Target sorting: topological sort of the target dependency graph ( [[sort_target]] ) Target scheduling: group targets into schedule regions based on the sorting ( [[schedule_targets]] ) Target building: generate targets by compilation or linking @note Note\n If compiled with OpenMP, targets will be build in parallel where possible. Incremental compilation The backend process supports incremental compilation whereby targets are not\n re-compiled if their corresponding dependencies have not been modified. Source-based targets ( i.e. objects) are not re-compiled if the corresponding source\n file is unmodified AND all of the target dependencies are not marked for re-compilation Link targets ( i.e. executables and libraries) are not re-compiled if the\n target output file already exists AND all of the target dependencies are not marked for\n re-compilation Source file modification is determined by a file digest (hash) which is calculated during\n the source parsing phase ( fpm_source_parsing ) and cached to disk after a target is\n successfully generated. Uses fpm_compile_commands fpm_error fpm_targets fpm_backend_output fpm_strings iso_fortran_env fpm_model fpm_filesystem Subroutines public subroutine build_package (targets, model, verbose, dry_run) Top-level routine to build package described by model Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(inout) :: targets (:) type( fpm_model_t ), intent(in) :: model logical, intent(in) :: verbose logical, intent(in) :: dry_run If dry_run, the build process is only mocked, but the list of compile_commands\nis still created public subroutine schedule_targets (queue, schedule_ptr, targets) Construct a build schedule from the sorted targets. Read more… Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(out), allocatable :: queue (:) integer, allocatable :: schedule_ptr (:) type( build_target_ptr ), intent(in) :: targets (:) public recursive subroutine sort_target (target, mock) Topologically sort a target for scheduling by\n recursing over its dependencies. Read more… Arguments Type Intent Optional Attributes Name type( build_target_t ), intent(inout), target :: target logical, intent(in), optional :: mock Optionally sort ALL targets if this is a dry run","tags":"","url":"module/fpm_backend.html"},{"title":"fpm_strings – Fortran-lang/fpm","text":"This module defines general procedures for string operations for both CHARACTER and\n TYPE(STRING_T) variables general routines for performing string operations Types TYPE(STRING_T) define a type to contain strings of variable length Type Conversions f_string return Fortran CHARACTER variable when given a C-like array of\n single characters terminated with a C_NULL_CHAR CHARACTER str Converts INTEGER or LOGICAL to CHARACTER string Case lower Changes a string to lowercase over optional specified column range Parsing and joining split parse string on delimiter characters and store tokens into an allocatable array split_first_last Computes the first and last indices of tokens in input string, delimited by the characters in set,\n and stores them into first and last output arrays. string_cat Concatenate an array of type(string_t) into a single CHARACTER variable join append an array of CHARACTER variables into a single CHARACTER variable Testing str_ends_with test if a CHARACTER string or array ends with a specified suffix string_array_contains Check if array of TYPE(STRING_T) matches a particular CHARACTER string OPERATOR(.IN.) Check if array of TYPE(STRING_T) matches a particular CHARACTER string glob function compares text strings, one of which can have wildcards (‘*’ or ‘?’). is_fortran_name determine whether a string is an acceptable Fortran entity name to_fortran_name replace allowed special but unusuable characters in names with underscore Whitespace notabs subroutine to expand tab characters assuming a tab space every eight characters dilate function to expand tab characters assuming a tab space every eight characters len_trim Determine total trimmed length of STRING_T array Miscellaneous fnv_1a Hash a CHARACTER(*) string of default kind or a TYPE(STRING_T) array replace Returns string with characters in charset replaced with target_char. resize increase the size of a TYPE(STRING_T) array by N elements Module naming License: Public Domain\n Changes a string to upprtcase over optional specified column range\n Author: Milan Curcic\n Computes the first and last indices of tokens in input string, delimited\n by the characters in set, and stores them into first and last output\n arrays.\n Author: Federico Perini\n Computes the first and last indices of lines in input string, delimited\n by either CR, LF, or CRLF, and stores them into first and last output\n arrays.\n Author: Milan Curcic\n If back is absent, computes the leftmost token delimiter in string whose\n position is > pos. If back is present and true, computes the rightmost\n token delimiter in string whose position is < pos. The result is stored\n in pos. Uses iso_c_binding iso_fortran_env Interfaces public interface fnv_1a private pure function fnv_1a_char(input, seed) result(hash) Hash a character(*) string of default kind Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: input integer(kind=int64), intent(in), optional :: seed Return Value integer(kind=int64) private pure function fnv_1a_string_t(input, seed) result(hash) Hash a string_t array of default kind Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: input (:) integer(kind=int64), intent(in), optional :: seed Return Value integer(kind=int64) public interface len_trim private elemental function string_len_trim(string) result(n) Determine total trimmed length of string_t array Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: string Return Value integer private pure function strings_len_trim(strings) result(n) Determine total trimmed length of string_t array Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: strings (:) Return Value integer public interface operator(.in.) public function string_array_contains (search_string, array) Check if array of TYPE(STRING_T) matches a particular CHARACTER string Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: search_string type( string_t ), intent(in) :: array (:) Return Value logical public interface operator(==) private pure function string_is_same(this, that) Check that two string objects are exactly identical Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: this two strings to be compared type( string_t ), intent(in) :: that two strings to be compared Return Value logical private pure function string_arrays_same(this, that) Check that two allocatable string object arrays are exactly identical Arguments Type Intent Optional Attributes Name type( string_t ), intent(in), allocatable :: this (:) two string arrays to be compared type( string_t ), intent(in), allocatable :: that (:) two string arrays to be compared Return Value logical public interface resize private subroutine resize_string(list, n) increase the size of a TYPE(STRING_T) array by N elements Arguments Type Intent Optional Attributes Name type( string_t ), intent(inout), allocatable :: list (:) Instance of the array to be resized integer, intent(in), optional :: n Dimension of the final array size public interface str private pure function str_int(i) result(s) Converts integer “i” to string Arguments Type Intent Optional Attributes Name integer, intent(in) :: i Return Value character(len=str_int_len) private pure function str_int64(i) result(s) Converts integer “i” to string Arguments Type Intent Optional Attributes Name integer(kind=int64), intent(in) :: i Return Value character(len=str_int64_len) private pure function str_logical(l) result(s) Converts logical “l” to string Arguments Type Intent Optional Attributes Name logical, intent(in) :: l Return Value character(len=str_logical_len) public interface str_ends_with private pure function str_ends_with_str(s, e) result(r) test if a CHARACTER string ends with a specified suffix Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: s character(len=*), intent(in) :: e Return Value logical private pure function str_ends_with_any(s, e) result(r) test if a CHARACTER string ends with any of an array of suffixs Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: s character(len=*), intent(in) :: e (:) Return Value logical private pure function str_ends_with_any_string(s, e) result(r) Test if a CHARACTER string ends with any of an array of string suffixs Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: s type( string_t ), intent(in) :: e (:) Return Value logical public interface string_t private function new_string_t(s) result(string) Helper function to generate a new string_t instance\n (Required due to the allocatable component) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: s Return Value type( string_t ) Derived Types type, public :: string_t Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: s Constructor private\n\n \n function new_string_t (s) Helper function to generate a new string_t instance\n (Required due to the allocatable component) Functions public function dilate (instr) result(outstr) Author John S. Urban License Public Domain Sample program: Read more… Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: instr Return Value character(len=:), allocatable public function f_string (c_string) return Fortran character variable when given a C-like array of\nsingle characters terminated with a C_NULL_CHAR character Arguments Type Intent Optional Attributes Name character(len=1), intent(in) :: c_string (:) Return Value character(len=:), allocatable public function glob (tame, wild) Author John S. Urban License Public Domain glob(3f) compares given STRING for match to PATTERN which may\n contain wildcard characters. Read more… Arguments Type Intent Optional Attributes Name character(len=*) :: tame A string without wildcards to compare to the globbing expression character(len=*) :: wild A (potentially) corresponding string with wildcards Return Value logical result of test public function has_valid_custom_prefix (module_name, custom_prefix) result(valid) Check that a module name is prefixed with a custom prefix:\n1) It must be a valid FORTRAN name subset (<=63 chars, begin with letter, only alphanumeric allowed)\n2) It must begin with the prefix\n3) If longer, package name must be followed by default separator (“_”) plus at least one char Read more… Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: module_name type( string_t ), intent(in) :: custom_prefix Return Value logical public function has_valid_standard_prefix (module_name, package_name) result(valid) Check that a module name is prefixed with the default package prefix:\n1) It must be a valid FORTRAN name (<=63 chars, begin with letter, “_” is only allowed non-alphanumeric)\n2) It must begin with the package name\n3) If longer, package name must be followed by default separator plus at least one char Read more… Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: module_name type( string_t ), intent(in) :: package_name Return Value logical public elemental function is_fortran_name (line) result(lout) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: line Return Value logical public function is_valid_module_name (module_name, package_name, custom_prefix, enforce_module_names) result(valid) Check that a module name fits the current naming rules:\n1) It must be a valid FORTRAN name (<=63 chars, begin with letter, “_” is only allowed non-alphanumeric)\n2) It must begin with the package name\n3) If longer, package name must be followed by default separator plus at least one char Read more… Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: module_name type( string_t ), intent(in) :: package_name type( string_t ), intent(in) :: custom_prefix logical, intent(in) :: enforce_module_names Return Value logical public function is_valid_module_prefix (module_prefix) result(valid) Check that a custom module prefix fits the current naming rules:\n1) Only alphanumeric characters (no spaces, dashes, underscores or other characters)\n2) Does not begin with a number (Fortran-compatible syntax) Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: module_prefix Return Value logical public pure function join (str, sep, trm, left, right, start, end) result(string) Author John S. Urban License Public Domain JOIN(3f) appends the elements of a CHARACTER array into a single\n CHARACTER variable, with elements 1 to N joined from left to right.\n By default each element is trimmed of trailing spaces and the\n default separator is a null string. Read more… Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: str (:) character(len=*), intent(in), optional :: sep logical, intent(in), optional :: trm character(len=*), intent(in), optional :: left character(len=*), intent(in), optional :: right character(len=*), intent(in), optional :: start character(len=*), intent(in), optional :: end Return Value character(len=:), allocatable public pure elemental function lower (str, begin, end) result(string) Author John S. Urban License Public Domain Changes a string to lowercase over optional specified column range Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: str integer, intent(in), optional :: begin integer, intent(in), optional :: end Return Value character(len=len(str)) public function module_prefix_template (project_name, custom_prefix) result(prefix) Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: project_name type( string_t ), intent(in) :: custom_prefix Return Value type( string_t ) public function module_prefix_type (project_name, custom_prefix) result(ptype) Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: project_name type( string_t ), intent(in) :: custom_prefix Return Value type( string_t ) public pure function replace (string, charset, target_char) result(res) Returns string with characters in charset replaced with target_char. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: string character(len=1), intent(in) :: charset (:) character(len=1), intent(in) :: target_char Return Value character(len=len(string)) public pure function str_begins_with_str (s, e, case_sensitive) result(r) test if a CHARACTER string begins with a specified prefix Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: s character(len=*), intent(in) :: e logical, intent(in), optional :: case_sensitive Return Value logical public function string_array_contains (search_string, array) Check if array of TYPE(STRING_T) matches a particular CHARACTER string Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: search_string type( string_t ), intent(in) :: array (:) Return Value logical public function string_cat (strings, delim) result(cat) Concatenate an array of type(string_t) into\n a single CHARACTER variable Arguments Type Intent Optional Attributes Name type( string_t ), intent(in) :: strings (:) character(len=*), intent(in), optional :: delim Return Value character(len=:), allocatable public pure function to_fortran_name (string) result(res) Returns string with special characters replaced with an underscore.\nFor now, only a hyphen is treated as a special character, but this can be\nexpanded to other characters if needed. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: string Return Value character(len=len(string)) public pure elemental function upper (str, begin, end) result(string) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: str integer, intent(in), optional :: begin integer, intent(in), optional :: end Return Value character(len=len(str)) Subroutines public impure elemental subroutine notabs (instr, outstr, ilen) Author John S. Urban License Public Domain notabs(3f) - [fpm_strings:NONALPHA] expand tab characters\n (LICENSE:PD) Read more… Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: instr character(len=*), intent(out) :: outstr integer, intent(out) :: ilen public subroutine remove_characters_in_set (string, set, replace_with) Arguments Type Intent Optional Attributes Name character(len=:), intent(inout), allocatable :: string character(len=*), intent(in) :: set character(len=1), intent(in), optional :: replace_with public subroutine remove_newline_characters (string) Arguments Type Intent Optional Attributes Name type( string_t ), intent(inout) :: string public subroutine split (input_line, array, delimiters, order, nulls) Author John S. Urban License Public Domain parse string on delimiter characters and store tokens into an allocatable array\ngiven a line of structure ” par1 par2 par3 … parn ” store each par(n) into a separate variable in array. Read more… Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: input_line input string to tokenize character(len=:), intent(out), allocatable :: array (:) output array of tokens character(len=*), intent(in), optional :: delimiters list of delimiter characters character(len=*), intent(in), optional :: order order of output array sequential|[reverse|right] character(len=*), intent(in), optional :: nulls return strings composed of delimiters or not ignore|return|ignoreend public pure subroutine split_first_last (string, set, first, last) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: string character(len=*), intent(in) :: set integer, intent(out), allocatable :: first (:) integer, intent(out), allocatable :: last (:) public pure subroutine split_lines_first_last (string, first, last) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: string integer, intent(out), allocatable :: first (:) integer, intent(out), allocatable :: last (:)","tags":"","url":"module/fpm_strings.html"},{"title":"fpm_versioning – Fortran-lang/fpm","text":"Implementation of versioning data for comparing packages Uses fpm_strings regex_module fpm_error Interfaces public interface new_version private subroutine new_version_from_string(self, string, error) Create a new version from a string Arguments Type Intent Optional Attributes Name type( version_t ), intent(out) :: self Instance of the versioning data character(len=*), intent(in) :: string String describing the version information type( error_t ), intent(out), allocatable :: error Error handling private subroutine new_version_from_int(self, num) Create a new version from a string Arguments Type Intent Optional Attributes Name type( version_t ), intent(out) :: self Instance of the versioning data integer, intent(in) :: num (:) Subversion numbers to define version data Derived Types type, public :: version_t Type-Bound Procedures generic, public :: operator(.match.) => match Compare a version against a version constraint (x.x.0 <= v < x.x.HUGE) generic, public :: operator(/=) => not_equals generic, public :: operator(<) => less generic, public :: operator(<=) => less_equals generic, public :: operator(==) => equals generic, public :: operator(>) => greater generic, public :: operator(>=) => greater_equals procedure, public :: s Create a printable string from a version data type Functions public function regex_version_from_text (text, what, error) result(ver) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: text character(len=*), intent(in) :: what type( error_t ), intent(out), allocatable :: error Return Value type( string_t )","tags":"","url":"module/fpm_versioning.html"},{"title":"fpm_targets – Fortran-lang/fpm","text":"Build target handling This module handles the construction of the build target list\n from the sources list ( [[targets_from_sources]] ), the\n resolution of module-dependencies between build targets\n ( [[resolve_module_dependencies]] ), and the enumeration of\n objects required for link targets ( [[resolve_target_linking]] ). A build target ( [[build_target_t]] ) is a file to be generated\n by the backend (compilation and linking). @note Note\n The current implementation is ignorant to the existence of\n module files ( .mod , .smod ). Dependencies arising from modules\n are based on the corresponding object files ( .o ) only. For more information, please read the documentation for the procedures: [[build_target_list]] [[resolve_module_dependencies]] Enumerations Target type: FPM_TARGET_* Describes the type of build target — determines backend build rules Uses fpm_error fpm_manifest_library fpm_manifest_preprocess fpm_environment fpm_compiler iso_fortran_env fpm_strings fpm_sources fpm_model fpm_filesystem Variables Type Visibility Attributes Name Initial integer, public, parameter :: FPM_TARGET_ARCHIVE = 2 Target type is library archive integer, public, parameter :: FPM_TARGET_CPP_OBJECT = 5 Target type is cpp compiled object integer, public, parameter :: FPM_TARGET_C_OBJECT = 4 Target type is c compiled object integer, public, parameter :: FPM_TARGET_EXECUTABLE = 1 Target type is executable integer, public, parameter :: FPM_TARGET_OBJECT = 3 Target type is compiled object integer, public, parameter :: FPM_TARGET_SHARED = 6 Target type is a shared library integer, public, parameter :: FPM_TARGET_UNKNOWN = -1 Target type is unknown (ignored) Interfaces public interface add_target private subroutine add_new_target(targets, package, type, output_name, source, link_libraries, features, preprocess, version, output_dir) Allocate a new target and append to target list Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(inout), allocatable :: targets (:) character(len=*), intent(in) :: package integer, intent(in) :: type character(len=*), intent(in) :: output_name type( srcfile_t ), intent(in), optional :: source type( string_t ), intent(in), optional :: link_libraries (:) type( fortran_features_t ), intent(in), optional :: features type( preprocess_config_t ), intent(in), optional :: preprocess character(len=*), intent(in), optional :: version character(len=*), intent(in), optional :: output_dir private subroutine add_old_target(targets, add_target) Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(inout), allocatable :: targets (:) type( build_target_ptr ), intent(in) :: add_target private subroutine add_old_targets(targets, add_targets) Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(inout), allocatable :: targets (:) type( build_target_ptr ), intent(in) :: add_targets (:) Derived Types type, public :: build_target_ptr Wrapper type for constructing arrays of [[build_target_t]] pointers Components Type Visibility Attributes Name Initial type( build_target_t ), public, pointer :: ptr => null() type, public :: build_target_t Type describing a generated build target Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: compile_flags Compile flags for this build target type( build_target_ptr ), public, allocatable :: dependencies (:) Resolved build dependencies integer(kind=int64), public, allocatable :: digest_cached Previous source file hash type( fortran_features_t ), public :: features Language features character(len=:), public, allocatable :: link_flags Link flags for this build target type( string_t ), public, allocatable :: link_libraries (:) Native libraries to link against type( string_t ), public, allocatable :: link_objects (:) Objects needed to link this target type( string_t ), public, allocatable :: macros (:) List of macros character(len=:), public, allocatable :: output_dir File path of output directory character(len=:), public, allocatable :: output_file File path of build target object relative to cwd character(len=:), public, allocatable :: output_log_file File path of build log file relative to cwd character(len=:), public, allocatable :: output_name File path of build target object relative to output_dir character(len=:), public, allocatable :: package_name Name of parent package integer, public :: schedule = -1 Targets in the same schedule group are guaranteed to be independent logical, public :: skip = .false. Flag set if build target will be skipped (not built) logical, public :: sorted = .false. Flag set if build target is sorted for building type( srcfile_t ), public, allocatable :: source Primary source for this build target integer, public :: target_type = FPM_TARGET_UNKNOWN Target type logical, public :: touched = .false. Flag set when first visited to check for circular dependencies character(len=:), public, allocatable :: version Version number Type-Bound Procedures procedure, public :: info Print information on this instance procedure, public :: is_executable_target procedure, public :: set_output_dir Set output directory Functions public pure function FPM_TARGET_NAME (type) result(msg) Target type name Arguments Type Intent Optional Attributes Name integer, intent(in) :: type Return Value character(len=:), allocatable public function new_target (package, type, output_name, source, link_libraries, features, preprocess, version, output_dir) Allocate a new target Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: package integer, intent(in) :: type character(len=*), intent(in) :: output_name type( srcfile_t ), intent(in), optional :: source type( string_t ), intent(in), optional :: link_libraries (:) type( fortran_features_t ), intent(in), optional :: features type( preprocess_config_t ), intent(in), optional :: preprocess character(len=*), intent(in), optional :: version character(len=*), intent(in), optional :: output_dir Return Value type( build_target_ptr ) Subroutines public subroutine add_dependency (target, dependency) Add pointer to dependeny in target%dependencies Arguments Type Intent Optional Attributes Name type( build_target_t ), intent(inout) :: target type( build_target_t ), intent(in), target :: dependency public subroutine filter_executable_targets (targets, scope, list) Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(in) :: targets (:) integer, intent(in) :: scope type( string_t ), intent(out), allocatable :: list (:) public subroutine filter_library_targets (targets, list) Returns pointers to all library targets Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(in) :: targets (:) type( build_target_ptr ), intent(out), allocatable :: list (:) public subroutine filter_modules (targets, list) Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(in) :: targets (:) type( string_t ), intent(out), allocatable :: list (:) public subroutine get_library_dirs (model, targets, shared_lib_dirs) Add link directories for all shared libraries in the dependency graph Arguments Type Intent Optional Attributes Name type( fpm_model_t ), intent(in) :: model type( build_target_ptr ), intent(inout), target :: targets (:) type( string_t ), intent(out), allocatable :: shared_lib_dirs (:) public subroutine resolve_module_dependencies (targets, external_modules, error) Add dependencies to source-based targets ( FPM_TARGET_OBJECT )\n based on any modules used by the corresponding source file. Read more… Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(inout), target :: targets (:) type( string_t ), intent(in) :: external_modules (:) type( error_t ), intent(out), allocatable :: error public subroutine targets_from_sources (targets, model, prune, library, error) High-level wrapper to generate build target information Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(out), allocatable :: targets (:) The generated list of build targets type( fpm_model_t ), intent(inout), target :: model The package model from which to construct the target list logical, intent(in) :: prune Enable tree-shaking/pruning of module dependencies type( library_config_t ), intent(in), optional :: library Library build configuration type( error_t ), intent(out), allocatable :: error Error structure","tags":"","url":"module/fpm_targets.html"},{"title":"fpm_manifest_preprocess – Fortran-lang/fpm","text":"Implementation of the meta data for preprocessing. A preprocess table can currently have the following fields [preprocess] [preprocess.cpp] suffixes = [ \"F90\" , \"f90\" ] directories = [ \"src/feature1\" , \"src/models\" ] macros = [] Uses fpm_toml tomlf fpm_error fpm_strings iso_fortran_env Derived Types type, public, extends( serializable_t ) :: preprocess_config_t Configuration meta data for a preprocessor Components Type Visibility Attributes Name Initial type( string_t ), public, allocatable :: directories (:) Directories to search for files to be preprocessed type( string_t ), public, allocatable :: macros (:) Macros to be defined for the preprocessor character(len=:), public, allocatable :: name Name of the preprocessor type( string_t ), public, allocatable :: suffixes (:) Suffixes of the files to be preprocessed Type-Bound Procedures procedure, public :: add_config procedure, public :: destroy Operations generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit procedure, public :: dump_to_toml procedure, public :: info Print information on this instance procedure, public :: is_cpp Properties procedure, public :: is_fypp generic, public :: load => load_from_toml , load_from_file, load_from_unit procedure, public :: load_from_toml generic, public :: new => new_cpp_config_with_macros, new_preprocess_config generic, public :: operator(==) => serializable_is_same procedure, public :: serializable_is_same => preprocess_is_same Serialization interface procedure, public, non_overridable :: test_serialization Test load/write roundtrip Subroutines public subroutine new_preprocessors (preprocessors, table, error) Construct new preprocess array from a TOML data structure. Arguments Type Intent Optional Attributes Name type( preprocess_config_t ), intent(out), allocatable :: preprocessors (:) Instance of the preprocess configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling","tags":"","url":"module/fpm_manifest_preprocess.html"},{"title":"fpm_compile_commands – Fortran-lang/fpm","text":"Store compiler commands in a compile_commands.json table Uses fpm_toml tomlf fpm_os fpm_error fpm_strings jonquil fpm_environment shlex_module Interfaces public interface compile_command_t public function cct_new (directory, arguments, file) result(cct) Override default initializer (GCC 15 bug) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: directory character(len=*), intent(in), optional :: arguments (:) character(len=*), intent(in) :: file Return Value type( compile_command_t ) Derived Types type, public, extends( serializable_t ) :: compile_command_t Definition of a build command Components Type Visibility Attributes Name Initial type( string_t ), public, allocatable :: arguments (:) type( string_t ), public :: directory type( string_t ), public :: file Constructor public\n\n \n function cct_new (directory, arguments, file) Override default initializer (GCC 15 bug) Type-Bound Procedures procedure, public :: destroy => compile_command_destroy Operation generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit procedure, public :: dump_to_toml => compile_command_dump_toml generic, public :: load => load_from_toml , load_from_file, load_from_unit procedure, public :: load_from_toml => compile_command_load_toml generic, public :: operator(==) => serializable_is_same procedure, public :: serializable_is_same => compile_command_is_same Serialization interface procedure, public, non_overridable :: test_serialization Test load/write roundtrip type, public, extends( serializable_t ) :: compile_command_table_t Components Type Visibility Attributes Name Initial type( compile_command_t ), public, allocatable :: command (:) Type-Bound Procedures procedure, public :: destroy => cct_destroy Operation generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit procedure, public :: dump_to_toml => cct_dump_toml generic, public :: load => load_from_toml , load_from_file, load_from_unit procedure, public :: load_from_toml => cct_load_toml generic, public :: operator(==) => serializable_is_same generic, public :: register => cct_register, cct_register_object procedure, public :: serializable_is_same => cct_is_same Serialization interface procedure, public, non_overridable :: test_serialization Test load/write roundtrip procedure, public :: write => cct_write Functions public function cct_is_same (this, that) Check that two compile_command_table_t objects are equal\nAll checks passed! Arguments Type Intent Optional Attributes Name class( compile_command_table_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical public function cct_new (directory, arguments, file) result(cct) Override default initializer (GCC 15 bug) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: directory character(len=*), intent(in), optional :: arguments (:) character(len=*), intent(in) :: file Return Value type( compile_command_t ) public function compile_command_is_same (this, that) Check that two compile_command_t objects are equal\nAll checks passed! Arguments Type Intent Optional Attributes Name class( compile_command_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical Subroutines public elemental subroutine cct_destroy (self) Cleanup a compile command table Arguments Type Intent Optional Attributes Name class( compile_command_table_t ), intent(inout) :: self Instance of the serializable object public subroutine cct_dump_array (self, array, error) Dump compile_command_table_t to a toml array Arguments Type Intent Optional Attributes Name class( compile_command_table_t ), intent(inout) :: self Instance of the serializable object type(toml_array), intent(inout) :: array Data structure type( error_t ), intent(out), allocatable :: error Error handling public subroutine cct_dump_toml (self, table, error) Dump compile_command_table_t to toml table Arguments Type Intent Optional Attributes Name class( compile_command_table_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling public subroutine cct_load_toml (self, table, error) Read compile_command_table_t from toml table (no checks made at this stage) Arguments Type Intent Optional Attributes Name class( compile_command_table_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling public subroutine cct_register (self, command, target_os, error) Register a new compile command Arguments Type Intent Optional Attributes Name class( compile_command_table_t ), intent(inout) :: self Instance of the serializable object character(len=*), intent(in) :: command Data structure integer, intent(in) :: target_os The target OS of the compile_commands.json (may be cross-compiling) type( error_t ), intent(out), allocatable :: error Error handling public pure subroutine cct_register_object (self, command, error) Arguments Type Intent Optional Attributes Name class( compile_command_table_t ), intent(inout) :: self Instance of the serializable object type( compile_command_t ), intent(in) :: command Data structure type( error_t ), intent(out), allocatable :: error Error handling public subroutine cct_write (self, filename, error) Write compile_commands.json file. Because Jonquil does not support non-named arrays,\ncreate a custom json here. Arguments Type Intent Optional Attributes Name class( compile_command_table_t ), intent(inout) :: self Instance of the serializable object character(len=*), intent(in) :: filename The file name type( error_t ), intent(out), allocatable :: error Error handling public elemental subroutine compile_command_destroy (self) Cleanup compile command Arguments Type Intent Optional Attributes Name class( compile_command_t ), intent(inout) :: self Instance of the serializable object public subroutine compile_command_dump_toml (self, table, error) Dump compile_command_t to toml table Arguments Type Intent Optional Attributes Name class( compile_command_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling public subroutine compile_command_load_toml (self, table, error) Read compile_command_t from toml table (no checks made at this stage) Arguments Type Intent Optional Attributes Name class( compile_command_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling","tags":"","url":"module/fpm_compile_commands.html"},{"title":"fpm_backend_output – Fortran-lang/fpm","text":"Build Backend Progress Output This module provides a derived type build_progress_t for printing build status\n and progress messages to the console while the backend is building the package. The build_progress_t type supports two modes: normal and plain where the former does ‘pretty’ output and the latter does not.\n The normal mode is intended for typical interactive usage whereas\n ‘plain’ mode is used with the --verbose flag or when stdout is not attached\n to a terminal (e.g. when piping or redirecting stdout ). In these cases,\n the pretty output must be suppressed to avoid control codes being output. Uses fpm_compile_commands fpm_error fpm_targets iso_fortran_env fpm_backend_console fpm_filesystem Interfaces public interface build_progress_t Constructor for build_progress_t private function new_build_progress(target_queue, plain_mode) result(progress) Initialise a new build progress object Arguments Type Intent Optional Attributes Name type( build_target_ptr ), intent(in), target :: target_queue (:) The queue of scheduled targets logical, intent(in), optional :: plain_mode Enable ‘plain’ output for progress object Return Value type( build_progress_t ) Progress object to initialise Derived Types type, public :: build_progress_t Build progress object Components Type Visibility Attributes Name Initial type( compile_command_table_t ), public :: compile_commands The compile_commands.json table type( console_t ), public :: console Console object for updating console lines integer, public :: n_complete Number of completed targets integer, public :: n_target Total number of targets scheduled integer, public, allocatable :: output_lines (:) Store needed when updating previous console lines logical, public :: plain_mode = .true. ‘Plain’ output (no colors or updating) type( build_target_ptr ), public, pointer :: target_queue (:) Queue of scheduled build targets Constructor Constructor for build_progress_t private\n\n \n function new_build_progress (target_queue, plain_mode) Initialise a new build progress object Type-Bound Procedures procedure, public :: compiling_status => output_status_compiling Output ‘compiling’ status for build target procedure, public :: completed_status => output_status_complete Output ‘complete’ status for build target procedure, public :: dump_commands => output_write_compile_commands Output ‘compile_commands.json’ to build/ folder procedure, public :: success => output_progress_success Output finished status for whole package","tags":"","url":"module/fpm_backend_output.html"},{"title":"fpm_release – Fortran-lang/fpm","text":"Release parameters Module fpm_release contains public constants storing this build’s unique version IDs Uses fpm_versioning fpm_error Functions public function fpm_version () Return the current fpm version from fpm_version_ID as a version type Arguments None Return Value type( version_t )","tags":"","url":"module/fpm_release.html"},{"title":"fpm_manifest – Fortran-lang/fpm","text":"Package configuration data. This module provides the necessary procedure to translate a TOML document\nto the corresponding Fortran type, while verifying it with respect to\nits schema. Additionally, the required data types for users of this module are reexported\nto hide the actual implementation details. Uses fpm_toml tomlf fpm_manifest_dependency fpm_manifest_example fpm_manifest_executable fpm_manifest_preprocess fpm_manifest_library fpm_error fpm_manifest_package fpm_manifest_test fpm_environment fpm_strings fpm_filesystem Subroutines public subroutine default_example (self, name) Populate test in case we find the default example/ directory Arguments Type Intent Optional Attributes Name type( example_config_t ), intent(out) :: self Instance of the executable meta data character(len=*), intent(in) :: name Name of the package public subroutine default_executable (self, name) Populate executable in case we find the default app directory Arguments Type Intent Optional Attributes Name type( executable_config_t ), intent(out) :: self Instance of the executable meta data character(len=*), intent(in) :: name Name of the package public subroutine default_library (self) Populate library in case we find the default src directory Arguments Type Intent Optional Attributes Name type( library_config_t ), intent(out) :: self Instance of the library meta data public subroutine default_test (self, name) Populate test in case we find the default test/ directory Arguments Type Intent Optional Attributes Name type( test_config_t ), intent(out) :: self Instance of the executable meta data character(len=*), intent(in) :: name Name of the package public subroutine get_package_data (package, file, error, apply_defaults) Obtain package meta data from a configuation file Arguments Type Intent Optional Attributes Name type( package_config_t ), intent(out) :: package Parsed package meta data character(len=*), intent(in) :: file Name of the package configuration file type( error_t ), intent(out), allocatable :: error Error status of the operation logical, intent(in), optional :: apply_defaults Apply package defaults (uses file system operations) public subroutine get_package_dependencies (package, main, deps) Arguments Type Intent Optional Attributes Name type( package_config_t ), intent(in) :: package Parsed package meta data logical, intent(in) :: main Is the main project type( dependency_config_t ), intent(out), allocatable :: deps (:) Unprocessed list of all dependencies listed in this manifest","tags":"","url":"module/fpm_manifest.html"},{"title":"fpm_filesystem – Fortran-lang/fpm","text":"This module contains general routines for interacting with the file system Directories are not files for the Intel compilers. If so, also use this compiler-dependent extension Uses iso_c_binding fpm_error fpm_strings fpm_environment iso_fortran_env Functions public function basename (path, suffix) result(base) Extract filename from path with/without suffix Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path logical, intent(in), optional :: suffix Return Value character(len=:), allocatable public function canon_path (path) Canonicalize path for comparison\n* Handles path string redundancies\n* Does not test existence of path Read more… Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path Return Value character(len=:), allocatable public function dirname (path) result(dir) Extract dirname from path Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path Return Value character(len=:), allocatable public function exists (filename) result(r) test if pathname already exists Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: filename Return Value logical public function get_dos_path (path, error) Ensure a windows path is converted to an 8.3 DOS path if it contains spaces\nNo need to convert if there are no spaces Read more… Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path type( error_t ), intent(out), allocatable :: error Return Value character(len=:), allocatable public function get_local_prefix (os) result(prefix) Determine the path prefix to the local folder. Used for installation, registry etc. Arguments Type Intent Optional Attributes Name integer, intent(in), optional :: os Platform identifier Return Value character(len=:), allocatable Installation prefix public function get_temp_filename () result(tempfile) Get a unused temporary filename\n Calls posix ‘tempnam’ - not recommended, but\n we have no security concerns for this application\n and use here is temporary.\nWorks with MinGW Arguments None Return Value character(len=:), allocatable public function is_absolute_path (path, is_unix) Returns .true. if provided path is absolute. Read more… Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path logical, intent(in), optional :: is_unix Return Value logical public function is_dir (dir) test if a name matches an existing directory path Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: dir Return Value logical public function is_hidden_file (file_basename) result(r) test if a file is hidden Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: file_basename Return Value logical public function join_path (a1, a2, a3, a4, a5) result(path) Construct path by joining strings with os file separator Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: a1 character(len=*), intent(in) :: a2 character(len=*), intent(in), optional :: a3 character(len=*), intent(in), optional :: a4 character(len=*), intent(in), optional :: a5 Return Value character(len=:), allocatable public function number_of_rows (s) result(nrows) Determine number or rows in a file given a LUN Arguments Type Intent Optional Attributes Name integer, intent(in) :: s Return Value integer public function parent_dir (path) result(dir) Extract dirname from path Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path Return Value character(len=:), allocatable public function read_lines (filename) result(lines) read lines into an array of TYPE(STRING_T) variables Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: filename Return Value type( string_t ), allocatable, (:) public function read_lines_expanded (filename) result(lines) read lines into an array of TYPE(STRING_T) variables expanding tabs Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: filename Return Value type( string_t ), allocatable, (:) public function unix_path (path) result(nixpath) Replace file system separators for unix Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path Return Value character(len=:), allocatable public function which (command) result(pathname) Author John S. Urban License Public Domain function which(command) result(pathname) Read more… Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: command Return Value character(len=:), allocatable public function windows_path (path) result(winpath) Replace file system separators for windows Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: path Return Value character(len=:), allocatable Subroutines public subroutine delete_file (file) delete a file by filename Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: file public subroutine execute_and_read_output (cmd, output, error, verbose) Execute command line and return output as a string. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: cmd Command to execute. character(len=:), intent(out), allocatable :: output Command line output. type( error_t ), intent(out), allocatable :: error Error to handle. logical, intent(in), optional :: verbose Print additional information if true. public subroutine fileclose (lun, ier) simple close of a LUN. On error show message and stop (by default) Arguments Type Intent Optional Attributes Name integer, intent(in) :: lun integer, intent(out), optional :: ier public subroutine fileopen (filename, lun, ier) procedure to open filename as a sequential “text” file Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: filename integer, intent(out) :: lun integer, intent(out), optional :: ier public subroutine filewrite (filename, filedata) procedure to write filedata to file filename Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: filename character(len=*), intent(in) :: filedata (:) public subroutine get_home (home, error) Get the HOME directory on Unix and the %USERPROFILE% directory on Windows. Arguments Type Intent Optional Attributes Name character(len=:), intent(out), allocatable :: home type( error_t ), intent(out), allocatable :: error public subroutine getline (unit, line, iostat, iomsg) Author fpm(1) contributors License MIT subroutine getline(unit,line,iostat,iomsg) Read more… Arguments Type Intent Optional Attributes Name integer, intent(in) :: unit Formatted IO unit character(len=:), intent(out), allocatable :: line Line to read integer, intent(out) :: iostat Status of operation character(len=:), optional, allocatable :: iomsg Error message public recursive subroutine list_files (dir, files, recurse) Get file & directory names in directory dir using iso_c_binding. Read more… Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: dir type( string_t ), intent(out), allocatable :: files (:) logical, intent(in), optional :: recurse public subroutine mkdir (dir, echo) Create a directory. Create subdirectories as needed Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: dir logical, intent(in), optional :: echo public subroutine os_delete_dir (is_unix, dir, echo) Delete directory using system OS remove directory commands Arguments Type Intent Optional Attributes Name logical, intent(in) :: is_unix character(len=*), intent(in) :: dir logical, intent(in), optional :: echo public subroutine run (cmd, echo, exitstat, verbose, redirect) Author fpm(1) contributors License MIT Execute the specified system command. Optionally Read more… Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: cmd logical, intent(in), optional :: echo integer, intent(out), optional :: exitstat logical, intent(in), optional :: verbose character(len=*), intent(in), optional :: redirect public subroutine warnwrite (fname, data) write trimmed character data to a file if it does not exist Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: fname character(len=*), intent(in) :: data (:)","tags":"","url":"module/fpm_filesystem.html"},{"title":"fpm_manifest_example – Fortran-lang/fpm","text":"Implementation of the meta data for an example. The example data structure is effectively a decorated version of an executable\n and shares most of its properties, except for the defaults and can be\n handled under most circumstances just like any other executable. A example table can currently have the following fields [[ example ]] name = \"string\" source-dir = \"path\" main = \"file\" link = [ \"lib\" ] [example.dependencies] Uses fpm_toml tomlf fpm_manifest_dependency fpm_error fpm_manifest_executable Derived Types type, public, extends( executable_config_t ) :: example_config_t Configuation meta data for an example Components Type Visibility Attributes Name Initial type( dependency_config_t ), public, allocatable :: dependency (:) Dependency meta data for this executable type( string_t ), public, allocatable :: link (:) Libraries to link against character(len=:), public, allocatable :: main Name of the source file declaring the main program character(len=:), public, allocatable :: name Name of the resulting executable character(len=:), public, allocatable :: source_dir Source directory for collecting the executable Type-Bound Procedures generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit procedure, public :: dump_to_toml procedure, public :: info Print information on this instance generic, public :: load => load_from_toml , load_from_file, load_from_unit procedure, public :: load_from_toml generic, public :: operator(==) => serializable_is_same procedure, public :: serializable_is_same => exe_is_same Serialization interface procedure, public, non_overridable :: test_serialization Test load/write roundtrip Subroutines public subroutine new_example (self, table, error) Construct a new example configuration from a TOML data structure Arguments Type Intent Optional Attributes Name type( example_config_t ), intent(out) :: self Instance of the example configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling","tags":"","url":"module/fpm_manifest_example.html"},{"title":"fpm_compiler – Fortran-lang/fpm","text":"Define compiler command options This module defines compiler options to use for the debug and release builds. Uses fpm_toml fpm_compile_commands tomlf fpm_manifest fpm_error fpm_strings fpm_environment iso_fortran_env shlex_module fpm_filesystem Variables Type Visibility Attributes Name Initial integer, public, parameter :: compiler_enum = kind(id_unknown) character(len=*), public, parameter :: flag_cray_fixed_form = \" -ffixed\" character(len=*), public, parameter :: flag_cray_free_form = \" -ffree\" character(len=*), public, parameter :: flag_cray_implicit_typing = \" -el\" character(len=*), public, parameter :: flag_cray_no_implicit_typing = \" -dl\" character(len=*), public, parameter :: flag_flang_new_openmp = \" -fopenmp\" character(len=*), public, parameter :: flag_gnu_backtrace = \" -fbacktrace\" character(len=*), public, parameter :: flag_gnu_check = \" -fcheck=bounds -fcheck=array-temps\" character(len=*), public, parameter :: flag_gnu_coarray = \" -fcoarray=single\" character(len=*), public, parameter :: flag_gnu_debug = \" -g\" character(len=*), public, parameter :: flag_gnu_external = \" -Wimplicit-interface\" character(len=*), public, parameter :: flag_gnu_fixed_form = \" -ffixed-form\" character(len=*), public, parameter :: flag_gnu_free_form = \" -ffree-form\" character(len=*), public, parameter :: flag_gnu_limit = \" -fmax-errors=1\" character(len=*), public, parameter :: flag_gnu_no_implicit_external = \" -Werror=implicit-interface\" character(len=*), public, parameter :: flag_gnu_no_implicit_typing = \" -fimplicit-none\" character(len=*), public, parameter :: flag_gnu_openmp = \" -fopenmp\" character(len=*), public, parameter :: flag_gnu_opt = \" -O3 -funroll-loops\" character(len=*), public, parameter :: flag_gnu_pic = \" -fPIC\" character(len=*), public, parameter :: flag_gnu_warn = \" -Wall -Wextra\" character(len=*), public, parameter :: flag_ibmxl_backslash = \" -qnoescape\" character(len=*), public, parameter :: flag_intel_align = \" -align all\" character(len=*), public, parameter :: flag_intel_align_win = \" /align:all\" character(len=*), public, parameter :: flag_intel_backtrace = \" -traceback\" character(len=*), public, parameter :: flag_intel_backtrace_win = \" /traceback\" character(len=*), public, parameter :: flag_intel_byterecl = \" -assume byterecl\" character(len=*), public, parameter :: flag_intel_byterecl_win = \" /assume:byterecl\" character(len=*), public, parameter :: flag_intel_check = \" -check all\" character(len=*), public, parameter :: flag_intel_check_win = \" /check:all\" character(len=*), public, parameter :: flag_intel_debug = \" -O0 -g\" character(len=*), public, parameter :: flag_intel_debug_win = \" /Od /Z7\" character(len=*), public, parameter :: flag_intel_fixed_form = \" -fixed\" character(len=*), public, parameter :: flag_intel_fixed_form_win = \" /fixed\" character(len=*), public, parameter :: flag_intel_fp = \" -fp-model precise -pc64\" character(len=*), public, parameter :: flag_intel_fp_win = \" /fp:precise\" character(len=*), public, parameter :: flag_intel_free_form = \" -free\" character(len=*), public, parameter :: flag_intel_free_form_win = \" /free\" character(len=*), public, parameter :: flag_intel_limit = \" -error-limit 1\" character(len=*), public, parameter :: flag_intel_limit_win = \" /error-limit:1\" character(len=*), public, parameter :: flag_intel_llvm_check = \" -check all,nouninit\" character(len=*), public, parameter :: flag_intel_nogen = \" -nogen-interfaces\" character(len=*), public, parameter :: flag_intel_nogen_win = \" /nogen-interfaces\" character(len=*), public, parameter :: flag_intel_openmp = \" -qopenmp\" character(len=*), public, parameter :: flag_intel_openmp_win = \" /Qopenmp\" character(len=*), public, parameter :: flag_intel_opt = \" -O3\" character(len=*), public, parameter :: flag_intel_opt_win = \" /O3\" character(len=*), public, parameter :: flag_intel_pthread = \" -reentrancy threaded\" character(len=*), public, parameter :: flag_intel_pthread_win = \" /reentrancy:threaded\" character(len=*), public, parameter :: flag_intel_standard_compliance = \" -standard-semantics\" character(len=*), public, parameter :: flag_intel_standard_compliance_win = \" /standard-semantics\" character(len=*), public, parameter :: flag_intel_unknown_cmd_err = \" -diag-error 10006\" character(len=*), public, parameter :: flag_intel_unknown_cmd_err_win = \" /Qdiag-error:10006\" character(len=*), public, parameter :: flag_intel_warn = \" -warn all\" character(len=*), public, parameter :: flag_intel_warn_win = \" /warn:all\" character(len=*), public, parameter :: flag_lfortran_fixed_form = \" --fixed-form\" character(len=*), public, parameter :: flag_lfortran_implicit_external = \" --implicit-interface\" character(len=*), public, parameter :: flag_lfortran_implicit_typing = \" --implicit-typing\" character(len=*), public, parameter :: flag_lfortran_openmp = \" --openmp\" character(len=*), public, parameter :: flag_lfortran_opt = \" --fast\" character(len=*), public, parameter :: flag_nag_backtrace = \" -gline\" character(len=*), public, parameter :: flag_nag_check = \" -C\" character(len=*), public, parameter :: flag_nag_coarray = \" -coarray=single\" character(len=*), public, parameter :: flag_nag_debug = \" -g -O0\" character(len=*), public, parameter :: flag_nag_fixed_form = \" -fixed\" character(len=*), public, parameter :: flag_nag_free_form = \" -free\" character(len=*), public, parameter :: flag_nag_no_implicit_typing = \" -u\" character(len=*), public, parameter :: flag_nag_openmp = \" -openmp\" character(len=*), public, parameter :: flag_nag_opt = \" -O4\" character(len=*), public, parameter :: flag_nag_pic = \" -PIC\" character(len=*), public, parameter :: flag_pgi_backslash = \" -Mbackslash\" character(len=*), public, parameter :: flag_pgi_check = \" -Mbounds -Mchkptr -Mchkstk\" character(len=*), public, parameter :: flag_pgi_debug = \" -g\" character(len=*), public, parameter :: flag_pgi_fixed_form = \" -Mfixed\" character(len=*), public, parameter :: flag_pgi_free_form = \" -Mfree\" character(len=*), public, parameter :: flag_pgi_openmp = \" -mp\" character(len=*), public, parameter :: flag_pgi_traceback = \" -traceback\" character(len=*), public, parameter :: flag_pgi_warn = \" -Minform=inform\" Enumerations enum, bind(c) Enumerators enumerator :: id_unknown = 0 enumerator :: id_gcc = 1 enumerator :: id_f95 = 2 enumerator :: id_caf = 3 enumerator :: id_intel_classic_nix = 4 enumerator :: id_intel_classic_mac = 5 enumerator :: id_intel_classic_windows = 6 enumerator :: id_intel_llvm_nix = 7 enumerator :: id_intel_llvm_windows = 8 enumerator :: id_intel_llvm_unknown = 9 enumerator :: id_pgi = 10 enumerator :: id_nvhpc = 11 enumerator :: id_nag = 12 enumerator :: id_flang = 13 enumerator :: id_flang_new = 14 enumerator :: id_f18 = 15 enumerator :: id_ibmxl = 16 enumerator :: id_cray = 17 enumerator :: id_lahey = 18 enumerator :: id_lfortran = 19 Interfaces public interface debug Create debug printout public pure function debug_compiler (self) result(repr) String representation of a compiler object Arguments Type Intent Optional Attributes Name type( compiler_t ), intent(in) :: self Instance of the compiler object Return Value character(len=:), allocatable Representation as string public pure function debug_archiver (self) result(repr) String representation of an archiver object Arguments Type Intent Optional Attributes Name type( archiver_t ), intent(in) :: self Instance of the archiver object Return Value character(len=:), allocatable Representation as string Derived Types type, public, extends( serializable_t ) :: archiver_t Definition of archiver object Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: ar Path to archiver logical, public :: echo = .true. Print all command logical, public :: use_response_file = .false. Use response files to pass arguments logical, public :: verbose = .true. Verbose output of command Type-Bound Procedures generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit procedure, public :: dump_to_toml generic, public :: load => load_from_toml , load_from_file, load_from_unit procedure, public :: load_from_toml procedure, public :: make_archive Create static archive generic, public :: operator(==) => serializable_is_same procedure, public :: serializable_is_same => ar_is_same Serialization interface procedure, public, non_overridable :: test_serialization Test load/write roundtrip type, public, extends( serializable_t ) :: compiler_t Definition of compiler object Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: cc Path to the C compiler character(len=:), public, allocatable :: cxx Path to the C++ compiler logical, public :: echo = .true. Print all commands character(len=:), public, allocatable :: fc Path to the Fortran compiler integer(kind=compiler_enum), public :: id = id_unknown Identifier of the compiler logical, public :: verbose = .true. Verbose output of command Type-Bound Procedures procedure, public :: check_flags_supported procedure, public :: check_fortran_source_runs Fortran feature support procedure, public :: compile_c Compile a C object procedure, public :: compile_cpp Compile a CPP object procedure, public :: compile_fortran Compile a Fortran object generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit procedure, public :: dump_to_toml => compiler_dump procedure, public :: enumerate_libraries Enumerate libraries, based on compiler and platform procedure, public :: get_default_flags Get default compiler flags procedure, public :: get_export_flags Get library export flags procedure, public :: get_feature_flag Get feature flag procedure, public :: get_headerpad_flags Generate header padding flags for macOS executables procedure, public :: get_include_flag Get flag for include directories procedure, public :: get_install_name_flags Get library install name flags procedure, public :: get_main_flags Get flags for the main linking command procedure, public :: get_module_flag Get flag for module output directories procedure, public :: is_gnu Check whether this is a GNU compiler procedure, public :: is_intel Check whether this is an Intel compiler procedure, public :: is_unknown Check whether compiler is recognized procedure, public :: link => link_executable Link executable procedure, public :: link_shared Link a shared library generic, public :: load => load_from_toml , load_from_file, load_from_unit procedure, public :: load_from_toml => compiler_load procedure, public :: name => compiler_name Return compiler name generic, public :: operator(==) => serializable_is_same procedure, public :: serializable_is_same => compiler_is_same Serialization interface procedure, public, non_overridable :: test_serialization Test load/write roundtrip procedure, public :: with_qp procedure, public :: with_xdp Functions public function ar_is_same (this, that) Check that two archiver_t objects are equal\nAll checks passed! Arguments Type Intent Optional Attributes Name class( archiver_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical public function check_compiler (compiler, expected) result(match) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: compiler character(len=*), intent(in) :: expected Return Value logical public function check_flags_supported (self, compile_flags, link_flags) Check if the given compile and/or link flags are accepted by the compiler Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in), optional :: compile_flags character(len=*), intent(in), optional :: link_flags Return Value logical public function check_fortran_source_runs (self, input, compile_flags, link_flags) result(success) Run a single-source Fortran program using the current compiler\nCompile a Fortran object\nCreate temporary source file\nWrite contents\nGet flags\nIntel: Needs -warn last for error on unknown command line arguments to work\nCompile and link program\nRun and retrieve exit code Read more… Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object character(len=*), intent(in) :: input Program Source character(len=*), intent(in), optional :: compile_flags Optional build and link flags character(len=*), intent(in), optional :: link_flags Optional build and link flags Return Value logical public function compiler_is_same (this, that) Check that two compiler_t objects are equal\nAll checks passed! Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: this class( serializable_t ), intent(in) :: that Return Value logical public pure function compiler_name (self) result(name) Return a compiler name string Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object Return Value character(len=:), allocatable Representation as string public pure function debug_archiver (self) result(repr) String representation of an archiver object Arguments Type Intent Optional Attributes Name type( archiver_t ), intent(in) :: self Instance of the archiver object Return Value character(len=:), allocatable Representation as string public pure function debug_compiler (self) result(repr) String representation of a compiler object Arguments Type Intent Optional Attributes Name type( compiler_t ), intent(in) :: self Instance of the compiler object Return Value character(len=:), allocatable Representation as string public function enumerate_libraries (self, prefix, libs) result(r) Enumerate libraries, based on compiler and platform Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: prefix type( string_t ), intent(in) :: libs (:) Return Value character(len=:), allocatable public function get_compiler_id (compiler) result(id) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: compiler Return Value integer(kind=compiler_enum) public function get_default_flags (self, release) result(flags) Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self logical, intent(in) :: release Return Value character(len=:), allocatable public function get_export_flags (self, target_dir, target_name) result(export_flags) Generate library export flags for a shared library build Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler character(len=*), intent(in) :: target_dir Path and package name character(len=*), intent(in) :: target_name Path and package name Return Value character(len=:), allocatable public function get_feature_flag (self, feature) result(flags) Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: feature Return Value character(len=:), allocatable public function get_headerpad_flags (self) result(flags) Generate header padding flags for install_name_tool compatibility on macOS Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Return Value character(len=:), allocatable public function get_id (compiler) result(id) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: compiler Return Value integer(kind=compiler_enum) public function get_include_flag (self, path) result(flags) Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: path Return Value character(len=:), allocatable public function get_install_name_flags (self, target_dir, target_name) result(flags) Generate install_name flag for a shared library build on macOS Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: target_dir character(len=*), intent(in) :: target_name Return Value character(len=:), allocatable public function get_macros (id, macros_list, version) result(macros) This function will parse and read the macros list and\nreturn them as defined flags.\nSet macro defintion symbol on the basis of compiler used\nCheck if macros are not allocated.\nSplit the macro name and value. Read more… Arguments Type Intent Optional Attributes Name integer(kind=compiler_enum), intent(in) :: id type( string_t ), intent(in), allocatable :: macros_list (:) character(len=:), intent(in), allocatable :: version Return Value character(len=:), allocatable public function get_module_flag (self, path) result(flags) Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: path Return Value character(len=:), allocatable public function get_shared_flag (self) result(shared_flag) Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Return Value character(len=:), allocatable public pure function is_gnu (self) Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Return Value logical public pure function is_intel (self) Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Return Value logical public pure function is_unknown (self) Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Return Value logical public function with_qp (self) Check if the current compiler supports 128-bit real precision Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object Return Value logical public function with_xdp (self) Check if the current compiler supports 80-bit “extended” real precision Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object Return Value logical Subroutines public subroutine append_clean_flags (flags, new_flags) Append new flags to existing flags, removing duplicates and empty flags (string version) Arguments Type Intent Optional Attributes Name character(len=:), intent(inout), allocatable :: flags character(len=*), intent(in) :: new_flags public subroutine append_clean_flags_array (flags_array, new_flags_array) Append new flags to existing flags, removing duplicates and empty flags (array version) Arguments Type Intent Optional Attributes Name type( string_t ), intent(inout), allocatable :: flags_array (:) type( string_t ), intent(in) :: new_flags_array (:) public subroutine compile_c (self, input, output, args, log_file, stat, table, dry_run) Compile a C object Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object character(len=*), intent(in) :: input Source file input character(len=*), intent(in) :: output Output file of object character(len=*), intent(in) :: args Arguments for compiler character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag type( compile_command_table_t ), intent(inout), optional :: table Optional compile_commands table logical, intent(in), optional :: dry_run Optional mocking public subroutine compile_cpp (self, input, output, args, log_file, stat, table, dry_run) Compile a CPP object Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object character(len=*), intent(in) :: input Source file input character(len=*), intent(in) :: output Output file of object character(len=*), intent(in) :: args Arguments for compiler character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag type( compile_command_table_t ), intent(inout), optional :: table Optional compile_commands table logical, intent(in), optional :: dry_run Optional mocking public subroutine compile_fortran (self, input, output, args, log_file, stat, table, dry_run) Compile a Fortran object Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object character(len=*), intent(in) :: input Source file input character(len=*), intent(in) :: output Output file of object character(len=*), intent(in) :: args Arguments for compiler character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag type( compile_command_table_t ), intent(inout), optional :: table Optional compile_commands table logical, intent(in), optional :: dry_run Optional mocking public subroutine compiler_dump (self, table, error) Dump dependency to toml table Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling public subroutine compiler_load (self, table, error) Read dependency from toml table (no checks made at this stage) Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling public subroutine dump_to_toml (self, table, error) Dump dependency to toml table Read more… Arguments Type Intent Optional Attributes Name class( archiver_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling public subroutine get_debug_compile_flags (id, flags) Arguments Type Intent Optional Attributes Name integer(kind=compiler_enum), intent(in) :: id character(len=:), intent(out), allocatable :: flags public subroutine get_default_c_compiler (f_compiler, c_compiler) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: f_compiler character(len=:), intent(out), allocatable :: c_compiler public subroutine get_default_cxx_compiler (f_compiler, cxx_compiler) Get C++ Compiler. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: f_compiler character(len=:), intent(out), allocatable :: cxx_compiler public subroutine get_main_flags (self, language, flags) Get special flags for the main linker Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self character(len=*), intent(in) :: language character(len=:), intent(out), allocatable :: flags public subroutine get_release_compile_flags (id, flags) Arguments Type Intent Optional Attributes Name integer(kind=compiler_enum), intent(in) :: id character(len=:), intent(out), allocatable :: flags public subroutine link_executable (self, output, args, log_file, stat, dry_run) Link an executable Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object character(len=*), intent(in) :: output Output file of object character(len=*), intent(in) :: args Arguments for compiler character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag logical, intent(in), optional :: dry_run Optional mocking public subroutine link_shared (self, output, args, log_file, stat, dry_run) Link a shared library Arguments Type Intent Optional Attributes Name class( compiler_t ), intent(in) :: self Instance of the compiler object character(len=*), intent(in) :: output Output file of shared library object character(len=*), intent(in) :: args Arguments for the compiler character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag logical, intent(in), optional :: dry_run Optional mocking public subroutine load_from_toml (self, table, error) Read dependency from toml table (no checks made at this stage) Arguments Type Intent Optional Attributes Name class( archiver_t ), intent(inout) :: self Instance of the serializable object type(toml_table), intent(inout) :: table Data structure type( error_t ), intent(out), allocatable :: error Error handling public subroutine make_archive (self, output, args, log_file, stat, dry_run) Create an archive Read more… Arguments Type Intent Optional Attributes Name class( archiver_t ), intent(in) :: self Instance of the archiver object character(len=*), intent(in) :: output Name of the archive to generate type( string_t ), intent(in) :: args (:) Object files to include into the archive character(len=*), intent(in) :: log_file Compiler output log file integer, intent(out) :: stat Status flag logical, intent(in), optional :: dry_run Optional mocking public subroutine new_archiver (self, ar, echo, verbose) Create new archiver instance Arguments Type Intent Optional Attributes Name type( archiver_t ), intent(out) :: self New instance of the archiver character(len=*), intent(in) :: ar User provided archiver command logical, intent(in) :: echo Echo compiler command logical, intent(in) :: verbose Verbose mode: dump compiler output public subroutine new_compiler (self, fc, cc, cxx, echo, verbose) Create new compiler instance Arguments Type Intent Optional Attributes Name type( compiler_t ), intent(out) :: self New instance of the compiler character(len=*), intent(in) :: fc Fortran compiler name or path character(len=*), intent(in) :: cc C compiler name or path character(len=*), intent(in) :: cxx C++ Compiler name or path logical, intent(in) :: echo Echo compiler command logical, intent(in) :: verbose Verbose mode: dump compiler output public pure subroutine set_cpp_preprocessor_flags (id, flags) Modify the flag_cpp_preprocessor on the basis of the compiler. Arguments Type Intent Optional Attributes Name integer(kind=compiler_enum), intent(in) :: id character(len=:), intent(inout), allocatable :: flags public subroutine tokenize_flags (flags, flags_array) Tokenize a string into an array of compiler flags Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: flags type( string_t ), intent(out), allocatable :: flags_array (:) public subroutine write_response_file (name, argv) Response files allow to read command line options from files.\nWhitespace is used to separate the arguments, we will use newlines\nas separator to create readable response files which can be inspected\nin case of errors. Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: name type( string_t ), intent(in) :: argv (:)","tags":"","url":"module/fpm_compiler.html"},{"title":"fpm_sources – Fortran-lang/fpm","text":"Discovery of sources This module implements subroutines for building a list of [[srcfile_t]] objects by looking for source files in the filesystem. Uses fpm_error fpm_source_parsing fpm_manifest_executable fpm_environment fpm_strings fpm_model fpm_filesystem Functions public function get_exe_name_with_suffix (source) result(suffixed) Build an executable name with suffix. Safe routine that always returns an allocated string Arguments Type Intent Optional Attributes Name type( srcfile_t ), intent(in) :: source Return Value character(len=:), allocatable Subroutines public subroutine add_executable_sources (sources, executables, scope, auto_discover, with_f_ext, error) Add to sources using the executable and test entries in the manifest and\napplies any executable-specific overrides such as executable%name .\nAdds all sources (including modules) from each executable%source_dir Compare lowercase strings to allow auto-discovery of pre-processed extensions Arguments Type Intent Optional Attributes Name type( srcfile_t ), intent(inout), allocatable, target :: sources (:) List of [[srcfile_t]] objects to append to. Allocated if not allocated class( executable_config_t ), intent(in) :: executables (:) List of [[executable_config_t]] entries from manifest integer, intent(in) :: scope Scope to apply to the discovered sources: either FPM_SCOPE_APP or FPM_SCOPE_TEST , see fpm_model logical, intent(in) :: auto_discover If .false. only executables and tests specified in the manifest are added to sources type( string_t ), intent(in), optional :: with_f_ext (:) Additional user-defined (preprocessor) extensions that should be treated as Fortran sources type( error_t ), intent(out), allocatable :: error Error handling public subroutine add_sources_from_dir (sources, directory, scope, with_executables, with_f_ext, recurse, error) Add to sources by looking for source files in directory Arguments Type Intent Optional Attributes Name type( srcfile_t ), intent(inout), allocatable, target :: sources (:) List of [[srcfile_t]] objects to append to. Allocated if not allocated character(len=*), intent(in) :: directory Directory in which to search for source files integer, intent(in) :: scope Scope to apply to the discovered sources, see fpm_model for enumeration logical, intent(in), optional :: with_executables Executable sources (fortran program s) are ignored unless with_executables=.true. type( string_t ), intent(in), optional :: with_f_ext (:) Additional user-defined (preprocessor) extensions that should be treated as Fortran sources logical, intent(in), optional :: recurse Whether to recursively search subdirectories, default is .true. type( error_t ), intent(out), allocatable :: error Error handling","tags":"","url":"module/fpm_sources.html"},{"title":"fpm_meta_base – Fortran-lang/fpm","text":"Uses fpm_versioning fpm_command_line fpm_manifest_dependency fpm_manifest fpm_error fpm_manifest_preprocess fpm_strings fpm_compiler fpm_model Derived Types type, public :: metapackage_t Type for describing a source file Components Type Visibility Attributes Name Initial type( string_t ), public :: cflags type( string_t ), public :: cxxflags type( dependency_config_t ), public, allocatable :: dependency (:) List of Development dependency meta data.\nMetapackage dependencies are never exported from the model type( string_t ), public, allocatable :: external_modules (:) type( string_t ), public :: fflags type( string_t ), public :: flags List of compiler flags and options to be added type( fortran_features_t ), public, allocatable :: fortran Special fortran features logical, public :: has_build_flags = .false. logical, public :: has_c_flags = .false. logical, public :: has_cxx_flags = .false. logical, public :: has_dependencies = .false. logical, public :: has_external_modules = .false. logical, public :: has_fortran_flags = .false. logical, public :: has_include_dirs = .false. logical, public :: has_link_flags = .false. logical, public :: has_link_libraries = .false. logical, public :: has_run_command = .false. type( string_t ), public, allocatable :: incl_dirs (:) type( string_t ), public :: link_flags type( string_t ), public, allocatable :: link_libs (:) character(len=:), public, allocatable :: name Package name type( preprocess_config_t ), public, allocatable :: preprocess Preprocessor configuration type( string_t ), public :: run_command type( version_t ), public, allocatable :: version Package version (if supported) Type-Bound Procedures procedure, public :: destroy Clean metapackage structure generic, public :: resolve => resolve_cmd, resolve_model, resolve_package_config Subroutines public elemental subroutine destroy (this) Arguments Type Intent Optional Attributes Name class( metapackage_t ), intent(inout) :: this","tags":"","url":"module/fpm_meta_base.html"},{"title":"fpm_downloader – Fortran-lang/fpm","text":"Uses fpm_versioning fpm_error fpm_strings jonquil fpm_filesystem Derived Types type, public :: downloader_t This type could be entirely avoided but it is quite practical because it can be mocked for testing. Type-Bound Procedures procedure, public, nopass :: get_file procedure, public, nopass :: get_pkg_data procedure, public, nopass :: unpack procedure, public, nopass :: upload_form","tags":"","url":"module/fpm_downloader.html"},{"title":"fpm_source_parsing – Fortran-lang/fpm","text":"Parsing of package source files This module exposes two functions, [[parse_f_source]] and [[parse_c_source]] ,\n which perform a rudimentary parsing of fortran and c source files\n in order to extract information required for module dependency tracking. Both functions additionally calculate and store a file digest (hash) which\n is used by the backend ( fpm_backend ) to skip compilation of unmodified sources. Both functions return an instance of the srcfile_t type. For more information, please read the documentation for each function: [[parse_f_source]] [[parse_c_source]] Uses fpm_strings fpm_model fpm_error fpm_filesystem Functions public function parse_c_source (c_filename, error) result(c_source) Parsing of c, cpp source files Read more… Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: c_filename type( error_t ), intent(out), allocatable :: error Return Value type( srcfile_t ) public function parse_f_source (f_filename, error) result(f_source) Parsing of free-form fortran source files Read more… Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: f_filename type( error_t ), intent(out), allocatable :: error Return Value type( srcfile_t ) Subroutines public subroutine parse_use_statement (f_filename, i, line, use_stmt, is_intrinsic, module_name, error) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: f_filename Current file name and line number (for error messaging) integer, intent(in) :: i character(len=*), intent(in) :: line The line being parsed. MUST BE preprocessed with trim(adjustl() logical, intent(out) :: use_stmt Does this line contain a use statement? logical, intent(out) :: is_intrinsic Is the module in this statement intrinsic? character(len=:), intent(out), allocatable :: module_name used module name type( error_t ), intent(out), allocatable :: error Error handling","tags":"","url":"module/fpm_source_parsing.html"},{"title":"fpm_manifest_executable – Fortran-lang/fpm","text":"Implementation of the meta data for an executables. An executable table can currently have the following fields [[ executable ]] name = \"string\" source-dir = \"path\" main = \"file\" link = [ \"lib\" ] [executable.dependencies] Uses fpm_toml tomlf fpm_manifest_dependency fpm_error fpm_strings Derived Types type, public, extends( serializable_t ) :: executable_config_t Configuation meta data for an executable Components Type Visibility Attributes Name Initial type( dependency_config_t ), public, allocatable :: dependency (:) Dependency meta data for this executable type( string_t ), public, allocatable :: link (:) Libraries to link against character(len=:), public, allocatable :: main Name of the source file declaring the main program character(len=:), public, allocatable :: name Name of the resulting executable character(len=:), public, allocatable :: source_dir Source directory for collecting the executable Type-Bound Procedures generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit procedure, public :: dump_to_toml procedure, public :: info Print information on this instance generic, public :: load => load_from_toml , load_from_file, load_from_unit procedure, public :: load_from_toml generic, public :: operator(==) => serializable_is_same procedure, public :: serializable_is_same => exe_is_same Serialization interface procedure, public, non_overridable :: test_serialization Test load/write roundtrip Subroutines public subroutine new_executable (self, table, error) Construct a new executable configuration from a TOML data structure Arguments Type Intent Optional Attributes Name type( executable_config_t ), intent(out) :: self Instance of the executable configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling","tags":"","url":"module/fpm_manifest_executable.html"},{"title":"fpm_meta_hdf5 – Fortran-lang/fpm","text":"Uses fpm_pkg_config fpm_error fpm_strings fpm_compiler fpm_meta_util fpm_manifest_metapackages fpm_meta_base fpm_filesystem Subroutines public subroutine init_hdf5 (this, compiler, all_meta, error) Initialize HDF5 metapackage for the current system\nCleanup\nSet name Read more… Arguments Type Intent Optional Attributes Name class( metapackage_t ), intent(inout) :: this type( compiler_t ), intent(in) :: compiler type( metapackage_request_t ), intent(in) :: all_meta (:) type( error_t ), intent(out), allocatable :: error","tags":"","url":"module/fpm_meta_hdf5.html"},{"title":"fpm_cmd_new – Fortran-lang/fpm","text":"Definition of the “new” subcommand A type of the general command base class fpm_cmd_settings was created for the “new” subcommand ==> type fpm_new_settings .\n This procedure read the values that were set on the command line\n from this type to decide what actions to take. It is virtually self-contained and so independant of the rest of the\n application that it could function as a separate program. The “new” subcommand options currently consist of a SINGLE top\n directory name to create that must have a name that is an\n allowable Fortran variable name. That should have been ensured\n by the command line processing before this procedure is called.\n So basically this routine has already had the options vetted and\n just needs to conditionally create a few files. As described in the documentation it will selectively\n create the subdirectories app/, test/, src/, and example/\n and populate them with sample files. It also needs to create an initial manifest file “fpm.toml”. It then calls the system command “git init”. It should test for file existence and not overwrite existing\n files and inform the user if there were conflicts. Any changes should be reflected in the documentation in fpm_command_line.f90 FUTURE\n A filename like “.” would need system commands or a standard routine\n like realpath(3c) to process properly. Perhaps allow more than one name on a single command. It is an arbitrary\n restriction based on a concensus preference, not a required limitation. Initially the name of the directory is used as the module name in the\n src file so it must be an allowable Fortran variable name. If there are\n complaints about it it might be changed. Handling unicode at this point\n might be problematic as not all current compilers handle it. Other\n utilities like content trackers (ie. git) or repositories like github\n might also have issues with alternative names or names with spaces, etc.\n So for the time being it seems prudent to encourage simple ASCII top directory\n names (similiar to the primary programming language Fortran itself). Should be able to create or pull more complicated initial examples\n based on various templates. It should place or mention other relevant\n documents such as a description of the manifest file format in user hands;\n or how to access registered packages and local packages,\n although some other command might provide that (and the help command should\n be the first go-to for a CLI utility). Uses fpm_command_line fpm_error fpm_strings fpm_environment iso_fortran_env fpm_filesystem Subroutines public subroutine cmd_new (settings) TOP DIRECTORY NAME PROCESSING\nsee if requested new directory already exists and process appropriately\ntemporarily change to new directory as a test. NB: System dependent Arguments Type Intent Optional Attributes Name type( fpm_new_settings ), intent(in) :: settings","tags":"","url":"module/fpm_cmd_new.html"},{"title":"fpm_manifest_library – Fortran-lang/fpm","text":"Implementation of the meta data for libraries. A library table can currently have the following fields [library] source-dir = \"path\" include-dir = [ \"path1\" , \"path2\" ] build-script = \"file\" Uses fpm_strings fpm_toml fpm_error tomlf Derived Types type, public, extends( serializable_t ) :: library_config_t Configuration meta data for a library Components Type Visibility Attributes Name Initial character(len=:), public, allocatable :: build_script Alternative build script to be invoked type( string_t ), public, allocatable :: include_dir (:) Include path prefix character(len=:), public, allocatable :: lib_type Shared / Static / Monolithic library character(len=:), public, allocatable :: source_dir Source path prefix Type-Bound Procedures generic, public :: dump => dump_to_toml , dump_to_file, dump_to_unit procedure, public :: dump_to_toml procedure, public :: info Print information on this instance generic, public :: load => load_from_toml , load_from_file, load_from_unit procedure, public :: load_from_toml procedure, public, non_overridable :: monolithic Check library types generic, public :: operator(==) => serializable_is_same procedure, public :: serializable_is_same => library_is_same Serialization interface procedure, public, non_overridable :: shared procedure, public, non_overridable :: static procedure, public, non_overridable :: test_serialization Test load/write roundtrip Subroutines public subroutine new_library (self, table, error) Construct a new library configuration from a TOML data structure Arguments Type Intent Optional Attributes Name type( library_config_t ), intent(out) :: self Instance of the library configuration type(toml_table), intent(inout) :: table Instance of the TOML data structure type( error_t ), intent(out), allocatable :: error Error handling","tags":"","url":"module/fpm_manifest_library.html"},{"title":"main – Fortran-lang/fpm","text":"Uses fpm_cmd_update fpm_cmd_export fpm_cmd_new fpm_command_line fpm_os fpm_error fpm fpm_cmd_install iso_fortran_env fpm_cmd_publish fpm_filesystem Variables Type Attributes Name Initial class( fpm_cmd_settings ), allocatable :: cmd_settings type( error_t ), allocatable :: error character(len=:), allocatable :: project_root character(len=:), allocatable :: pwd_start character(len=:), allocatable :: pwd_working character(len=:), allocatable :: working_dir Functions function has_manifest (dir) Arguments Type Intent Optional Attributes Name character(len=*), intent(in) :: dir Return Value logical Subroutines subroutine get_working_dir (settings, working_dir_) Save access to working directory in settings, in case setting have not been allocated Arguments Type Intent Optional Attributes Name class( fpm_cmd_settings ), intent(in), optional :: settings character(len=:), intent(out), allocatable :: working_dir_ subroutine handle_error (error_) Arguments Type Intent Optional Attributes Name type( error_t ), intent(in), optional :: error_ Source Code program main use , intrinsic :: iso_fortran_env , only : error_unit , output_unit use fpm_command_line , only : & fpm_cmd_settings , & fpm_new_settings , & fpm_build_settings , & fpm_export_settings , & fpm_run_settings , & fpm_test_settings , & fpm_install_settings , & fpm_update_settings , & fpm_clean_settings , & fpm_publish_settings , & get_command_line_settings use fpm_error , only : error_t use fpm_filesystem , only : exists , parent_dir , join_path use fpm , only : cmd_build , cmd_run , cmd_clean use fpm_cmd_install , only : cmd_install use fpm_cmd_export , only : cmd_export use fpm_cmd_new , only : cmd_new use fpm_cmd_update , only : cmd_update use fpm_cmd_publish , only : cmd_publish use fpm_os , only : change_directory , get_current_directory implicit none class ( fpm_cmd_settings ), allocatable :: cmd_settings type ( error_t ), allocatable :: error character ( len = :), allocatable :: pwd_start , pwd_working , working_dir , project_root call get_command_line_settings ( cmd_settings ) call get_current_directory ( pwd_start , error ) call handle_error ( error ) call get_working_dir ( cmd_settings , working_dir ) if ( allocated ( working_dir )) then ! Change working directory if requested if ( len_trim ( working_dir ) > 0 ) then call change_directory ( working_dir , error ) call handle_error ( error ) call get_current_directory ( pwd_working , error ) call handle_error ( error ) write ( output_unit , '(*(a))' ) \"fpm: Entering directory '\" // pwd_working // \"'\" else pwd_working = pwd_start end if else pwd_working = pwd_start end if select type ( settings => cmd_settings ) type is ( fpm_new_settings ) class default if (. not . has_manifest ( pwd_working )) then project_root = pwd_working do while (. not . has_manifest ( project_root )) working_dir = parent_dir ( project_root ) if ( len ( working_dir ) == 0 ) exit project_root = working_dir end do if ( has_manifest ( project_root )) then call change_directory ( project_root , error ) call handle_error ( error ) write ( output_unit , '(*(a))' ) \"fpm: Entering directory '\" // project_root // \"'\" end if end if end select select type ( settings => cmd_settings ) type is ( fpm_new_settings ) call cmd_new ( settings ) type is ( fpm_build_settings ) call cmd_build ( settings ) type is ( fpm_run_settings ) call cmd_run ( settings , test = . false .) type is ( fpm_test_settings ) call cmd_run ( settings , test = . true .) type is ( fpm_export_settings ) call cmd_export ( settings ) type is ( fpm_install_settings ) call cmd_install ( settings ) type is ( fpm_update_settings ) call cmd_update ( settings ) type is ( fpm_clean_settings ) call cmd_clean ( settings ) type is ( fpm_publish_settings ) call cmd_publish ( settings ) end select if ( allocated ( project_root )) then write ( output_unit , '(*(a))' ) \"fpm: Leaving directory '\" // project_root // \"'\" end if if ( pwd_start /= pwd_working ) then write ( output_unit , '(*(a))' ) \"fpm: Leaving directory '\" // pwd_working // \"'\" end if contains function has_manifest ( dir ) character ( len =* ), intent ( in ) :: dir logical :: has_manifest has_manifest = exists ( join_path ( dir , \"fpm.toml\" )) end function has_manifest subroutine handle_error ( error_ ) type ( error_t ), optional , intent ( in ) :: error_ if ( present ( error_ )) then write ( error_unit , '(\"[Error]\", 1x, a)' ) error_ % message stop 1 end if end subroutine handle_error !> Save access to working directory in settings, in case setting have not been allocated subroutine get_working_dir ( settings , working_dir_ ) class ( fpm_cmd_settings ), optional , intent ( in ) :: settings character ( len = :), allocatable , intent ( out ) :: working_dir_ if ( present ( settings )) then working_dir_ = settings % working_dir end if end subroutine get_working_dir end program main","tags":"","url":"program/main.html"},{"title":"fpm_model.f90 – Fortran-lang/fpm","text":"Source Code !># The fpm package model !> !> Defines the fpm model data types which encapsulate all information !> required to correctly build a package and its dependencies. !> !> The process (see `[[build_model(subroutine)]]`) for generating a valid `[[fpm_model]]` involves !> source files discovery ([[fpm_sources]]) and parsing ([[fpm_source_parsing]]). !> !> Once a valid `[[fpm_model]]` has been constructed, it may be passed to `[[fpm_targets:targets_from_sources]]` to !> generate a list of build targets for the backend. !> !>### Enumerations !> !> __Source type:__ `FPM_UNIT_*` !> Describes the type of source file — determines build target generation !> !> The logical order of precedence for assigning `unit_type` is as follows: !> !>``` !> if source-file contains program then !> unit_type = FPM_UNIT_PROGRAM !> else if source-file contains non-module subroutine/function then !> unit_type = FPM_UNIT_SUBPROGRAM !> else if source-file contains submodule then !> unit_type = FPM_UNIT_SUBMODULE !> else if source-file contains module then !> unit_type = FPM_UNIT_MODULE !> end if !>``` !> !> @note A source file is only designated `FPM_UNIT_MODULE` if it **only** contains modules - no non-module subprograms. !> (This allows tree-shaking/pruning of build targets based on unused module dependencies.) !> !> __Source scope:__ `FPM_SCOPE_*` !> Describes the scoping rules for using modules — controls module dependency resolution !> module fpm_model use iso_fortran_env , only : int64 use fpm_compiler , only : compiler_t , archiver_t , debug use fpm_dependency , only : dependency_tree_t use fpm_strings , only : string_t , str , len_trim , upper , operator ( == ) use tomlf , only : toml_table , toml_stat use fpm_toml , only : serializable_t , set_value , set_list , get_value , & & get_list , add_table , toml_key , add_array , set_string use fpm_error , only : error_t , fatal_error use fpm_environment , only : OS_WINDOWS , OS_MACOS use fpm_manifest_preprocess , only : preprocess_config_t implicit none private public :: fpm_model_t , srcfile_t , show_model , fortran_features_t , package_t public :: FPM_UNIT_UNKNOWN , FPM_UNIT_PROGRAM , FPM_UNIT_MODULE , & FPM_UNIT_SUBMODULE , FPM_UNIT_SUBPROGRAM , FPM_UNIT_CSOURCE , & FPM_UNIT_CHEADER , FPM_SCOPE_UNKNOWN , FPM_SCOPE_LIB , & FPM_SCOPE_DEP , FPM_SCOPE_APP , FPM_SCOPE_EXAMPLE , FPM_SCOPE_TEST , & FPM_UNIT_CPPSOURCE , FPM_SCOPE_NAME , FPM_UNIT_NAME !> Source type unknown integer , parameter :: FPM_UNIT_UNKNOWN = - 1 !> Source contains a fortran program integer , parameter :: FPM_UNIT_PROGRAM = 1 !> Source **only** contains one or more fortran modules integer , parameter :: FPM_UNIT_MODULE = 2 !> Source contains one or more fortran submodules integer , parameter :: FPM_UNIT_SUBMODULE = 3 !> Source contains one or more fortran subprogram not within modules integer , parameter :: FPM_UNIT_SUBPROGRAM = 4 !> Source type is c source file integer , parameter :: FPM_UNIT_CSOURCE = 5 !> Source type is c header file integer , parameter :: FPM_UNIT_CHEADER = 6 !> Souce type is c++ source file. integer , parameter :: FPM_UNIT_CPPSOURCE = 7 !> Source has no module-use scope integer , parameter :: FPM_SCOPE_UNKNOWN = - 1 !> Module-use scope is library/dependency modules only integer , parameter :: FPM_SCOPE_LIB = 1 !> Module-use scope is library/dependency modules only integer , parameter :: FPM_SCOPE_DEP = 2 !> Module-use scope is library/dependency and app modules integer , parameter :: FPM_SCOPE_APP = 3 !> Module-use scope is library/dependency and test modules integer , parameter :: FPM_SCOPE_TEST = 4 integer , parameter :: FPM_SCOPE_EXAMPLE = 5 !> Enabled Fortran language features type , extends ( serializable_t ) :: fortran_features_t !> Use default implicit typing logical :: implicit_typing = . false . !> Use implicit external interface logical :: implicit_external = . false . !> Form to use for all Fortran sources character (:), allocatable :: source_form contains !> Serialization interface procedure :: serializable_is_same => fft_is_same procedure :: dump_to_toml => fft_dump_to_toml procedure :: load_from_toml => fft_load_from_toml end type fortran_features_t !> Type for describing a source file type , extends ( serializable_t ) :: srcfile_t !> File path relative to cwd character (:), allocatable :: file_name !> Name of executable for FPM_UNIT_PROGRAM character (:), allocatable :: exe_name !> Target module-use scope integer :: unit_scope = FPM_SCOPE_UNKNOWN !> Modules provided by this source file (lowerstring) type ( string_t ), allocatable :: modules_provided (:) !> Type of source unit integer :: unit_type = FPM_UNIT_UNKNOWN !> Parent modules (submodules only) type ( string_t ), allocatable :: parent_modules (:) !> Modules USEd by this source file (lowerstring) type ( string_t ), allocatable :: modules_used (:) !> Files INCLUDEd by this source file type ( string_t ), allocatable :: include_dependencies (:) !> Native libraries to link against type ( string_t ), allocatable :: link_libraries (:) !> Current hash integer ( int64 ) :: digest contains !> Serialization interface procedure :: serializable_is_same => srcfile_is_same procedure :: dump_to_toml => srcfile_dump_to_toml procedure :: load_from_toml => srcfile_load_from_toml end type srcfile_t !> Type for describing a single package type , extends ( serializable_t ) :: package_t !> Name of package character (:), allocatable :: name !> Array of sources type ( srcfile_t ), allocatable :: sources (:) !> List of macros. type ( preprocess_config_t ) :: preprocess !> Package version number. character (:), allocatable :: version !> Module naming conventions logical :: enforce_module_names = . false . !> Prefix for all module names type ( string_t ) :: module_prefix !> Language features type ( fortran_features_t ) :: features contains !> Check if a package will create a library procedure :: has_library => package_has_library !> Serialization interface procedure :: serializable_is_same => package_is_same procedure :: dump_to_toml => package_dump_to_toml procedure :: load_from_toml => package_load_from_toml end type package_t !> Type describing everything required to build !> the root package and its dependencies. type , extends ( serializable_t ) :: fpm_model_t !> Name of root package character (:), allocatable :: package_name !> Array of packages (including the root package) type ( package_t ), allocatable :: packages (:) !> Compiler object type ( compiler_t ) :: compiler !> Archiver object type ( archiver_t ) :: archiver !> Command line flags passed to fortran for compilation character (:), allocatable :: fortran_compile_flags !> Command line flags passed to C for compilation character (:), allocatable :: c_compile_flags !> Command line flags passed to C++ for compilation character (:), allocatable :: cxx_compile_flags !> Command line flags passed to the linker character (:), allocatable :: link_flags !> Base directory for build character (:), allocatable :: build_prefix !> Include directories type ( string_t ), allocatable :: include_dirs (:) !> Native libraries to link against type ( string_t ), allocatable :: link_libraries (:) !> External modules used type ( string_t ), allocatable :: external_modules (:) !> Project dependencies type ( dependency_tree_t ) :: deps !> Whether tests should be added to the build list logical :: include_tests = . true . !> Whether module names should be prefixed with the package name logical :: enforce_module_names = . false . !> Prefix for all module names type ( string_t ) :: module_prefix contains !> Get target link flags procedure :: get_package_libraries_link !> Serialization interface procedure :: serializable_is_same => model_is_same procedure :: dump_to_toml => model_dump_to_toml procedure :: load_from_toml => model_load_from_toml end type fpm_model_t contains function info_package ( p ) result ( s ) ! Returns representation of package_t type ( package_t ), intent ( in ) :: p character (:), allocatable :: s integer :: i s = s // 'package_t(' s = s // 'name=\"' // p % name // '\"' s = s // ', sources=[' do i = 1 , size ( p % sources ) s = s // info_srcfile ( p % sources ( i )) if ( i < size ( p % sources )) s = s // \", \" end do s = s // \"]\" ! Print module naming convention s = s // ', enforce_module_names=\"' // merge ( 'T' , 'F' , p % enforce_module_names ) // '\"' ! Print custom prefix if ( p % enforce_module_names . and . len_trim ( p % module_prefix ) > 0 ) & s = s // ', custom_prefix=\"' // p % module_prefix % s // '\"' s = s // \")\" end function info_package function info_srcfile ( source ) result ( s ) type ( srcfile_t ), intent ( in ) :: source character (:), allocatable :: s integer :: i !type srcfile_t s = \"srcfile_t(\" ! character(:), allocatable :: file_name s = s // 'file_name=\"' // source % file_name // '\"' ! character(:), allocatable :: exe_name s = s // ', exe_name=\"' // source % exe_name // '\"' ! integer :: unit_scope = FPM_SCOPE_UNKNOWN s = s // ', unit_scope=\"' // FPM_SCOPE_NAME ( source % unit_scope ) // '\"' ! type(string_t), allocatable :: modules_provided(:) s = s // \", modules_provided=[\" do i = 1 , size ( source % modules_provided ) s = s // '\"' // source % modules_provided ( i )% s // '\"' if ( i < size ( source % modules_provided )) s = s // \", \" end do s = s // \"]\" s = s // \", parent_modules=[\" do i = 1 , size ( source % parent_modules ) s = s // '\"' // source % parent_modules ( i )% s // '\"' if ( i < size ( source % parent_modules )) s = s // \", \" end do s = s // \"]\" ! integer :: unit_type = FPM_UNIT_UNKNOWN s = s // ', unit_type=\"' // FPM_UNIT_NAME ( source % unit_type ) // '\"' ! type(string_t), allocatable :: modules_used(:) s = s // \", modules_used=[\" do i = 1 , size ( source % modules_used ) s = s // '\"' // source % modules_used ( i )% s // '\"' if ( i < size ( source % modules_used )) s = s // \", \" end do s = s // \"]\" ! type(string_t), allocatable :: include_dependencies(:) s = s // \", include_dependencies=[\" do i = 1 , size ( source % include_dependencies ) s = s // '\"' // source % include_dependencies ( i )% s // '\"' if ( i < size ( source % include_dependencies )) s = s // \", \" end do s = s // \"]\" ! type(string_t), allocatable :: link_libraries(:) s = s // \", link_libraries=[\" do i = 1 , size ( source % link_libraries ) s = s // '\"' // source % link_libraries ( i )% s // '\"' if ( i < size ( source % link_libraries )) s = s // \", \" end do s = s // \"]\" ! integer(int64) :: digest s = s // \", digest=\" // str ( source % digest ) !end type srcfile_t s = s // \")\" end function info_srcfile function info_srcfile_short ( source ) result ( s ) ! Prints a shortened version of srcfile_t type ( srcfile_t ), intent ( in ) :: source character (:), allocatable :: s s = \"srcfile_t(\" s = s // 'file_name=\"' // source % file_name // '\"' s = s // \", ...)\" end function info_srcfile_short function info_model ( model ) result ( s ) type ( fpm_model_t ), intent ( in ) :: model character (:), allocatable :: s integer :: i !type :: fpm_model_t s = \"fpm_model_t(\" ! character(:), allocatable :: package_name s = s // 'package_name=\"' // model % package_name // '\"' ! type(srcfile_t), allocatable :: sources(:) s = s // \", packages=[\" do i = 1 , size ( model % packages ) s = s // info_package ( model % packages ( i )) if ( i < size ( model % packages )) s = s // \", \" end do s = s // \"]\" s = s // ', compiler=(' // debug ( model % compiler ) // ')' s = s // ', archiver=(' // debug ( model % archiver ) // ')' ! character(:), allocatable :: fortran_compile_flags s = s // ', fortran_compile_flags=\"' // model % fortran_compile_flags // '\"' s = s // ', c_compile_flags=\"' // model % c_compile_flags // '\"' s = s // ', cxx_compile_flags=\"' // model % cxx_compile_flags // '\"' s = s // ', link_flags=\"' // model % link_flags // '\"' s = s // ', build_prefix=\"' // model % build_prefix // '\"' ! type(string_t), allocatable :: link_libraries(:) s = s // \", link_libraries=[\" do i = 1 , size ( model % link_libraries ) s = s // '\"' // model % link_libraries ( i )% s // '\"' if ( i < size ( model % link_libraries )) s = s // \", \" end do s = s // \"]\" ! type(string_t), allocatable :: external_modules(:) s = s // \", external_modules=[\" do i = 1 , size ( model % external_modules ) s = s // '\"' // model % external_modules ( i )% s // '\"' if ( i < size ( model % external_modules )) s = s // \", \" end do s = s // \"]\" ! type(dependency_tree_t) :: deps ! TODO: print `dependency_tree_t` properly, which should become part of the ! model, not imported from another file s = s // \", deps=dependency_tree_t(...)\" ! Print module naming convention s = s // ', enforce_module_names=\"' // merge ( 'T' , 'F' , model % enforce_module_names ) // '\"' ! Print custom prefix if ( model % enforce_module_names . and . len_trim ( model % module_prefix ) > 0 ) & s = s // ', custom_prefix=\"' // model % module_prefix % s // '\"' !end type fpm_model_t s = s // \")\" end function info_model subroutine show_model ( model ) ! Prints a human readable representation of the Model type ( fpm_model_t ), intent ( in ) :: model print * , info_model ( model ) end subroutine show_model !> Return the character name of a scope flag function FPM_SCOPE_NAME ( flag ) result ( name ) integer , intent ( in ) :: flag character ( len = :), allocatable :: name select case ( flag ) case ( FPM_SCOPE_UNKNOWN ); name = \"FPM_SCOPE_UNKNOWN\" case ( FPM_SCOPE_LIB ); name = \"FPM_SCOPE_LIB\" case ( FPM_SCOPE_DEP ); name = \"FPM_SCOPE_DEP\" case ( FPM_SCOPE_APP ); name = \"FPM_SCOPE_APP\" case ( FPM_SCOPE_TEST ); name = \"FPM_SCOPE_TEST\" case ( FPM_SCOPE_EXAMPLE ); name = \"FPM_SCOPE_EXAMPLE\" case default ; name = \"INVALID\" end select end function FPM_SCOPE_NAME !> Parse git FPM_SCOPE identifier from a string integer function parse_scope ( name ) result ( scope ) character ( len =* ), intent ( in ) :: name character ( len = len ( name )) :: uppercase !> Make it Case insensitive uppercase = upper ( name ) select case ( trim ( uppercase )) case ( \"FPM_SCOPE_UNKNOWN\" ); scope = FPM_SCOPE_UNKNOWN case ( \"FPM_SCOPE_LIB\" ); scope = FPM_SCOPE_LIB case ( \"FPM_SCOPE_DEP\" ); scope = FPM_SCOPE_DEP case ( \"FPM_SCOPE_APP\" ); scope = FPM_SCOPE_APP case ( \"FPM_SCOPE_TEST\" ); scope = FPM_SCOPE_TEST case ( \"FPM_SCOPE_EXAMPLE\" ); scope = FPM_SCOPE_EXAMPLE case default ; scope = - 9999 end select end function parse_scope !> Return the character name of a unit flag function FPM_UNIT_NAME ( flag ) result ( name ) integer , intent ( in ) :: flag character ( len = :), allocatable :: name select case ( flag ) case ( FPM_UNIT_UNKNOWN ); name = \"FPM_UNIT_UNKNOWN\" case ( FPM_UNIT_PROGRAM ); name = \"FPM_UNIT_PROGRAM\" case ( FPM_UNIT_MODULE ); name = \"FPM_UNIT_MODULE\" case ( FPM_UNIT_SUBMODULE ); name = \"FPM_UNIT_SUBMODULE\" case ( FPM_UNIT_SUBPROGRAM ); name = \"FPM_UNIT_SUBPROGRAM\" case ( FPM_UNIT_CSOURCE ); name = \"FPM_UNIT_CSOURCE\" case ( FPM_UNIT_CPPSOURCE ); name = \"FPM_UNIT_CPPSOURCE\" case ( FPM_UNIT_CHEADER ); name = \"FPM_UNIT_CHEADER\" case default ; name = \"INVALID\" end select end function FPM_UNIT_NAME !> Parse git FPM_UNIT identifier from a string integer function parse_unit ( name ) result ( unit ) character ( len =* ), intent ( in ) :: name character ( len = len ( name )) :: uppercase !> Make it Case insensitive uppercase = upper ( name ) select case ( trim ( uppercase )) case ( \"FPM_UNIT_UNKNOWN\" ); unit = FPM_UNIT_UNKNOWN case ( \"FPM_UNIT_PROGRAM\" ); unit = FPM_UNIT_PROGRAM case ( \"FPM_UNIT_MODULE\" ); unit = FPM_UNIT_MODULE case ( \"FPM_UNIT_SUBMODULE\" ); unit = FPM_UNIT_SUBMODULE case ( \"FPM_UNIT_SUBPROGRAM\" ); unit = FPM_UNIT_SUBPROGRAM case ( \"FPM_UNIT_CSOURCE\" ); unit = FPM_UNIT_CSOURCE case ( \"FPM_UNIT_CPPSOURCE\" ); unit = FPM_UNIT_CPPSOURCE case ( \"FPM_UNIT_CHEADER\" ); unit = FPM_UNIT_CHEADER case default ; unit = - 9999 end select end function parse_unit !> Check that two source files are equal logical function srcfile_is_same ( this , that ) class ( srcfile_t ), intent ( in ) :: this class ( serializable_t ), intent ( in ) :: that srcfile_is_same = . false . select type ( other => that ) type is ( srcfile_t ) if ( allocated ( this % file_name ). neqv . allocated ( other % file_name )) return if ( allocated ( this % file_name )) then if (. not .( this % file_name == other % file_name )) return end if if ( allocated ( this % exe_name ). neqv . allocated ( other % exe_name )) return if ( allocated ( this % exe_name )) then if (. not .( this % exe_name == other % exe_name )) return end if if (. not .( this % unit_scope == other % unit_scope )) return if ( allocated ( this % modules_provided ). neqv . allocated ( other % modules_provided )) return if ( allocated ( this % modules_provided )) then if (. not .( this % modules_provided == other % modules_provided )) return end if if (. not .( this % unit_type == other % unit_type )) return if ( allocated ( this % parent_modules ). neqv . allocated ( other % parent_modules )) return if ( allocated ( this % parent_modules )) then if (. not .( this % parent_modules == other % parent_modules )) return end if if ( allocated ( this % modules_used ). neqv . allocated ( other % modules_used )) return if ( allocated ( this % modules_used )) then if (. not .( this % modules_used == other % modules_used )) return end if if ( allocated ( this % include_dependencies ). neqv . allocated ( other % include_dependencies )) return if ( allocated ( this % include_dependencies )) then if (. not .( this % include_dependencies == other % include_dependencies )) return end if if ( allocated ( this % link_libraries ). neqv . allocated ( other % link_libraries )) return if ( allocated ( this % link_libraries )) then if (. not .( this % link_libraries == other % link_libraries )) return end if if (. not .( this % digest == other % digest )) return class default ! Not the same type return end select !> All checks passed! srcfile_is_same = . true . end function srcfile_is_same !> Dump dependency to toml table subroutine srcfile_dump_to_toml ( self , table , error ) !> Instance of the serializable object class ( srcfile_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: ierr call set_string ( table , \"file-name\" , self % file_name , error , 'srcfile_t' ) if ( allocated ( error )) return call set_string ( table , \"exe-name\" , self % exe_name , error , 'srcfile_t' ) if ( allocated ( error )) return call set_value ( table , \"digest\" , self % digest , error , 'srcfile_t' ) if ( allocated ( error )) return ! unit_scope and unit_type are saved as strings so the output is independent ! of the internal representation call set_string ( table , \"unit-scope\" , FPM_SCOPE_NAME ( self % unit_scope ), error , 'srcfile_t' ) if ( allocated ( error )) return call set_string ( table , \"unit-type\" , FPM_UNIT_NAME ( self % unit_type ), error , 'srcfile_t' ) if ( allocated ( error )) return call set_list ( table , \"modules-provided\" , self % modules_provided , error ) if ( allocated ( error )) return call set_list ( table , \"parent-modules\" , self % parent_modules , error ) if ( allocated ( error )) return call set_list ( table , \"modules-used\" , self % modules_used , error ) if ( allocated ( error )) return call set_list ( table , \"include-dependencies\" , self % include_dependencies , error ) if ( allocated ( error )) return call set_list ( table , \"link-libraries\" , self % link_libraries , error ) if ( allocated ( error )) return end subroutine srcfile_dump_to_toml !> Read dependency from toml table (no checks made at this stage) subroutine srcfile_load_from_toml ( self , table , error ) !> Instance of the serializable object class ( srcfile_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error character ( len = :), allocatable :: flag integer :: ierr call get_value ( table , \"file-name\" , self % file_name ) call get_value ( table , \"exe-name\" , self % exe_name ) call get_value ( table , \"digest\" , self % digest , error , 'srcfile_t' ) if ( allocated ( error )) return ! unit_scope and unit_type are saved as strings so the output is independent ! of the internal representation call get_value ( table , \"unit-scope\" , flag ) if ( allocated ( flag )) self % unit_scope = parse_scope ( flag ) call get_value ( table , \"unit-type\" , flag ) if ( allocated ( flag )) self % unit_type = parse_unit ( flag ) call get_list ( table , \"modules-provided\" , self % modules_provided , error ) if ( allocated ( error )) return call get_list ( table , \"parent-modules\" , self % parent_modules , error ) if ( allocated ( error )) return call get_list ( table , \"modules-used\" , self % modules_used , error ) if ( allocated ( error )) return call get_list ( table , \"include-dependencies\" , self % include_dependencies , error ) if ( allocated ( error )) return call get_list ( table , \"link-libraries\" , self % link_libraries , error ) if ( allocated ( error )) return end subroutine srcfile_load_from_toml !> Check that two fortran feature objects are equal logical function fft_is_same ( this , that ) class ( fortran_features_t ), intent ( in ) :: this class ( serializable_t ), intent ( in ) :: that fft_is_same = . false . select type ( other => that ) type is ( fortran_features_t ) if (. not .( this % implicit_typing . eqv . other % implicit_typing )) return if (. not .( this % implicit_external . eqv . other % implicit_external )) return if ( allocated ( this % source_form ). neqv . allocated ( other % source_form )) return if ( allocated ( this % source_form )) then if (. not .( this % source_form == other % source_form )) return end if class default ! Not the same type return end select !> All checks passed! fft_is_same = . true . end function fft_is_same !> Dump fortran features to toml table subroutine fft_dump_to_toml ( self , table , error ) !> Instance of the serializable object class ( fortran_features_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error call set_value ( table , \"implicit-typing\" , self % implicit_typing , error , 'fortran_features_t' ) if ( allocated ( error )) return call set_value ( table , \"implicit-external\" , self % implicit_external , error , 'fortran_features_t' ) if ( allocated ( error )) return call set_string ( table , \"source-form\" , self % source_form , error , 'fortran_features_t' ) if ( allocated ( error )) return end subroutine fft_dump_to_toml !> Read dependency from toml table (no checks made at this stage) subroutine fft_load_from_toml ( self , table , error ) !> Instance of the serializable object class ( fortran_features_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: ierr call get_value ( table , \"implicit-typing\" , self % implicit_typing , error , 'fortran_features_t' ) if ( allocated ( error )) return call get_value ( table , \"implicit-external\" , self % implicit_external , error , 'fortran_features_t' ) if ( allocated ( error )) return ! Return unallocated value if not present call get_value ( table , \"source-form\" , self % source_form ) end subroutine fft_load_from_toml !> Check that two package objects are equal logical function package_is_same ( this , that ) class ( package_t ), intent ( in ) :: this class ( serializable_t ), intent ( in ) :: that integer :: ii package_is_same = . false . select type ( other => that ) type is ( package_t ) if ( allocated ( this % name ). neqv . allocated ( other % name )) return if ( allocated ( this % name )) then if (. not .( this % name == other % name )) return end if if ( allocated ( this % sources ). neqv . allocated ( other % sources )) return if ( allocated ( this % sources )) then if (. not .( size ( this % sources ) == size ( other % sources ))) return do ii = 1 , size ( this % sources ) if (. not .( this % sources ( ii ) == other % sources ( ii ))) return end do end if if (. not .( this % preprocess == other % preprocess )) return if ( allocated ( this % version ). neqv . allocated ( other % version )) return if ( allocated ( this % version )) then if (. not .( this % version == other % version )) return end if !> Module naming if (. not .( this % enforce_module_names . eqv . other % enforce_module_names )) return if (. not .( this % module_prefix == other % module_prefix )) return !> Fortran features if (. not .( this % features == other % features )) return class default ! Not the same type return end select !> All checks passed! package_is_same = . true . end function package_is_same !> Dump dependency to toml table subroutine package_dump_to_toml ( self , table , error ) !> Instance of the serializable object class ( package_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: ierr , ii type ( toml_table ), pointer :: ptr , this_source character ( 16 ) :: src_name call set_string ( table , \"name\" , self % name , error , 'package_t' ) if ( allocated ( error )) return call set_string ( table , \"version\" , self % version , error , 'package_t' ) if ( allocated ( error )) return call set_value ( table , \"module-naming\" , self % enforce_module_names , error , 'package_t' ) if ( allocated ( error )) return call set_string ( table , \"module-prefix\" , self % module_prefix , error , 'package_t' ) if ( allocated ( error )) return !> Create a preprocessor table call add_table ( table , \"preprocess\" , ptr , error , 'package_t' ) if ( allocated ( error )) return call self % preprocess % dump_to_toml ( ptr , error ) if ( allocated ( error )) return !> Create a fortran table call add_table ( table , \"fortran\" , ptr , error , 'package_t' ) if ( allocated ( error )) return call self % features % dump_to_toml ( ptr , error ) if ( allocated ( error )) return !> Create a sources table if ( allocated ( self % sources )) then call add_table ( table , \"sources\" , ptr , error , 'package_t' ) if ( allocated ( error )) return do ii = 1 , size ( self % sources ) write ( src_name , 1 ) ii call add_table ( ptr , trim ( src_name ), this_source , error , 'package_t[source]' ) if ( allocated ( error )) return call self % sources ( ii )% dump_to_toml ( this_source , error ) if ( allocated ( error )) return end do end if 1 format ( 'src_' , i0 ) end subroutine package_dump_to_toml !> Read dependency from toml table (no checks made at this stage) subroutine package_load_from_toml ( self , table , error ) !> Instance of the serializable object class ( package_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: ierr , ii , jj type ( toml_key ), allocatable :: keys (:), src_keys (:) type ( toml_table ), pointer :: ptr_sources , ptr , ptr_fortran , ptr_preprocess type ( error_t ), allocatable :: new_error call get_value ( table , \"name\" , self % name ) call get_value ( table , \"version\" , self % version ) call get_value ( table , \"module-naming\" , self % enforce_module_names , error , 'package_t' ) if ( allocated ( error )) return ! Return unallocated value if not present call get_value ( table , \"module-prefix\" , self % module_prefix % s ) ! Sources call table % get_keys ( keys ) find_others : do ii = 1 , size ( keys ) select case ( keys ( ii )% key ) case ( \"fortran\" ) call get_value ( table , keys ( ii ), ptr_fortran ) if (. not . associated ( ptr_fortran )) then call fatal_error ( error , 'package_t: error retrieving fortran table from TOML table' ) return end if call self % features % load_from_toml ( ptr_fortran , error ) if ( allocated ( error )) return case ( \"preprocess\" ) call get_value ( table , keys ( ii ), ptr_preprocess ) if (. not . associated ( ptr_preprocess )) then call fatal_error ( error , 'package_t: error retrieving preprocess table from TOML table' ) return end if call self % preprocess % load_from_toml ( ptr_preprocess , error ) if ( allocated ( error )) return case ( \"sources\" ) call get_value ( table , keys ( ii ), ptr_sources ) if (. not . associated ( ptr_sources )) then call fatal_error ( error , 'package_t: error retrieving sources table from TOML table' ) return end if !> Read all dependencies call ptr_sources % get_keys ( src_keys ) allocate ( self % sources ( size ( src_keys ))) do jj = 1 , size ( src_keys ) call get_value ( ptr_sources , src_keys ( jj ), ptr ) call self % sources ( jj )% load_from_toml ( ptr , error ) if ( allocated ( error )) return end do case default cycle find_others end select end do find_others end subroutine package_load_from_toml !> Check that two model objects are equal logical function model_is_same ( this , that ) class ( fpm_model_t ), intent ( in ) :: this class ( serializable_t ), intent ( in ) :: that type ( fpm_model_t ), pointer :: other integer :: ii model_is_same = . false . select type ( other => that ) type is ( fpm_model_t ) if (( allocated ( this % package_name ). neqv . allocated ( other % package_name ))) return if ( allocated ( this % package_name )) then if (. not .( this % package_name == other % package_name )) return end if if (. not .( allocated ( this % packages ). eqv . allocated ( other % packages ))) return if ( allocated ( this % packages )) then if (. not .( size ( this % packages ) == size ( other % packages ))) return do ii = 1 , size ( this % packages ) if (. not .( this % packages ( ii ) == other % packages ( ii ))) return end do end if if (. not .( this % compiler == other % compiler )) return if (. not .( this % archiver == other % archiver )) return if ( allocated ( this % fortran_compile_flags ). neqv . allocated ( other % fortran_compile_flags )) return if ( allocated ( this % fortran_compile_flags )) then if (. not .( this % fortran_compile_flags == other % fortran_compile_flags )) return end if if ( allocated ( this % c_compile_flags ). neqv . allocated ( other % c_compile_flags )) return if ( allocated ( this % c_compile_flags )) then if (. not .( this % c_compile_flags == other % c_compile_flags )) return end if if ( allocated ( this % cxx_compile_flags ). neqv . allocated ( other % cxx_compile_flags )) return if ( allocated ( this % cxx_compile_flags )) then if (. not .( this % cxx_compile_flags == other % cxx_compile_flags )) return end if if ( allocated ( this % link_flags ). neqv . allocated ( other % link_flags )) return if ( allocated ( this % link_flags )) then if (. not .( this % link_flags == other % link_flags )) return end if if ( allocated ( this % build_prefix ). neqv . allocated ( other % build_prefix )) return if ( allocated ( this % build_prefix )) then if (. not .( this % build_prefix == other % build_prefix )) return end if if ( allocated ( this % include_dirs ). neqv . allocated ( other % include_dirs )) return if ( allocated ( this % include_dirs )) then if (. not .( this % include_dirs == other % include_dirs )) return end if if ( allocated ( this % link_libraries ). neqv . allocated ( other % link_libraries )) return if ( allocated ( this % link_libraries )) then if (. not .( this % link_libraries == other % link_libraries )) return end if if ( allocated ( this % external_modules ). neqv . allocated ( other % external_modules )) return if ( allocated ( this % external_modules )) then if (. not .( this % external_modules == other % external_modules )) return end if if (. not .( this % deps == other % deps )) return if (. not .( this % include_tests . eqv . other % include_tests )) return if (. not .( this % enforce_module_names . eqv . other % enforce_module_names )) return if (. not .( this % module_prefix == other % module_prefix )) return class default ! Not the same type return end select !> All checks passed! model_is_same = . true . end function model_is_same !> Dump dependency to toml table subroutine model_dump_to_toml ( self , table , error ) !> Instance of the serializable object class ( fpm_model_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: ierr , ii type ( toml_table ), pointer :: ptr , ptr_pkg character ( 27 ) :: unnamed call set_string ( table , \"package-name\" , self % package_name , error , 'fpm_model_t' ) if ( allocated ( error )) return call add_table ( table , \"compiler\" , ptr , error , 'fpm_model_t' ) if ( allocated ( error )) return call self % compiler % dump_to_toml ( ptr , error ) if ( allocated ( error )) return call add_table ( table , \"archiver\" , ptr , error , 'fpm_model_t' ) if ( allocated ( error )) return call self % archiver % dump_to_toml ( ptr , error ) if ( allocated ( error )) return call set_string ( table , \"fortran-flags\" , self % fortran_compile_flags , error , 'fpm_model_t' ) if ( allocated ( error )) return call set_string ( table , \"c-flags\" , self % c_compile_flags , error , 'fpm_model_t' ) if ( allocated ( error )) return call set_string ( table , \"cxx-flags\" , self % cxx_compile_flags , error , 'fpm_model_t' ) if ( allocated ( error )) return call set_string ( table , \"link-flags\" , self % link_flags , error , 'fpm_model_t' ) if ( allocated ( error )) return call set_string ( table , \"build-prefix\" , self % build_prefix , error , 'fpm_model_t' ) if ( allocated ( error )) return call set_list ( table , \"include-dirs\" , self % include_dirs , error ) if ( allocated ( error )) return call set_list ( table , \"link-libraries\" , self % link_libraries , error ) if ( allocated ( error )) return call set_list ( table , \"external-modules\" , self % external_modules , error ) if ( allocated ( error )) return call set_value ( table , \"include-tests\" , self % include_tests , error , 'fpm_model_t' ) if ( allocated ( error )) return call set_value ( table , \"module-naming\" , self % enforce_module_names , error , 'fpm_model_t' ) if ( allocated ( error )) return call set_string ( table , \"module-prefix\" , self % module_prefix , error , 'fpm_model_t' ) if ( allocated ( error )) return call add_table ( table , \"deps\" , ptr , error , 'fpm_model_t' ) if ( allocated ( error )) return call self % deps % dump_to_toml ( ptr , error ) if ( allocated ( error )) return !> Array of packages (including the root package) if ( allocated ( self % packages )) then ! Create packages table call add_table ( table , \"packages\" , ptr_pkg ) if (. not . associated ( ptr_pkg )) then call fatal_error ( error , \"fpm_model_t cannot create dependency table \" ) return end if do ii = 1 , size ( self % packages ) associate ( pkg => self % packages ( ii )) !> Because dependencies are named, fallback if this has no name !> So, serialization will work regardless of size(self%dep) == self%ndep if ( len_trim ( pkg % name ) == 0 ) then write ( unnamed , 1 ) ii call add_table ( ptr_pkg , trim ( unnamed ), ptr , error , 'fpm_model_t[package]' ) else call add_table ( ptr_pkg , pkg % name , ptr , error , 'fpm_model_t[package]' ) end if if ( allocated ( error )) return call pkg % dump_to_toml ( ptr , error ) if ( allocated ( error )) return end associate end do end if 1 format ( 'UNNAMED_PACKAGE_' , i0 ) end subroutine model_dump_to_toml !> Read dependency from toml table (no checks made at this stage) subroutine model_load_from_toml ( self , table , error ) !> Instance of the serializable object class ( fpm_model_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_key ), allocatable :: keys (:), pkg_keys (:) integer :: ierr , ii , jj type ( toml_table ), pointer :: ptr , ptr_pkg call table % get_keys ( keys ) call get_value ( table , \"package-name\" , self % package_name ) call get_value ( table , \"fortran-flags\" , self % fortran_compile_flags ) call get_value ( table , \"c-flags\" , self % c_compile_flags ) call get_value ( table , \"cxx-flags\" , self % cxx_compile_flags ) call get_value ( table , \"link-flags\" , self % link_flags ) call get_value ( table , \"build-prefix\" , self % build_prefix ) if ( allocated ( self % packages )) deallocate ( self % packages ) sub_deps : do ii = 1 , size ( keys ) select case ( keys ( ii )% key ) case ( \"compiler\" ) call get_value ( table , keys ( ii ), ptr ) if (. not . associated ( ptr )) then call fatal_error ( error , 'fpm_model_t: error retrieving compiler table' ) return end if call self % compiler % load_from_toml ( ptr , error ) if ( allocated ( error )) return case ( \"archiver\" ) call get_value ( table , keys ( ii ), ptr ) if (. not . associated ( ptr )) then call fatal_error ( error , 'fpm_model_t: error retrieving archiver table' ) return end if call self % archiver % load_from_toml ( ptr , error ) if ( allocated ( error )) return case ( \"deps\" ) call get_value ( table , keys ( ii ), ptr ) if (. not . associated ( ptr )) then call fatal_error ( error , 'fpm_model_t: error retrieving dependency tree table' ) return end if call self % deps % load_from_toml ( ptr , error ) if ( allocated ( error )) return case ( \"packages\" ) call get_value ( table , keys ( ii ), ptr ) if (. not . associated ( ptr )) then call fatal_error ( error , 'fpm_model_t: error retrieving packages table' ) return end if !> Read all packages call ptr % get_keys ( pkg_keys ) allocate ( self % packages ( size ( pkg_keys ))) do jj = 1 , size ( pkg_keys ) call get_value ( ptr , pkg_keys ( jj ), ptr_pkg ) call self % packages ( jj )% load_from_toml ( ptr_pkg , error ) if ( allocated ( error )) return end do case default cycle sub_deps end select end do sub_deps call get_list ( table , \"include-dirs\" , self % include_dirs , error ) if ( allocated ( error )) return call get_list ( table , \"link-libraries\" , self % link_libraries , error ) if ( allocated ( error )) return call get_list ( table , \"external-modules\" , self % external_modules , error ) if ( allocated ( error )) return call get_value ( table , \"include-tests\" , self % include_tests , error , 'fpm_model_t' ) if ( allocated ( error )) return call get_value ( table , \"module-naming\" , self % enforce_module_names , error , 'fpm_model_t' ) if ( allocated ( error )) return call get_value ( table , \"module-prefix\" , self % module_prefix % s ) end subroutine model_load_from_toml function get_package_libraries_link ( model , package_name , prefix , exclude_self , dep_IDs , error ) result ( r ) class ( fpm_model_t ), intent ( in ) :: model character ( * ), intent ( in ) :: package_name type ( error_t ), allocatable , intent ( out ) :: error character ( * ), intent ( in ) :: prefix !> Option to exclude linking to the given package (needed building it as a library) logical , optional , intent ( in ) :: exclude_self !> Optionally export the list of dependency IDs integer , allocatable , optional , intent ( out ) :: dep_IDs (:) character ( len = :), allocatable :: r integer :: id , ndep , i logical :: no_root integer , allocatable :: sorted_package_IDs (:) logical , allocatable :: has_lib (:) type ( string_t ), allocatable :: package_deps (:) ! Get dependency ID of this target id = model % deps % find ( package_name ) if ( id <= 0 ) then call fatal_error ( error , \"Internal error: shared library \" // package_name // & \" does not correspond to a package\" ) return end if ! Get ordered IDs of the shared libraries that should be linked against call model % deps % local_link_order ( id , sorted_package_IDs , error ) if ( allocated ( error )) return ! Get names of the package dependencies ndep = size ( sorted_package_IDs ) if ( ndep <= 0 ) then r = prefix if ( present ( dep_IDs )) allocate ( dep_IDs ( 0 )) return end if ! Optional exclusion of self (top-level) package no_root = . false . if ( present ( exclude_self )) no_root = exclude_self if ( no_root ) then sorted_package_IDs = pack ( sorted_package_IDs , sorted_package_IDs /= id ) ndep = size ( sorted_package_IDs ) endif ! Exclusion of package IDs marked \"empty\" (i.e. they contain no sources) has_lib = model % packages % has_library () if ( any (. not . has_lib )) then sorted_package_IDs = pack ( sorted_package_IDs , has_lib ( sorted_package_IDs )) ndep = size ( sorted_package_IDs ) end if package_deps = [( string_t ( model % deps % dep ( sorted_package_IDs ( i ))% name ), i = 1 , ndep )] r = model % compiler % enumerate_libraries ( prefix , package_deps ) ! If requested, export the list of dependency IDs if ( present ( dep_IDs )) call move_alloc ( from = sorted_package_IDs , to = dep_IDs ) end function get_package_libraries_link !> Check whether a package has an object library elemental logical function package_has_library ( self ) result ( has_library ) class ( package_t ), intent ( in ) :: self if ( allocated ( self % sources )) then has_library = any ( self % sources % unit_scope == FPM_SCOPE_LIB ) else has_library = . false . end if end function package_has_library end module fpm_model","tags":"","url":"sourcefile/fpm_model.f90.html"},{"title":"fpm_environment.f90 – Fortran-lang/fpm","text":"Source Code !> This module contains procedures that interact with the programming environment. !! !! * [get_os_type] -- Determine the OS type !! * [get_env] -- return the value of an environment variable module fpm_environment use , intrinsic :: iso_fortran_env , only : stdin => input_unit , & & stdout => output_unit , & & stderr => error_unit use , intrinsic :: iso_c_binding , only : c_char , c_int , c_null_char use fpm_error , only : fpm_stop implicit none private public :: get_os_type public :: os_is_unix public :: get_env public :: set_env public :: delete_env public :: get_command_arguments_quoted public :: separator public :: library_filename public :: OS_NAME integer , parameter , public :: OS_UNKNOWN = 0 integer , parameter , public :: OS_LINUX = 1 integer , parameter , public :: OS_MACOS = 2 integer , parameter , public :: OS_WINDOWS = 3 integer , parameter , public :: OS_CYGWIN = 4 integer , parameter , public :: OS_SOLARIS = 5 integer , parameter , public :: OS_FREEBSD = 6 integer , parameter , public :: OS_OPENBSD = 7 contains !> Utility function: return library filename pure function library_filename ( package_name , shared , import , target_os ) result ( name ) character ( * ), intent ( in ) :: package_name !> Whether it's a shared library logical , intent ( in ) :: shared !> Whether it's for linking (import library) or actual library logical , intent ( in ) :: import !> Build target OS: one of OS_WINDOWS, OS_MACOS, ... integer , intent ( in ) :: target_os character ( len = :), allocatable :: name if ( shared ) then select case ( target_os ) case ( OS_WINDOWS ) if ( import ) then ! Linking requires the import library name = 'lib' // package_name // '.lib' else ! The actual shared object is a DLL name = 'lib' // package_name // '.dll' end if case ( OS_MACOS ) name = 'lib' // package_name // '.dylib' case default name = 'lib' // package_name // '.so' end select else ! Static library (same for all platforms) name = 'lib' // package_name // '.a' end if end function library_filename !> Return string describing the OS type flag pure function OS_NAME ( os ) integer , intent ( in ) :: os character ( len = :), allocatable :: OS_NAME select case ( os ) case ( OS_LINUX ); OS_NAME = \"Linux\" case ( OS_MACOS ); OS_NAME = \"macOS\" case ( OS_WINDOWS ); OS_NAME = \"Windows\" case ( OS_CYGWIN ); OS_NAME = \"Cygwin\" case ( OS_SOLARIS ); OS_NAME = \"Solaris\" case ( OS_FREEBSD ); OS_NAME = \"FreeBSD\" case ( OS_OPENBSD ); OS_NAME = \"OpenBSD\" case ( OS_UNKNOWN ); OS_NAME = \"Unknown\" case default ; OS_NAME = \"UNKNOWN\" end select end function OS_NAME !> Determine the OS type integer function get_os_type () result ( r ) !! !! Returns one of OS_UNKNOWN, OS_LINUX, OS_MACOS, OS_WINDOWS, OS_CYGWIN, !! OS_SOLARIS, OS_FREEBSD, OS_OPENBSD. !! !! At first, the environment variable `OS` is checked, which is usually !! found on Windows. Then, `OSTYPE` is read in and compared with common !! names. If this fails too, check the existence of files that can be !! found on specific system types only. !! !! Returns OS_UNKNOWN if the operating system cannot be determined. character ( len = 255 ) :: val integer :: length , rc logical :: file_exists logical , save :: first_run = . true . integer , save :: ret = OS_UNKNOWN !$omp threadprivate(ret, first_run) if (. not . first_run ) then r = ret return end if first_run = . false . r = OS_UNKNOWN ! Check environment variable `OSTYPE`. call get_environment_variable ( 'OSTYPE' , val , length , rc ) if ( rc == 0 . and . length > 0 ) then ! Linux if ( index ( val , 'linux' ) > 0 ) then r = OS_LINUX ret = r return end if ! macOS if ( index ( val , 'darwin' ) > 0 ) then r = OS_MACOS ret = r return end if ! Windows, MSYS, MinGW, Git Bash if ( index ( val , 'win' ) > 0 . or . index ( val , 'msys' ) > 0 ) then r = OS_WINDOWS ret = r return end if ! Cygwin if ( index ( val , 'cygwin' ) > 0 ) then r = OS_CYGWIN ret = r return end if ! Solaris, OpenIndiana, ... if ( index ( val , 'SunOS' ) > 0 . or . index ( val , 'solaris' ) > 0 ) then r = OS_SOLARIS ret = r return end if ! FreeBSD if ( index ( val , 'FreeBSD' ) > 0 . or . index ( val , 'freebsd' ) > 0 ) then r = OS_FREEBSD ret = r return end if ! OpenBSD if ( index ( val , 'OpenBSD' ) > 0 . or . index ( val , 'openbsd' ) > 0 ) then r = OS_OPENBSD ret = r return end if end if ! Check environment variable `OS`. call get_environment_variable ( 'OS' , val , length , rc ) if ( rc == 0 . and . length > 0 . and . index ( val , 'Windows_NT' ) > 0 ) then r = OS_WINDOWS ret = r return end if ! Linux inquire ( file = '/etc/os-release' , exist = file_exists ) if ( file_exists ) then r = OS_LINUX ret = r return end if ! macOS inquire ( file = '/usr/bin/sw_vers' , exist = file_exists ) if ( file_exists ) then r = OS_MACOS ret = r return end if ! FreeBSD inquire ( file = '/bin/freebsd-version' , exist = file_exists ) if ( file_exists ) then r = OS_FREEBSD ret = r return end if end function get_os_type !> Compare the output of [[get_os_type]] or the optional !! passed INTEGER value to the value for OS_WINDOWS !! and return .TRUE. if they match and .FALSE. otherwise logical function os_is_unix ( os ) integer , intent ( in ), optional :: os integer :: build_os if ( present ( os )) then build_os = os else build_os = get_os_type () end if os_is_unix = build_os /= OS_WINDOWS end function os_is_unix !> get named environment variable value. It it is blank or !! not set return the optional default value function get_env ( NAME , DEFAULT ) result ( VALUE ) implicit none !> name of environment variable to get the value of character ( len =* ), intent ( in ) :: NAME !> default value to return if the requested value is undefined or blank character ( len =* ), intent ( in ), optional :: DEFAULT !> the returned value character ( len = :), allocatable :: VALUE integer :: howbig integer :: stat integer :: length ! get length required to hold value length = 0 if ( NAME /= '' ) then call get_environment_variable ( NAME , length = howbig , status = stat , trim_name = . true .) select case ( stat ) case ( 1 ) !*!print *, NAME, \" is not defined in the environment. Strange...\" VALUE = '' case ( 2 ) !*!print *, \"This processor doesn't support environment variables. Boooh!\" VALUE = '' case default ! make string to hold value of sufficient size allocate ( character ( len = max ( howbig , 1 )) :: VALUE ) ! get value call get_environment_variable ( NAME , VALUE , status = stat , trim_name = . true .) if ( stat /= 0 ) VALUE = '' end select else VALUE = '' endif if ( VALUE == '' . and . present ( DEFAULT )) VALUE = DEFAULT end function get_env function get_command_arguments_quoted () result ( args ) character ( len = :), allocatable :: args character ( len = :), allocatable :: arg character ( len = 1 ) :: quote integer :: ilength , istatus , i ilength = 0 args = '' quote = merge ( '\"' , \"'\" , separator () == '\\') do i=2,command_argument_count() ! look at all arguments after subcommand call get_command_argument(number=i,length=ilength,status=istatus) if(istatus /= 0) then write(stderr,' ( * ( g0 , 1 x )) ')' < ERROR >* get_command_arguments_stack * error obtaining argument ',i exit else if(allocated(arg))deallocate(arg) allocate(character(len=ilength) :: arg) call get_command_argument(number=i,value=arg,length=ilength,status=istatus) if(istatus /= 0) then write(stderr,' ( * ( g0 , 1 x )) ')' < ERROR >* get_command_arguments_stack * error obtaining argument ',i exit elseif(ilength>0)then if(index(arg//' ',' - ')/=1)then args=args//quote//arg//quote//' ' elseif(index(arg,' ')/=0)then args=args//quote//arg//quote//' ' else args=args//arg//' ' endif else args=args//repeat(quote,2)//' ' endif endif enddo end function get_command_arguments_quoted function separator() result(sep) !> !!##NAME !! separator(3f) - [M_io:ENVIRONMENT] try to determine pathname directory separator character !! (LICENSE:PD) !! !!##SYNOPSIS !! !! function separator() result(sep) !! !! character(len=1) :: sep !! !!##DESCRIPTION !! First using the name the program was invoked with, then the name !! returned by an INQUIRE(3f) of that name, then \".\\NAME\" and \"./NAME\" !! try to determine the separator character used to separate directory !! names from file basenames. !! !! If a slash or backslash is not found in the name, the environment !! variable PATH is examined first for a backslash, then a slash. !! !! Can be very system dependent. If the queries fail the default returned !! is \"/\". !! !!##EXAMPLE !! !! sample usage !! !! program demo_separator !! use M_io, only : separator !! implicit none !! write(*,*)' separator = ',separator() !! end program demo_separator ! use the pathname returned as arg0 to determine pathname separator implicit none character(len=:),allocatable :: arg0 integer :: arg0_length integer :: istat logical :: existing character(len=1) :: sep !*ifort_bug*!character(len=1),save :: sep_cache=' ' character(len=4096) :: name character(len=:),allocatable :: fname !*ifort_bug*! if(sep_cache/=' ')then ! use cached value. NOTE: A parallel code might theoretically use multiple OS !*ifort_bug*! sep=sep_cache !*ifort_bug*! return !*ifort_bug*! endif arg0_length=0 name=' ' call get_command_argument(0,length=arg0_length,status=istat) if(allocated(arg0))deallocate(arg0) allocate(character(len=arg0_length) :: arg0) call get_command_argument(0,arg0,status=istat) ! check argument name if(index(arg0,' \\ ')/=0)then sep=' \\ ' elseif(index(arg0,' / ')/=0)then sep=' / ' else ! try name returned by INQUIRE(3f) existing=.false. name=' ' inquire(file=arg0,iostat=istat,exist=existing,name=name) if(index(name,' \\ ')/=0)then sep=' \\ ' elseif(index(name,' / ')/=0)then sep=' / ' else ! well, try some common syntax and assume in current directory fname=' . \\ '//arg0 inquire(file=fname,iostat=istat,exist=existing) if(existing)then sep=' \\ ' else fname=' . / '//arg0 inquire(file=fname,iostat=istat,exist=existing) if(existing)then sep=' / ' else ! check environment variable PATH sep=merge(' \\ ',' / ',index(get_env(' PATH '),' \\ ')/=0) !*!write(*,*)' < WARNING > unknown system directory path separator ' endif endif endif endif !*ifort_bug*!sep_cache=sep end function separator !> Set an environment variable for the current environment using the C standard library logical function set_env ( name , value , overwrite ) !> Variable name character ( * ), intent ( in ) :: name !> Variable value character ( * ), intent ( in ) :: value !> Should a former value be overwritten? default = .true. logical , optional , intent ( in ) :: overwrite ! Local variables logical :: can_overwrite integer ( c_int ) :: cover , cerr character ( kind = c_char , len = 1 ), allocatable :: c_value (:), c_name (:) interface integer ( c_int ) function c_setenv ( envname , envval , overwrite ) & bind ( C , name = \"c_setenv\" ) import c_int , c_char implicit none !> Pointer to the name string character ( kind = c_char , len = 1 ), intent ( in ) :: envname ( * ) !> Pointer to the value string character ( kind = c_char , len = 1 ), intent ( in ) :: envval ( * ) !> Overwrite option integer ( c_int ), intent ( in ), value :: overwrite end function c_setenv end interface !> Overwrite setting cerr = 0_c_int can_overwrite = . true . if ( present ( overwrite )) can_overwrite = overwrite cover = merge ( 1_c_int , 0_c_int , can_overwrite ) !> C strings call f2cs ( name , c_name ) call f2cs ( value , c_value ) !> Call setenv #ifndef FPM_BOOTSTRAP cerr = c_setenv ( c_name , c_value , cover ) #endif set_env = cerr == 0_c_int end function set_env !> Deletes an environment variable for the current environment using the C standard library !> Returns an error if the variable did not exist in the first place logical function delete_env ( name ) result ( success ) !> Variable name character ( * ), intent ( in ) :: name ! Local variables integer ( c_int ) :: cerr character ( kind = c_char , len = 1 ), allocatable :: c_name (:) interface integer ( c_int ) function c_unsetenv ( envname ) bind ( C , name = \"c_unsetenv\" ) import c_int , c_char implicit none !> Pointer to the name string character ( kind = c_char , len = 1 ), intent ( in ) :: envname ( * ) end function c_unsetenv end interface !> C strings call f2cs ( name , c_name ) !> Call setenv #ifndef FPM_BOOTSTRAP cerr = c_unsetenv ( c_name ) #endif success = cerr == 0_c_int end function delete_env !> Fortran to C allocatable string pure subroutine f2cs ( f , c ) use iso_c_binding , only : c_char , c_null_char character ( * ), intent ( in ) :: f character ( len = 1 , kind = c_char ), allocatable , intent ( out ) :: c (:) integer :: lf , i lf = len ( f ) allocate ( c ( lf + 1 )) c ( lf + 1 ) = c_null_char forall ( i = 1 : lf ) c ( i ) = f ( i : i ) end subroutine f2cs end module fpm_environment","tags":"","url":"sourcefile/fpm_environment.f90.html"},{"title":"fpm_meta_blas.f90 – Fortran-lang/fpm","text":"Source Code module fpm_meta_blas use fpm_compiler , only : compiler_t , get_include_flag use fpm_environment , only : get_os_type , OS_MACOS , OS_WINDOWS use fpm_meta_base , only : metapackage_t , destroy use fpm_meta_util , only : add_pkg_config_compile_options use fpm_pkg_config , only : assert_pkg_config , pkgcfg_has_package use fpm_manifest_metapackages , only : metapackage_request_t use fpm_strings , only : string_t use fpm_error , only : error_t , fatal_error implicit none private public :: init_blas contains !> Initialize blas metapackage for the current system subroutine init_blas ( this , compiler , all_meta , error ) class ( metapackage_t ), intent ( inout ) :: this type ( compiler_t ), intent ( in ) :: compiler type ( metapackage_request_t ), intent ( in ) :: all_meta (:) type ( error_t ), allocatable , intent ( out ) :: error integer :: i character ( len = :), allocatable :: include_flag , libdir character ( * ), parameter :: candidates ( * ) = & [ character ( 20 ) :: 'mkl-dynamic-lp64-tbb' , 'openblas' , 'blas' ] include_flag = get_include_flag ( compiler , \"\" ) !> Cleanup call destroy ( this ) allocate ( this % link_libs ( 0 ), this % incl_dirs ( 0 ), this % external_modules ( 0 )) this % link_flags = string_t ( \"\" ) this % flags = string_t ( \"\" ) this % has_external_modules = . false . !> Set name this % name = \"\" if ( get_os_type () == OS_MACOS ) then if ( compile_and_link_flags_supported ( compiler , \"-framework Accelerate\" )) then call set_compile_and_link_flags ( this , compiler , \"-framework Accelerate\" ) return end if end if if ( compiler % is_intel ()) then if ( get_os_type () == OS_WINDOWS ) then if ( compile_and_link_flags_supported ( compiler , \"/Qmkl\" )) then call set_compile_and_link_flags ( this , compiler , \"/Qmkl\" ) return end if else if ( compile_and_link_flags_supported ( compiler , \"-qmkl\" )) then call set_compile_and_link_flags ( this , compiler , \"-qmkl\" ) return endif end if !> Assert pkg-config is installed if (. not . assert_pkg_config ()) then call fatal_error ( error , 'blas metapackage requires pkg-config to continue lookup' ) return end if do i = 1 , size ( candidates ) if ( pkgcfg_has_package ( trim ( candidates ( i )))) then call add_pkg_config_compile_options ( & this , trim ( candidates ( i )), include_flag , libdir , error ) print * , 'found blas package: ' , trim ( candidates ( i )) return end if end do call fatal_error ( error , 'pkg-config could not find a suitable blas package.' ) end subroutine init_blas function compile_and_link_flags_supported ( compiler , flags ) result ( is_supported ) type ( compiler_t ), intent ( in ) :: compiler character ( len =* ), intent ( in ) :: flags logical :: is_supported is_supported = compiler % check_flags_supported ( compile_flags = flags , link_flags = flags ) end function compile_and_link_flags_supported subroutine set_compile_and_link_flags ( this , compiler , flags ) class ( metapackage_t ), intent ( inout ) :: this type ( compiler_t ), intent ( in ) :: compiler character ( len =* ), intent ( in ) :: flags this % flags = string_t ( flags ) this % link_flags = string_t ( flags ) this % has_build_flags = . true . this % has_link_flags = . true . end subroutine set_compile_and_link_flags end module fpm_meta_blas","tags":"","url":"sourcefile/fpm_meta_blas.f90.html"},{"title":"fpm_pkg_config.f90 – Fortran-lang/fpm","text":"Source Code !># The fpm interface to pkg-config !> !> This module contains wrapper functions to interface with a pkg-config installation. !> module fpm_pkg_config use fpm_strings , only : string_t , str_begins_with_str , len_trim , remove_newline_characters , & split use fpm_error , only : error_t , fatal_error , fpm_stop use fpm_filesystem , only : get_temp_filename , getline use fpm_environment , only : get_env , os_is_unix , set_env , delete_env use shlex_module , only : shlex_split => split implicit none private public :: assert_pkg_config public :: pkgcfg_get_version public :: pkgcfg_get_libs public :: pkgcfg_get_build_flags public :: pkgcfg_has_package public :: pkgcfg_list_all public :: run_wrapper contains !> Check whether pkg-config is available on the local system logical function assert_pkg_config () integer :: exitcode logical :: success type ( string_t ) :: log call run_wrapper ( wrapper = string_t ( 'pkg-config' ), args = [ string_t ( '-h' )], & exitcode = exitcode , cmd_success = success , screen_output = log ) assert_pkg_config = exitcode == 0 . and . success end function assert_pkg_config !> Get package version from pkg-config type ( string_t ) function pkgcfg_get_version ( package , error ) result ( screen ) !> Package name character ( * ), intent ( in ) :: package !> Error handler type ( error_t ), allocatable , intent ( out ) :: error integer :: exitcode logical :: success type ( string_t ) :: log call run_wrapper ( wrapper = string_t ( 'pkg-config' ), & args = [ string_t ( package ), string_t ( '--modversion' )], & exitcode = exitcode , cmd_success = success , screen_output = log ) if ( success . and . exitcode == 0 ) then call remove_newline_characters ( log ) screen = log else screen = string_t ( \"\" ) end if end function pkgcfg_get_version !> Check if pkgcfg has package logical function pkgcfg_has_package ( name ) result ( success ) !> Package name character ( * ), intent ( in ) :: name integer :: exitcode logical :: cmdok type ( string_t ) :: log call run_wrapper ( wrapper = string_t ( 'pkg-config' ), & args = [ string_t ( name ), string_t ( '--exists' )], & exitcode = exitcode , cmd_success = cmdok , screen_output = log ) !> pkg-config --exists returns 0 only if the package exists success = cmdok . and . exitcode == 0 end function pkgcfg_has_package !> Get package libraries from pkg-config function pkgcfg_get_libs ( package , error ) result ( libraries ) !> Package name character ( * ), intent ( in ) :: package !> Error handler type ( error_t ), allocatable , intent ( out ) :: error !> A list of libraries type ( string_t ), allocatable :: libraries (:) integer :: exitcode , nlib , i logical :: success character ( len = :), allocatable :: tokens (:) type ( string_t ) :: log call run_wrapper ( wrapper = string_t ( 'pkg-config' ), & args = [ string_t ( package ), string_t ( '--libs' )], & exitcode = exitcode , cmd_success = success , screen_output = log ) if ( success . and . exitcode == 0 ) then call remove_newline_characters ( log ) ! Split all arguments tokens = shlex_split ( log % s ) nlib = size ( tokens ) allocate ( libraries ( nlib )) do i = 1 , nlib libraries ( i ) = string_t ( trim ( adjustl ( tokens ( i )))) end do else allocate ( libraries ( 0 )) call fatal_error ( error , 'cannot get <' // package // '> libraries from pkg-config' ) end if end function pkgcfg_get_libs !> Return whole list of available pkg-cfg packages function pkgcfg_list_all ( error , descriptions ) result ( modules ) !> Error handler type ( error_t ), allocatable , intent ( out ) :: error !> A list of all available packages type ( string_t ), allocatable :: modules (:) !> An optional list of package descriptions type ( string_t ), optional , allocatable , intent ( out ) :: descriptions (:) integer :: exitcode , i , spc logical :: success character ( len = :), allocatable :: lines (:) type ( string_t ) :: log type ( string_t ), allocatable :: mods (:), descr (:) character ( * ), parameter :: CRLF = achar ( 13 ) // new_line ( 'a' ) call run_wrapper ( wrapper = string_t ( 'pkg-config' ), & args = [ string_t ( '--list-all' )], & exitcode = exitcode , cmd_success = success , screen_output = log ) if (. not .( success . and . exitcode == 0 )) then call fatal_error ( error , 'cannot get pkg-config modules' ) allocate ( modules ( 0 )) return end if !> Extract list call split ( log % s , lines , CRLF ) allocate ( mods ( size ( lines )), descr ( size ( lines ))) do i = 1 , size ( lines ) ! Module names have no spaces spc = index ( lines ( i ), ' ' ) if ( spc > 0 ) then mods ( i ) = string_t ( trim ( adjustl ( lines ( i )( 1 : spc )))) descr ( i ) = string_t ( trim ( adjustl ( lines ( i )( spc + 1 :)))) else mods ( i ) = string_t ( trim ( adjustl ( lines ( i )))) descr ( i ) = string_t ( \"\" ) end if end do call move_alloc ( from = mods , to = modules ) if ( present ( descriptions )) call move_alloc ( from = descr , to = descriptions ) end function pkgcfg_list_all !> Get build flags (option to include flags from system directories, that !> gfortran does not look into by default) function pkgcfg_get_build_flags ( name , allow_system , error ) result ( flags ) !> Package name character ( * ), intent ( in ) :: name !> Should pkg-config look in system paths? This is necessary for gfortran !> that doesn't otherwise look into them logical , intent ( in ) :: allow_system !> Error flag type ( error_t ), allocatable , intent ( out ) :: error !> List of compile flags type ( string_t ), allocatable :: flags (:) integer :: exitcode , i , nlib logical :: old_had , success , old_allow character (:), allocatable :: old , tokens (:) type ( string_t ) :: log ! Check if the current environment includes system flags old = get_env ( 'PKG_CONFIG_ALLOW_SYSTEM_CFLAGS' , default = 'ERROR' ) old_had = old /= 'ERROR' old_allow = merge ( old == '1' ,. false ., old_had ) ! Set system flags success = set_env ( 'PKG_CONFIG_ALLOW_SYSTEM_CFLAGS' , value = merge ( '1' , '0' , allow_system )) if (. not . success ) then call fatal_error ( error , 'Cannot get pkg-config build flags: environment variable error.' ) return end if ! Now run wrapper call run_wrapper ( wrapper = string_t ( 'pkg-config' ), & args = [ string_t ( name ), string_t ( '--cflags' )], & exitcode = exitcode , cmd_success = success , screen_output = log ) if ( success . and . exitcode == 0 ) then call remove_newline_characters ( log ) ! Split all arguments tokens = shlex_split ( log % s ) nlib = size ( tokens ) allocate ( flags ( nlib )) do i = 1 , nlib flags ( i ) = string_t ( trim ( adjustl ( tokens ( i )))) end do else allocate ( flags ( 0 )) call fatal_error ( error , 'cannot get <' // name // '> build flags from pkg-config' ) end if ! Restore environment variable if ( old_had ) then success = set_env ( 'PKG_CONFIG_ALLOW_SYSTEM_CFLAGS' , value = old ) else success = delete_env ( 'PKG_CONFIG_ALLOW_SYSTEM_CFLAGS' ) end if if (. not . success ) then call fatal_error ( error , 'Cannot get pkg-config build flags: environment variable error.' ) return end if end function pkgcfg_get_build_flags !> Simple call to execute_command_line involving one mpi* wrapper subroutine run_wrapper ( wrapper , args , verbose , exitcode , cmd_success , screen_output ) type ( string_t ), intent ( in ) :: wrapper type ( string_t ), intent ( in ), optional :: args (:) logical , intent ( in ), optional :: verbose integer , intent ( out ), optional :: exitcode logical , intent ( out ), optional :: cmd_success type ( string_t ), intent ( out ), optional :: screen_output logical :: echo_local character (:), allocatable :: redirect_str , command , redirect , line integer :: iunit , iarg , stat , cmdstat if ( present ( verbose )) then echo_local = verbose else echo_local = . false . end if ! No redirection and non-verbose output if ( present ( screen_output )) then redirect = get_temp_filename () redirect_str = \">\" // redirect // \" 2>&1\" else if ( os_is_unix ()) then redirect_str = \" >/dev/null 2>&1\" else redirect_str = \" >NUL 2>&1\" end if end if ! Empty command if ( len_trim ( wrapper ) <= 0 ) then if ( echo_local ) print * , '+ ' if ( present ( exitcode )) exitcode = 0 if ( present ( cmd_success )) cmd_success = . true . if ( present ( screen_output )) screen_output = string_t ( \"\" ) return end if ! Init command command = trim ( wrapper % s ) add_arguments : if ( present ( args )) then do iarg = 1 , size ( args ) if ( len_trim ( args ( iarg )) <= 0 ) cycle command = trim ( command ) // ' ' // args ( iarg )% s end do endif add_arguments if ( echo_local ) print * , '+ ' , command ! Test command call execute_command_line ( command // redirect_str , exitstat = stat , cmdstat = cmdstat ) ! Command successful? if ( present ( cmd_success )) cmd_success = cmdstat == 0 ! Program exit code? if ( present ( exitcode )) exitcode = stat ! Want screen output? if ( present ( screen_output ) . and . cmdstat == 0 ) then allocate ( character ( len = 0 ) :: screen_output % s ) open ( newunit = iunit , file = redirect , status = 'old' , iostat = stat ) if ( stat == 0 ) then do call getline ( iunit , line , stat ) if ( stat /= 0 ) exit screen_output % s = screen_output % s // new_line ( 'a' ) // line if ( echo_local ) write ( * , '(A)' ) trim ( line ) end do ! Close and delete file close ( iunit , status = 'delete' ) else call fpm_stop ( 1 , 'cannot read temporary file from successful MPI wrapper' ) endif end if end subroutine run_wrapper end module fpm_pkg_config","tags":"","url":"sourcefile/fpm_pkg_config.f90.html"},{"title":"fpm_backend_console.f90 – Fortran-lang/fpm","text":"Source Code !># Build Backend Console !> This module provides a lightweight implementation for printing to the console !> and updating previously-printed console lines. It used by `[[fpm_backend_output]]` !> for pretty-printing build status and progress. !> !> @note The implementation for updating previous lines relies on no other output !> going to `stdout`/`stderr` except through the `console_t` object provided. !> !> @note All write statements to `stdout` are enclosed within OpenMP `critical` regions !> module fpm_backend_console use iso_fortran_env , only : stdout => output_unit implicit none private public :: console_t public :: LINE_RESET public :: COLOR_RED , COLOR_GREEN , COLOR_YELLOW , COLOR_RESET character ( len =* ), parameter :: ESC = char ( 27 ) !> Escape code for erasing current line character ( len =* ), parameter :: LINE_RESET = ESC // \"[2K\" // ESC // \"[1G\" !> Escape code for moving up one line character ( len =* ), parameter :: LINE_UP = ESC // \"[1A\" !> Escape code for moving down one line character ( len =* ), parameter :: LINE_DOWN = ESC // \"[1B\" !> Escape code for red foreground color character ( len =* ), parameter :: COLOR_RED = ESC // \"[31m\" !> Escape code for green foreground color character ( len =* ), parameter :: COLOR_GREEN = ESC // \"[32m\" !> Escape code for yellow foreground color character ( len =* ), parameter :: COLOR_YELLOW = ESC // \"[93m\" !> Escape code to reset foreground color character ( len =* ), parameter :: COLOR_RESET = ESC // \"[0m\" !> Console object type console_t !> Number of lines printed integer :: n_line = 1 contains !> Write a single line to the console procedure :: write_line => console_write_line !> Update a previously-written console line procedure :: update_line => console_update_line end type console_t contains !> Write a single line to the standard output subroutine console_write_line ( console , str , line , advance ) !> Console object class ( console_t ), intent ( inout ) :: console !> String to write character ( * ), intent ( in ) :: str !> Integer needed to later update console line integer , intent ( out ), optional :: line !> Advancing output (print newline?) logical , intent ( in ), optional :: advance character ( 3 ) :: adv adv = \"yes\" if ( present ( advance )) then if (. not . advance ) then adv = \"no\" end if end if !$omp critical if ( present ( line )) then line = console % n_line end if write ( stdout , '(A)' , advance = trim ( adv )) LINE_RESET // str if ( adv == \"yes\" ) then console % n_line = console % n_line + 1 end if !$omp end critical end subroutine console_write_line !> Overwrite a previously-written line in standard output subroutine console_update_line ( console , line_no , str ) !> Console object class ( console_t ), intent ( in ) :: console !> Integer output from `[[console_write_line]]` integer , intent ( in ) :: line_no !> New string to overwrite line character ( * ), intent ( in ) :: str integer :: n !$omp critical n = console % n_line - line_no ! Step back to line write ( stdout , '(A)' , advance = \"no\" ) repeat ( LINE_UP , n ) // LINE_RESET write ( stdout , '(A)' , advance = \"no\" ) str ! Step forward to end write ( stdout , '(A)' , advance = \"no\" ) repeat ( LINE_DOWN , n ) // LINE_RESET !$omp end critical end subroutine console_update_line end module fpm_backend_console","tags":"","url":"sourcefile/fpm_backend_console.f90.html"},{"title":"fpm_meta_mpi.f90 – Fortran-lang/fpm","text":"Source Code module fpm_meta_mpi use fpm_compiler , only : compiler_t , id_gcc , get_os_type , OS_WINDOWS , get_include_flag , & get_module_flag , new_compiler , compiler_name , id_f95 , id_intel_classic_windows , & id_intel_llvm_windows , id_intel_classic_nix , id_intel_llvm_nix , id_intel_classic_mac , & id_intel_llvm_unknown , id_pgi , id_nvhpc , id_cray use fpm_filesystem , only : join_path , exists , get_dos_path , run , getline , is_dir , & get_temp_filename use fpm_os , only : get_absolute_path use fpm_error , only : error_t , fatal_error , syntax_error use fpm_versioning , only : version_t , new_version , regex_version_from_text use fpm_strings , only : string_t , len_trim , split , str_begins_with_str , str_ends_with , & remove_newline_characters use fpm_environment , only : get_env , get_os_type , os_is_unix , OS_MACOS , OS_WINDOWS use fpm_meta_base , only : metapackage_t , destroy use fpm_manifest_metapackages , only : metapackage_request_t use fpm_pkg_config , only : run_wrapper use shlex_module , only : shlex_split => split implicit none private public :: init_mpi , MPI_TYPE_NAME integer , parameter :: MPI_TYPE_NONE = 0 integer , parameter :: MPI_TYPE_OPENMPI = 1 integer , parameter :: MPI_TYPE_MPICH = 2 integer , parameter :: MPI_TYPE_INTEL = 3 integer , parameter :: MPI_TYPE_MSMPI = 4 !> Debugging information logical , parameter , private :: verbose = . false . integer , parameter , private :: LANG_FORTRAN = 1 integer , parameter , private :: LANG_C = 2 integer , parameter , private :: LANG_CXX = 3 character ( * ), parameter :: LANG_NAME ( * ) = [ character ( 7 ) :: 'Fortran' , 'C' , 'C++' ] contains !> Initialize MPI metapackage for the current system subroutine init_mpi ( this , compiler , all_meta , error ) class ( metapackage_t ), intent ( inout ) :: this type ( compiler_t ), intent ( in ) :: compiler type ( metapackage_request_t ), intent ( in ) :: all_meta (:) type ( error_t ), allocatable , intent ( out ) :: error type ( string_t ), allocatable :: c_wrappers (:), cpp_wrappers (:), fort_wrappers (:) type ( string_t ) :: output , fwrap , cwrap , cxxwrap character ( 256 ) :: msg_out character ( len = :), allocatable :: tokens (:) integer :: wcfit ( 3 ), mpilib ( 3 ), ic , icpp , i logical :: found !> Cleanup call destroy ( this ) !> Set name this % name = \"mpi\" !> Get all candidate MPI wrappers call mpi_wrappers ( compiler , fort_wrappers , c_wrappers , cpp_wrappers ) if ( verbose ) print 1 , size ( fort_wrappers ), size ( c_wrappers ), size ( cpp_wrappers ) call wrapper_compiler_fit ( fort_wrappers , c_wrappers , cpp_wrappers , compiler , wcfit , mpilib , error ) if ( allocated ( error ) . or . all ( wcfit == 0 )) then !> No wrapper compiler fit. Are we on Windows? use MSMPI-specific search found = msmpi_init ( this , compiler , error ) if ( allocated ( error )) return !> All attempts failed if (. not . found ) then call fatal_error ( error , \"cannot find MPI wrappers or libraries for \" // compiler % name () // \" compiler\" ) return endif else if ( wcfit ( LANG_FORTRAN ) > 0 ) fwrap = fort_wrappers ( wcfit ( LANG_FORTRAN )) if ( wcfit ( LANG_C ) > 0 ) cwrap = c_wrappers ( wcfit ( LANG_C )) if ( wcfit ( LANG_CXX ) > 0 ) cxxwrap = cpp_wrappers ( wcfit ( LANG_CXX )) !> If there's only an available Fortran wrapper, and the compiler's different than fpm's baseline !> fortran compiler suite, we still want to enable C language flags as that is most likely being !> ABI-compatible anyways. However, issues may arise. !> see e.g. Homebrew with clabng C/C++ and GNU fortran at https://gitlab.kitware.com/cmake/cmake/-/issues/18139 if ( wcfit ( LANG_FORTRAN ) > 0 . and . all ( wcfit ([ LANG_C , LANG_CXX ]) == 0 )) then cwrap = fort_wrappers ( wcfit ( LANG_FORTRAN )) cxxwrap = fort_wrappers ( wcfit ( LANG_FORTRAN )) end if if ( verbose ) print * , '+ MPI fortran wrapper: ' , fwrap % s if ( verbose ) print * , '+ MPI c wrapper: ' , cwrap % s if ( verbose ) print * , '+ MPI c++ wrapper: ' , cxxwrap % s !> Initialize MPI package from wrapper command call init_mpi_from_wrappers ( this , compiler , mpilib ( LANG_FORTRAN ), fwrap , cwrap , cxxwrap , error ) if ( allocated ( error )) return !> Request Fortran implicit typing if ( mpilib ( LANG_FORTRAN ) /= MPI_TYPE_INTEL ) then allocate ( this % fortran ) this % fortran % implicit_typing = . true . this % fortran % implicit_external = . true . endif end if !> Not all MPI implementations offer modules mpi and mpi_f08: hence, include them !> to the list of external modules, so they won't be requested as standard source files this % has_external_modules = . true . this % external_modules = [ string_t ( \"mpi\" ), string_t ( \"mpi_f08\" )] 1 format ( 'MPI wrappers found: fortran=' , i0 , ' c=' , i0 , ' c++=' , i0 ) end subroutine init_mpi !> Check if we're on a 64-bit environment !> Accept answer from https://stackoverflow.com/questions/49141093/get-system-information-with-fortran logical function is_64bit_environment () use iso_c_binding , only : c_intptr_t integer , parameter :: nbits = bit_size ( 0_c_intptr_t ) is_64bit_environment = nbits == 64 end function is_64bit_environment !> Return a name for the MPI library pure function MPI_TYPE_NAME ( mpilib ) result ( name ) integer , intent ( in ) :: mpilib character ( len = :), allocatable :: name select case ( mpilib ) case ( MPI_TYPE_NONE ); name = \"none\" case ( MPI_TYPE_OPENMPI ); name = \"OpenMPI\" case ( MPI_TYPE_MPICH ); name = \"MPICH\" case ( MPI_TYPE_INTEL ); name = \"INTELMPI\" case ( MPI_TYPE_MSMPI ); name = \"MS-MPI\" case default ; name = \"UNKNOWN\" end select end function MPI_TYPE_NAME !> Check if there is a wrapper-compiler fit subroutine wrapper_compiler_fit ( fort_wrappers , c_wrappers , cpp_wrappers , compiler , wrap , mpi , error ) type ( string_t ), allocatable , intent ( in ) :: fort_wrappers (:), c_wrappers (:), cpp_wrappers (:) type ( compiler_t ), intent ( in ) :: compiler type ( error_t ), allocatable , intent ( out ) :: error integer , intent ( out ), dimension ( 3 ) :: wrap , mpi type ( error_t ), allocatable :: wrap_error wrap = 0 mpi = MPI_TYPE_NONE if ( size ( fort_wrappers ) > 0 ) & call mpi_compiler_match ( LANG_FORTRAN , fort_wrappers , compiler , wrap ( LANG_FORTRAN ), mpi ( LANG_FORTRAN ), wrap_error ) if ( size ( c_wrappers ) > 0 ) & call mpi_compiler_match ( LANG_C , c_wrappers , compiler , wrap ( LANG_C ), mpi ( LANG_C ), wrap_error ) if ( size ( cpp_wrappers ) > 0 ) & call mpi_compiler_match ( LANG_CXX , cpp_wrappers , compiler , wrap ( LANG_CXX ), mpi ( LANG_CXX ), wrap_error ) !> Find a Fortran wrapper for the current compiler if ( all ( wrap == 0 )) then call fatal_error ( error , 'no valid wrappers match current compiler, ' // compiler_name ( compiler )) return end if end subroutine wrapper_compiler_fit !> Check if a local MS-MPI SDK build is found logical function msmpi_init ( this , compiler , error ) result ( found ) class ( metapackage_t ), intent ( inout ) :: this type ( compiler_t ), intent ( in ) :: compiler type ( error_t ), allocatable , intent ( out ) :: error character ( len = :), allocatable :: incdir , windir , libdir , bindir , post , reall , msysdir type ( version_t ) :: ver , ver10 type ( string_t ) :: cpath , msys_path , runner_path logical :: msys2 !> Default: not found found = . false . if ( get_os_type () == OS_WINDOWS ) then ! to run MSMPI on Windows, is_minGW : if ( compiler % id == id_gcc ) then call compiler_get_version ( compiler , ver , msys2 , error ) if ( allocated ( error )) return endif is_minGW ! Check we're on a 64-bit environment if ( is_64bit_environment ()) then libdir = get_env ( 'MSMPI_LIB64' ) post = 'x64' else libdir = get_env ( 'MSMPI_LIB32' ) post = 'x86' !> Not working on 32-bit Windows yet call fatal_error ( error , 'MS-MPI error: this package requires 64-bit Windows environment' ) return end if ! Check that the runtime is installed bindir = \"\" call get_absolute_path ( get_env ( 'MSMPI_BIN' ), bindir , error ) if ( verbose ) print * , '+ %MSMPI_BIN%=' , bindir ! In some environments, variable %MSMPI_BIN% is missing (i.e. in GitHub Action images). ! Do a second attempt: search for the default location if ( len_trim ( bindir ) <= 0 . or . allocated ( error )) then if ( verbose ) print * , '+ %MSMPI_BIN% empty, searching C:\\Program Files\\Microsoft MPI\\Bin\\ ...' call get_absolute_path ( 'C:\\Program Files\\Microsoft MPI\\Bin\\mpiexec.exe' , bindir , error ) endif ! Third attempt for bash-style shell if ( len_trim ( bindir ) <= 0 . or . allocated ( error )) then if ( verbose ) print * , '+ %MSMPI_BIN% empty, searching /c/Program Files/Microsoft MPI/Bin/ ...' call get_absolute_path ( '/c/Program Files/Microsoft MPI/Bin/mpiexec.exe' , bindir , error ) endif ! Do a fourth attempt: search for mpiexec.exe in PATH location if ( len_trim ( bindir ) <= 0 . or . allocated ( error )) then if ( verbose ) print * , '+ C:\\Program Files\\Microsoft MPI\\Bin\\ not found. searching %PATH%...' call get_mpi_runner ( runner_path , verbose , error ) if (. not . allocated ( error )) then if ( verbose ) print * , '+ mpiexec found: ' , runner_path % s call find_command_location ( runner_path % s , bindir , verbose = verbose , error = error ) endif endif if ( allocated ( error )) then call fatal_error ( error , 'MS-MPI error: MS-MPI Runtime directory is missing. ' // & 'check environment variable %MSMPI_BIN% or that the folder is in %PATH%.' ) return end if ! Success! found = . true . ! Init ms-mpi call destroy ( this ) ! MSYS2 provides a pre-built static msmpi.dll.a library. Use that if possible use_prebuilt : if ( msys2 ) then ! MSYS executables are in %MSYS_ROOT%/bin call compiler_get_path ( compiler , cpath , error ) if ( allocated ( error )) return call get_absolute_path ( join_path ( cpath % s , '..' ), msys_path % s , error ) if ( allocated ( error )) return call get_absolute_path ( join_path ( msys_path % s , 'include' ), incdir , error ) if ( allocated ( error )) return call get_absolute_path ( join_path ( msys_path % s , 'lib' ), libdir , error ) if ( allocated ( error )) return if ( verbose ) print 1 , 'include' , incdir , exists ( incdir ) if ( verbose ) print 1 , 'library' , libdir , exists ( libdir ) ! Check that the necessary files exist call get_absolute_path ( join_path ( libdir , 'libmsmpi.dll.a' ), post , error ) if ( allocated ( error )) return if ( len_trim ( post ) <= 0 . or . . not . exists ( post )) then call fatal_error ( error , 'MS-MPI available through the MSYS2 system not found. ' // & 'Run ' // & 'or your system-specific version to install.' ) return end if ! Add dir cpath this % has_link_flags = . true . this % link_flags = string_t ( ' -L' // get_dos_path ( libdir , error )) this % has_link_libraries = . true . this % link_libs = [ string_t ( 'msmpi.dll' )] if ( allocated ( error )) return this % has_include_dirs = . true . this % incl_dirs = [ string_t ( get_dos_path ( incdir , error ))] if ( allocated ( error )) return else call fatal_error ( error , 'MS-MPI cannot work with non-MSYS2 GNU compilers yet' ) return ! Add dir path this % has_link_flags = . true . this % link_flags = string_t ( ' -L' // get_dos_path ( libdir , error )) this % has_link_libraries = . true . this % link_libs = [ string_t ( 'msmpi' ), string_t ( 'msmpifec' ), string_t ( 'msmpifmc' )] if ( allocated ( error )) return this % has_include_dirs = . true . this % incl_dirs = [ string_t ( get_dos_path ( incdir , error )), & string_t ( get_dos_path ( incdir // post , error ))] if ( allocated ( error )) return end if use_prebuilt !> Request Fortran implicit typing allocate ( this % fortran ) this % fortran % implicit_typing = . true . this % fortran % implicit_external = . true . ! gfortran>=10 is incompatible with the old-style mpif.h MS-MPI headers. ! If so, add flags to allow old-style BOZ constants in mpif.h allow_BOZ : if ( compiler % id == id_gcc ) then call new_version ( ver10 , '10.0.0' , error ) if ( allocated ( error )) return if ( ver >= ver10 ) then this % has_build_flags = . true . this % flags = string_t ( ' -fallow-invalid-boz' ) end if endif allow_BOZ !> Add default run command this % has_run_command = . true . this % run_command = string_t ( join_path ( get_dos_path ( bindir , error ), 'mpiexec.exe' ) // ' -np * ' ) else !> Not on Windows found = . false . end if 1 format ( 'MSMSPI ' , a , ' directory: PATH=' , a , ' EXISTS=' , l1 ) end function msmpi_init !> Check if we're under a WSL bash shell logical function wsl_shell () if ( get_os_type () == OS_WINDOWS ) then wsl_shell = exists ( '/proc/sys/fs/binfmt_misc/WSLInterop' ) else wsl_shell = . false . endif end function wsl_shell !> Find the location of a valid command subroutine find_command_location ( command , path , echo , verbose , error ) character ( * ), intent ( in ) :: command character ( len = :), allocatable , intent ( out ) :: path logical , optional , intent ( in ) :: echo , verbose type ( error_t ), allocatable , intent ( out ) :: error character (:), allocatable :: tmp_file , screen_output , line , fullpath , search_command integer :: stat , iunit , ire , length , try character ( * ), parameter :: search ( 2 ) = [ \"where \" , \"which \" ] if ( len_trim ( command ) <= 0 ) then call fatal_error ( error , 'empty command provided in find_command_location' ) return end if tmp_file = get_temp_filename () ! On Windows, we try both commands because we may be on WSL do try = merge ( 1 , 2 , get_os_type () == OS_WINDOWS ), 2 search_command = search ( try ) // command call run ( search_command , echo = echo , exitstat = stat , verbose = verbose , redirect = tmp_file ) if ( stat == 0 ) exit end do if ( stat /= 0 ) then call fatal_error ( error , 'find_command_location failed for ' // command ) return end if ! Only read first instance (first line) allocate ( character ( len = 0 ) :: screen_output ) open ( newunit = iunit , file = tmp_file , status = 'old' , iostat = stat ) if ( stat == 0 ) then do call getline ( iunit , line , stat ) if ( stat /= 0 ) exit if ( len ( screen_output ) > 0 ) then screen_output = screen_output // new_line ( 'a' ) // line else screen_output = line endif end do ! Close and delete file close ( iunit , status = 'delete' ) else call fatal_error ( error , 'cannot read temporary file from successful find_command_location' ) return endif ! Only use the first instance length = index ( screen_output , new_line ( 'a' )) multiline : if ( length > 1 ) then fullpath = screen_output ( 1 : length - 1 ) else fullpath = screen_output endif multiline if ( len_trim ( fullpath ) < 1 ) then call fatal_error ( error , 'no paths found to command (' // command // ')' ) return end if ! Extract path only length = index ( fullpath , command , BACK = . true .) if ( length <= 0 ) then call fatal_error ( error , 'full path to command (' // command // ') does not include command name' ) return elseif ( length == 1 ) then ! Compiler is in the current folder path = '.' else path = fullpath ( 1 : length - 1 ) end if if ( allocated ( error )) return ! On Windows, be sure to return a path with no spaces if ( get_os_type () == OS_WINDOWS ) path = get_dos_path ( path , error ) if ( allocated ( error ) . or . . not . is_dir ( path )) then call fatal_error ( error , 'full path (' // path // ') to command (' // command // ') is not a directory' ) return end if end subroutine find_command_location !> Get MPI runner in $PATH subroutine get_mpi_runner ( command , verbose , error ) type ( string_t ), intent ( out ) :: command logical , intent ( in ) :: verbose type ( error_t ), allocatable , intent ( out ) :: error character ( * ), parameter :: try ( * ) = [ character ( 11 ) :: 'mpiexec' , 'mpirun' , 'mpiexec.exe' , 'mpirun.exe' , 'srun' ] character (:), allocatable :: bindir integer :: itri logical :: success ! Try several commands do itri = 1 , size ( try ) call find_command_location ( trim ( try ( itri )), command % s , verbose = verbose , error = error ) if ( allocated ( error )) cycle ! Success! success = len_trim ( command % s ) > 0 if ( success ) then if ( verbose ) print * , '+ runner folder found: ' // command % s command % s = join_path ( command % s , trim ( try ( itri ))) return endif end do ! On windows, also search in %MSMPI_BIN% if ( get_os_type () == OS_WINDOWS ) then ! Check that the runtime is installed bindir = \"\" call get_absolute_path ( get_env ( 'MSMPI_BIN' ), bindir , error ) if ( verbose ) print * , '+ %MSMPI_BIN%=' , bindir ! In some environments, variable %MSMPI_BIN% is missing (i.e. in GitHub Action images). ! Do a second attempt: search for the default location if ( len_trim ( bindir ) <= 0 . or . allocated ( error )) then if ( verbose ) print * , '+ %MSMPI_BIN% empty, searching C:\\Program Files\\Microsoft MPI\\Bin\\ ...' call get_absolute_path ( 'C:\\Program Files\\Microsoft MPI\\Bin\\mpiexec.exe' , bindir , error ) endif if ( len_trim ( bindir ) > 0 . and . . not . allocated ( error )) then ! MSMPI_BIN directory found command % s = join_path ( bindir , 'mpiexec.exe' ) return endif endif ! No valid command found call fatal_error ( error , 'cannot find a valid mpi runner command' ) return end subroutine get_mpi_runner !> Return compiler path subroutine compiler_get_path ( self , path , error ) type ( compiler_t ), intent ( in ) :: self type ( string_t ), intent ( out ) :: path type ( error_t ), allocatable , intent ( out ) :: error call find_command_location ( self % fc , path % s , self % echo , self % verbose , error ) end subroutine compiler_get_path !> Return compiler version subroutine compiler_get_version ( self , version , is_msys2 , error ) type ( compiler_t ), intent ( in ) :: self type ( version_t ), intent ( out ) :: version logical , intent ( out ) :: is_msys2 type ( error_t ), allocatable , intent ( out ) :: error character (:), allocatable :: tmp_file , screen_output , line type ( string_t ) :: ver integer :: stat , iunit , ire , length is_msys2 = . false . select case ( self % id ) case ( id_gcc ) tmp_file = get_temp_filename () call run ( self % fc // \" --version \" , echo = self % echo , verbose = self % verbose , redirect = tmp_file , exitstat = stat ) if ( stat /= 0 ) then call fatal_error ( error , 'compiler_get_version failed for ' // self % fc ) return end if allocate ( character ( len = 0 ) :: screen_output ) open ( newunit = iunit , file = tmp_file , status = 'old' , iostat = stat ) if ( stat == 0 ) then do call getline ( iunit , line , stat ) if ( stat /= 0 ) exit screen_output = screen_output // ' ' // line // ' ' end do ! Close and delete file close ( iunit , status = 'delete' ) else call fatal_error ( error , 'cannot read temporary file from successful compiler_get_version' ) return endif ! Check if this gcc is from the MSYS2 project is_msys2 = index ( screen_output , 'MSYS2' ) > 0 ver = regex_version_from_text ( screen_output , self % fc // ' compiler' , error ) if ( allocated ( error )) return ! Extract version call new_version ( version , ver % s , error ) case default call fatal_error ( error , 'compiler_get_version not yet implemented for compiler ' // self % fc ) return end select end subroutine compiler_get_version !> Initialize an MPI metapackage from a valid wrapper command ('mpif90', etc...) subroutine init_mpi_from_wrappers ( this , compiler , mpilib , fort_wrapper , c_wrapper , cxx_wrapper , error ) class ( metapackage_t ), intent ( inout ) :: this type ( compiler_t ), intent ( in ) :: compiler integer , intent ( in ) :: mpilib type ( string_t ), intent ( in ) :: fort_wrapper , c_wrapper , cxx_wrapper type ( error_t ), allocatable , intent ( out ) :: error type ( version_t ) :: version type ( error_t ), allocatable :: runner_error ! Cleanup structure call destroy ( this ) ! Get linking flags this % link_flags = mpi_wrapper_query ( mpilib , fort_wrapper , 'link' , verbose , error ) if ( allocated ( error )) return ! Remove useless/dangerous flags call filter_link_arguments ( compiler , this % link_flags ) this % has_link_flags = len_trim ( this % link_flags ) > 0 ! Request to use libs in arbitrary order if ( this % has_link_flags . and . compiler % is_gnu () . and . os_is_unix () . and . get_os_type () /= OS_MACOS ) then this % link_flags = string_t ( ' -Wl,--start-group ' // this % link_flags % s ) end if ! Add language-specific flags call set_language_flags ( compiler , mpilib , fort_wrapper , this % has_fortran_flags , this % fflags , verbose , error ) if ( allocated ( error )) return call set_language_flags ( compiler , mpilib , c_wrapper , this % has_c_flags , this % cflags , verbose , error ) if ( allocated ( error )) return call set_language_flags ( compiler , mpilib , cxx_wrapper , this % has_cxx_flags , this % cxxflags , verbose , error ) if ( allocated ( error )) return ! Get library version version = mpi_version_get ( mpilib , fort_wrapper , error ) if ( allocated ( error )) then return else allocate ( this % version , source = version ) end if !> Add default run command, if present this % run_command = mpi_wrapper_query ( mpilib , fort_wrapper , 'runner' , verbose , runner_error ) this % has_run_command = ( len_trim ( this % run_command ) > 0 ) . and . . not . allocated ( runner_error ) contains subroutine set_language_flags ( compiler , mpilib , wrapper , has_flags , flags , verbose , error ) type ( compiler_t ), intent ( in ) :: compiler integer , intent ( in ) :: mpilib type ( string_t ), intent ( in ) :: wrapper logical , intent ( inout ) :: has_flags type ( string_t ), intent ( inout ) :: flags logical , intent ( in ) :: verbose type ( error_t ), allocatable , intent ( out ) :: error ! Get build flags for each language if ( len_trim ( wrapper ) > 0 ) then flags = mpi_wrapper_query ( mpilib , wrapper , 'flags' , verbose , error ) if ( allocated ( error )) return has_flags = len_trim ( flags ) > 0 ! Add heading space flags = string_t ( ' ' // flags % s ) if ( verbose ) print * , '+ MPI language flags from wrapper <' , wrapper % s , '>: flags=' , flags % s call filter_build_arguments ( compiler , flags ) endif end subroutine set_language_flags end subroutine init_mpi_from_wrappers !> Match one of the available compiler wrappers with the current compiler subroutine mpi_compiler_match ( language , wrappers , compiler , which_one , mpilib , error ) integer , intent ( in ) :: language type ( string_t ), intent ( in ) :: wrappers (:) type ( compiler_t ), intent ( in ) :: compiler integer , intent ( out ) :: which_one , mpilib type ( error_t ), allocatable , intent ( out ) :: error integer :: i , same_vendor , vendor_mpilib type ( string_t ) :: screen character ( 128 ) :: msg_out type ( compiler_t ) :: mpi_compiler which_one = 0 same_vendor = 0 mpilib = MPI_TYPE_NONE if ( verbose ) print * , '+ Trying to match available ' , LANG_NAME ( language ), ' MPI wrappers to ' , compiler % fc , '...' do i = 1 , size ( wrappers ) mpilib = which_mpi_library ( wrappers ( i ), compiler , verbose = . false .) screen = mpi_wrapper_query ( mpilib , wrappers ( i ), 'compiler' , verbose = . false ., error = error ) if ( allocated ( error )) return if ( verbose ) print * , ' Wrapper ' , wrappers ( i )% s , ' lib=' , MPI_TYPE_NAME ( mpilib ), ' uses ' , screen % s select case ( language ) case ( LANG_FORTRAN ) ! Build compiler type. The ID is created based on the Fortran name call new_compiler ( mpi_compiler , screen % s , '' , '' , echo = . true ., verbose = . false .) ! Fortran match found! if ( mpi_compiler % id == compiler % id ) then which_one = i return end if case ( LANG_C ) ! For other languages, we can only hope that the name matches the expected one if ( screen % s == compiler % cc . or . screen % s == compiler % fc ) then which_one = i return end if case ( LANG_CXX ) if ( screen % s == compiler % cxx . or . screen % s == compiler % fc ) then which_one = i return end if end select ! Because the intel mpi library does not support llvm_ compiler wrappers yet, ! we must check for that manually if ( is_intel_classic_option ( language , same_vendor , screen , compiler , mpi_compiler )) then same_vendor = i vendor_mpilib = mpilib end if end do ! Intel compiler: if an exact match is not found, attempt closest wrapper if ( which_one == 0 . and . same_vendor > 0 ) then which_one = same_vendor mpilib = vendor_mpilib end if ! None of the available wrappers matched the current Fortran compiler write ( msg_out , 1 ) size ( wrappers ), compiler % fc call fatal_error ( error , trim ( msg_out )) 1 format ( ' None out of ' , i0 , ' valid MPI wrappers matches compiler ' , a ) end subroutine mpi_compiler_match !> Because the Intel mpi library does not support llvm_ compiler wrappers yet, !> we must save the Intel-classic option and later manually replace it logical function is_intel_classic_option ( language , same_vendor_ID , screen_out , compiler , mpi_compiler ) integer , intent ( in ) :: language , same_vendor_ID type ( string_t ), intent ( in ) :: screen_out type ( compiler_t ), intent ( in ) :: compiler , mpi_compiler if ( same_vendor_ID /= 0 ) then is_intel_classic_option = . false . else select case ( language ) case ( LANG_FORTRAN ) is_intel_classic_option = mpi_compiler % is_intel () . and . compiler % is_intel () case ( LANG_C ) is_intel_classic_option = screen_out % s == 'icc' . and . compiler % cc == 'icx' case ( LANG_CXX ) is_intel_classic_option = screen_out % s == 'icpc' . and . compiler % cc == 'icpx' end select end if end function is_intel_classic_option !> Return library version from the MPI wrapper command type ( version_t ) function mpi_version_get ( mpilib , wrapper , error ) integer , intent ( in ) :: mpilib type ( string_t ), intent ( in ) :: wrapper type ( error_t ), allocatable , intent ( out ) :: error type ( string_t ) :: version_line ! Get version string version_line = mpi_wrapper_query ( mpilib , wrapper , 'version' , error = error ) if ( allocated ( error )) return ! Wrap to object call new_version ( mpi_version_get , version_line % s , error ) end function mpi_version_get !> Return several mpi wrappers, and return subroutine mpi_wrappers ( compiler , fort_wrappers , c_wrappers , cpp_wrappers ) type ( compiler_t ), intent ( in ) :: compiler type ( string_t ), allocatable , intent ( out ) :: c_wrappers (:), cpp_wrappers (:), fort_wrappers (:) character ( len = :), allocatable :: mpi_root , intel_wrap type ( error_t ), allocatable :: error ! Attempt gathering MPI wrapper names from the environment variables c_wrappers = [ string_t ( get_env ( 'MPICC' , 'mpicc' ))] cpp_wrappers = [ string_t ( get_env ( 'MPICXX' , 'mpic++' ))] fort_wrappers = [ string_t ( get_env ( 'MPIFC' , 'mpifc' )),& string_t ( get_env ( 'MPIf90' , 'mpif90' )),& string_t ( get_env ( 'MPIf77' , 'mpif77' ))] if ( get_os_type () == OS_WINDOWS ) then c_wrappers = [ c_wrappers , string_t ( 'mpicc.bat' )] cpp_wrappers = [ cpp_wrappers , string_t ( 'mpicxx.bat' )] fort_wrappers = [ fort_wrappers , string_t ( 'mpifc.bat' )] endif ! Add compiler-specific wrappers compiler_specific : select case ( compiler % id ) case ( id_gcc , id_f95 ) c_wrappers = [ c_wrappers , string_t ( 'mpigcc' ), string_t ( 'mpgcc' )] cpp_wrappers = [ cpp_wrappers , string_t ( 'mpig++' ), string_t ( 'mpg++' )] fort_wrappers = [ fort_wrappers , string_t ( 'mpigfortran' ), string_t ( 'mpgfortran' ),& string_t ( 'mpig77' ), string_t ( 'mpg77' )] case ( id_intel_classic_windows , id_intel_classic_nix , id_intel_classic_mac ) c_wrappers = [ string_t ( get_env ( 'I_MPI_CC' , 'mpiicc' ))] cpp_wrappers = [ string_t ( get_env ( 'I_MPI_CXX' , 'mpiicpc' ))] fort_wrappers = [ string_t ( get_env ( 'I_MPI_F90' , 'mpiifort' ))] ! Also search MPI wrappers via the base MPI folder mpi_root = get_env ( 'I_MPI_ROOT' ) if ( mpi_root /= \"\" ) then mpi_root = join_path ( mpi_root , 'bin' ) intel_wrap = join_path ( mpi_root , 'mpiifort' ) if ( get_os_type () == OS_WINDOWS ) intel_wrap = get_dos_path ( intel_wrap , error ) if ( intel_wrap /= \"\" ) fort_wrappers = [ fort_wrappers , string_t ( intel_wrap )] intel_wrap = join_path ( mpi_root , 'mpiicc' ) if ( get_os_type () == OS_WINDOWS ) intel_wrap = get_dos_path ( intel_wrap , error ) if ( intel_wrap /= \"\" ) c_wrappers = [ c_wrappers , string_t ( intel_wrap )] intel_wrap = join_path ( mpi_root , 'mpiicpc' ) if ( get_os_type () == OS_WINDOWS ) intel_wrap = get_dos_path ( intel_wrap , error ) if ( intel_wrap /= \"\" ) cpp_wrappers = [ cpp_wrappers , string_t ( intel_wrap )] end if case ( id_intel_llvm_windows , id_intel_llvm_nix , id_intel_llvm_unknown ) c_wrappers = [ string_t ( get_env ( 'I_MPI_CC' , 'mpiicx' ))] cpp_wrappers = [ string_t ( get_env ( 'I_MPI_CXX' , 'mpiicpx' ))] fort_wrappers = [ string_t ( get_env ( 'I_MPI_F90' , 'mpiifx' ))] ! Also search MPI wrappers via the base MPI folder mpi_root = get_env ( 'I_MPI_ROOT' ) if ( mpi_root /= \"\" ) then mpi_root = join_path ( mpi_root , 'bin' ) intel_wrap = join_path ( mpi_root , 'mpiifx' ) if ( get_os_type () == OS_WINDOWS ) intel_wrap = get_dos_path ( intel_wrap , error ) if ( intel_wrap /= \"\" ) fort_wrappers = [ fort_wrappers , string_t ( intel_wrap )] intel_wrap = join_path ( mpi_root , 'mpiicx' ) if ( get_os_type () == OS_WINDOWS ) intel_wrap = get_dos_path ( intel_wrap , error ) if ( intel_wrap /= \"\" ) c_wrappers = [ c_wrappers , string_t ( intel_wrap )] intel_wrap = join_path ( mpi_root , 'mpiicpx' ) if ( get_os_type () == OS_WINDOWS ) intel_wrap = get_dos_path ( intel_wrap , error ) if ( intel_wrap /= \"\" ) cpp_wrappers = [ cpp_wrappers , string_t ( intel_wrap )] end if case ( id_pgi , id_nvhpc ) c_wrappers = [ c_wrappers , string_t ( 'mpipgicc' ), string_t ( 'mpgcc' )] cpp_wrappers = [ cpp_wrappers , string_t ( 'mpipgic++' )] fort_wrappers = [ fort_wrappers , string_t ( 'mpipgifort' ), string_t ( 'mpipgf90' )] case ( id_cray ) c_wrappers = [ c_wrappers , string_t ( 'cc' )] cpp_wrappers = [ cpp_wrappers , string_t ( 'CC' )] fort_wrappers = [ fort_wrappers , string_t ( 'ftn' )] end select compiler_specific call assert_mpi_wrappers ( fort_wrappers , compiler ) call assert_mpi_wrappers ( c_wrappers , compiler ) call assert_mpi_wrappers ( cpp_wrappers , compiler ) end subroutine mpi_wrappers !> Filter out invalid/unavailable mpi wrappers subroutine assert_mpi_wrappers ( wrappers , compiler , verbose ) type ( string_t ), allocatable , intent ( inout ) :: wrappers (:) type ( compiler_t ), intent ( in ) :: compiler logical , optional , intent ( in ) :: verbose integer :: i integer , allocatable :: works (:) allocate ( works ( size ( wrappers ))) do i = 1 , size ( wrappers ) if ( present ( verbose )) then if ( verbose ) print * , '+ MPI test wrapper <' , wrappers ( i )% s , '>' endif works ( i ) = which_mpi_library ( wrappers ( i ), compiler , verbose ) end do ! Filter out non-working wrappers wrappers = pack ( wrappers , works /= MPI_TYPE_NONE ) end subroutine assert_mpi_wrappers !> Get MPI library type from the wrapper command. Currently, only OpenMPI is supported integer function which_mpi_library ( wrapper , compiler , verbose ) type ( string_t ), intent ( in ) :: wrapper type ( compiler_t ), intent ( in ) :: compiler logical , intent ( in ), optional :: verbose logical :: is_mpi_wrapper integer :: stat ! Init as currently unsupported library which_mpi_library = MPI_TYPE_NONE if ( len_trim ( wrapper ) <= 0 ) return ! Run mpi wrapper first call run_wrapper ( wrapper , verbose = verbose , cmd_success = is_mpi_wrapper ) if ( is_mpi_wrapper ) then if ( compiler % is_intel ()) then which_mpi_library = MPI_TYPE_INTEL return end if ! Attempt to decipher which library this wrapper comes from. ! OpenMPI responds to '--showme' calls call run_wrapper ( wrapper ,[ string_t ( '--showme' )], verbose ,& exitcode = stat , cmd_success = is_mpi_wrapper ) if ( stat == 0 . and . is_mpi_wrapper ) then which_mpi_library = MPI_TYPE_OPENMPI return endif ! MPICH responds to '-show' calls call run_wrapper ( wrapper ,[ string_t ( '-show' )], verbose ,& exitcode = stat , cmd_success = is_mpi_wrapper ) if ( stat == 0 . and . is_mpi_wrapper ) then which_mpi_library = MPI_TYPE_MPICH return endif end if end function which_mpi_library !> Test if an MPI wrapper works type ( string_t ) function mpi_wrapper_query ( mpilib , wrapper , command , verbose , error ) result ( screen ) integer , intent ( in ) :: mpilib type ( string_t ), intent ( in ) :: wrapper character ( * ), intent ( in ) :: command logical , intent ( in ), optional :: verbose type ( error_t ), allocatable , intent ( out ) :: error logical :: success character (:), allocatable :: redirect_str , tokens (:), unsupported_msg type ( string_t ) :: cmdstr type ( compiler_t ) :: mpi_compiler integer :: stat , cmdstat , ire , length unsupported_msg = 'the MPI library of wrapper ' // wrapper % s // ' does not support task ' // trim ( command ) select case ( command ) ! Get MPI compiler name case ( 'compiler' ) select case ( mpilib ) case ( MPI_TYPE_OPENMPI ); cmdstr = string_t ( '--showme:command' ) case ( MPI_TYPE_MPICH ); cmdstr = string_t ( '-compile-info' ) case ( MPI_TYPE_INTEL ); cmdstr = string_t ( '-show' ) case default call fatal_error ( error , unsupported_msg ) return end select call run_wrapper ( wrapper ,[ cmdstr ], verbose = verbose , & exitcode = stat , cmd_success = success , screen_output = screen ) if ( stat /= 0 . or . . not . success ) then call syntax_error ( error , 'local ' // MPI_TYPE_NAME ( mpilib ) // & ' library wrapper does not support flag ' // cmdstr % s ) return end if ! Take out the first command from the whole line call remove_newline_characters ( screen ) call split ( screen % s , tokens , delimiters = ' ' ) screen % s = trim ( adjustl ( tokens ( 1 ))) ! Get a list of additional compiler flags case ( 'flags' ) select case ( mpilib ) case ( MPI_TYPE_OPENMPI ); cmdstr = string_t ( '--showme:compile' ) case ( MPI_TYPE_MPICH ); cmdstr = string_t ( '-compile-info' ) case ( MPI_TYPE_INTEL ); cmdstr = string_t ( '-show' ) case default call fatal_error ( error , unsupported_msg ) return end select call run_wrapper ( wrapper ,[ cmdstr ], verbose = verbose , & exitcode = stat , cmd_success = success , screen_output = screen ) if ( stat /= 0 . or . . not . success ) then call syntax_error ( error , 'local ' // MPI_TYPE_NAME ( mpilib ) // & ' library wrapper does not support flag ' // cmdstr % s ) return end if ! Post-process output select case ( mpilib ) case ( MPI_TYPE_OPENMPI ) ! This library reports the compiler name only call remove_newline_characters ( screen ) case ( MPI_TYPE_MPICH , MPI_TYPE_INTEL ) ! These libraries report the full command including the compiler name. Remove it if so call remove_newline_characters ( screen ) call split ( screen % s , tokens ) ! Remove trailing compiler name screen % s = screen % s ( len_trim ( tokens ( 1 )) + 1 :) case default call fatal_error ( error , 'invalid MPI library type' ) return end select ! Get a list of additional linker flags case ( 'link' ) select case ( mpilib ) case ( MPI_TYPE_OPENMPI ); cmdstr = string_t ( '--showme:link' ) case ( MPI_TYPE_MPICH ); cmdstr = string_t ( '-link-info' ) case ( MPI_TYPE_INTEL ); cmdstr = string_t ( '-show' ) case default call fatal_error ( error , unsupported_msg ) return end select call run_wrapper ( wrapper ,[ cmdstr ], verbose = verbose , & exitcode = stat , cmd_success = success , screen_output = screen ) if ( stat /= 0 . or . . not . success ) then call syntax_error ( error , 'local ' // MPI_TYPE_NAME ( mpilib ) // & ' library wrapper does not support flag ' // cmdstr % s ) return end if select case ( mpilib ) case ( MPI_TYPE_OPENMPI ) call remove_newline_characters ( screen ) case ( MPI_TYPE_MPICH , MPI_TYPE_INTEL ) ! MPICH reports the full command including the compiler name. Remove it if so call remove_newline_characters ( screen ) call split ( screen % s , tokens ) ! Remove trailing compiler name screen % s = screen % s ( len_trim ( tokens ( 1 )) + 1 :) case default call fatal_error ( error , unsupported_msg ) return end select ! Get a list of MPI library directories case ( 'link_dirs' ) select case ( mpilib ) case ( MPI_TYPE_OPENMPI ) ! --showme:command returns the build command of this wrapper call run_wrapper ( wrapper ,[ string_t ( '--showme:libdirs' )], verbose = verbose , & exitcode = stat , cmd_success = success , screen_output = screen ) if ( stat /= 0 . or . . not . success ) then call syntax_error ( error , 'local OpenMPI library does not support --showme:libdirs' ) return end if case default call fatal_error ( error , unsupported_msg ) return end select ! Get a list of include directories for the MPI headers/modules case ( 'incl_dirs' ) select case ( mpilib ) case ( MPI_TYPE_OPENMPI ) ! --showme:command returns the build command of this wrapper call run_wrapper ( wrapper ,[ string_t ( '--showme:incdirs' )], verbose = verbose , & exitcode = stat , cmd_success = success , screen_output = screen ) if ( stat /= 0 . or . . not . success ) then call syntax_error ( error , 'local OpenMPI library does not support --showme:incdirs' ) return end if case default call fatal_error ( error , unsupported_msg ) return end select call remove_newline_characters ( screen ) ! Retrieve library version case ( 'version' ) select case ( mpilib ) case ( MPI_TYPE_OPENMPI ) ! --showme:command returns the build command of this wrapper call run_wrapper ( wrapper ,[ string_t ( '--showme:version' )], verbose = verbose , & exitcode = stat , cmd_success = success , screen_output = screen ) if ( stat /= 0 . or . . not . success ) then call syntax_error ( error , 'local OpenMPI library does not support --showme:version' ) return else call remove_newline_characters ( screen ) end if case ( MPI_TYPE_MPICH ) !> MPICH offers command \"mpichversion\" in the same system folder as the MPI wrappers. !> So, attempt to run that first cmdstr = string_t ( 'mpichversion' ) call run_wrapper ( cmdstr , verbose = verbose , & exitcode = stat , cmd_success = success , screen_output = screen ) ! Second option: run mpich wrapper + \"-v\" if ( stat /= 0 . or . . not . success ) then call run_wrapper ( wrapper ,[ string_t ( '-v' )], verbose = verbose , & exitcode = stat , cmd_success = success , screen_output = screen ) call remove_newline_characters ( screen ) endif ! Third option: mpiexec --version if ( stat /= 0 . or . . not . success ) then cmdstr = string_t ( 'mpiexec --version' ) call run_wrapper ( cmdstr , verbose = verbose , & exitcode = stat , cmd_success = success , screen_output = screen ) endif if ( stat /= 0 . or . . not . success ) then call syntax_error ( error , & 'cannot retrieve MPICH library version from ' ) return end if case ( MPI_TYPE_INTEL ) ! -v returns the build command of this wrapper call run_wrapper ( wrapper ,[ string_t ( '-v' )], verbose = verbose , & exitcode = stat , cmd_success = success , screen_output = screen ) ! LLVM wrappers bug: non-zero exit code when checking for \"-v\" -> only check for ! successful command: https://github.com/spack/spack/issues/47672 if (. not . success ) then call syntax_error ( error , 'local INTEL MPI library does not support -v' ) return else call remove_newline_characters ( screen ) end if case default call fatal_error ( error , unsupported_msg ) return end select ! Extract version screen = regex_version_from_text ( screen % s , MPI_TYPE_NAME ( mpilib ) // ' library' , error ) if ( allocated ( error )) return ! Get path to the MPI runner command case ( 'runner' ) select case ( mpilib ) case ( MPI_TYPE_OPENMPI , MPI_TYPE_MPICH , MPI_TYPE_MSMPI , MPI_TYPE_INTEL ) call get_mpi_runner ( screen , verbose , error ) case default call fatal_error ( error , unsupported_msg ) return end select case default ; call fatal_error ( error , 'an invalid MPI wrapper command (' // command // & ') was invoked for wrapper <' // wrapper % s // '>.' ) return end select end function mpi_wrapper_query !> Check if input is a useful linker argument logical function is_link_argument ( compiler , string ) type ( compiler_t ), intent ( in ) :: compiler character ( * ), intent ( in ) :: string select case ( compiler % id ) case ( id_intel_classic_windows , id_intel_llvm_windows ) is_link_argument = string == '/link' & . or . str_begins_with_str ( string , '/LIBPATH' )& . or . str_ends_with ( string , '.lib' ) ! always .lib whether static or dynamic case default ! fix OpenMPI's Fortran wrapper bug (https://github.com/open-mpi/ompi/issues/11636) here is_link_argument = ( str_begins_with_str ( string , '-L' ) & . or . str_begins_with_str ( string , '-l' ) & . or . str_begins_with_str ( string , '-Xlinker' ) & . or . string == '-pthread' & . or . ( str_begins_with_str ( string , '-W' ) . and . & ( string /= '-Wall' ) . and . (. not . str_begins_with_str ( string , '-Werror' ))) ) & . and . . not . ( & ( get_os_type () == OS_MACOS . and . index ( string , '-commons,use_dylibs' ) > 0 ) ) end select end function is_link_argument !> From build, remove optimization and other unnecessary flags subroutine filter_build_arguments ( compiler , command ) type ( compiler_t ), intent ( in ) :: compiler type ( string_t ), intent ( inout ) :: command character ( len = :), allocatable :: tokens (:) integer :: i , n , re_i , re_l logical , allocatable :: keep (:) logical :: keep_next character ( len = :), allocatable :: module_flag , include_flag if ( len_trim ( command ) <= 0 ) return ! Split command into arguments tokens = shlex_split ( command % s ) module_flag = get_module_flag ( compiler , \"\" ) include_flag = get_include_flag ( compiler , \"\" ) n = size ( tokens ) allocate ( keep ( n ), source = . false .) keep_next = . false . do i = 1 , n if ( get_os_type () == OS_MACOS . and . index ( tokens ( i ), '-commons,use_dylibs' ) > 0 ) then keep ( i ) = . false . keep_next = . false . elseif ( str_begins_with_str ( tokens ( i ), '-D' ) . or . & str_begins_with_str ( tokens ( i ), '-f' ) . or . & str_begins_with_str ( tokens ( i ), '-I' ) . or . & str_begins_with_str ( tokens ( i ), module_flag ) . or . & str_begins_with_str ( tokens ( i ), include_flag ) . or . & tokens ( i ) == '-pthread' . or . & ( str_begins_with_str ( tokens ( i ), '-W' ) . and . tokens ( i ) /= '-Wall' . and . & . not . str_begins_with_str ( tokens ( i ), '-Werror' )) & ) then keep ( i ) = . true . if ( tokens ( i ) == module_flag . or . tokens ( i ) == include_flag . or . tokens ( i ) == '-I' ) keep_next = . true . elseif ( keep_next ) then keep ( i ) = . true . keep_next = . false . end if end do ! Backfill command = string_t ( \"\" ) do i = 1 , n if (. not . keep ( i )) cycle command % s = command % s // ' ' // trim ( tokens ( i )) end do end subroutine filter_build_arguments !> From the linker flags, remove optimization and other unnecessary flags subroutine filter_link_arguments ( compiler , command ) type ( compiler_t ), intent ( in ) :: compiler type ( string_t ), intent ( inout ) :: command character ( len = :), allocatable :: tokens (:) integer :: i , n logical , allocatable :: keep (:) logical :: keep_next if ( len_trim ( command ) <= 0 ) return ! Split command into arguments tokens = shlex_split ( command % s ) n = size ( tokens ) allocate ( keep ( n ), source = . false .) keep_next = . false . do i = 1 , n if ( is_link_argument ( compiler , tokens ( i ))) then keep ( i ) = . true . if ( tokens ( i ) == '-L' . or . tokens ( i ) == '-Xlinker' ) keep_next = . true . elseif ( keep_next ) then keep ( i ) = . true . keep_next = . false . end if end do ! Backfill command = string_t ( \"\" ) do i = 1 , n if (. not . keep ( i )) cycle command % s = command % s // ' ' // trim ( tokens ( i )) end do end subroutine filter_link_arguments end module fpm_meta_mpi","tags":"","url":"sourcefile/fpm_meta_mpi.f90.html"},{"title":"package.f90 – Fortran-lang/fpm","text":"Source Code !> Define the package data containing the meta data from the configuration file. !> !> The package data defines a Fortran type corresponding to the respective !> TOML document, after creating it from a package file no more interaction !> with the TOML document is required. !> !> Every configuration type provides it custom constructor (prefixed with `new_`) !> and knows how to deserialize itself from a TOML document. !> To ensure we find no untracked content in the package file all keywords are !> checked and possible entries have to be explicitly allowed in the `check` !> function. !> If entries are mutally exclusive or interdependent inside the current table !> the `check` function is required to enforce this schema on the data structure. !> !> The package file root allows the following keywords !> !>```toml !>name = \"string\" !>version = \"string\" !>license = \"string\" !>author = \"string\" !>maintainer = \"string\" !>copyright = \"string\" !>[library] !>[dependencies] !>[dev-dependencies] !>[profiles] !>[build] !>[install] !>[fortran] !>[[ executable ]] !>[[ example ]] !>[[ test ]] !>[extra] !>``` module fpm_manifest_package use fpm_manifest_build , only : build_config_t , new_build_config use fpm_manifest_dependency , only : dependency_config_t , new_dependencies use fpm_manifest_profile , only : profile_config_t , new_profiles , get_default_profiles use fpm_manifest_example , only : example_config_t , new_example use fpm_manifest_executable , only : executable_config_t , new_executable use fpm_manifest_fortran , only : fortran_config_t , new_fortran_config use fpm_manifest_library , only : library_config_t , new_library use fpm_manifest_install , only : install_config_t , new_install_config use fpm_manifest_test , only : test_config_t , new_test use fpm_manifest_preprocess , only : preprocess_config_t , new_preprocessors use fpm_manifest_metapackages , only : metapackage_config_t , new_meta_config use fpm_filesystem , only : exists , getline , join_path use fpm_error , only : error_t , fatal_error , syntax_error , bad_name_error use tomlf , only : toml_table , toml_array , toml_key , toml_stat use fpm_toml , only : get_value , len , serializable_t , set_value , set_string , set_list , add_table use fpm_versioning , only : version_t , new_version implicit none private public :: package_config_t , new_package interface unique_programs module procedure :: unique_programs1 module procedure :: unique_programs2 end interface unique_programs !> Package meta data type , extends ( serializable_t ) :: package_config_t !> Name of the package character ( len = :), allocatable :: name !> Package version type ( version_t ) :: version !> Build configuration data type ( build_config_t ) :: build !> Metapackage data type ( metapackage_config_t ) :: meta !> Installation configuration data type ( install_config_t ) :: install !> Fortran meta data type ( fortran_config_t ) :: fortran !> License meta data character ( len = :), allocatable :: license !> Author meta data character ( len = :), allocatable :: author !> Maintainer meta data character ( len = :), allocatable :: maintainer !> Copyright meta data character ( len = :), allocatable :: copyright !> Library meta data type ( library_config_t ), allocatable :: library !> Executable meta data type ( executable_config_t ), allocatable :: executable (:) !> Dependency meta data type ( dependency_config_t ), allocatable :: dependency (:) !> Development dependency meta data type ( dependency_config_t ), allocatable :: dev_dependency (:) !> Profiles meta data type ( profile_config_t ), allocatable :: profiles (:) !> Example meta data type ( example_config_t ), allocatable :: example (:) !> Test meta data type ( test_config_t ), allocatable :: test (:) !> Preprocess meta data type ( preprocess_config_t ), allocatable :: preprocess (:) contains !> Print information on this instance procedure :: info !> Serialization interface procedure :: serializable_is_same => manifest_is_same procedure :: dump_to_toml procedure :: load_from_toml end type package_config_t character ( len =* ), parameter , private :: class_name = 'package_config_t' contains !> Construct a new package configuration from a TOML data structure subroutine new_package ( self , table , root , error ) !> Instance of the package configuration type ( package_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Root directory of the manifest character ( len =* ), intent ( in ), optional :: root !> Error handling type ( error_t ), allocatable , intent ( out ) :: error ! Backspace (8), tabulator (9), newline (10), formfeed (12) and carriage ! return (13) are invalid in package names character ( len =* ), parameter :: invalid_chars = & achar ( 8 ) // achar ( 9 ) // achar ( 10 ) // achar ( 12 ) // achar ( 13 ) type ( toml_table ), pointer :: child , node type ( toml_array ), pointer :: children character ( len = :), allocatable :: version , version_file integer :: ii , nn , stat , io call check ( table , error ) if ( allocated ( error )) return call get_value ( table , \"name\" , self % name ) if (. not . allocated ( self % name )) then call syntax_error ( error , \"Could not retrieve package name\" ) return end if if ( bad_name_error ( error , 'package' , self % name )) then return endif call get_value ( table , \"license\" , self % license ) call get_value ( table , \"author\" , self % author ) call get_value ( table , \"maintainer\" , self % maintainer ) call get_value ( table , \"copyright\" , self % copyright ) if ( len ( self % name ) <= 0 ) then call syntax_error ( error , \"Package name must be a non-empty string\" ) return end if ii = scan ( self % name , invalid_chars ) if ( ii > 0 ) then call syntax_error ( error , \"Package name contains invalid characters\" ) return end if call get_value ( table , \"build\" , child , requested = . true ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Type mismatch for build entry, must be a table\" ) return end if call new_build_config ( self % build , child , self % name , error ) if ( allocated ( error )) return call get_value ( table , \"install\" , child , requested = . true ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Type mismatch for install entry, must be a table\" ) return end if call new_install_config ( self % install , child , error ) if ( allocated ( error )) return call get_value ( table , \"fortran\" , child , requested = . true ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Type mismatch for fortran entry, must be a table\" ) return end if call new_fortran_config ( self % fortran , child , error ) if ( allocated ( error )) return call get_value ( table , \"version\" , version , \"0\" ) call new_version ( self % version , version , error ) if ( allocated ( error ) . and . present ( root )) then version_file = join_path ( root , version ) if ( exists ( version_file )) then deallocate ( error ) open ( file = version_file , newunit = io , iostat = stat ) if ( stat == 0 ) then call getline ( io , version , iostat = stat ) end if if ( stat == 0 ) then close ( io , iostat = stat ) end if if ( stat == 0 ) then call new_version ( self % version , version , error ) else call fatal_error ( error , \"Reading version number from file '\" & & // version_file // \"' failed\" ) end if end if end if if ( allocated ( error )) return call get_value ( table , \"dependencies\" , child , requested = . false .) if ( associated ( child )) then call new_dependencies ( self % dependency , child , root , self % meta , error ) if ( allocated ( error )) return end if call get_value ( table , \"dev-dependencies\" , child , requested = . false .) if ( associated ( child )) then call new_dependencies ( self % dev_dependency , child , root , error = error ) if ( allocated ( error )) return end if call get_value ( table , \"library\" , child , requested = . false .) if ( associated ( child )) then allocate ( self % library ) call new_library ( self % library , child , error ) if ( allocated ( error )) return end if call get_value ( table , \"profiles\" , child , requested = . false .) if ( associated ( child )) then call new_profiles ( self % profiles , child , error ) if ( allocated ( error )) return else self % profiles = get_default_profiles ( error ) if ( allocated ( error )) return end if call get_value ( table , \"executable\" , children , requested = . false .) if ( associated ( children )) then nn = len ( children ) allocate ( self % executable ( nn )) do ii = 1 , nn call get_value ( children , ii , node , stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Could not retrieve executable from array entry\" ) exit end if call new_executable ( self % executable ( ii ), node , error ) if ( allocated ( error )) exit end do if ( allocated ( error )) return call unique_programs ( self % executable , error ) if ( allocated ( error )) return end if call get_value ( table , \"example\" , children , requested = . false .) if ( associated ( children )) then nn = len ( children ) allocate ( self % example ( nn )) do ii = 1 , nn call get_value ( children , ii , node , stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Could not retrieve example from array entry\" ) exit end if call new_example ( self % example ( ii ), node , error ) if ( allocated ( error )) exit end do if ( allocated ( error )) return call unique_programs ( self % example , error ) if ( allocated ( error )) return if ( allocated ( self % executable )) then call unique_programs ( self % executable , self % example , error ) if ( allocated ( error )) return end if end if call get_value ( table , \"test\" , children , requested = . false .) if ( associated ( children )) then nn = len ( children ) allocate ( self % test ( nn )) do ii = 1 , nn call get_value ( children , ii , node , stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Could not retrieve test from array entry\" ) exit end if call new_test ( self % test ( ii ), node , error ) if ( allocated ( error )) exit end do if ( allocated ( error )) return call unique_programs ( self % test , error ) if ( allocated ( error )) return end if call get_value ( table , \"preprocess\" , child , requested = . false .) if ( associated ( child )) then call new_preprocessors ( self % preprocess , child , error ) if ( allocated ( error )) return end if end subroutine new_package !> Check local schema for allowed entries subroutine check ( table , error ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_key ), allocatable :: list (:) logical :: name_present integer :: ikey name_present = . false . call table % get_keys ( list ) if ( size ( list ) < 1 ) then call syntax_error ( error , \"Package file is empty\" ) return end if do ikey = 1 , size ( list ) select case ( list ( ikey )% key ) case default call syntax_error ( error , \"Key \" // list ( ikey )% key // \" is not allowed in package file\" ) exit case ( \"name\" ) name_present = . true . case ( \"version\" , \"license\" , \"author\" , \"maintainer\" , \"copyright\" , & & \"description\" , \"keywords\" , \"categories\" , \"homepage\" , \"build\" , & & \"dependencies\" , \"dev-dependencies\" , \"profiles\" , \"test\" , \"executable\" , & & \"example\" , \"library\" , \"install\" , \"extra\" , \"preprocess\" , \"fortran\" ) continue end select end do if ( allocated ( error )) return if (. not . name_present ) then call syntax_error ( error , \"Package name is not provided, please add a name entry\" ) end if end subroutine check !> Write information on instance subroutine info ( self , unit , verbosity ) !> Instance of the package configuration class ( package_config_t ), intent ( in ) :: self !> Unit for IO integer , intent ( in ) :: unit !> Verbosity of the printout integer , intent ( in ), optional :: verbosity integer :: pr , ii character ( len =* ), parameter :: fmt = '(\"#\", 1x, a, t30, a)' , & & fmti = '(\"#\", 1x, a, t30, i0)' if ( present ( verbosity )) then pr = verbosity else pr = 1 end if if ( pr < 1 ) return write ( unit , fmt ) \"Package\" if ( allocated ( self % name )) then write ( unit , fmt ) \"- name\" , self % name end if call self % build % info ( unit , pr - 1 ) call self % install % info ( unit , pr - 1 ) if ( allocated ( self % library )) then write ( unit , fmt ) \"- target\" , \"archive\" call self % library % info ( unit , pr - 1 ) end if if ( allocated ( self % executable )) then if ( size ( self % executable ) > 1 . or . pr > 2 ) then write ( unit , fmti ) \"- executables\" , size ( self % executable ) end if do ii = 1 , size ( self % executable ) call self % executable ( ii )% info ( unit , pr - 1 ) end do end if if ( allocated ( self % dependency )) then if ( size ( self % dependency ) > 1 . or . pr > 2 ) then write ( unit , fmti ) \"- dependencies\" , size ( self % dependency ) end if do ii = 1 , size ( self % dependency ) call self % dependency ( ii )% info ( unit , pr - 1 ) end do end if if ( allocated ( self % example )) then if ( size ( self % example ) > 1 . or . pr > 2 ) then write ( unit , fmti ) \"- examples\" , size ( self % example ) end if do ii = 1 , size ( self % example ) call self % example ( ii )% info ( unit , pr - 1 ) end do end if if ( allocated ( self % test )) then if ( size ( self % test ) > 1 . or . pr > 2 ) then write ( unit , fmti ) \"- tests\" , size ( self % test ) end if do ii = 1 , size ( self % test ) call self % test ( ii )% info ( unit , pr - 1 ) end do end if if ( allocated ( self % dev_dependency )) then if ( size ( self % dev_dependency ) > 1 . or . pr > 2 ) then write ( unit , fmti ) \"- development deps.\" , size ( self % dev_dependency ) end if do ii = 1 , size ( self % dev_dependency ) call self % dev_dependency ( ii )% info ( unit , pr - 1 ) end do end if if ( allocated ( self % profiles )) then if ( size ( self % profiles ) > 1 . or . pr > 2 ) then write ( unit , fmti ) \"- profiles\" , size ( self % profiles ) end if do ii = 1 , size ( self % profiles ) call self % profiles ( ii )% info ( unit , pr - 1 ) end do end if end subroutine info !> Check whether or not the names in a set of executables are unique subroutine unique_programs1 ( executable , error ) !> Array of executables class ( executable_config_t ), intent ( in ) :: executable (:) !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: i , j do i = 1 , size ( executable ) do j = 1 , i - 1 if ( executable ( i )% name == executable ( j )% name ) then call fatal_error ( error , \"The program named '\" // & executable ( j )% name // \"' is duplicated. \" // & \"Unique program names are required.\" ) exit end if end do end do if ( allocated ( error )) return end subroutine unique_programs1 !> Check whether or not the names in a set of executables are unique subroutine unique_programs2 ( executable_i , executable_j , error ) !> Array of executables class ( executable_config_t ), intent ( in ) :: executable_i (:) !> Array of executables class ( executable_config_t ), intent ( in ) :: executable_j (:) !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: i , j do i = 1 , size ( executable_i ) do j = 1 , size ( executable_j ) if ( executable_i ( i )% name == executable_j ( j )% name ) then call fatal_error ( error , \"The program named '\" // & executable_j ( j )% name // \"' is duplicated. \" // & \"Unique program names are required.\" ) exit end if end do end do if ( allocated ( error )) return end subroutine unique_programs2 logical function manifest_is_same ( this , that ) class ( package_config_t ), intent ( in ) :: this class ( serializable_t ), intent ( in ) :: that integer :: ii manifest_is_same = . false . select type ( other => that ) type is ( package_config_t ) if ( allocated ( this % name ). neqv . allocated ( other % name )) return if ( allocated ( this % name ) . and . allocated ( other % name )) then if (. not . this % name == other % name ) return end if if (. not . this % version == other % version ) return if (. not . this % build == other % build ) return if (. not . this % install == other % install ) return if (. not . this % fortran == other % fortran ) return if ( allocated ( this % license ). neqv . allocated ( other % license )) return if ( allocated ( this % license )) then if (. not . this % license == other % license ) return end if if ( allocated ( this % author ). neqv . allocated ( other % author )) return if ( allocated ( this % author )) then if (. not . this % author == other % author ) return end if if ( allocated ( this % maintainer ). neqv . allocated ( other % maintainer )) return if ( allocated ( this % maintainer )) then if (. not . this % maintainer == other % maintainer ) return end if if ( allocated ( this % copyright ). neqv . allocated ( other % copyright )) return if ( allocated ( this % copyright )) then if (. not . this % copyright == other % copyright ) return end if if ( allocated ( this % library ). neqv . allocated ( other % library )) return if ( allocated ( this % library )) then if (. not . this % library == other % library ) return endif if ( allocated ( this % executable ). neqv . allocated ( other % executable )) return if ( allocated ( this % executable )) then if (. not . size ( this % executable ) == size ( other % executable )) return do ii = 1 , size ( this % executable ) if (. not . this % executable ( ii ) == other % executable ( ii )) return end do end if if ( allocated ( this % dependency ). neqv . allocated ( other % dependency )) return if ( allocated ( this % dependency )) then if (. not . size ( this % dependency ) == size ( other % dependency )) return do ii = 1 , size ( this % dependency ) if (. not . this % dependency ( ii ) == other % dependency ( ii )) return end do end if if ( allocated ( this % dev_dependency ). neqv . allocated ( other % dev_dependency )) return if ( allocated ( this % dev_dependency )) then if (. not . size ( this % dev_dependency ) == size ( other % dev_dependency )) return do ii = 1 , size ( this % dev_dependency ) if (. not . this % dev_dependency ( ii ) == other % dev_dependency ( ii )) return end do end if if ( allocated ( this % profiles ). neqv . allocated ( other % profiles )) return if ( allocated ( this % profiles )) then if (. not . size ( this % profiles ) == size ( other % profiles )) return do ii = 1 , size ( this % profiles ) if (. not . this % profiles ( ii ) == other % profiles ( ii )) return end do end if if ( allocated ( this % example ). neqv . allocated ( other % example )) return if ( allocated ( this % example )) then if (. not . size ( this % example ) == size ( other % example )) return do ii = 1 , size ( this % example ) if (. not . this % example ( ii ) == other % example ( ii )) return end do end if if ( allocated ( this % preprocess ). neqv . allocated ( other % preprocess )) return if ( allocated ( this % preprocess )) then if (. not . size ( this % preprocess ) == size ( other % preprocess )) return do ii = 1 , size ( this % preprocess ) if (. not . this % preprocess ( ii ) == other % preprocess ( ii )) return end do end if if ( allocated ( this % test ). neqv . allocated ( other % test )) return if ( allocated ( this % test )) then if (. not . size ( this % test ) == size ( other % test )) return do ii = 1 , size ( this % test ) if (. not . this % test ( ii ) == other % test ( ii )) return end do end if class default ! Not the same type return end select !> All checks passed! manifest_is_same = . true . end function manifest_is_same !> Dump manifest to toml table subroutine dump_to_toml ( self , table , error ) !> Instance of the serializable object class ( package_config_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: ii type ( toml_table ), pointer :: ptr , ptr_pkg character ( 30 ) :: unnamed character ( 128 ) :: profile_name call set_string ( table , \"name\" , self % name , error , class_name ) if ( allocated ( error )) return call set_string ( table , \"version\" , self % version % s (), error , class_name ) if ( allocated ( error )) return call set_string ( table , \"license\" , self % license , error , class_name ) if ( allocated ( error )) return call set_string ( table , \"author\" , self % author , error , class_name ) if ( allocated ( error )) return call set_string ( table , \"maintainer\" , self % maintainer , error , class_name ) if ( allocated ( error )) return call set_string ( table , \"copyright\" , self % copyright , error , class_name ) if ( allocated ( error )) return call add_table ( table , \"build\" , ptr , error , class_name ) if ( allocated ( error )) return call self % build % dump_to_toml ( ptr , error ) if ( allocated ( error )) return call add_table ( table , \"fortran\" , ptr , error , class_name ) if ( allocated ( error )) return call self % fortran % dump_to_toml ( ptr , error ) if ( allocated ( error )) return call add_table ( table , \"install\" , ptr , error , class_name ) if ( allocated ( error )) return call self % install % dump_to_toml ( ptr , error ) if ( allocated ( error )) return if ( allocated ( self % library )) then call add_table ( table , \"library\" , ptr , error , class_name ) if ( allocated ( error )) return call self % library % dump_to_toml ( ptr , error ) if ( allocated ( error )) return end if if ( allocated ( self % executable )) then call add_table ( table , \"executable\" , ptr_pkg ) if (. not . associated ( ptr_pkg )) then call fatal_error ( error , class_name // \" cannot create 'executable' table \" ) return end if do ii = 1 , size ( self % executable ) associate ( pkg => self % executable ( ii )) !> Because dependencies are named, fallback if this has no name !> So, serialization will work regardless of size(self%dep) == self%ndep if ( len_trim ( pkg % name ) == 0 ) then write ( unnamed , 1 ) 'EXECUTABLE' , ii call add_table ( ptr_pkg , trim ( unnamed ), ptr , error , class_name // '(executable)' ) else call add_table ( ptr_pkg , pkg % name , ptr , error , class_name // '(executable)' ) end if if ( allocated ( error )) return call pkg % dump_to_toml ( ptr , error ) if ( allocated ( error )) return end associate end do end if if ( allocated ( self % dependency )) then call add_table ( table , \"dependencies\" , ptr_pkg ) if (. not . associated ( ptr_pkg )) then call fatal_error ( error , class_name // \" cannot create 'dependencies' table \" ) return end if do ii = 1 , size ( self % dependency ) associate ( pkg => self % dependency ( ii )) !> Because dependencies are named, fallback if this has no name !> So, serialization will work regardless of size(self%dep) == self%ndep if ( len_trim ( pkg % name ) == 0 ) then write ( unnamed , 1 ) 'DEPENDENCY' , ii call add_table ( ptr_pkg , trim ( unnamed ), ptr , error , class_name // '(dependencies)' ) else call add_table ( ptr_pkg , pkg % name , ptr , error , class_name // '(dependencies)' ) end if if ( allocated ( error )) return call pkg % dump_to_toml ( ptr , error ) if ( allocated ( error )) return end associate end do end if if ( allocated ( self % dev_dependency )) then call add_table ( table , \"dev-dependencies\" , ptr_pkg ) if (. not . associated ( ptr_pkg )) then call fatal_error ( error , class_name // \" cannot create 'dev-dependencies' table \" ) return end if do ii = 1 , size ( self % dev_dependency ) associate ( pkg => self % dev_dependency ( ii )) !> Because dependencies are named, fallback if this has no name !> So, serialization will work regardless of size(self%dep) == self%ndep if ( len_trim ( pkg % name ) == 0 ) then write ( unnamed , 1 ) 'DEV-DEPENDENCY' , ii call add_table ( ptr_pkg , trim ( unnamed ), ptr , error , class_name // '(dev-dependencies)' ) else call add_table ( ptr_pkg , pkg % name , ptr , error , class_name // '(dev-dependencies)' ) end if if ( allocated ( error )) return call pkg % dump_to_toml ( ptr , error ) if ( allocated ( error )) return end associate end do end if if ( allocated ( self % profiles )) then call add_table ( table , \"profiles\" , ptr_pkg ) if (. not . associated ( ptr_pkg )) then call fatal_error ( error , class_name // \" cannot create 'profiles' table \" ) return end if do ii = 1 , size ( self % profiles ) associate ( pkg => self % profiles ( ii )) !> Duplicate profile names are possible, as multiple profiles are possible with the !> same name, same compiler, etc. So, use a unique name here write ( profile_name , 2 ) ii call add_table ( ptr_pkg , trim ( profile_name ), ptr , error , class_name // '(profiles)' ) if ( allocated ( error )) return call pkg % dump_to_toml ( ptr , error ) if ( allocated ( error )) return end associate end do end if if ( allocated ( self % example )) then call add_table ( table , \"example\" , ptr_pkg ) if (. not . associated ( ptr_pkg )) then call fatal_error ( error , class_name // \" cannot create 'example' table \" ) return end if do ii = 1 , size ( self % example ) associate ( pkg => self % example ( ii )) !> Because dependencies are named, fallback if this has no name !> So, serialization will work regardless of size(self%dep) == self%ndep if ( len_trim ( pkg % name ) == 0 ) then write ( unnamed , 1 ) 'EXAMPLE' , ii call add_table ( ptr_pkg , trim ( unnamed ), ptr , error , class_name // '(example)' ) else call add_table ( ptr_pkg , pkg % name , ptr , error , class_name // '(example)' ) end if if ( allocated ( error )) return call pkg % dump_to_toml ( ptr , error ) if ( allocated ( error )) return end associate end do end if if ( allocated ( self % test )) then call add_table ( table , \"test\" , ptr_pkg ) if (. not . associated ( ptr_pkg )) then call fatal_error ( error , class_name // \" cannot create 'test' table \" ) return end if do ii = 1 , size ( self % test ) associate ( pkg => self % test ( ii )) !> Because dependencies are named, fallback if this has no name !> So, serialization will work regardless of size(self%dep) == self%ndep if ( len_trim ( pkg % name ) == 0 ) then write ( unnamed , 1 ) 'TEST' , ii call add_table ( ptr_pkg , trim ( unnamed ), ptr , error , class_name // '(test)' ) else call add_table ( ptr_pkg , pkg % name , ptr , error , class_name // '(test)' ) end if if ( allocated ( error )) return call pkg % dump_to_toml ( ptr , error ) if ( allocated ( error )) return end associate end do end if if ( allocated ( self % preprocess )) then call add_table ( table , \"preprocess\" , ptr_pkg ) if (. not . associated ( ptr_pkg )) then call fatal_error ( error , class_name // \" cannot create 'preprocess' table \" ) return end if do ii = 1 , size ( self % preprocess ) associate ( pkg => self % preprocess ( ii )) !> Because dependencies are named, fallback if this has no name !> So, serialization will work regardless of size(self%dep) == self%ndep if ( len_trim ( pkg % name ) == 0 ) then write ( unnamed , 1 ) 'PREPROCESS' , ii call add_table ( ptr_pkg , trim ( unnamed ), ptr , error , class_name // '(preprocess)' ) else call add_table ( ptr_pkg , pkg % name , ptr , error , class_name // '(preprocess)' ) end if if ( allocated ( error )) return call pkg % dump_to_toml ( ptr , error ) if ( allocated ( error )) return end associate end do end if 1 format ( 'UNNAMED_' , a , '_' , i0 ) 2 format ( 'PROFILE_' , i0 ) end subroutine dump_to_toml !> Read manifest from toml table (no checks made at this stage) subroutine load_from_toml ( self , table , error ) !> Instance of the serializable object class ( package_config_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_key ), allocatable :: keys (:), pkg_keys (:) integer :: ii , jj character ( len = :), allocatable :: flag type ( toml_table ), pointer :: ptr , ptr_pkg call table % get_keys ( keys ) call get_value ( table , \"name\" , self % name ) call get_value ( table , \"license\" , self % license ) call get_value ( table , \"author\" , self % author ) call get_value ( table , \"maintainer\" , self % maintainer ) call get_value ( table , \"copyright\" , self % copyright ) call get_value ( table , \"version\" , flag ) call new_version ( self % version , flag , error ) if ( allocated ( error )) then error % message = class_name // ': version error from TOML table - ' // error % message return endif if ( allocated ( self % library )) deallocate ( self % library ) if ( allocated ( self % executable )) deallocate ( self % executable ) if ( allocated ( self % dependency )) deallocate ( self % dependency ) if ( allocated ( self % dev_dependency )) deallocate ( self % dev_dependency ) if ( allocated ( self % profiles )) deallocate ( self % profiles ) if ( allocated ( self % example )) deallocate ( self % example ) if ( allocated ( self % test )) deallocate ( self % test ) if ( allocated ( self % preprocess )) deallocate ( self % preprocess ) sub_deps : do ii = 1 , size ( keys ) select case ( keys ( ii )% key ) case ( \"build\" ) call get_value ( table , keys ( ii ), ptr ) if (. not . associated ( ptr )) then call fatal_error ( error , class_name // ': error retrieving ' // keys ( ii )% key // ' table' ) return end if call self % build % load_from_toml ( ptr , error ) if ( allocated ( error )) return case ( \"install\" ) call get_value ( table , keys ( ii ), ptr ) if (. not . associated ( ptr )) then call fatal_error ( error , class_name // ': error retrieving ' // keys ( ii )% key // ' table' ) return end if call self % install % load_from_toml ( ptr , error ) case ( \"fortran\" ) call get_value ( table , keys ( ii ), ptr ) if (. not . associated ( ptr )) then call fatal_error ( error , class_name // ': error retrieving ' // keys ( ii )% key // ' table' ) return end if call self % fortran % load_from_toml ( ptr , error ) case ( \"library\" ) allocate ( self % library ) call get_value ( table , keys ( ii ), ptr ) if (. not . associated ( ptr )) then call fatal_error ( error , class_name // ': error retrieving ' // keys ( ii )% key // ' table' ) return end if call self % library % load_from_toml ( ptr , error ) case ( \"executable\" ) call get_value ( table , keys ( ii ), ptr ) if (. not . associated ( ptr )) then call fatal_error ( error , class_name // ': error retrieving executable table' ) return end if !> Read all packages call ptr % get_keys ( pkg_keys ) allocate ( self % executable ( size ( pkg_keys ))) do jj = 1 , size ( pkg_keys ) call get_value ( ptr , pkg_keys ( jj ), ptr_pkg ) call self % executable ( jj )% load_from_toml ( ptr_pkg , error ) if ( allocated ( error )) return end do case ( \"dependencies\" ) call get_value ( table , keys ( ii ), ptr ) if (. not . associated ( ptr )) then call fatal_error ( error , class_name // ': error retrieving dependency table' ) return end if !> Read all packages call ptr % get_keys ( pkg_keys ) allocate ( self % dependency ( size ( pkg_keys ))) do jj = 1 , size ( pkg_keys ) call get_value ( ptr , pkg_keys ( jj ), ptr_pkg ) call self % dependency ( jj )% load_from_toml ( ptr_pkg , error ) if ( allocated ( error )) return end do case ( \"dev-dependencies\" ) call get_value ( table , keys ( ii ), ptr ) if (. not . associated ( ptr )) then call fatal_error ( error , class_name // ': error retrieving dev-dependencies table' ) return end if !> Read all packages call ptr % get_keys ( pkg_keys ) allocate ( self % dev_dependency ( size ( pkg_keys ))) do jj = 1 , size ( pkg_keys ) call get_value ( ptr , pkg_keys ( jj ), ptr_pkg ) call self % dev_dependency ( jj )% load_from_toml ( ptr_pkg , error ) if ( allocated ( error )) return end do case ( \"profiles\" ) call get_value ( table , keys ( ii ), ptr ) if (. not . associated ( ptr )) then call fatal_error ( error , class_name // ': error retrieving profiles table' ) return end if !> Read all packages call ptr % get_keys ( pkg_keys ) allocate ( self % profiles ( size ( pkg_keys ))) do jj = 1 , size ( pkg_keys ) call get_value ( ptr , pkg_keys ( jj ), ptr_pkg ) call self % profiles ( jj )% load_from_toml ( ptr_pkg , error ) if ( allocated ( error )) return end do case ( \"example\" ) call get_value ( table , keys ( ii ), ptr ) if (. not . associated ( ptr )) then call fatal_error ( error , class_name // ': error retrieving example table' ) return end if !> Read all packages call ptr % get_keys ( pkg_keys ) allocate ( self % example ( size ( pkg_keys ))) do jj = 1 , size ( pkg_keys ) call get_value ( ptr , pkg_keys ( jj ), ptr_pkg ) call self % example ( jj )% load_from_toml ( ptr_pkg , error ) if ( allocated ( error )) return end do case ( \"test\" ) call get_value ( table , keys ( ii ), ptr ) if (. not . associated ( ptr )) then call fatal_error ( error , class_name // ': error retrieving test table' ) return end if !> Read all packages call ptr % get_keys ( pkg_keys ) allocate ( self % test ( size ( pkg_keys ))) do jj = 1 , size ( pkg_keys ) call get_value ( ptr , pkg_keys ( jj ), ptr_pkg ) call self % test ( jj )% load_from_toml ( ptr_pkg , error ) if ( allocated ( error )) return end do case ( \"preprocess\" ) call get_value ( table , keys ( ii ), ptr ) if (. not . associated ( ptr )) then call fatal_error ( error , class_name // ': error retrieving preprocess table' ) return end if !> Read all packages call ptr % get_keys ( pkg_keys ) allocate ( self % preprocess ( size ( pkg_keys ))) do jj = 1 , size ( pkg_keys ) call get_value ( ptr , pkg_keys ( jj ), ptr_pkg ) call self % preprocess ( jj )% load_from_toml ( ptr_pkg , error ) if ( allocated ( error )) return end do case default cycle sub_deps end select end do sub_deps end subroutine load_from_toml end module fpm_manifest_package","tags":"","url":"sourcefile/package.f90.html"},{"title":"error.f90 – Fortran-lang/fpm","text":"Source Code !> Implementation of basic error handling. module fpm_error use , intrinsic :: iso_fortran_env , only : stdin => input_unit , stdout => output_unit , stderr => error_unit use fpm_strings , only : is_fortran_name , to_fortran_name implicit none private public :: error_t public :: fatal_error , syntax_error , file_not_found_error public :: file_parse_error public :: bad_name_error public :: fpm_stop !> Data type defining an error type :: error_t !> Error message character ( len = :), allocatable :: message end type error_t contains !> Generic fatal runtime error subroutine fatal_error ( error , message ) !> Instance of the error data type ( error_t ), allocatable , intent ( out ) :: error !> Error message character ( len =* ), intent ( in ) :: message allocate ( error ) error % message = message end subroutine fatal_error subroutine syntax_error ( error , message ) !> Instance of the error data type ( error_t ), allocatable , intent ( out ) :: error !> Error message character ( len =* ), intent ( in ) :: message allocate ( error ) error % message = message end subroutine syntax_error function bad_name_error ( error , label , name ) !> Instance of the error data type ( error_t ), allocatable , intent ( out ) :: error !> Error message label to add to message character ( len =* ), intent ( in ) :: label !> name value to check character ( len =* ), intent ( in ) :: name logical :: bad_name_error if (. not . is_fortran_name ( to_fortran_name ( name ))) then bad_name_error = . true . allocate ( error ) error % message = 'manifest file syntax error: ' // label // ' name must be composed only of & &alphanumerics, \"-\" and \"_\" and start with a letter ::' // name else bad_name_error = . false . endif end function bad_name_error !> Error created when a file is missing or not found subroutine file_not_found_error ( error , file_name ) !> Instance of the error data type ( error_t ), allocatable , intent ( out ) :: error !> Name of the missing file character ( len =* ), intent ( in ) :: file_name allocate ( error ) error % message = \"'\" // file_name // \"' could not be found, check if the file exists\" end subroutine file_not_found_error !> Error created when file parsing fails subroutine file_parse_error ( error , file_name , message , line_num , & line_string , line_col ) !> Instance of the error data type ( error_t ), allocatable , intent ( out ) :: error !> Name of file character ( len =* ), intent ( in ) :: file_name !> Parse error message character ( len =* ), intent ( in ) :: message !> Line number of parse error integer , intent ( in ), optional :: line_num !> Line context string character ( len =* ), intent ( in ), optional :: line_string !> Line context column integer , intent ( in ), optional :: line_col character ( 50 ) :: temp_string allocate ( error ) error % message = 'Parse error: ' // message // new_line ( 'a' ) error % message = error % message // file_name if ( present ( line_num )) then write ( temp_string , '(I0)' ) line_num error % message = error % message // ':' // trim ( temp_string ) end if if ( present ( line_col )) then if ( line_col > 0 ) then write ( temp_string , '(I0)' ) line_col error % message = error % message // ':' // trim ( temp_string ) end if end if if ( present ( line_string )) then error % message = error % message // new_line ( 'a' ) error % message = error % message // ' | ' // line_string if ( present ( line_col )) then if ( line_col > 0 ) then error % message = error % message // new_line ( 'a' ) error % message = error % message // ' | ' // repeat ( ' ' , line_col - 1 ) // '^' end if end if end if end subroutine file_parse_error subroutine fpm_stop ( value , message ) ! TODO: if verbose mode, call ERROR STOP instead of STOP ! TODO: if M_escape is used, add color ! to work with older compilers might need a case statement for values !> value to use on STOP integer , intent ( in ) :: value !> Error message character ( len =* ), intent ( in ) :: message integer :: iostat if ( message /= '' ) then flush ( unit = stderr , iostat = iostat ) flush ( unit = stdout , iostat = iostat ) if ( value > 0 ) then write ( stderr , '(\" \",a)' ) trim ( message ) else write ( stderr , '(\" \",a)' ) trim ( message ) endif flush ( unit = stderr , iostat = iostat ) endif stop value end subroutine fpm_stop end module fpm_error","tags":"","url":"sourcefile/error.f90.html"},{"title":"fpm_meta_openmp.f90 – Fortran-lang/fpm","text":"Source Code module fpm_meta_openmp use fpm_compiler , only : compiler_t , id_gcc , id_f95 , id_intel_classic_windows , & id_intel_llvm_windows , id_intel_classic_nix , id_intel_llvm_nix , & id_intel_classic_mac , id_pgi , id_nvhpc , id_ibmxl , id_nag , id_lfortran , & id_flang , id_flang_new , flag_gnu_openmp , flag_intel_openmp_win , & flag_intel_openmp , flag_pgi_openmp , flag_nag_openmp , & flag_lfortran_openmp , flag_flang_new_openmp use fpm_strings , only : string_t use fpm_meta_base , only : metapackage_t , destroy use fpm_error , only : error_t , fatal_error use fpm_manifest_metapackages , only : metapackage_request_t implicit none private public :: init_openmp contains !> Initialize OpenMP metapackage for the current system subroutine init_openmp ( this , compiler , all_meta , error ) class ( metapackage_t ), intent ( inout ) :: this type ( compiler_t ), intent ( in ) :: compiler type ( metapackage_request_t ), intent ( in ) :: all_meta (:) type ( error_t ), allocatable , intent ( out ) :: error !> Cleanup call destroy ( this ) !> Set name this % name = \"openmp\" !> OpenMP has compiler flags this % has_build_flags = . true . this % has_link_flags = . true . !> OpenMP flags should be added to which_compiler : select case ( compiler % id ) case ( id_gcc , id_f95 ) this % flags = string_t ( flag_gnu_openmp ) this % link_flags = string_t ( flag_gnu_openmp ) case ( id_intel_classic_windows , id_intel_llvm_windows ) this % flags = string_t ( flag_intel_openmp_win ) this % link_flags = string_t ( flag_intel_openmp_win ) case ( id_intel_classic_nix , id_intel_classic_mac ,& id_intel_llvm_nix ) this % flags = string_t ( flag_intel_openmp ) this % link_flags = string_t ( flag_intel_openmp ) case ( id_pgi , id_nvhpc ) this % flags = string_t ( flag_pgi_openmp ) this % link_flags = string_t ( flag_pgi_openmp ) case ( id_ibmxl ) this % flags = string_t ( \" -qsmp=omp\" ) this % link_flags = string_t ( \" -qsmp=omp\" ) case ( id_nag ) this % flags = string_t ( flag_nag_openmp ) this % link_flags = string_t ( flag_nag_openmp ) case ( id_lfortran ) this % flags = string_t ( flag_lfortran_openmp ) this % link_flags = string_t ( flag_lfortran_openmp ) case ( id_flang , id_flang_new ) this % flags = string_t ( flag_flang_new_openmp ) this % link_flags = string_t ( flag_flang_new_openmp ) case default call fatal_error ( error , 'openmp not supported on compiler ' // compiler % name () // ' yet' ) end select which_compiler end subroutine init_openmp end module fpm_meta_openmp","tags":"","url":"sourcefile/fpm_meta_openmp.f90.html"},{"title":"build.f90 – Fortran-lang/fpm","text":"Source Code !> Implementation of the build configuration data. !> !> A build table can currently have the following fields !> !>```toml !>[build] !>auto-executables = bool !>auto-examples = bool !>auto-tests = bool !>link = [\"lib\"] !>``` module fpm_manifest_build use fpm_error , only : error_t , syntax_error , fatal_error use fpm_strings , only : string_t , len_trim , is_valid_module_prefix , operator ( == ) use tomlf , only : toml_table , toml_key , toml_stat use fpm_toml , only : serializable_t , get_value , get_list , set_value , set_string , set_list implicit none private public :: build_config_t , new_build_config !> Configuration data for build type , extends ( serializable_t ) :: build_config_t !> Automatic discovery of executables logical :: auto_executables = . true . !> Automatic discovery of examples logical :: auto_examples = . true . !> Automatic discovery of tests logical :: auto_tests = . true . !> Enforcing of package module names logical :: module_naming = . false . type ( string_t ) :: module_prefix !> Libraries to link against type ( string_t ), allocatable :: link (:) !> External modules to use type ( string_t ), allocatable :: external_modules (:) contains !> Print information on this instance procedure :: info !> Serialization interface procedure :: serializable_is_same => build_conf_is_same procedure :: dump_to_toml procedure :: load_from_toml end type build_config_t character ( * ), parameter , private :: class_name = 'build_config_t' contains !> Construct a new build configuration from a TOML data structure subroutine new_build_config ( self , table , package_name , error ) !> Instance of the build configuration type ( build_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Package name character ( len =* ), intent ( in ) :: package_name !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: stat call check ( table , package_name , error ) if ( allocated ( error )) return call get_value ( table , \"auto-executables\" , self % auto_executables , . true ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error while reading value for 'auto-executables' in fpm.toml, expecting logical\" ) return end if call get_value ( table , \"auto-tests\" , self % auto_tests , . true ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error while reading value for 'auto-tests' in fpm.toml, expecting logical\" ) return end if call get_value ( table , \"auto-examples\" , self % auto_examples , . true ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error while reading value for 'auto-examples' in fpm.toml, expecting logical\" ) return end if !> Module naming: fist, attempt boolean value first call get_value ( table , \"module-naming\" , self % module_naming , . false ., stat = stat ) if ( stat == toml_stat % success ) then ! Boolean value found. Set no custom prefix. This also falls back to key not provided if ( allocated ( self % module_prefix % s )) deallocate ( self % module_prefix % s ) else !> Value found, but not a boolean. Attempt to read a prefix string call get_value ( table , \"module-naming\" , self % module_prefix % s ) if (. not . allocated ( self % module_prefix % s )) then call syntax_error ( error , \"Could not read value for 'module-naming' in fpm.toml, expecting logical or a string\" ) return end if if (. not . is_valid_module_prefix ( self % module_prefix )) then call syntax_error ( error , \"Invalid custom module name prefix for in fpm.toml: <\" // self % module_prefix % s // & \">, expecting a valid alphanumeric string\" ) return end if ! Set module naming to ON self % module_naming = . true . end if call get_list ( table , \"link\" , self % link , error ) if ( allocated ( error )) return call get_list ( table , \"external-modules\" , self % external_modules , error ) if ( allocated ( error )) return end subroutine new_build_config !> Check local schema for allowed entries subroutine check ( table , package_name , error ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Package name character ( len =* ), intent ( in ) :: package_name !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_key ), allocatable :: list (:) integer :: ikey call table % get_keys ( list ) ! table can be empty if ( size ( list ) < 1 ) return do ikey = 1 , size ( list ) select case ( list ( ikey )% key ) case ( \"auto-executables\" , \"auto-examples\" , \"auto-tests\" , \"link\" , \"external-modules\" , \"module-naming\" ) continue case default call syntax_error ( error , 'Manifest file syntax error: key \"' // list ( ikey )% key // '\" found in the [build] ' // & 'section of package/dependency \"' // package_name // '\" fpm.toml is not allowed' ) exit end select end do end subroutine check !> Write information on build configuration instance subroutine info ( self , unit , verbosity ) !> Instance of the build configuration class ( build_config_t ), intent ( in ) :: self !> Unit for IO integer , intent ( in ) :: unit !> Verbosity of the printout integer , intent ( in ), optional :: verbosity integer :: pr , ilink , imod character ( len =* ), parameter :: fmt = '(\"#\", 1x, a, t30, a)' if ( present ( verbosity )) then pr = verbosity else pr = 1 end if if ( pr < 1 ) return write ( unit , fmt ) \"Build configuration\" write ( unit , fmt ) \" - auto-discovery (apps) \" , merge ( \"enabled \" , \"disabled\" , self % auto_executables ) write ( unit , fmt ) \" - auto-discovery (examples) \" , merge ( \"enabled \" , \"disabled\" , self % auto_examples ) write ( unit , fmt ) \" - auto-discovery (tests) \" , merge ( \"enabled \" , \"disabled\" , self % auto_tests ) write ( unit , fmt ) \" - enforce module naming \" , merge ( \"enabled \" , \"disabled\" , self % module_naming ) if ( allocated ( self % link )) then write ( unit , fmt ) \" - link against\" do ilink = 1 , size ( self % link ) write ( unit , fmt ) \" - \" // self % link ( ilink )% s end do end if if ( allocated ( self % external_modules )) then write ( unit , fmt ) \" - external modules\" do imod = 1 , size ( self % external_modules ) write ( unit , fmt ) \" - \" // self % external_modules ( imod )% s end do end if end subroutine info !> Check that two dependency trees are equal logical function build_conf_is_same ( this , that ) class ( build_config_t ), intent ( in ) :: this class ( serializable_t ), intent ( in ) :: that build_conf_is_same = . false . select type ( other => that ) type is ( build_config_t ) if ( this % auto_executables . neqv . other % auto_executables ) return if ( this % auto_examples . neqv . other % auto_examples ) return if ( this % auto_tests . neqv . other % auto_tests ) return if ( this % module_naming . neqv . other % module_naming ) return if (. not . this % module_prefix == other % module_prefix ) return if (. not . this % link == other % link ) return if (. not . this % external_modules == other % external_modules ) return class default ! Not the same type return end select !> All checks passed! build_conf_is_same = . true . end function build_conf_is_same !> Dump build config to toml table subroutine dump_to_toml ( self , table , error ) !> Instance of the serializable object class ( build_config_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error call set_value ( table , \"auto-executables\" , self % auto_executables , error , class_name ) if ( allocated ( error )) return call set_value ( table , \"auto-tests\" , self % auto_tests , error , class_name ) if ( allocated ( error )) return call set_value ( table , \"auto-examples\" , self % auto_examples , error , class_name ) if ( allocated ( error )) return ! Module naming can either contain a boolean value, or the prefix has_prefix : if ( self % module_naming . and . len_trim ( self % module_prefix ) > 0 ) then call set_string ( table , \"module-naming\" , self % module_prefix , error , class_name ) else call set_value ( table , \"module-naming\" , self % module_naming , error , class_name ) end if has_prefix if ( allocated ( error )) return call set_list ( table , \"link\" , self % link , error ) if ( allocated ( error )) return call set_list ( table , \"external-modules\" , self % external_modules , error ) if ( allocated ( error )) return end subroutine dump_to_toml !> Read build config from toml table (no checks made at this stage) subroutine load_from_toml ( self , table , error ) !> Instance of the serializable object class ( build_config_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: stat call get_value ( table , \"auto-executables\" , self % auto_executables , error , class_name ) if ( allocated ( error )) return call get_value ( table , \"auto-tests\" , self % auto_tests , error , class_name ) if ( allocated ( error )) return call get_value ( table , \"auto-examples\" , self % auto_examples , error , class_name ) if ( allocated ( error )) return !> Module naming: fist, attempt boolean value first call get_value ( table , \"module-naming\" , self % module_naming , . false ., stat = stat ) if ( stat == toml_stat % success ) then ! Boolean value found. Set no custom prefix. This also falls back to key not provided if ( allocated ( self % module_prefix % s )) deallocate ( self % module_prefix % s ) else !> Value found, but not a boolean. Attempt to read a prefix string call get_value ( table , \"module-naming\" , self % module_prefix % s ) if (. not . allocated ( self % module_prefix % s )) then call syntax_error ( error , \"Could not read value for 'module-naming' in fpm.toml, expecting logical or a string\" ) return end if self % module_naming = . true . end if call get_list ( table , \"link\" , self % link , error ) if ( allocated ( error )) return call get_list ( table , \"external-modules\" , self % external_modules , error ) if ( allocated ( error )) return end subroutine load_from_toml end module fpm_manifest_build","tags":"","url":"sourcefile/build.f90.html"},{"title":"fpm_settings.f90 – Fortran-lang/fpm","text":"Source Code !> Manages global settings which are defined in the global config file. module fpm_settings use fpm_filesystem , only : exists , join_path , get_local_prefix , is_absolute_path , mkdir use fpm_environment , only : os_is_unix use fpm_error , only : error_t , fatal_error use tomlf , only : toml_table , toml_error , toml_stat , toml_load use fpm_toml , only : get_value , check_keys use fpm_os , only : get_current_directory , change_directory , get_absolute_path , convert_to_absolute_path implicit none private public :: fpm_global_settings , get_global_settings , get_registry_settings , official_registry_base_url character ( * ), parameter :: official_registry_base_url = 'https://fpm-registry.vercel.app' character ( * ), parameter :: default_config_file_name = 'config.toml' type :: fpm_global_settings !> Path to the global config file excluding the file name. character ( len = :), allocatable :: path_to_config_folder !> Name of the global config file. The default is `config.toml`. character ( len = :), allocatable :: config_file_name !> Registry configs. type ( fpm_registry_settings ), allocatable :: registry_settings contains procedure :: has_custom_location , full_path , path_to_config_folder_or_empty end type type :: fpm_registry_settings !> The path to the local registry. If allocated, the local registry !> will be used instead of the remote registry and replaces the !> local cache. character ( len = :), allocatable :: path !> The URL to the remote registry. Can be used to get packages !> from the official or a custom registry. character ( len = :), allocatable :: url !> The path to the cache folder. If not specified, the default cache !> folders are `~/.local/share/fpm/dependencies` on Unix and !> `%APPDATA%\\local\\fpm\\dependencies` on Windows. !> Cannot be used together with `path`. character ( len = :), allocatable :: cache_path end type contains !> Obtain global settings from the global config file. subroutine get_global_settings ( global_settings , error ) !> Global settings to be obtained. type ( fpm_global_settings ), intent ( inout ) :: global_settings !> Error reading config file. type ( error_t ), allocatable , intent ( out ) :: error !> TOML table to be filled with global config settings. type ( toml_table ), allocatable :: table !> Error parsing to TOML table. type ( toml_error ), allocatable :: parse_error type ( toml_table ), pointer :: registry_table integer :: stat ! Use custom path to the config file if it was specified. if ( global_settings % has_custom_location ()) then ! Throw error if folder doesn't exist. if (. not . exists ( global_settings % path_to_config_folder )) then call fatal_error ( error , \"Folder not found: '\" // global_settings % path_to_config_folder // \"'.\" ); return end if ! Throw error if the file doesn't exist. if (. not . exists ( global_settings % full_path ())) then call fatal_error ( error , \"File not found: '\" // global_settings % full_path () // \"'.\" ); return end if ! Make sure that the path to the global config file is absolute. call convert_to_absolute_path ( global_settings % path_to_config_folder , error ) if ( allocated ( error )) return else ! Use default path if it wasn't specified. if ( os_is_unix ()) then global_settings % path_to_config_folder = join_path ( get_local_prefix (), 'share' , 'fpm' ) else global_settings % path_to_config_folder = join_path ( get_local_prefix (), 'fpm' ) end if ! Use default file name. global_settings % config_file_name = default_config_file_name ! Apply default registry settings and return if config file doesn't exist. if (. not . exists ( global_settings % full_path ())) then call use_default_registry_settings ( global_settings ); return end if end if ! Load into TOML table. call toml_load ( table , global_settings % full_path (), error = parse_error ) if ( allocated ( parse_error )) then allocate ( error ); call move_alloc ( parse_error % message , error % message ); return end if call get_value ( table , 'registry' , registry_table , requested = . false ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error reading registry from config file '\" // & & global_settings % full_path () // \"'.\" ); return end if ! A registry table was found. if ( associated ( registry_table )) then call get_registry_settings ( registry_table , global_settings , error ) else call use_default_registry_settings ( global_settings ) end if end !> Default registry settings are typically applied if the config file doesn't exist or no registry table was found in !> the global config file. subroutine use_default_registry_settings ( global_settings ) type ( fpm_global_settings ), intent ( inout ) :: global_settings if (. not . allocated ( global_settings % registry_settings )) allocate ( global_settings % registry_settings ) global_settings % registry_settings % url = official_registry_base_url global_settings % registry_settings % cache_path = join_path ( global_settings % path_to_config_folder_or_empty (), & & 'dependencies' ) end !> Read registry settings from the global config file. subroutine get_registry_settings ( table , global_settings , error ) !> The [registry] subtable from the global config file. type ( toml_table ), target , intent ( inout ) :: table !> The global settings which can be filled with the registry settings. type ( fpm_global_settings ), intent ( inout ) :: global_settings !> Error handling. type ( error_t ), allocatable , intent ( out ) :: error character (:), allocatable :: path , url , cache_path integer :: stat !> List of valid keys for the dependency table. character ( * ), dimension ( * ), parameter :: valid_keys = [ character ( 10 ) :: & & 'path' , & & 'url' , & & 'cache_path' & & ] call check_keys ( table , valid_keys , error ) if ( allocated ( error )) return allocate ( global_settings % registry_settings ) if ( table % has_key ( 'path' )) then call get_value ( table , 'path' , path , stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error reading registry path: '\" // path // \"'.\" ); return end if end if if ( allocated ( path )) then if ( is_absolute_path ( path )) then global_settings % registry_settings % path = path else ! Get canonical, absolute path on both Unix and Windows. call get_absolute_path ( join_path ( global_settings % path_to_config_folder_or_empty (), path ), & & global_settings % registry_settings % path , error ) if ( allocated ( error )) return ! Check if the path to the registry exists. if (. not . exists ( global_settings % registry_settings % path )) then call fatal_error ( error , \"Directory '\" // global_settings % registry_settings % path // & & \"' doesn't exist.\" ); return end if end if end if if ( table % has_key ( 'url' )) then call get_value ( table , 'url' , url , stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error reading registry url: '\" // url // \"'.\" ); return end if end if if ( allocated ( url )) then ! Throw error when both path and url were provided. if ( allocated ( path )) then call fatal_error ( error , 'Do not provide both path and url to the registry.' ); return end if global_settings % registry_settings % url = url else if (. not . allocated ( path )) then global_settings % registry_settings % url = official_registry_base_url end if if ( table % has_key ( 'cache_path' )) then call get_value ( table , 'cache_path' , cache_path , stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error reading path to registry cache: '\" // cache_path // \"'.\" ); return end if end if if ( allocated ( cache_path )) then ! Throw error when both path and cache_path were provided. if ( allocated ( path )) then call fatal_error ( error , \"Do not provide both 'path' and 'cache_path'.\" ); return end if if ( is_absolute_path ( cache_path )) then if (. not . exists ( cache_path )) call mkdir ( cache_path ) global_settings % registry_settings % cache_path = cache_path else cache_path = join_path ( global_settings % path_to_config_folder_or_empty (), cache_path ) if (. not . exists ( cache_path )) call mkdir ( cache_path ) ! Get canonical, absolute path on both Unix and Windows. call get_absolute_path ( cache_path , global_settings % registry_settings % cache_path , error ) if ( allocated ( error )) return end if else if (. not . allocated ( path )) then global_settings % registry_settings % cache_path = & join_path ( global_settings % path_to_config_folder_or_empty (), 'dependencies' ) end if end !> True if the global config file is not at the default location. elemental logical function has_custom_location ( self ) class ( fpm_global_settings ), intent ( in ) :: self has_custom_location = allocated ( self % path_to_config_folder ) . and . allocated ( self % config_file_name ) if (. not . has_custom_location ) return has_custom_location = len_trim ( self % path_to_config_folder ) > 0 . and . len_trim ( self % config_file_name ) > 0 end !> The full path to the global config file. function full_path ( self ) result ( result ) class ( fpm_global_settings ), intent ( in ) :: self character ( len = :), allocatable :: result result = join_path ( self % path_to_config_folder_or_empty (), self % config_file_name ) end !> The path to the global config directory. pure function path_to_config_folder_or_empty ( self ) class ( fpm_global_settings ), intent ( in ) :: self character ( len = :), allocatable :: path_to_config_folder_or_empty if ( allocated ( self % path_to_config_folder )) then path_to_config_folder_or_empty = self % path_to_config_folder else path_to_config_folder_or_empty = \"\" end if end end","tags":"","url":"sourcefile/fpm_settings.f90.html"},{"title":"dependency.f90 – Fortran-lang/fpm","text":"Source Code !> # Dependency management !> !> ## Fetching dependencies and creating a dependency tree !> !> Dependencies on the top-level can be specified from: !> !> - `package%dependencies` !> - `package%dev_dependencies` !> - `package%executable(:)%dependencies` !> - `package%test(:)%dependencies` !> !> Each dependency is fetched in some way and provides a path to its package !> manifest. !> The `package%dependencies` of the dependencies are resolved recursively. !> !> To initialize the dependency tree all dependencies are recursively fetched !> and stored in a flat data structure to avoid retrieving a package twice. !> The data structure used to store this information should describe the current !> status of the dependency tree. Important information are: !> !> - name of the package !> - version of the package !> - path to the package root !> !> Additionally, for version controlled dependencies the following should be !> stored along with the package: !> !> - the upstream url !> - the current checked out revision !> !> Fetching a remote (version controlled) dependency turns it for our purpose !> into a local path dependency which is handled by the same means. !> !> ## Updating dependencies !> !> For a given dependency tree all top-level dependencies can be updated. !> We have two cases to consider, a remote dependency and a local dependency, !> again, remote dependencies turn into local dependencies by fetching. !> Therefore we will update remote dependencies by simply refetching them. !> !> For remote dependencies we have to refetch if the revision in the manifest !> changes or the upstream HEAD has changed (for branches _and_ tags). !> !> @Note For our purpose a tag is just a fancy branch name. Tags can be delete and !> modified afterwards, therefore they do not differ too much from branches !> from our perspective. !> !> For the latter case we only know if we actually fetch from the upstream URL. !> !> In case of local (and fetched remote) dependencies we have to read the package !> manifest and compare its dependencies against our dependency tree, any change !> requires updating the respective dependencies as well. !> !> ## Handling dependency compatibilties !> !> Currenly ignored. First come, first serve. module fpm_dependency use , intrinsic :: iso_fortran_env , only : output_unit use fpm_environment , only : get_os_type , OS_WINDOWS , os_is_unix use fpm_error , only : error_t , fatal_error use fpm_filesystem , only : exists , join_path , mkdir , canon_path , windows_path , list_files , is_dir , basename , & os_delete_dir , get_temp_filename , parent_dir use fpm_git , only : git_target_revision , git_target_default , git_revision , serializable_t use fpm_manifest , only : package_config_t , dependency_config_t , get_package_data , get_package_dependencies use fpm_manifest_dependency , only : manifest_has_changed , dependency_destroy use fpm_manifest_preprocess , only : operator ( == ) use fpm_strings , only : string_t , operator (. in .), operator ( == ), str use tomlf , only : toml_table , toml_key , toml_error , toml_load , toml_stat , toml_array , len , add_array use fpm_toml , only : toml_serialize , get_value , set_value , add_table , set_string , get_list , set_list use fpm_versioning , only : version_t , new_version use fpm_settings , only : fpm_global_settings , get_global_settings , official_registry_base_url use fpm_downloader , only : downloader_t use jonquil , only : json_object implicit none private public :: dependency_tree_t , new_dependency_tree , dependency_node_t , new_dependency_node , resize , & & check_and_read_pkg_data , destroy_dependency_node !> Overloaded reallocation interface interface resize module procedure :: resize_dependency_node end interface resize !> Dependency node in the projects dependency tree type , extends ( dependency_config_t ) :: dependency_node_t !> Actual version of this dependency type ( version_t ), allocatable :: version !> Installation prefix of this dependencies character ( len = :), allocatable :: proj_dir !> Checked out revision of the version control system character ( len = :), allocatable :: revision !> Dependency is handled logical :: done = . false . !> Dependency should be updated logical :: update = . false . !> Dependency was loaded from a cache logical :: cached = . false . !> Package dependencies of this node type ( string_t ), allocatable :: package_dep (:) contains !> Update dependency from project manifest. procedure :: register !> Get dependency from the registry. procedure :: get_from_registry procedure , private :: get_from_local_registry !> Print information on this instance procedure :: info !> Serialization interface procedure :: serializable_is_same => dependency_node_is_same procedure :: dump_to_toml => node_dump_to_toml procedure :: load_from_toml => node_load_from_toml end type dependency_node_t !> Respresentation of a projects dependencies !> !> The dependencies are stored in a simple array for now, this can be replaced !> with a binary-search tree or a hash table in the future. type , extends ( serializable_t ) :: dependency_tree_t !> Unit for IO integer :: unit = output_unit !> Verbosity of printout integer :: verbosity = 1 !> Installation prefix for dependencies character ( len = :), allocatable :: dep_dir !> Number of currently registered dependencies integer :: ndep = 0 !> Flattend list of all dependencies type ( dependency_node_t ), allocatable :: dep (:) !> Cache file character ( len = :), allocatable :: cache !> Custom path to the global config file character ( len = :), allocatable :: path_to_config contains !> Overload procedure to add new dependencies to the tree generic :: add => add_project , add_project_dependencies , add_dependencies , & add_dependency , add_dependency_node !> Main entry point to add a project procedure , private :: add_project !> Add a project and its dependencies to the dependency tree procedure , private :: add_project_dependencies !> Add a list of dependencies to the dependency tree procedure , private :: add_dependencies !> Add a single dependency to the dependency tree procedure , private :: add_dependency !> Add a single dependency node to the dependency tree procedure , private :: add_dependency_node !> Resolve dependencies generic :: resolve => resolve_dependencies , resolve_dependency !> Resolve dependencies procedure , private :: resolve_dependencies !> Resolve dependency procedure , private :: resolve_dependency !> True if entity can be found generic :: has => has_dependency !> True if dependency is part of the tree procedure , private :: has_dependency !> Find a dependency in the tree generic :: find => find_name !> Find a dependency by its name procedure , private :: find_name !> Establish local link order for a node's package dependencies procedure :: local_link_order !> Depedendncy resolution finished procedure :: finished !> Reading of dependency tree generic :: load_cache => load_cache_from_file , load_cache_from_unit , load_cache_from_toml !> Read dependency tree from file procedure , private :: load_cache_from_file !> Read dependency tree from formatted unit procedure , private :: load_cache_from_unit !> Read dependency tree from TOML data structure procedure , private :: load_cache_from_toml !> Writing of dependency tree generic :: dump_cache => dump_cache_to_file , dump_cache_to_unit , dump_cache_to_toml !> Write dependency tree to file procedure , private :: dump_cache_to_file !> Write dependency tree to formatted unit procedure , private :: dump_cache_to_unit !> Write dependency tree to TOML data structure procedure , private :: dump_cache_to_toml !> Update dependency tree generic :: update => update_dependency , update_tree !> Update a list of dependencies procedure , private :: update_dependency !> Update all dependencies in the tree procedure , private :: update_tree !> Serialization interface procedure :: serializable_is_same => dependency_tree_is_same procedure :: dump_to_toml => tree_dump_to_toml procedure :: load_from_toml => tree_load_from_toml end type dependency_tree_t !> Common output format for writing to the command line character ( len =* ), parameter :: out_fmt = '(\"#\", *(1x, g0))' contains !> Create a new dependency tree subroutine new_dependency_tree ( self , verbosity , cache , path_to_config ) !> Instance of the dependency tree type ( dependency_tree_t ), intent ( out ) :: self !> Verbosity of printout integer , intent ( in ), optional :: verbosity !> Name of the cache file character ( len =* ), intent ( in ), optional :: cache !> Path to the global config file. character ( len =* ), intent ( in ), optional :: path_to_config call resize ( self % dep ) self % dep_dir = join_path ( \"build\" , \"dependencies\" ) if ( present ( verbosity )) self % verbosity = verbosity if ( present ( cache )) self % cache = cache if ( present ( path_to_config )) self % path_to_config = path_to_config end subroutine new_dependency_tree !> Create a new dependency node from a configuration subroutine new_dependency_node ( self , dependency , version , proj_dir , update ) !> Instance of the dependency node type ( dependency_node_t ), intent ( out ) :: self !> Dependency configuration data type ( dependency_config_t ), intent ( in ) :: dependency !> Version of the dependency type ( version_t ), intent ( in ), optional :: version !> Installation prefix of the dependency character ( len =* ), intent ( in ), optional :: proj_dir !> Dependency should be updated logical , intent ( in ), optional :: update self % dependency_config_t = dependency if ( present ( version )) then self % version = version end if if ( present ( proj_dir )) then self % proj_dir = proj_dir end if if ( present ( update )) then self % update = update end if end subroutine new_dependency_node !> Write information on instance subroutine info ( self , unit , verbosity ) !> Instance of the dependency configuration class ( dependency_node_t ), intent ( in ) :: self !> Unit for IO integer , intent ( in ) :: unit !> Verbosity of the printout integer , intent ( in ), optional :: verbosity integer :: pr , i character ( len =* ), parameter :: fmt = '(\"#\", 1x, a, t30, a)' if ( present ( verbosity )) then pr = verbosity else pr = 1 end if !> Call base object info call self % dependency_config_t % info ( unit , pr ) if ( allocated ( self % version )) then write ( unit , fmt ) \"- version\" , self % version % s () end if if ( allocated ( self % proj_dir )) then write ( unit , fmt ) \"- dir\" , self % proj_dir end if if ( allocated ( self % revision )) then write ( unit , fmt ) \"- revision\" , self % revision end if write ( unit , fmt ) \"- done\" , merge ( 'YES' , 'NO ' , self % done ) write ( unit , fmt ) \"- update\" , merge ( 'YES' , 'NO ' , self % update ) if ( allocated ( self % package_dep )) then write ( unit , fmt ) \" - package_dep \" do i = 1 , size ( self % package_dep ) write ( unit , fmt ) \" - \" // self % package_dep ( i )% s end do end if end subroutine info !> Add project dependencies, each depth level after each other. !> !> We implement this algorithm in an interative rather than a recursive fashion !> as a choice of design. subroutine add_project ( self , package , error ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( inout ) :: self !> Project configuration to add type ( package_config_t ), intent ( in ) :: package !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( dependency_config_t ) :: dependency type ( dependency_tree_t ) :: cached character ( len =* ), parameter :: root = '.' integer :: id if (. not . exists ( self % dep_dir )) then call mkdir ( self % dep_dir ) end if ! Create this project as the first dependency node (depth 0) dependency % name = package % name dependency % path = root call self % add ( dependency , error ) if ( allocated ( error )) return ! Resolve the root project call self % resolve ( root , error ) if ( allocated ( error )) return ! Add the root project dependencies (depth 1) call self % add ( package , root , . true ., error ) if ( allocated ( error )) return ! After resolving all dependencies, check if we have cached ones to avoid updates if ( allocated ( self % cache )) then call new_dependency_tree ( cached , verbosity = self % verbosity , cache = self % cache ) call cached % load_cache ( self % cache , error ) if ( allocated ( error )) return ! Skip root node do id = 2 , cached % ndep cached % dep ( id )% cached = . true . call self % add ( cached % dep ( id ), error ) if ( allocated ( error )) return end do end if ! Now decent into the dependency tree, level for level do while (. not . self % finished ()) call self % resolve ( root , error ) if ( allocated ( error )) exit end do if ( allocated ( error )) return ! Resolve internal dependency graph and remove temporary package storage call resolve_dependency_graph ( self , package , error ) if ( allocated ( error )) return if ( allocated ( self % cache )) then call self % dump_cache ( self % cache , error ) if ( allocated ( error )) return end if end subroutine add_project subroutine resolve_dependency_graph ( self , main , error ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( inout ) :: self !> Main project configuration type ( package_config_t ), intent ( in ) :: main !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: i , nit integer , parameter :: MAXIT = 50 logical , allocatable :: finished (:) type ( string_t ), allocatable :: old_package_dep (:) if ( self % ndep < 1 ) then call fatal_error ( error , \"Trying to compute the dependency graph of an empty tree\" ) return end if nit = 0 allocate ( finished ( self % ndep ), source = . false .) do while (. not . all ( finished ) . and . nit < MAXIT ) nit = nit + 1 do i = 1 , self % ndep ! Save old deps call move_alloc ( from = self % dep ( i )% package_dep , to = old_package_dep ) call get_required_packages ( self , i , error = error ) if ( allocated ( error )) return finished ( i ) = all_alloc ( self % dep ( i )% package_dep , old_package_dep ) end do end do if ( nit >= MAXIT ) call fatal_error ( error , \"Infinite loop detected computing the dependency graph\" ) contains pure logical function all_alloc ( this , that ) type ( string_t ), intent ( in ), allocatable :: this (:), that (:) all_alloc = . false . if ( allocated ( this ). neqv . allocated ( that )) return if (. not . allocated ( this )) then all_alloc = . true . else if ( size ( this ) /= size ( that )) return if (. not .( this == that )) return all_alloc = . true . end if end function all_alloc end subroutine resolve_dependency_graph !> Add a project and its dependencies to the dependency tree recursive subroutine add_project_dependencies ( self , package , root , main , error ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( inout ) :: self !> Project configuration to add type ( package_config_t ), intent ( in ) :: package !> Current project root directory character ( len =* ), intent ( in ) :: root !> Is the main project logical , intent ( in ) :: main !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: ii if ( allocated ( package % dependency )) then call self % add ( package % dependency , error ) if ( allocated ( error )) return end if if ( main ) then if ( allocated ( package % dev_dependency )) then call self % add ( package % dev_dependency , error ) if ( allocated ( error )) return end if if ( allocated ( package % executable )) then do ii = 1 , size ( package % executable ) if ( allocated ( package % executable ( ii )% dependency )) then call self % add ( package % executable ( ii )% dependency , error ) if ( allocated ( error )) exit end if end do if ( allocated ( error )) return end if if ( allocated ( package % example )) then do ii = 1 , size ( package % example ) if ( allocated ( package % example ( ii )% dependency )) then call self % add ( package % example ( ii )% dependency , error ) if ( allocated ( error )) exit end if end do if ( allocated ( error )) return end if if ( allocated ( package % test )) then do ii = 1 , size ( package % test ) if ( allocated ( package % test ( ii )% dependency )) then call self % add ( package % test ( ii )% dependency , error ) if ( allocated ( error )) exit end if end do if ( allocated ( error )) return end if end if !> Ensure allocation fits call resize ( self % dep , self % ndep ) end subroutine add_project_dependencies !> Add a list of dependencies to the dependency tree subroutine add_dependencies ( self , dependency , error ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( inout ) :: self !> Dependency configuration to add type ( dependency_config_t ), intent ( in ) :: dependency (:) !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: ii , ndep ndep = size ( self % dep ) if ( ndep < size ( dependency ) + self % ndep ) then call resize ( self % dep , ndep + ndep / 2 + size ( dependency )) end if do ii = 1 , size ( dependency ) call self % add ( dependency ( ii ), error ) if ( allocated ( error )) exit end do if ( allocated ( error )) return !> Ensure allocation fits ndep call resize ( self % dep , self % ndep ) end subroutine add_dependencies !> Add a single dependency node to the dependency tree !> Dependency nodes contain additional information (version, git, revision) subroutine add_dependency_node ( self , dependency , error ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( inout ) :: self !> Dependency configuration to add type ( dependency_node_t ), intent ( in ) :: dependency !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: id if ( self % has_dependency ( dependency )) then ! A dependency with this same name is already in the dependency tree. ! Check if it needs to be updated id = self % find ( dependency % name ) ! If this dependency was in the cache, and we're now requesting a different version ! in the manifest, ensure it is marked for update. Otherwise, if we're just querying ! the same dependency from a lower branch of the dependency tree, the existing one from ! the manifest has priority if ( dependency % cached ) then if ( dependency_has_changed ( dependency , self % dep ( id ), self % verbosity , self % unit )) then if ( self % verbosity > 0 ) write ( self % unit , out_fmt ) \"Dependency change detected:\" , dependency % name self % dep ( id )% update = . true . else ! Store the cached one self % dep ( id ) = dependency self % dep ( id )% update = . false . end if end if else !> Safety: reallocate if necessary if ( size ( self % dep ) == self % ndep ) call resize ( self % dep , self % ndep + 1 ) ! New dependency: add from scratch self % ndep = self % ndep + 1 self % dep ( self % ndep ) = dependency self % dep ( self % ndep )% update = . false . end if end subroutine add_dependency_node !> Add a single dependency to the dependency tree subroutine add_dependency ( self , dependency , error ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( inout ) :: self !> Dependency configuration to add type ( dependency_config_t ), intent ( in ) :: dependency !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( dependency_node_t ) :: node call new_dependency_node ( node , dependency ) call add_dependency_node ( self , node , error ) end subroutine add_dependency !> Update dependency tree subroutine update_dependency ( self , name , error ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( inout ) :: self !> Name of the dependency to update character ( len =* ), intent ( in ) :: name !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: id character ( len = :), allocatable :: proj_dir , root id = self % find ( name ) root = \".\" if ( id <= 0 ) then call fatal_error ( error , \"Cannot update dependency '\" // name // \"'\" ) return end if associate ( dep => self % dep ( id )) if ( allocated ( dep % git ) . and . dep % update ) then if ( self % verbosity > 0 ) write ( self % unit , out_fmt ) \"Update:\" , dep % name proj_dir = join_path ( self % dep_dir , dep % name ) call dep % git % checkout ( proj_dir , error ) if ( allocated ( error )) return ! Unset dependency and remove updatable attribute dep % done = . false . dep % update = . false . ! Now decent into the dependency tree, level for level do while (. not . self % finished ()) call self % resolve ( root , error ) if ( allocated ( error )) exit end do if ( allocated ( error )) return end if end associate end subroutine update_dependency !> Update whole dependency tree subroutine update_tree ( self , error ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( inout ) :: self !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: i ! Update dependencies where needed do i = 1 , self % ndep call self % update ( self % dep ( i )% name , error ) if ( allocated ( error )) return end do end subroutine update_tree !> Resolve all dependencies in the tree subroutine resolve_dependencies ( self , root , error ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( inout ) :: self !> Current installation prefix character ( len =* ), intent ( in ) :: root !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( fpm_global_settings ) :: global_settings character (:), allocatable :: parent_directory integer :: ii ! Register path to global config file if it was entered via the command line. if ( allocated ( self % path_to_config )) then if ( len_trim ( self % path_to_config ) > 0 ) then parent_directory = parent_dir ( self % path_to_config ) if ( len_trim ( parent_directory ) == 0 ) then global_settings % path_to_config_folder = \".\" else global_settings % path_to_config_folder = parent_directory end if global_settings % config_file_name = basename ( self % path_to_config ) end if end if call get_global_settings ( global_settings , error ) if ( allocated ( error )) return do ii = 1 , self % ndep call self % resolve ( self % dep ( ii ), global_settings , root , error ) if ( allocated ( error )) exit end do if ( allocated ( error )) return end subroutine resolve_dependencies !> Resolve a single dependency node subroutine resolve_dependency ( self , dependency , global_settings , root , error ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( inout ) :: self !> Dependency configuration to add type ( dependency_node_t ), intent ( inout ) :: dependency !> Global configuration settings. type ( fpm_global_settings ), intent ( in ) :: global_settings !> Current installation prefix character ( len =* ), intent ( in ) :: root !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( package_config_t ) :: package character ( len = :), allocatable :: manifest , proj_dir , revision logical :: fetch if ( dependency % done ) return fetch = . false . if ( allocated ( dependency % proj_dir )) then proj_dir = dependency % proj_dir else if ( allocated ( dependency % path )) then proj_dir = join_path ( root , dependency % path ) else if ( allocated ( dependency % git )) then proj_dir = join_path ( self % dep_dir , dependency % name ) fetch = . not . exists ( proj_dir ) if ( fetch ) then call dependency % git % checkout ( proj_dir , error ) if ( allocated ( error )) return end if else call dependency % get_from_registry ( proj_dir , global_settings , error ) if ( allocated ( error )) return end if if ( allocated ( dependency % git )) then call git_revision ( proj_dir , revision , error ) if ( allocated ( error )) return end if manifest = join_path ( proj_dir , \"fpm.toml\" ) call get_package_data ( package , manifest , error ) if ( allocated ( error )) return call dependency % register ( package , proj_dir , fetch , revision , error ) if ( allocated ( error )) return if ( self % verbosity > 1 ) then write ( self % unit , out_fmt ) & \"Dep:\" , dependency % name , \"version\" , dependency % version % s (), & \"at\" , dependency % proj_dir end if call self % add ( package , proj_dir , . false ., error ) if ( allocated ( error )) return end subroutine resolve_dependency !> Get a dependency from the registry. Whether the dependency is fetched !> from a local, a custom remote or the official registry is determined !> by the global configuration settings. subroutine get_from_registry ( self , target_dir , global_settings , error , downloader_ ) !> Instance of the dependency configuration. class ( dependency_node_t ), intent ( in ) :: self !> The target directory of the dependency. character (:), allocatable , intent ( out ) :: target_dir !> Global configuration settings. type ( fpm_global_settings ), intent ( in ) :: global_settings !> Error handling. type ( error_t ), allocatable , intent ( out ) :: error !> Downloader instance. class ( downloader_t ), optional , intent ( in ) :: downloader_ character (:), allocatable :: cache_path , target_url , tmp_file type ( version_t ) :: version integer :: stat , unit type ( json_object ) :: json class ( downloader_t ), allocatable :: downloader if ( present ( downloader_ )) then downloader = downloader_ else allocate ( downloader ) end if ! Use local registry if it was specified in the global config file. if ( allocated ( global_settings % registry_settings % path )) then call self % get_from_local_registry ( target_dir , global_settings % registry_settings % path , error ); return end if ! Include namespace and package name in the cache path. cache_path = join_path ( global_settings % registry_settings % cache_path , self % namespace , self % name ) ! Check cache before downloading from the remote registry if a specific version was requested. When no specific ! version was requested, do network request first to check which is the newest version. if ( allocated ( self % requested_version )) then if ( exists ( join_path ( cache_path , self % requested_version % s (), 'fpm.toml' ))) then print * , \"Using cached version of '\" , join_path ( self % namespace , self % name , self % requested_version % s ()), \"'.\" target_dir = join_path ( cache_path , self % requested_version % s ()); return end if end if tmp_file = get_temp_filename () open ( newunit = unit , file = tmp_file , action = 'readwrite' , iostat = stat ) if ( stat /= 0 ) then call fatal_error ( error , \"Error creating temporary file for downloading package '\" // self % name // \"'.\" ); return end if ! Include namespace and package name in the target url and download package data. target_url = global_settings % registry_settings % url // '/packages/' // self % namespace // '/' // self % name call downloader % get_pkg_data ( target_url , self % requested_version , tmp_file , json , error ) close ( unit , status = 'delete' ) if ( allocated ( error )) return ! Verify package data and read relevant information. call check_and_read_pkg_data ( json , self , target_url , version , error ) if ( allocated ( error )) return ! Open new tmp file for downloading the actual package. open ( newunit = unit , file = tmp_file , action = 'readwrite' , iostat = stat ) if ( stat /= 0 ) then call fatal_error ( error , \"Error creating temporary file for downloading package '\" // self % name // \"'.\" ); return end if ! Include version number in the cache path. If no cached version exists, download it. cache_path = join_path ( cache_path , version % s ()) if (. not . exists ( join_path ( cache_path , 'fpm.toml' ))) then if ( is_dir ( cache_path )) call os_delete_dir ( os_is_unix (), cache_path ) call mkdir ( cache_path ) call downloader % get_file ( target_url , tmp_file , error ) if ( allocated ( error )) then close ( unit , status = 'delete' ); return end if ! Unpack the downloaded package to the final location. call downloader % unpack ( tmp_file , cache_path , error ) close ( unit , status = 'delete' ) if ( allocated ( error )) return end if target_dir = cache_path end subroutine get_from_registry subroutine check_and_read_pkg_data ( json , node , download_url , version , error ) type ( json_object ), intent ( inout ) :: json class ( dependency_node_t ), intent ( in ) :: node character (:), allocatable , intent ( out ) :: download_url type ( version_t ), intent ( out ) :: version type ( error_t ), allocatable , intent ( out ) :: error integer :: code , stat type ( json_object ), pointer :: p , q character (:), allocatable :: version_key , version_str , error_message , namespace , name namespace = \"\" name = \"UNNAMED_NODE\" if ( allocated ( node % namespace )) namespace = node % namespace if ( allocated ( node % name )) name = node % name if (. not . json % has_key ( 'code' )) then call fatal_error ( error , \"Failed to download '\" // join_path ( namespace , name ) // \"': No status code.\" ); return end if call get_value ( json , 'code' , code , stat = stat ) if ( stat /= 0 ) then call fatal_error ( error , \"Failed to download '\" // join_path ( namespace , name ) // \"': \" // & & \"Failed to read status code.\" ); return end if if ( code /= 200 ) then if (. not . json % has_key ( 'message' )) then call fatal_error ( error , \"Failed to download '\" // join_path ( namespace , name ) // \"': No error message.\" ); return end if call get_value ( json , 'message' , error_message , stat = stat ) if ( stat /= 0 ) then call fatal_error ( error , \"Failed to download '\" // join_path ( namespace , name ) // \"': \" // & & \"Failed to read error message.\" ); return end if call fatal_error ( error , \"Failed to download '\" // join_path ( namespace , name ) // \"'. Status code: '\" // & & str ( code ) // \"'. Error message: '\" // error_message // \"'.\" ); return end if if (. not . json % has_key ( 'data' )) then call fatal_error ( error , \"Failed to download '\" // join_path ( namespace , name ) // \"': No data.\" ); return end if call get_value ( json , 'data' , p , stat = stat ) if ( stat /= 0 ) then call fatal_error ( error , \"Failed to read package data for '\" // join_path ( namespace , name ) // \"'.\" ); return end if if ( allocated ( node % requested_version )) then version_key = 'version_data' else version_key = 'latest_version_data' end if if (. not . p % has_key ( version_key )) then call fatal_error ( error , \"Failed to download '\" // join_path ( namespace , name ) // \"': No version data.\" ); return end if call get_value ( p , version_key , q , stat = stat ) if ( stat /= 0 ) then call fatal_error ( error , \"Failed to retrieve version data for '\" // join_path ( namespace , name ) // \"'.\" ); return end if if (. not . q % has_key ( 'download_url' )) then call fatal_error ( error , \"Failed to download '\" // join_path ( namespace , name ) // \"': No download url.\" ); return end if call get_value ( q , 'download_url' , download_url , stat = stat ) if ( stat /= 0 ) then call fatal_error ( error , \"Failed to read download url for '\" // join_path ( namespace , name ) // \"'.\" ); return end if download_url = official_registry_base_url // download_url if (. not . q % has_key ( 'version' )) then call fatal_error ( error , \"Failed to download '\" // join_path ( namespace , name ) // \"': No version found.\" ); return end if call get_value ( q , 'version' , version_str , stat = stat ) if ( stat /= 0 ) then call fatal_error ( error , \"Failed to read version data for '\" // join_path ( namespace , name ) // \"'.\" ); return end if call new_version ( version , version_str , error ) if ( allocated ( error )) then call fatal_error ( error , \"'\" // version_str // \"' is not a valid version for '\" // & & join_path ( namespace , name ) // \"'.\" ); return end if end subroutine !> Get the dependency from a local registry. subroutine get_from_local_registry ( self , target_dir , registry_path , error ) !> Instance of the dependency configuration. class ( dependency_node_t ), intent ( in ) :: self !> The target directory to download the dependency to. character (:), allocatable , intent ( out ) :: target_dir !> The path to the local registry. character ( * ), intent ( in ) :: registry_path !> Error handling. type ( error_t ), allocatable , intent ( out ) :: error character (:), allocatable :: path_to_name type ( string_t ), allocatable :: files (:) type ( version_t ), allocatable :: versions (:) type ( version_t ) :: version integer :: i path_to_name = join_path ( registry_path , self % namespace , self % name ) if (. not . exists ( path_to_name )) then call fatal_error ( error , \"Dependency resolution of '\" // self % name // & & \"': Directory '\" // path_to_name // \"' doesn't exist.\" ); return end if call list_files ( path_to_name , files ) if ( size ( files ) == 0 ) then call fatal_error ( error , \"No versions of '\" // self % name // \"' found in '\" // path_to_name // \"'.\" ); return end if ! Version requested, find it in the cache. if ( allocated ( self % requested_version )) then do i = 1 , size ( files ) ! Identify directory that matches the version number. if ( files ( i )% s == join_path ( path_to_name , self % requested_version % s ()) . and . is_dir ( files ( i )% s )) then if (. not . exists ( join_path ( files ( i )% s , 'fpm.toml' ))) then call fatal_error ( error , \"'\" // files ( i )% s // \"' is missing an 'fpm.toml' file.\" ); return end if target_dir = files ( i )% s ; return end if end do call fatal_error ( error , \"Version '\" // self % requested_version % s () // \"' not found in '\" // path_to_name // \"'\" ) return end if ! No specific version requested, therefore collect available versions. allocate ( versions ( 0 )) do i = 1 , size ( files ) if ( is_dir ( files ( i )% s )) then call new_version ( version , basename ( files ( i )% s ), error ) if ( allocated ( error )) return versions = [ versions , version ] end if end do if ( size ( versions ) == 0 ) then call fatal_error ( error , \"No versions found in '\" // path_to_name // \"'\" ); return end if ! Find the latest version. version = versions ( 1 ) do i = 1 , size ( versions ) if ( versions ( i ) > version ) version = versions ( i ) end do path_to_name = join_path ( path_to_name , version % s ()) if (. not . exists ( join_path ( path_to_name , 'fpm.toml' ))) then call fatal_error ( error , \"'\" // path_to_name // \"' is missing an 'fpm.toml' file.\" ); return end if target_dir = path_to_name end subroutine get_from_local_registry !> True if dependency is part of the tree pure logical function has_dependency ( self , dependency ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( in ) :: self !> Dependency configuration to check class ( dependency_node_t ), intent ( in ) :: dependency has_dependency = self % find ( dependency % name ) /= 0 end function has_dependency !> Find a dependency in the dependency tree pure function find_name ( self , name ) result ( pos ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( in ) :: self !> Dependency configuration to add character ( len =* ), intent ( in ) :: name !> Index of the dependency integer :: pos integer :: ii pos = 0 do ii = 1 , self % ndep if ( name == self % dep ( ii )% name ) then pos = ii exit end if end do end function find_name !> Check if we are done with the dependency resolution pure function finished ( self ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( in ) :: self !> All dependencies are updated logical :: finished finished = all ( self % dep (: self % ndep )% done ) end function finished !> Update dependency from project manifest subroutine register ( node , package , root , fetch , revision , error ) !> Instance of the dependency node class ( dependency_node_t ), intent ( inout ) :: node !> Package configuration data type ( package_config_t ), intent ( in ) :: package !> Project has been fetched logical , intent ( in ) :: fetch !> Root directory of the project character ( len =* ), intent ( in ) :: root !> Git revision of the project character ( len =* ), intent ( in ), optional :: revision !> Error handling type ( error_t ), allocatable , intent ( out ) :: error logical :: update update = . false . if ( node % name /= package % name ) then call fatal_error ( error , \"Dependency name '\" // package % name // & & \"' found, but expected '\" // node % name // \"' instead\" ) return end if node % version = package % version node % proj_dir = root if ( allocated ( node % git ) . and . present ( revision )) then node % revision = revision if (. not . fetch ) then ! Change in revision ID was checked already. Only update if ALL git information is missing update = . not . allocated ( node % git % url ) end if end if if ( update ) node % update = update node % done = . true . end subroutine register !> Capture the list of \"required\" packages while the manifest is loaded. !> This subroutine should be called during the \"resolve\" phase, i.e. when the whole !> dependency tree has been built already subroutine get_required_packages ( tree , node_ID , error ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( inout ) :: tree !> Instance of the dependency node integer , intent ( in ) :: node_ID !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: nreq , k , id type ( dependency_config_t ), allocatable :: dependency (:) type ( package_config_t ) :: manifest logical :: required ( tree % ndep ), main associate ( node => tree % dep ( node_ID )) ! Is the main project main = node_ID == 1 ! Get manifest call get_package_data ( manifest , join_path ( node % proj_dir , \"fpm.toml\" ), error ) if ( allocated ( error )) return call get_package_dependencies ( manifest , main , dependency ) nreq = size ( dependency ) ! Translate names -> indices required = . false . do k = 1 , nreq id = tree % find ( dependency ( k )% name ) if ( id <= 0 ) then ! Shouldn't happen because tree already contains every dep call fatal_error ( error , \"Internal error: \" // trim ( node % name ) // & & \" cannot find resolved dependency \" // trim ( dependency ( k )% name ) // \" in tree\" ) return end if ! Recurse dependencies call recurse_deps ( tree , id , required ) end do ! Recursed list nreq = count ( required ) if ( allocated ( node % package_dep )) deallocate ( node % package_dep ) allocate ( node % package_dep ( nreq )) k = 0 do id = 1 , tree % ndep if (. not . required ( id )) cycle k = k + 1 node % package_dep ( k ) = string_t ( tree % dep ( id )% name ) end do endassociate contains recursive subroutine recurse_deps ( tree , id , required ) class ( dependency_tree_t ), intent ( in ) :: tree integer , intent ( in ) :: id logical , intent ( inout ) :: required (:) integer :: j , dep_id if ( required ( id )) return required ( id ) = . true . if ( allocated ( tree % dep ( id )% package_dep )) then do j = 1 , size ( tree % dep ( id )% package_dep ) dep_id = tree % find ( tree % dep ( id )% package_dep ( j )% s ) call recurse_deps ( tree , dep_id , required ) end do end if end subroutine recurse_deps end subroutine get_required_packages !> Build a correct topological link order for a given dependency node. !> !> This routine returns the list of dependencies required to build `root_id`, !> sorted such that each dependency appears *before* any node that depends on it. !> This is suitable for correct linker ordering: `-lA -lB` means B can use symbols from A. !> !> The returned list includes both the transitive dependencies and the node itself. !> Example: if node 3 requires [5, 7, 9, 2] and 9 also requires 2, !> then the result will ensure that 2 appears before 9, etc. subroutine local_link_order ( tree , root_id , order , error ) !> The full dependency graph class ( dependency_tree_t ), intent ( in ) :: tree !> Index of the node for which to compute link order (e.g., the target being linked) integer , intent ( in ) :: root_id !> Ordered list of dependency indices (subset of tree%dep(:)) in link-safe order integer , allocatable , intent ( out ) :: order (:) !> Optional fatal error if a cycle is detected (not expected) type ( error_t ), allocatable , intent ( out ) :: error !> Track which nodes have been visited logical , allocatable :: visited (:) !> Work stack holding post-order DFS traversal integer , allocatable :: stack (:) !> Total number of nodes and current stack position integer :: n , top n = tree % ndep allocate ( visited ( n ), source = . false .) allocate ( stack ( n ), source = 0 ) top = 0 !> Depth-First Search from root node call dfs ( root_id , visited , stack , top , error ) if ( allocated ( error )) return !> The final link order is the reverse of the DFS post-order allocate ( order ( top )) if ( top > 0 ) order (:) = stack (: top ) contains !> Recursive depth-first search, post-order recursive subroutine dfs ( i , visited , stack , top , error ) integer , intent ( in ) :: i logical , intent ( inout ) :: visited (:) integer , intent ( inout ) :: stack (:), top type ( error_t ), allocatable , intent ( out ) :: error integer :: k , id if (. not .( i > 0 . and . i <= tree % ndep )) then call fatal_error ( error , 'package graph failed: invalid dependency ID' ) return end if if ( visited ( i )) return visited ( i ) = . true . ! Visit all required dependencies before this node if ( allocated ( tree % dep ( i )% package_dep )) then do k = 1 , size ( tree % dep ( i )% package_dep ) id = tree % find ( tree % dep ( i )% package_dep ( k )% s ) if (. not .( id > 0 . and . id <= tree % ndep )) then call fatal_error ( error , 'package graph failed: cannot find ' // tree % dep ( i )% package_dep ( k )% s ) return end if call dfs ( id , visited , stack , top , error ) if ( allocated ( error )) return end do end if ! Now that all dependencies are handled, record this node top = top + 1 stack ( top ) = i end subroutine dfs end subroutine local_link_order !> Read dependency tree from file subroutine load_cache_from_file ( self , file , error ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( inout ) :: self !> File name character ( len =* ), intent ( in ) :: file !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: unit logical :: exist inquire ( file = file , exist = exist ) if (. not . exist ) return open ( file = file , newunit = unit ) call self % load_cache ( unit , error ) close ( unit ) end subroutine load_cache_from_file !> Read dependency tree from file subroutine load_cache_from_unit ( self , unit , error ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( inout ) :: self !> File name integer , intent ( in ) :: unit !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_error ), allocatable :: parse_error type ( toml_table ), allocatable :: table call toml_load ( table , unit , error = parse_error ) if ( allocated ( parse_error )) then allocate ( error ) call move_alloc ( parse_error % message , error % message ) return end if call self % load_cache ( table , error ) if ( allocated ( error )) return end subroutine load_cache_from_unit !> Read dependency tree from TOML data structure subroutine load_cache_from_toml ( self , table , error ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: ndep , ii logical :: is_unix character ( len = :), allocatable :: version , url , obj , rev , proj_dir type ( toml_key ), allocatable :: list (:) type ( toml_table ), pointer :: ptr call table % get_keys ( list ) ndep = size ( self % dep ) if ( ndep < size ( list ) + self % ndep ) then call resize ( self % dep , ndep + ndep / 2 + size ( list )) end if is_unix = get_os_type () /= OS_WINDOWS do ii = 1 , size ( list ) call get_value ( table , list ( ii )% key , ptr ) call get_value ( ptr , \"version\" , version ) call get_value ( ptr , \"proj-dir\" , proj_dir ) call get_value ( ptr , \"git\" , url ) call get_value ( ptr , \"obj\" , obj ) call get_value ( ptr , \"rev\" , rev ) if (. not . allocated ( proj_dir )) cycle self % ndep = self % ndep + 1 associate ( dep => self % dep ( self % ndep )) dep % name = list ( ii )% key if ( is_unix ) then dep % proj_dir = proj_dir else dep % proj_dir = windows_path ( proj_dir ) end if dep % done = . false . if ( allocated ( version )) then if (. not . allocated ( dep % version )) allocate ( dep % version ) call new_version ( dep % version , version , error ) if ( allocated ( error )) exit end if if ( allocated ( url )) then if ( allocated ( obj )) then dep % git = git_target_revision ( url , obj ) else dep % git = git_target_default ( url ) end if if ( allocated ( rev )) then dep % revision = rev end if else dep % path = proj_dir end if end associate end do if ( allocated ( error )) return self % ndep = size ( list ) end subroutine load_cache_from_toml !> Write dependency tree to file subroutine dump_cache_to_file ( self , file , error ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( inout ) :: self !> File name character ( len =* ), intent ( in ) :: file !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: unit open ( file = file , newunit = unit ) call self % dump_cache ( unit , error ) close ( unit ) if ( allocated ( error )) return end subroutine dump_cache_to_file !> Write dependency tree to file subroutine dump_cache_to_unit ( self , unit , error ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( inout ) :: self !> Formatted unit integer , intent ( in ) :: unit !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_table ) :: table table = toml_table () call self % dump_cache ( table , error ) write ( unit , '(a)' ) toml_serialize ( table ) end subroutine dump_cache_to_unit !> Write dependency tree to TOML datastructure subroutine dump_cache_to_toml ( self , table , error ) !> Instance of the dependency tree class ( dependency_tree_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: ii type ( toml_table ), pointer :: ptr character ( len = :), allocatable :: proj_dir do ii = 1 , self % ndep associate ( dep => self % dep ( ii )) call add_table ( table , dep % name , ptr ) if (. not . associated ( ptr )) then call fatal_error ( error , \"Cannot create entry for \" // dep % name ) exit end if if ( allocated ( dep % version )) then call set_value ( ptr , \"version\" , dep % version % s ()) end if proj_dir = canon_path ( dep % proj_dir ) call set_value ( ptr , \"proj-dir\" , proj_dir ) if ( allocated ( dep % git )) then call set_value ( ptr , \"git\" , dep % git % url ) if ( allocated ( dep % git % object )) then call set_value ( ptr , \"obj\" , dep % git % object ) end if if ( allocated ( dep % revision )) then call set_value ( ptr , \"rev\" , dep % revision ) end if end if end associate end do if ( allocated ( error )) return end subroutine dump_cache_to_toml !> Reallocate a list of dependencies pure subroutine resize_dependency_node ( var , n ) !> Instance of the array to be resized type ( dependency_node_t ), allocatable , intent ( inout ) :: var (:) !> Dimension of the final array size integer , intent ( in ), optional :: n type ( dependency_node_t ), allocatable :: tmp (:) integer :: this_size , new_size integer , parameter :: initial_size = 16 if ( allocated ( var )) then this_size = size ( var , 1 ) call move_alloc ( var , tmp ) else this_size = initial_size end if if ( present ( n )) then new_size = n else new_size = this_size + this_size / 2 + 1 end if allocate ( var ( new_size )) if ( allocated ( tmp )) then this_size = min ( size ( tmp , 1 ), size ( var , 1 )) var (: this_size ) = tmp (: this_size ) deallocate ( tmp ) end if end subroutine resize_dependency_node !> Check if a dependency node has changed logical function dependency_has_changed ( cached , manifest , verbosity , iunit ) result ( has_changed ) !> Two instances of the same dependency to be compared type ( dependency_node_t ), intent ( in ) :: cached , manifest !> Log verbosity integer , intent ( in ) :: verbosity , iunit integer :: ip has_changed = . true . !> All the following entities must be equal for the dependency to not have changed if ( manifest_has_changed ( cached = cached , manifest = manifest , verbosity = verbosity , iunit = iunit )) return !> For now, only perform the following checks if both are available. A dependency in cache.toml !> will always have this metadata; a dependency from fpm.toml which has not been fetched yet !> may not have it if ( allocated ( cached % version ) . and . allocated ( manifest % version )) then if ( cached % version /= manifest % version ) then if ( verbosity > 1 ) write ( iunit , out_fmt ) \"VERSION has changed: \" // cached % version % s () // \" vs. \" // manifest % version % s () return end if else if ( verbosity > 1 ) write ( iunit , out_fmt ) \"VERSION has changed presence \" end if if ( allocated ( cached % revision ) . and . allocated ( manifest % revision )) then if ( cached % revision /= manifest % revision ) then if ( verbosity > 1 ) write ( iunit , out_fmt ) \"REVISION has changed: \" // cached % revision // \" vs. \" // manifest % revision return end if else if ( verbosity > 1 ) write ( iunit , out_fmt ) \"REVISION has changed presence \" end if if ( allocated ( cached % proj_dir ) . and . allocated ( manifest % proj_dir )) then if ( cached % proj_dir /= manifest % proj_dir ) then if ( verbosity > 1 ) write ( iunit , out_fmt ) \"PROJECT DIR has changed: \" // cached % proj_dir // \" vs. \" // manifest % proj_dir return end if else if ( verbosity > 1 ) write ( iunit , out_fmt ) \"PROJECT DIR has changed presence \" end if if ( allocated ( cached % preprocess ) . eqv . allocated ( manifest % preprocess )) then if ( allocated ( cached % preprocess )) then if ( size ( cached % preprocess ) /= size ( manifest % preprocess )) then if ( verbosity > 1 ) write ( iunit , out_fmt ) \"PREPROCESS has changed size\" return end if do ip = 1 , size ( cached % preprocess ) if (. not .( cached % preprocess ( ip ) == manifest % preprocess ( ip ))) then if ( verbosity > 1 ) write ( iunit , out_fmt ) \"PREPROCESS config has changed\" return end if end do endif else if ( verbosity > 1 ) write ( iunit , out_fmt ) \"PREPROCESS has changed presence \" return end if !> All checks passed: the two dependencies have no differences has_changed = . false . end function dependency_has_changed !> Check that two dependency nodes are equal logical function dependency_node_is_same ( this , that ) class ( dependency_node_t ), intent ( in ) :: this class ( serializable_t ), intent ( in ) :: that dependency_node_is_same = . false . select type ( other => that ) type is ( dependency_node_t ) ! Base class must match if (. not .( this % dependency_config_t == other % dependency_config_t )) return ! Extension must match if (. not .( this % done . eqv . other % done )) return if (. not .( this % update . eqv . other % update )) return if (. not .( this % cached . eqv . other % cached )) return if ( allocated ( this % proj_dir ) . neqv . allocated ( other % proj_dir )) return if ( allocated ( this % proj_dir )) then if (. not .( this % proj_dir == other % proj_dir )) return endif if ( allocated ( this % revision ) . neqv . allocated ( other % revision )) return if ( allocated ( this % revision )) then if (. not .( this % revision == other % revision )) return endif if ( allocated ( this % version ). neqv . allocated ( other % version )) return if ( allocated ( this % version )) then if (. not .( this % version == other % version )) return endif if ( allocated ( this % package_dep ). neqv . allocated ( other % package_dep )) return if ( allocated ( this % package_dep )) then if (. not . size ( this % package_dep ) == size ( other % package_dep )) return if (. not .( this % package_dep == other % package_dep )) return endif class default ! Not the same type return end select !> All checks passed! dependency_node_is_same = . true . end function dependency_node_is_same !> Dump dependency to toml table subroutine node_dump_to_toml ( self , table , error ) !> Instance of the serializable object class ( dependency_node_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: i , n , ierr type ( toml_array ), pointer :: array ! Dump parent class call self % dependency_config_t % dump_to_toml ( table , error ) if ( allocated ( error )) return if ( allocated ( self % version )) then call set_string ( table , \"version\" , self % version % s (), error , 'dependency_node_t' ) if ( allocated ( error )) return endif call set_string ( table , \"proj-dir\" , self % proj_dir , error , 'dependency_node_t' ) if ( allocated ( error )) return call set_string ( table , \"revision\" , self % revision , error , 'dependency_node_t' ) if ( allocated ( error )) return call set_value ( table , \"done\" , self % done , error , 'dependency_node_t' ) if ( allocated ( error )) return call set_value ( table , \"update\" , self % update , error , 'dependency_node_t' ) if ( allocated ( error )) return call set_value ( table , \"cached\" , self % cached , error , 'dependency_node_t' ) if ( allocated ( error )) return call set_list ( table , \"package-dep\" , self % package_dep , error ) if ( allocated ( error )) return end subroutine node_dump_to_toml !> Read dependency from toml table (no checks made at this stage) subroutine node_load_from_toml ( self , table , error ) !> Instance of the serializable object class ( dependency_node_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Local variables character ( len = :), allocatable :: version integer :: ierr , i , n type ( toml_array ), pointer :: array call destroy_dependency_node ( self ) ! Load parent class call self % dependency_config_t % load_from_toml ( table , error ) if ( allocated ( error )) return call get_value ( table , \"done\" , self % done , error , 'dependency_node_t' ) if ( allocated ( error )) return call get_value ( table , \"update\" , self % update , error , 'dependency_node_t' ) if ( allocated ( error )) return call get_value ( table , \"cached\" , self % cached , error , 'dependency_node_t' ) if ( allocated ( error )) return call get_value ( table , \"proj-dir\" , self % proj_dir ) call get_value ( table , \"revision\" , self % revision ) call get_value ( table , \"version\" , version ) if ( allocated ( version )) then allocate ( self % version ) call new_version ( self % version , version , error ) if ( allocated ( error )) then error % message = 'dependency_node_t: version error from TOML table - ' // error % message return endif end if call get_list ( table , \"package-dep\" , self % package_dep , error ) if ( allocated ( error )) return end subroutine node_load_from_toml !> Destructor elemental subroutine destroy_dependency_node ( self ) class ( dependency_node_t ), intent ( inout ) :: self integer :: ierr call dependency_destroy ( self ) deallocate ( self % version , stat = ierr ) deallocate ( self % proj_dir , stat = ierr ) deallocate ( self % revision , stat = ierr ) deallocate ( self % package_dep , stat = ierr ) self % done = . false . self % update = . false . self % cached = . false . end subroutine destroy_dependency_node !> Check that two dependency trees are equal logical function dependency_tree_is_same ( this , that ) class ( dependency_tree_t ), intent ( in ) :: this class ( serializable_t ), intent ( in ) :: that integer :: ii dependency_tree_is_same = . false . select type ( other => that ) type is ( dependency_tree_t ) if (. not .( this % unit == other % unit )) return if (. not .( this % verbosity == other % verbosity )) return if ( allocated ( this % dep_dir ) . neqv . allocated ( other % dep_dir )) return if ( allocated ( this % dep_dir )) then if (. not .( this % dep_dir == other % dep_dir )) return endif if (. not .( this % ndep == other % ndep )) return if (. not .( allocated ( this % dep ). eqv . allocated ( other % dep ))) return if ( allocated ( this % dep )) then if (. not .( size ( this % dep ) == size ( other % dep ))) return do ii = 1 , size ( this % dep ) if (. not .( this % dep ( ii ) == other % dep ( ii ))) return end do endif if ( allocated ( this % cache ) . neqv . allocated ( other % cache )) return if ( allocated ( this % cache )) then if (. not .( this % cache == other % cache )) return endif class default ! Not the same type return end select !> All checks passed! dependency_tree_is_same = . true . end function dependency_tree_is_same !> Dump dependency to toml table subroutine tree_dump_to_toml ( self , table , error ) !> Instance of the serializable object class ( dependency_tree_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: ierr , ii type ( toml_table ), pointer :: ptr_deps , ptr character ( 27 ) :: unnamed call set_value ( table , \"unit\" , self % unit , error , 'dependency_tree_t' ) if ( allocated ( error )) return call set_value ( table , \"verbosity\" , self % verbosity , error , 'dependency_tree_t' ) if ( allocated ( error )) return call set_string ( table , \"dep-dir\" , self % dep_dir , error , 'dependency_tree_t' ) if ( allocated ( error )) return call set_string ( table , \"cache\" , self % cache , error , 'dependency_tree_t' ) if ( allocated ( error )) return call set_value ( table , \"ndep\" , self % ndep , error , 'dependency_tree_t' ) if ( allocated ( error )) return if ( allocated ( self % dep )) then ! Create dependency table call add_table ( table , \"dependencies\" , ptr_deps ) if (. not . associated ( ptr_deps )) then call fatal_error ( error , \"dependency_tree_t cannot create dependency table \" ) return end if do ii = 1 , size ( self % dep ) associate ( dep => self % dep ( ii )) !> Because dependencies are named, fallback if this has no name !> So, serialization will work regardless of size(self%dep) == self%ndep if (. not . allocated ( dep % name )) then write ( unnamed , 1 ) ii call add_table ( ptr_deps , trim ( unnamed ), ptr ) else if ( len_trim ( dep % name ) == 0 ) then write ( unnamed , 1 ) ii call add_table ( ptr_deps , trim ( unnamed ), ptr ) else call add_table ( ptr_deps , dep % name , ptr ) end if if (. not . associated ( ptr )) then call fatal_error ( error , \"dependency_tree_t cannot create entry for dependency \" // dep % name ) return end if call dep % dump_to_toml ( ptr , error ) if ( allocated ( error )) return end associate end do endif 1 format ( 'UNNAMED_DEPENDENCY_' , i0 ) end subroutine tree_dump_to_toml !> Read dependency from toml table (no checks made at this stage) subroutine tree_load_from_toml ( self , table , error ) !> Instance of the serializable object class ( dependency_tree_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Local variables type ( toml_key ), allocatable :: keys (:), dep_keys (:) type ( toml_table ), pointer :: ptr_deps , ptr integer :: ii , jj , ierr call table % get_keys ( keys ) call get_value ( table , \"unit\" , self % unit , error , 'dependency_tree_t' ) if ( allocated ( error )) return call get_value ( table , \"verbosity\" , self % verbosity , error , 'dependency_tree_t' ) if ( allocated ( error )) return call get_value ( table , \"ndep\" , self % ndep , error , 'dependency_tree_t' ) if ( allocated ( error )) return call get_value ( table , \"dep-dir\" , self % dep_dir ) call get_value ( table , \"cache\" , self % cache ) find_deps_table : do ii = 1 , size ( keys ) if ( keys ( ii )% key == \"dependencies\" ) then call get_value ( table , keys ( ii ), ptr_deps ) if (. not . associated ( ptr_deps )) then call fatal_error ( error , 'dependency_tree_t: error retrieving dependency table from TOML table' ) return end if !> Read all dependencies call ptr_deps % get_keys ( dep_keys ) call resize ( self % dep , size ( dep_keys )) do jj = 1 , size ( dep_keys ) call get_value ( ptr_deps , dep_keys ( jj ), ptr ) call self % dep ( jj )% load_from_toml ( ptr , error ) if ( allocated ( error )) return end do exit find_deps_table endif end do find_deps_table end subroutine tree_load_from_toml end module fpm_dependency","tags":"","url":"sourcefile/dependency.f90.html"},{"title":"git.f90 – Fortran-lang/fpm","text":"Source Code !> Implementation for interacting with git repositories. module fpm_git use fpm_error , only : error_t , fatal_error use fpm_filesystem , only : get_temp_filename , getline , join_path , execute_and_read_output , run use tomlf , only : toml_table , toml_stat use fpm_toml , only : serializable_t , get_value , set_value , set_string implicit none public :: git_target_t , git_target_default , git_target_branch , git_target_tag , git_target_revision , git_revision , & & git_archive , git_matches_manifest , compressed_package_name !> Name of the compressed package that is generated temporarily. character ( len =* ), parameter :: compressed_package_name = 'compressed_package' !> Possible git target type :: enum_descriptor !> Default target integer :: default = 200 !> Branch in git repository integer :: branch = 201 !> Tag in git repository integer :: tag = 202 !> Commit hash integer :: revision = 203 !> Invalid descriptor integer :: error = - 999 end type enum_descriptor !> Actual enumerator for descriptors type ( enum_descriptor ), parameter :: git_descriptor = enum_descriptor () !> Description of an git target type , extends ( serializable_t ) :: git_target_t !> Kind of the git target integer :: descriptor = git_descriptor % default !> Target URL of the git repository character ( len = :), allocatable :: url !> Additional descriptor of the git object character ( len = :), allocatable :: object contains !> Fetch and checkout in local directory procedure :: checkout !> Show information on instance procedure :: info !> Serialization interface procedure :: serializable_is_same => git_is_same procedure :: dump_to_toml procedure :: load_from_toml end type git_target_t !> Common output format for writing to the command line character ( len =* ), parameter :: out_fmt = '(\"#\", *(1x, g0))' contains !> Default target function git_target_default ( url ) result ( self ) !> Target URL of the git repository character ( len =* ), intent ( in ) :: url !> New git target type ( git_target_t ) :: self self % descriptor = git_descriptor % default self % url = url end function git_target_default !> Target a branch in the git repository function git_target_branch ( url , branch ) result ( self ) !> Target URL of the git repository character ( len =* ), intent ( in ) :: url !> Name of the branch of interest character ( len =* ), intent ( in ) :: branch !> New git target type ( git_target_t ) :: self self % descriptor = git_descriptor % branch self % url = url self % object = branch end function git_target_branch !> Target a specific git revision function git_target_revision ( url , sha1 ) result ( self ) !> Target URL of the git repository character ( len =* ), intent ( in ) :: url !> Commit hash of interest character ( len =* ), intent ( in ) :: sha1 !> New git target type ( git_target_t ) :: self self % descriptor = git_descriptor % revision self % url = url self % object = sha1 end function git_target_revision !> Target a git tag function git_target_tag ( url , tag ) result ( self ) !> Target URL of the git repository character ( len =* ), intent ( in ) :: url !> Tag name of interest character ( len =* ), intent ( in ) :: tag !> New git target type ( git_target_t ) :: self self % descriptor = git_descriptor % tag self % url = url self % object = tag end function git_target_tag !> Check that two git targets are equal logical function git_is_same ( this , that ) class ( git_target_t ), intent ( in ) :: this class ( serializable_t ), intent ( in ) :: that git_is_same = . false . select type ( other => that ) type is ( git_target_t ) if (. not .( this % descriptor == other % descriptor )) return if ( allocated ( this % url ) . neqv . allocated ( other % url )) return if ( allocated ( this % url )) then if (. not .( this % url == other % url )) return end if if ( allocated ( this % object ) . neqv . allocated ( other % object )) return if ( allocated ( this % object )) then if (. not .( this % object == other % object )) return end if class default ! Not the same type return end select !> All checks passed! git_is_same = . true . end function git_is_same !> Check that a cached dependency matches a manifest request logical function git_matches_manifest ( cached , manifest , verbosity , iunit ) !> Two input git targets type ( git_target_t ), intent ( in ) :: cached , manifest integer , intent ( in ) :: verbosity , iunit git_matches_manifest = cached % url == manifest % url if (. not . git_matches_manifest ) then if ( verbosity > 1 ) write ( iunit , out_fmt ) \"GIT URL has changed: \" , cached % url , \" vs. \" , manifest % url return endif !> The manifest dependency only contains partial information (what's requested), !> while the cached dependency always stores a commit hash because it's built !> after the repo is available (saved as git_descriptor%revision==revision). !> So, comparing against the descriptor is not reliable git_matches_manifest = allocated ( cached % object ) . eqv . allocated ( manifest % object ) if ( git_matches_manifest . and . allocated ( cached % object )) & git_matches_manifest = cached % object == manifest % object if (. not . git_matches_manifest ) then if ( verbosity > 1 ) write ( iunit , out_fmt ) \"GIT OBJECT has changed: \" , cached % object , \" vs. \" , manifest % object end if end function git_matches_manifest subroutine checkout ( self , local_path , error ) !> Instance of the git target class ( git_target_t ), intent ( in ) :: self !> Local path to checkout in character ( * ), intent ( in ) :: local_path !> Error type ( error_t ), allocatable , intent ( out ) :: error integer :: stat character ( len = :), allocatable :: object , workdir if ( allocated ( self % object )) then object = self % object else object = 'HEAD' end if workdir = \"--work-tree=\" // local_path // \" --git-dir=\" // join_path ( local_path , \".git\" ) call execute_command_line ( \"git init \" // local_path , exitstat = stat ) if ( stat /= 0 ) then call fatal_error ( error , 'Error while initiating git repository for remote dependency' ) return end if call execute_command_line ( \"git \" // workdir // \" fetch --depth=1 \" // & self % url // \" \" // object , exitstat = stat ) if ( stat /= 0 ) then call fatal_error ( error , 'Error while fetching git repository for remote dependency' ) return end if call execute_command_line ( \"git \" // workdir // \" checkout -qf FETCH_HEAD\" , exitstat = stat ) if ( stat /= 0 ) then call fatal_error ( error , 'Error while checking out git repository for remote dependency' ) return end if end subroutine checkout subroutine git_revision ( local_path , object , error ) !> Local path to checkout in character ( * ), intent ( in ) :: local_path !> Git object reference character ( len = :), allocatable , intent ( out ) :: object !> Error type ( error_t ), allocatable , intent ( out ) :: error integer :: stat , unit , istart , iend character ( len = :), allocatable :: temp_file , line , iomsg , workdir character ( len =* ), parameter :: hexdigits = '0123456789abcdef' workdir = \"--work-tree=\" // local_path // \" --git-dir=\" // join_path ( local_path , \".git\" ) allocate ( temp_file , source = get_temp_filename ()) line = \"git \" // workdir // \" log -n 1 > \" // temp_file call execute_command_line ( line , exitstat = stat ) if ( stat /= 0 ) then call fatal_error ( error , \"Error while retrieving commit information\" ) return end if open ( file = temp_file , newunit = unit ) call getline ( unit , line , stat , iomsg ) if ( stat /= 0 ) then call fatal_error ( error , iomsg ) return end if close ( unit , status = \"delete\" ) ! Tokenize: ! commit 0123456789abcdef (HEAD, ...) istart = scan ( line , ' ' ) + 1 iend = verify ( line ( istart :), hexdigits ) + istart - 1 if ( iend < istart ) iend = len ( line ) object = line ( istart : iend ) end subroutine git_revision !> Show information on git target subroutine info ( self , unit , verbosity ) !> Instance of the git target class ( git_target_t ), intent ( in ) :: self !> Unit for IO integer , intent ( in ) :: unit !> Verbosity of the printout integer , intent ( in ), optional :: verbosity integer :: pr character ( len =* ), parameter :: fmt = '(\"#\", 1x, a, t30, a)' if ( present ( verbosity )) then pr = verbosity else pr = 1 end if if ( pr < 1 ) return write ( unit , fmt ) \"Git target\" if ( allocated ( self % url )) then write ( unit , fmt ) \"- URL\" , self % url end if if ( allocated ( self % object )) then select case ( self % descriptor ) case default write ( unit , fmt ) \"- object\" , self % object case ( git_descriptor % tag ) write ( unit , fmt ) \"- tag\" , self % object case ( git_descriptor % branch ) write ( unit , fmt ) \"- branch\" , self % object case ( git_descriptor % revision ) write ( unit , fmt ) \"- sha1\" , self % object end select end if end subroutine info !> Dump dependency to toml table subroutine dump_to_toml ( self , table , error ) !> Instance of the serializable object class ( git_target_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: ierr call set_string ( table , \"descriptor\" , descriptor_name ( self % descriptor ), error , 'git_target_t' ) if ( allocated ( error )) return call set_string ( table , \"url\" , self % url , error , 'git_target_t' ) if ( allocated ( error )) return call set_string ( table , \"object\" , self % object , error , 'git_target_t' ) if ( allocated ( error )) return end subroutine dump_to_toml !> Read dependency from toml table (no checks made at this stage) subroutine load_from_toml ( self , table , error ) !> Instance of the serializable object class ( git_target_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Local variables character ( len = :), allocatable :: descriptor_name call get_value ( table , \"descriptor\" , descriptor_name ) self % descriptor = parse_descriptor ( descriptor_name ) if ( self % descriptor == git_descriptor % error ) then call fatal_error ( error , \"invalid descriptor ID <\" // descriptor_name // \"> in TOML entry\" ) return end if !> Target URL of the git repository call get_value ( table , \"url\" , self % url ) !> Additional descriptor of the git object call get_value ( table , \"object\" , self % object ) end subroutine load_from_toml !> Parse git descriptor identifier from a string pure integer function parse_descriptor ( name ) character ( len =* ), intent ( in ) :: name select case ( name ) case ( \"default\" ); parse_descriptor = git_descriptor % default case ( \"branch\" ); parse_descriptor = git_descriptor % branch case ( \"tag\" ); parse_descriptor = git_descriptor % tag case ( \"revision\" ); parse_descriptor = git_descriptor % revision case default ; parse_descriptor = git_descriptor % error end select end function parse_descriptor !> Code git descriptor to a string pure function descriptor_name ( descriptor ) result ( name ) integer , intent ( in ) :: descriptor character ( len = :), allocatable :: name select case ( descriptor ) case ( git_descriptor % default ); name = \"default\" case ( git_descriptor % branch ); name = \"branch\" case ( git_descriptor % tag ); name = \"tag\" case ( git_descriptor % revision ); name = \"revision\" case default ; name = \"ERROR\" end select end function descriptor_name !> Archive a folder using `git archive`. subroutine git_archive ( source , destination , ref , additional_files , verbose , error ) !> Directory to archive. character ( * ), intent ( in ) :: source !> Destination of the archive. character ( * ), intent ( in ) :: destination !> (Symbolic) Reference to be archived. character ( * ), intent ( in ) :: ref !> (Optional) list of additional untracked files to be added to the archive. character ( * ), optional , intent ( in ) :: additional_files (:) !> Print additional information if true. logical , intent ( in ) :: verbose !> Error handling. type ( error_t ), allocatable , intent ( out ) :: error integer :: stat , i character ( len = :), allocatable :: cmd_output , archive_format , add_files call execute_and_read_output ( 'git archive -l' , cmd_output , error , verbose ) if ( allocated ( error )) return if ( index ( cmd_output , 'tar.gz' ) /= 0 ) then archive_format = 'tar.gz' else call fatal_error ( error , \"Cannot find a suitable archive format for 'git archive'.\" ); return end if allocate ( character ( len = 0 ) :: add_files ) if ( present ( additional_files )) then do i = 1 , size ( additional_files ) add_files = trim ( add_files ) // ' --add-file=' // adjustl ( additional_files ( i )) end do endif call run ( 'git archive ' // ref // ' & & --format=' // archive_format // & & add_files // ' & & -o ' // destination , & & echo = verbose , & & exitstat = stat ) if ( stat /= 0 ) then call fatal_error ( error , \"Error packing '\" // source // \"'.\" ); return end if end end module fpm_git","tags":"","url":"sourcefile/git.f90.html"},{"title":"meta.f90 – Fortran-lang/fpm","text":"Source Code !> Implementation of the metapackage configuration data. !> !> A metapackage table can currently have the following fields !> !>```toml !>[metapackages] !>fpm = \"0.1.0\" !>openmp = bool !>stdlib = bool !>``` module fpm_manifest_metapackages use fpm_error , only : error_t , fatal_error , syntax_error use tomlf , only : toml_table , toml_key , toml_stat use fpm_toml , only : get_value use fpm_environment implicit none private public :: metapackage_config_t , new_meta_config , is_meta_package public :: metapackage_request_t , new_meta_request !> Configuration data for a single metapackage request type :: metapackage_request_t !> Request flag logical :: on = . false . !> Metapackage name character ( len = :), allocatable :: name !> Version Specification string character ( len = :), allocatable :: version end type metapackage_request_t !> Configuration data for metapackages type :: metapackage_config_t !> Request MPI support type ( metapackage_request_t ) :: mpi !> Request OpenMP support type ( metapackage_request_t ) :: openmp !> Request stdlib support type ( metapackage_request_t ) :: stdlib !> fortran-lang minpack type ( metapackage_request_t ) :: minpack !> HDF5 type ( metapackage_request_t ) :: hdf5 !> NetCDF type ( metapackage_request_t ) :: netcdf !> BLAS type ( metapackage_request_t ) :: blas contains procedure :: get_requests end type metapackage_config_t contains !> Destroy a metapackage request elemental subroutine request_destroy ( self ) !> Instance of the request class ( metapackage_request_t ), intent ( inout ) :: self self % on = . false . if ( allocated ( self % version )) deallocate ( self % version ) if ( allocated ( self % name )) deallocate ( self % name ) end subroutine request_destroy !> Parse version string of a metapackage request subroutine request_parse ( self , version_request , error ) ! Instance of this metapackage type ( metapackage_request_t ), intent ( inout ) :: self ! Parse version request character ( len =* ), intent ( in ) :: version_request ! Error message type ( error_t ), allocatable , intent ( out ) :: error ! wildcard = use any versions if ( version_request == \"*\" ) then ! Any version is OK self % on = . true . self % version = version_request else call fatal_error ( error , 'Value <' // version_request // '> for metapackage ' // self % name // & 'is not currently supported. Try \"*\" instead. ' ) return end if end subroutine request_parse !> Construct a new metapackage request from the dependencies table subroutine new_meta_request ( self , key , table , meta_allowed , error ) type ( metapackage_request_t ), intent ( out ) :: self !> The package name character ( len =* ), intent ( in ) :: key !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> List of keys allowed to be metapackages logical , intent ( in ), optional :: meta_allowed (:) !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: stat , i character ( len = :), allocatable :: value logical , allocatable :: allow_meta (:) type ( toml_key ), allocatable :: keys (:) call request_destroy ( self ) !> Set name self % name = key if (. not . is_meta_package ( key )) then call fatal_error ( error , \"Error reading fpm.toml: <\" // key // \"> is not a valid metapackage name\" ) return end if !> The toml table is not checked here because it already passed !> the \"new_dependencies\" check call table % get_keys ( keys ) !> Set list of entries that are allowed to be metapackages if ( present ( meta_allowed )) then if ( size ( meta_allowed ) /= size ( keys )) then call fatal_error ( error , \"Internal error: list of metapackage-enable entries does not match table size\" ) return end if allow_meta = meta_allowed else allocate ( allow_meta ( size ( keys )), source = . true .) endif do i = 1 , size ( keys ) ! Skip standard dependencies if (. not . allow_meta ( i )) cycle if ( keys ( i )% key == key ) then call get_value ( table , key , value ) if (. not . allocated ( value )) then call syntax_error ( error , \"Could not retrieve version string for metapackage key <\" // key // \">. Check syntax\" ) return else call request_parse ( self , value , error ) return endif end if end do ! Key is not present, metapackage not requested return end subroutine new_meta_request !> Construct a new build configuration from a TOML data structure subroutine new_meta_config ( self , table , meta_allowed , error ) !> Instance of the build configuration type ( metapackage_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> List of keys allowed to be metapackages logical , intent ( in ) :: meta_allowed (:) !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: stat !> The toml table is not checked here because it already passed !> the \"new_dependencies\" check call new_meta_request ( self % openmp , \"openmp\" , table , meta_allowed , error ) if ( allocated ( error )) return call new_meta_request ( self % stdlib , \"stdlib\" , table , meta_allowed , error ) if ( allocated ( error )) return call new_meta_request ( self % minpack , \"minpack\" , table , meta_allowed , error ) if ( allocated ( error )) return call new_meta_request ( self % mpi , \"mpi\" , table , meta_allowed , error ) if ( allocated ( error )) return call new_meta_request ( self % hdf5 , \"hdf5\" , table , meta_allowed , error ) if ( allocated ( error )) return call new_meta_request ( self % netcdf , \"netcdf\" , table , meta_allowed , error ) if ( allocated ( error )) return call new_meta_request ( self % blas , \"blas\" , table , meta_allowed , error ) if ( allocated ( error )) return end subroutine new_meta_config !> Check local schema for allowed entries logical function is_meta_package ( key ) !> Instance of the TOML data structure character ( * ), intent ( in ) :: key select case ( key ) !> Supported metapackages case ( \"openmp\" , \"stdlib\" , \"mpi\" , \"minpack\" , \"hdf5\" , \"netcdf\" , \"blas\" ) is_meta_package = . true . case default is_meta_package = . false . end select end function is_meta_package !> Return a list of metapackages requested for the current build function get_requests ( meta ) result ( requests ) !> Instance of the build configuration class ( metapackage_config_t ), intent ( in ) :: meta !> The list of requested metapackages (always allocated) type ( metapackage_request_t ), allocatable :: requests (:) integer :: nreq !> Count requests nreq = 0 if ( meta % mpi % on ) nreq = nreq + 1 if ( meta % openmp % on ) nreq = nreq + 1 if ( meta % stdlib % on ) nreq = nreq + 1 if ( meta % minpack % on ) nreq = nreq + 1 if ( meta % hdf5 % on ) nreq = nreq + 1 if ( meta % netcdf % on ) nreq = nreq + 1 if ( meta % blas % on ) nreq = nreq + 1 !> Prepare requests allocate ( requests ( nreq )); if ( nreq <= 0 ) return nreq = 0 if ( meta % mpi % on ) then nreq = nreq + 1 requests ( nreq ) = meta % mpi end if if ( meta % openmp % on ) then nreq = nreq + 1 requests ( nreq ) = meta % openmp end if if ( meta % stdlib % on ) then nreq = nreq + 1 requests ( nreq ) = meta % stdlib end if if ( meta % minpack % on ) then nreq = nreq + 1 requests ( nreq ) = meta % minpack end if if ( meta % hdf5 % on ) then nreq = nreq + 1 requests ( nreq ) = meta % hdf5 end if if ( meta % netcdf % on ) then nreq = nreq + 1 requests ( nreq ) = meta % netcdf end if if ( meta % blas % on ) then nreq = nreq + 1 requests ( nreq ) = meta % blas end if end function get_requests end module fpm_manifest_metapackages","tags":"","url":"sourcefile/meta.f90.html"},{"title":"fpm_os.F90 – Fortran-lang/fpm","text":"Source Code module fpm_os use , intrinsic :: iso_c_binding , only : c_char , c_int , c_null_char , c_ptr , c_associated use fpm_filesystem , only : exists , join_path , get_home use fpm_environment , only : os_is_unix use fpm_error , only : error_t , fatal_error implicit none private public :: change_directory , get_current_directory , get_absolute_path , convert_to_absolute_path , & & get_absolute_path_by_cd integer ( c_int ), parameter :: buffersize = 1000_c_int #ifndef _WIN32 character ( len =* ), parameter :: pwd_env = \"PWD\" #else character ( len =* ), parameter :: pwd_env = \"CD\" #endif interface function chdir_ ( path ) result ( stat ) & #ifndef _WIN32 bind ( C , name = \"chdir\" ) #else bind ( C , name = \"_chdir\" ) #endif import :: c_char , c_int character ( kind = c_char , len = 1 ), intent ( in ) :: path ( * ) integer ( c_int ) :: stat end function chdir_ function getcwd_ ( buf , bufsize ) result ( path ) & #ifndef _WIN32 bind ( C , name = \"getcwd\" ) #else bind ( C , name = \"_getcwd\" ) #endif import :: c_char , c_int , c_ptr character ( kind = c_char , len = 1 ), intent ( in ) :: buf ( * ) integer ( c_int ), value , intent ( in ) :: bufsize type ( c_ptr ) :: path end function getcwd_ !> Determine the absolute, canonicalized path for a given path. Unix-only. function realpath ( path , resolved_path ) result ( ptr ) bind ( C ) import :: c_ptr , c_char , c_int character ( kind = c_char , len = 1 ), intent ( in ) :: path ( * ) character ( kind = c_char , len = 1 ), intent ( out ) :: resolved_path ( * ) type ( c_ptr ) :: ptr end function realpath !> Determine the absolute, canonicalized path for a given path. Windows-only. function fullpath ( resolved_path , path , maxLength ) result ( ptr ) bind ( C , name = \"_fullpath\" ) import :: c_ptr , c_char , c_int character ( kind = c_char , len = 1 ), intent ( in ) :: path ( * ) character ( kind = c_char , len = 1 ), intent ( out ) :: resolved_path ( * ) integer ( c_int ), value , intent ( in ) :: maxLength type ( c_ptr ) :: ptr end function fullpath !> Determine the absolute, canonicalized path for a given path. !> Calls custom C routine because the `_WIN32` macro is correctly exported !> in C using `gfortran`. function c_realpath ( path , resolved_path , maxLength ) result ( ptr ) & bind ( C , name = \"c_realpath\" ) import :: c_ptr , c_char , c_int character ( kind = c_char , len = 1 ), intent ( in ) :: path ( * ) character ( kind = c_char , len = 1 ), intent ( out ) :: resolved_path ( * ) integer ( c_int ), value , intent ( in ) :: maxLength type ( c_ptr ) :: ptr end function c_realpath end interface contains subroutine change_directory ( path , error ) character ( len =* ), intent ( in ) :: path type ( error_t ), allocatable , intent ( out ) :: error character ( kind = c_char , len = 1 ), allocatable :: cpath (:) integer :: stat allocate ( cpath ( len ( path ) + 1 )) call f_c_character ( path , cpath , len ( path ) + 1 ) stat = chdir_ ( cpath ) if ( stat /= 0 ) then call fatal_error ( error , \"Failed to change directory to '\" // path // \"'\" ) end if end subroutine change_directory subroutine get_current_directory ( path , error ) character ( len = :), allocatable , intent ( out ) :: path type ( error_t ), allocatable , intent ( out ) :: error character ( kind = c_char , len = 1 ), allocatable :: cpath (:) type ( c_ptr ) :: tmp allocate ( cpath ( buffersize )) tmp = getcwd_ ( cpath , buffersize ) if ( c_associated ( tmp )) then call c_f_character ( cpath , path ) else call fatal_error ( error , \"Failed to retrieve current directory\" ) end if end subroutine get_current_directory subroutine f_c_character ( rhs , lhs , len ) character ( kind = c_char ), intent ( out ) :: lhs ( * ) character ( len =* ), intent ( in ) :: rhs integer , intent ( in ) :: len integer :: length length = min ( len - 1 , len_trim ( rhs )) lhs ( 1 : length ) = transfer ( rhs ( 1 : length ), lhs ( 1 : length )) lhs ( length + 1 : length + 1 ) = c_null_char end subroutine f_c_character subroutine c_f_character ( rhs , lhs ) character ( kind = c_char ), intent ( in ) :: rhs ( * ) character ( len = :), allocatable , intent ( out ) :: lhs integer :: ii do ii = 1 , huge ( ii ) - 1 if ( rhs ( ii ) == c_null_char ) then exit end if end do allocate ( character ( len = ii - 1 ) :: lhs ) lhs = transfer ( rhs ( 1 : ii - 1 ), lhs ) end subroutine c_f_character !> Determine the canonical, absolute path for the given path. !> !> Calls a C routine that uses the `_WIN32` macro to determine the correct function. !> !> Cannot be used in bootstrap mode. subroutine get_realpath ( path , real_path , error ) character ( len =* ), intent ( in ) :: path character ( len = :), allocatable , intent ( out ) :: real_path type ( error_t ), allocatable , intent ( out ) :: error character ( kind = c_char , len = 1 ), allocatable :: appended_path (:) character ( kind = c_char , len = 1 ), allocatable :: cpath (:) type ( c_ptr ) :: ptr if (. not . exists ( path )) then call fatal_error ( error , \"Cannot determine absolute path. Path '\" // path // \"' does not exist.\" ) return end if allocate ( appended_path ( len ( path ) + 1 )) call f_c_character ( path , appended_path , len ( path ) + 1 ) allocate ( cpath ( buffersize )) #ifndef FPM_BOOTSTRAP ptr = c_realpath ( appended_path , cpath , buffersize ) #endif if ( c_associated ( ptr )) then call c_f_character ( cpath , real_path ) else call fatal_error ( error , \"Failed to retrieve absolute path for '\" // path // \"'.\" ) end if end subroutine !> Determine the canonical, absolute path for the given path. !> Expands home folder (~) on both Unix and Windows. subroutine get_absolute_path ( path , absolute_path , error ) character ( len =* ), intent ( in ) :: path character ( len = :), allocatable , intent ( out ) :: absolute_path type ( error_t ), allocatable , intent ( out ) :: error character ( len = :), allocatable :: home #ifdef FPM_BOOTSTRAP call get_absolute_path_by_cd ( path , absolute_path , error ); return #endif if ( len_trim ( path ) < 1 ) then call fatal_error ( error , 'Path cannot be empty' ); return else if ( path ( 1 : 1 ) == '~' ) then call get_home ( home , error ) if ( allocated ( error )) return if ( len_trim ( path ) == 1 ) then absolute_path = home ; return end if if ( os_is_unix ()) then if ( path ( 2 : 2 ) /= '/' ) then call fatal_error ( error , \"Wrong separator in path: '\" // path // \"'\" ); return end if else if ( path ( 2 : 2 ) /= '\\') then call fatal_error(error, \"Wrong separator in path: ' \"//path//\" '\"); return end if end if if (len_trim(path) == 2) then absolute_path = home; return end if absolute_path = join_path(home, path(3:len_trim(path))) if (.not. exists(absolute_path)) then call fatal_error(error, \"Path not found: ' \"//absolute_path//\" '\" ); return end if else ! Get canonicalized absolute path from either the absolute or the relative path. call get_realpath ( path , absolute_path , error ) end if end subroutine !> Alternative to `get_absolute_path` that uses `chdir`/`_chdir` to determine the absolute path. !> !> `get_absolute_path` is preferred but `get_absolute_path_by_cd` can be used in bootstrap mode. subroutine get_absolute_path_by_cd ( path , absolute_path , error ) character ( len =* ), intent ( in ) :: path character ( len = :), allocatable , intent ( out ) :: absolute_path type ( error_t ), allocatable , intent ( out ) :: error character ( len = :), allocatable :: current_path call get_current_directory ( current_path , error ) if ( allocated ( error )) return call change_directory ( path , error ) if ( allocated ( error )) return call get_current_directory ( absolute_path , error ) if ( allocated ( error )) return call change_directory ( current_path , error ) if ( allocated ( error )) return end subroutine !> Converts a path to an absolute, canonical path. subroutine convert_to_absolute_path ( path , error ) character ( len = :), allocatable , intent ( inout ) :: path type ( error_t ), allocatable , intent ( out ) :: error character ( len = :), allocatable :: absolute_path call get_absolute_path ( path , absolute_path , error ) path = absolute_path end subroutine end module fpm_os","tags":"","url":"sourcefile/fpm_os.f90.html"},{"title":"fortran.f90 – Fortran-lang/fpm","text":"Source Code module fpm_manifest_fortran use fpm_error , only : error_t , syntax_error , fatal_error use tomlf , only : toml_table , toml_key , toml_stat use fpm_toml , only : get_value , serializable_t , set_value , set_string implicit none private public :: fortran_config_t , new_fortran_config !> Configuration data for Fortran type , extends ( serializable_t ) :: fortran_config_t !> Enable default implicit typing logical :: implicit_typing = . false . !> Enable implicit external interfaces logical :: implicit_external = . false . !> Form to use for all Fortran sources character (:), allocatable :: source_form contains !> Serialization interface procedure :: serializable_is_same => fortran_is_same procedure :: dump_to_toml procedure :: load_from_toml end type fortran_config_t character ( len =* ), parameter , private :: class_name = 'fortran_config_t' contains !> Construct a new build configuration from a TOML data structure subroutine new_fortran_config ( self , table , error ) !> Instance of the fortran configuration type ( fortran_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: stat character (:), allocatable :: source_form call check ( table , error ) if ( allocated ( error )) return call get_value ( table , \"implicit-typing\" , self % implicit_typing , . false ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error while reading value for 'implicit-typing' in fpm.toml, expecting logical\" ) return end if call get_value ( table , \"implicit-external\" , self % implicit_external , . false ., stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error while reading value for 'implicit-external' in fpm.toml, expecting logical\" ) return end if call get_value ( table , \"source-form\" , source_form , \"free\" , stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Error while reading value for 'source-form' in fpm.toml, expecting logical\" ) return end if select case ( source_form ) case default call fatal_error ( error , \"Value of source-form cannot be '\" // source_form // \"'\" ) return case ( \"free\" , \"fixed\" , \"default\" ) self % source_form = source_form end select end subroutine new_fortran_config !> Check local schema for allowed entries subroutine check ( table , error ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_key ), allocatable :: list (:) integer :: ikey call table % get_keys ( list ) ! table can be empty if ( size ( list ) < 1 ) return do ikey = 1 , size ( list ) select case ( list ( ikey )% key ) case ( \"implicit-typing\" , \"implicit-external\" , \"source-form\" ) continue case default call syntax_error ( error , \"Key \" // list ( ikey )% key // \" is not allowed in fortran\" ) exit end select end do end subroutine check logical function fortran_is_same ( this , that ) class ( fortran_config_t ), intent ( in ) :: this class ( serializable_t ), intent ( in ) :: that fortran_is_same = . false . select type ( other => that ) type is ( fortran_config_t ) if ( this % implicit_typing . neqv . other % implicit_typing ) return if ( this % implicit_external . neqv . other % implicit_external ) return if ( allocated ( this % source_form ). neqv . allocated ( other % source_form )) return if ( allocated ( this % source_form )) then if (. not . this % source_form == other % source_form ) return end if class default ! Not the same type return end select !> All checks passed! fortran_is_same = . true . end function fortran_is_same !> Dump install config to toml table subroutine dump_to_toml ( self , table , error ) !> Instance of the serializable object class ( fortran_config_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error call set_value ( table , \"implicit-typing\" , self % implicit_typing , error , class_name ) if ( allocated ( error )) return call set_value ( table , \"implicit-external\" , self % implicit_external , error , class_name ) if ( allocated ( error )) return call set_string ( table , \"source-form\" , self % source_form , error , class_name ) if ( allocated ( error )) return end subroutine dump_to_toml !> Read install config from toml table (no checks made at this stage) subroutine load_from_toml ( self , table , error ) !> Instance of the serializable object class ( fortran_config_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error call get_value ( table , \"implicit-typing\" , self % implicit_typing , error , class_name ) if ( allocated ( error )) return call get_value ( table , \"implicit-external\" , self % implicit_external , error , class_name ) if ( allocated ( error )) return call get_value ( table , \"source-form\" , self % source_form ) end subroutine load_from_toml end module fpm_manifest_fortran","tags":"","url":"sourcefile/fortran.f90.html"},{"title":"test.f90 – Fortran-lang/fpm","text":"Source Code !> Implementation of the meta data for a test. !> !> The test data structure is effectively a decorated version of an executable !> and shares most of its properties, except for the defaults and can be !> handled under most circumstances just like any other executable. !> !> A test table can currently have the following fields !> !>```toml !>[[ test ]] !>name = \"string\" !>source-dir = \"path\" !>main = \"file\" !>link = [\"lib\"] !>[test.dependencies] !>``` module fpm_manifest_test use fpm_manifest_dependency , only : new_dependencies use fpm_manifest_executable , only : executable_config_t use fpm_error , only : error_t , syntax_error , bad_name_error use tomlf , only : toml_table , toml_key , toml_stat use fpm_toml , only : get_value , get_list implicit none private public :: test_config_t , new_test !> Configuation meta data for an test type , extends ( executable_config_t ) :: test_config_t contains !> Print information on this instance procedure :: info end type test_config_t contains !> Construct a new test configuration from a TOML data structure subroutine new_test ( self , table , error ) !> Instance of the test configuration type ( test_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_table ), pointer :: child call check ( table , error ) if ( allocated ( error )) return call get_value ( table , \"name\" , self % name ) if (. not . allocated ( self % name )) then call syntax_error ( error , \"Could not retrieve test name\" ) return end if if ( bad_name_error ( error , 'test' , self % name )) then return endif call get_value ( table , \"source-dir\" , self % source_dir , \"test\" ) call get_value ( table , \"main\" , self % main , \"main.f90\" ) call get_value ( table , \"dependencies\" , child , requested = . false .) if ( associated ( child )) then call new_dependencies ( self % dependency , child , error = error ) if ( allocated ( error )) return end if call get_list ( table , \"link\" , self % link , error ) if ( allocated ( error )) return end subroutine new_test !> Check local schema for allowed entries subroutine check ( table , error ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_key ), allocatable :: list (:) logical :: name_present integer :: ikey name_present = . false . call table % get_keys ( list ) if ( size ( list ) < 1 ) then call syntax_error ( error , \"Test section does not provide sufficient entries\" ) return end if do ikey = 1 , size ( list ) select case ( list ( ikey )% key ) case default call syntax_error ( error , \"Key \" // list ( ikey )% key // \" is not allowed in test entry\" ) exit case ( \"name\" ) name_present = . true . case ( \"source-dir\" , \"main\" , \"dependencies\" , \"link\" ) continue end select end do if ( allocated ( error )) return if (. not . name_present ) then call syntax_error ( error , \"Test name is not provided, please add a name entry\" ) end if end subroutine check !> Write information on instance subroutine info ( self , unit , verbosity ) !> Instance of the test configuration class ( test_config_t ), intent ( in ) :: self !> Unit for IO integer , intent ( in ) :: unit !> Verbosity of the printout integer , intent ( in ), optional :: verbosity integer :: pr , ii character ( len =* ), parameter :: fmt = '(\"#\", 1x, a, t30, a)' , & & fmti = '(\"#\", 1x, a, t30, i0)' if ( present ( verbosity )) then pr = verbosity else pr = 1 end if if ( pr < 1 ) return write ( unit , fmt ) \"Test target\" if ( allocated ( self % name )) then write ( unit , fmt ) \"- name\" , self % name end if if ( allocated ( self % source_dir )) then if ( self % source_dir /= \"test\" . or . pr > 2 ) then write ( unit , fmt ) \"- source directory\" , self % source_dir end if end if if ( allocated ( self % main )) then if ( self % main /= \"main.f90\" . or . pr > 2 ) then write ( unit , fmt ) \"- test source\" , self % main end if end if if ( allocated ( self % dependency )) then if ( size ( self % dependency ) > 1 . or . pr > 2 ) then write ( unit , fmti ) \"- dependencies\" , size ( self % dependency ) end if do ii = 1 , size ( self % dependency ) call self % dependency ( ii )% info ( unit , pr - 1 ) end do end if end subroutine info end module fpm_manifest_test","tags":"","url":"sourcefile/test.f90.html"},{"title":"install.f90 – Fortran-lang/fpm","text":"Source Code !> Implementation of the installation configuration. !> !> An install table can currently have the following fields !> !>```toml !>library = bool !>``` module fpm_manifest_install use fpm_error , only : error_t , fatal_error , syntax_error use tomlf , only : toml_table , toml_key , toml_stat use fpm_toml , only : get_value , set_value , serializable_t implicit none private public :: install_config_t , new_install_config !> Configuration data for installation type , extends ( serializable_t ) :: install_config_t !> Install library with this project logical :: library = . false . !> Install tests with this project logical :: test = . false . contains !> Print information on this instance procedure :: info !> Serialization interface procedure :: serializable_is_same => install_conf_same procedure :: dump_to_toml procedure :: load_from_toml end type install_config_t character ( * ), parameter , private :: class_name = 'install_config_t' contains !> Create a new installation configuration from a TOML data structure subroutine new_install_config ( self , table , error ) !> Instance of the install configuration type ( install_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error call check ( table , error ) if ( allocated ( error )) return call get_value ( table , \"library\" , self % library , . false .) call get_value ( table , \"test\" , self % test , . false .) end subroutine new_install_config !> Check local schema for allowed entries subroutine check ( table , error ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_key ), allocatable :: list (:) integer :: ikey call table % get_keys ( list ) if ( size ( list ) < 1 ) return do ikey = 1 , size ( list ) select case ( list ( ikey )% key ) case default call syntax_error ( error , \"Key \" // list ( ikey )% key // \" is not allowed in install table\" ) exit case ( \"library\" , \"test\" ) continue end select end do if ( allocated ( error )) return end subroutine check !> Write information on install configuration instance subroutine info ( self , unit , verbosity ) !> Instance of the build configuration class ( install_config_t ), intent ( in ) :: self !> Unit for IO integer , intent ( in ) :: unit !> Verbosity of the printout integer , intent ( in ), optional :: verbosity integer :: pr character ( len =* ), parameter :: fmt = '(\"#\", 1x, a, t30, a)' if ( present ( verbosity )) then pr = verbosity else pr = 1 end if if ( pr < 1 ) return write ( unit , fmt ) \"Install configuration\" write ( unit , fmt ) \" - library install\" , trim ( merge ( \"enabled \" , \"disabled\" , self % library )) write ( unit , fmt ) \" - test install\" , trim ( merge ( \"enabled \" , \"disabled\" , self % test )) end subroutine info logical function install_conf_same ( this , that ) class ( install_config_t ), intent ( in ) :: this class ( serializable_t ), intent ( in ) :: that install_conf_same = . false . select type ( other => that ) type is ( install_config_t ) if ( this % library . neqv . other % library ) return if ( this % test . neqv . other % test ) return class default ! Not the same type return end select !> All checks passed! install_conf_same = . true . end function install_conf_same !> Dump install config to toml table subroutine dump_to_toml ( self , table , error ) !> Instance of the serializable object class ( install_config_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error call set_value ( table , \"library\" , self % library , error , class_name ) if ( allocated ( error )) return call set_value ( table , \"test\" , self % test , error , class_name ) if ( allocated ( error )) return end subroutine dump_to_toml !> Read install config from toml table (no checks made at this stage) subroutine load_from_toml ( self , table , error ) !> Instance of the serializable object class ( install_config_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: stat call get_value ( table , \"library\" , self % library , error , class_name ) if ( allocated ( error )) return call get_value ( table , \"test\" , self % test , error , class_name ) if ( allocated ( error )) return end subroutine load_from_toml end module fpm_manifest_install","tags":"","url":"sourcefile/install.f90.html"},{"title":"fpm_meta.f90 – Fortran-lang/fpm","text":"Source Code !># The fpm meta-package model !> !> This is a wrapper data type that encapsulate all pre-processing information !> (compiler flags, linker libraries, etc.) required to correctly enable a package !> to use a core library. !> !> !>### Available core libraries !> !> - OpenMP !> - MPI !> - HDF5 !> - fortran-lang stdlib !> - fortran-lang minpack !> !> !> @note Core libraries are enabled in the [build] section of the fpm.toml manifest !> !> module fpm_meta use fpm_compiler , only : compiler_t use fpm_manifest , only : package_config_t use fpm_model , only : fpm_model_t use fpm_command_line , only : fpm_cmd_settings , fpm_build_settings , fpm_run_settings use fpm_error , only : error_t , syntax_error , fatal_error use fpm_meta_base , only : metapackage_t , destroy use fpm_meta_openmp , only : init_openmp use fpm_meta_stdlib , only : init_stdlib use fpm_meta_minpack , only : init_minpack use fpm_meta_mpi , only : init_mpi use fpm_meta_hdf5 , only : init_hdf5 use fpm_meta_netcdf , only : init_netcdf use fpm_meta_blas , only : init_blas use fpm_manifest_metapackages , only : metapackage_request_t use shlex_module , only : shlex_split => split use regex_module , only : regex use iso_fortran_env , only : stdout => output_unit implicit none private public :: resolve_metapackages interface resolve_metapackages module procedure resolve_metapackage_model end interface resolve_metapackages contains !> Initialize a metapackage from the given name subroutine init_from_request ( this , request , compiler , all_meta , error ) class ( metapackage_t ), intent ( inout ) :: this type ( metapackage_request_t ), intent ( in ) :: request type ( compiler_t ), intent ( in ) :: compiler !> Pass a list of all metapackage requests so dependencies can be sorted out type ( metapackage_request_t ), intent ( in ) :: all_meta (:) type ( error_t ), allocatable , intent ( out ) :: error !> Initialize metapackage by name select case ( request % name ) case ( \"openmp\" ); call init_openmp ( this , compiler , all_meta , error ) case ( \"stdlib\" ); call init_stdlib ( this , compiler , all_meta , error ) case ( \"minpack\" ); call init_minpack ( this , compiler , all_meta , error ) case ( \"mpi\" ); call init_mpi ( this , compiler , all_meta , error ) case ( \"hdf5\" ); call init_hdf5 ( this , compiler , all_meta , error ) case ( \"netcdf\" ); call init_netcdf ( this , compiler , all_meta , error ) case ( \"blas\" ); call init_blas ( this , compiler , all_meta , error ) case default call syntax_error ( error , \"Package \" // request % name // \" is not supported in [metapackages]\" ) return end select end subroutine init_from_request !> Add named metapackage dependency to the model subroutine add_metapackage_model ( model , package , settings , meta , error ) type ( fpm_model_t ), intent ( inout ) :: model type ( package_config_t ), intent ( inout ) :: package class ( fpm_cmd_settings ), intent ( inout ) :: settings type ( metapackage_t ), intent ( inout ) :: meta type ( error_t ), allocatable , intent ( out ) :: error !> Add it into the model call meta % resolve ( model , error ) if ( allocated ( error )) return !> Add it into the package call meta % resolve ( package , error ) if ( allocated ( error )) return !> Add it into the settings call meta % resolve ( settings , error ) if ( allocated ( error )) return ! If we need to run executables, there should be an MPI runner if ( meta % name == \"mpi\" ) then select type ( settings ) class is ( fpm_run_settings ) ! run, test if (. not . meta % has_run_command ) & call fatal_error ( error , \"cannot find a valid mpi runner on the local host\" ) end select endif end subroutine add_metapackage_model !> Resolve all metapackages into the package config subroutine resolve_metapackage_model ( model , package , settings , error ) type ( fpm_model_t ), intent ( inout ) :: model type ( package_config_t ), intent ( inout ) :: package class ( fpm_build_settings ), intent ( inout ) :: settings type ( error_t ), allocatable , intent ( out ) :: error integer :: m type ( metapackage_t ) :: meta type ( metapackage_request_t ), allocatable :: requested (:) ! Dependencies are added to the package config, so they're properly resolved ! into the dependency tree later. ! Flags are added to the model (whose compiler needs to be already initialized) if ( model % compiler % is_unknown ()) & write ( stdout , '(a)' ) ' compiler not initialized: metapackages may not be available' ! Get all requested metapackages requested = package % meta % get_requests () if ( size ( requested ) < 1 ) return do m = 1 , size ( requested ) call init_from_request ( meta , requested ( m ), model % compiler , requested , error ) if ( allocated ( error )) return call add_metapackage_model ( model , package , settings , meta , error ) if ( allocated ( error )) return end do end subroutine resolve_metapackage_model end module fpm_meta","tags":"","url":"sourcefile/fpm_meta.f90.html"},{"title":"install.f90 – Fortran-lang/fpm","text":"Source Code module fpm_cmd_install use , intrinsic :: iso_fortran_env , only : output_unit use fpm , only : build_model use fpm_backend , only : build_package use fpm_command_line , only : fpm_install_settings use fpm_error , only : error_t , fatal_error , fpm_stop use fpm_filesystem , only : join_path , list_files use fpm_installer , only : installer_t , new_installer use fpm_manifest , only : package_config_t , get_package_data use fpm_model , only : fpm_model_t , FPM_SCOPE_APP , FPM_SCOPE_TEST use fpm_targets , only : targets_from_sources , build_target_t , & build_target_ptr , FPM_TARGET_EXECUTABLE , & filter_library_targets , filter_executable_targets , filter_modules use fpm_strings , only : string_t , resize implicit none private public :: cmd_install contains !> Entry point for the fpm-install subcommand subroutine cmd_install ( settings ) !> Representation of the command line settings type ( fpm_install_settings ), intent ( inout ) :: settings type ( package_config_t ) :: package type ( error_t ), allocatable :: error type ( fpm_model_t ) :: model type ( build_target_ptr ), allocatable :: targets (:), libraries (:) type ( installer_t ) :: installer type ( string_t ), allocatable :: list (:) logical :: installable integer :: ntargets , i call get_package_data ( package , \"fpm.toml\" , error , apply_defaults = . true .) call handle_error ( error ) call build_model ( model , settings , package , error ) call handle_error ( error ) ! ifx bug: does not resolve allocatable -> optional if ( allocated ( package % library )) then call targets_from_sources ( targets , model , settings % prune , package % library , error ) else call targets_from_sources ( targets , model , settings % prune , error = error ) endif call handle_error ( error ) call install_info ( output_unit , settings % list , targets , ntargets ) if ( settings % list ) return installable = ( allocated ( package % library ) . and . package % install % library ) & . or . allocated ( package % executable ) . or . ntargets > 0 if (. not . installable ) then call fatal_error ( error , \"Project does not contain any installable targets\" ) call handle_error ( error ) end if if (. not . settings % no_rebuild ) then call build_package ( targets , model , verbose = settings % verbose , dry_run = settings % list ) end if call new_installer ( installer , prefix = settings % prefix , & bindir = settings % bindir , libdir = settings % libdir , testdir = settings % testdir , & includedir = settings % includedir , & verbosity = merge ( 2 , 1 , settings % verbose )) if ( allocated ( package % library ) . and . package % install % library ) then call filter_library_targets ( targets , libraries ) if ( size ( libraries ) > 0 ) then do i = 1 , size ( libraries ) call installer % install_library ( libraries ( i )% ptr , error ) call handle_error ( error ) end do call install_module_files ( installer , targets , error ) call handle_error ( error ) end if end if if ( allocated ( package % executable ) . or . ntargets > 0 ) then call install_executables ( installer , targets , error ) call handle_error ( error ) end if if ( allocated ( package % test ) . and . ( package % install % test . or . model % include_tests )) then call install_tests ( installer , targets , error ) call handle_error ( error ) end if end subroutine cmd_install subroutine install_info ( unit , verbose , targets , ntargets ) integer , intent ( in ) :: unit logical , intent ( in ) :: verbose type ( build_target_ptr ), intent ( in ) :: targets (:) integer , intent ( out ) :: ntargets integer :: ii type ( string_t ), allocatable :: install_target (:), temp (:) type ( build_target_ptr ), allocatable :: libs (:) allocate ( install_target ( 0 )) call filter_library_targets ( targets , libs ) install_target = [ install_target , ( string_t ( libs ( ii )% ptr % output_file ), ii = 1 , size ( libs ))] call filter_executable_targets ( targets , FPM_SCOPE_APP , temp ) install_target = [ install_target , temp ] call filter_executable_targets ( targets , FPM_SCOPE_TEST , temp ) install_target = [ install_target , temp ] ntargets = size ( install_target ) if ( verbose ) then write ( unit , '(\"#\", *(1x, g0))' ) & \"total number of installable targets:\" , ntargets do ii = 1 , ntargets write ( unit , '(\"-\", *(1x, g0))' ) install_target ( ii )% s end do endif end subroutine install_info subroutine install_module_files ( installer , targets , error ) type ( installer_t ), intent ( inout ) :: installer type ( build_target_ptr ), intent ( in ) :: targets (:) type ( error_t ), allocatable , intent ( out ) :: error type ( string_t ), allocatable :: modules (:) integer :: ii call filter_modules ( targets , modules ) do ii = 1 , size ( modules ) call installer % install_header ( modules ( ii )% s // \".mod\" , error ) if ( allocated ( error )) exit end do if ( allocated ( error )) return end subroutine install_module_files subroutine install_executables ( installer , targets , error ) type ( installer_t ), intent ( inout ) :: installer type ( build_target_ptr ), intent ( in ) :: targets (:) type ( error_t ), allocatable , intent ( out ) :: error integer :: ii do ii = 1 , size ( targets ) if ( targets ( ii )% ptr % is_executable_target ( FPM_SCOPE_APP )) then call installer % install_executable ( targets ( ii )% ptr % output_file , error ) if ( allocated ( error )) exit end if end do if ( allocated ( error )) return end subroutine install_executables subroutine install_tests ( installer , targets , error ) type ( installer_t ), intent ( inout ) :: installer type ( build_target_ptr ), intent ( in ) :: targets (:) type ( error_t ), allocatable , intent ( out ) :: error integer :: ii do ii = 1 , size ( targets ) if ( targets ( ii )% ptr % is_executable_target ( FPM_SCOPE_TEST )) then call installer % install_test ( targets ( ii )% ptr % output_file , error ) if ( allocated ( error )) exit end if end do if ( allocated ( error )) return end subroutine install_tests subroutine handle_error ( error ) type ( error_t ), intent ( in ), optional :: error if ( present ( error )) then call fpm_stop ( 1 , '*cmd_install* error: ' // error % message ) end if end subroutine handle_error end module fpm_cmd_install","tags":"","url":"sourcefile/install.f90~2.html"},{"title":"fpm_command_line.f90 – Fortran-lang/fpm","text":"Source Code !># Definition of the command line interface !> !> This module uses [M_CLI2](https://github.com/urbanjost/M_CLI2) to define !> the command line interface. !> To define a command line interface create a new command settings type !> from the [[fpm_cmd_settings]] base class or the respective parent command !> settings. !> !> The subcommand is selected by the first non-option argument in the command !> line. In the subcase block the actual command line is defined and transferred !> to an instance of the [[fpm_cmd_settings]], the actual type is used by the !> *fpm* main program to determine which command entry point is chosen. !> !> To add a new subcommand add a new case to select construct and specify the !> wanted command line and the expected default values. !> Some of the following points also apply if you add a new option or argument !> to an existing *fpm* subcommand. !> At this point you should create a help page for the new command in a simple !> catman-like format as well in the ``set_help`` procedure. !> Make sure to register new subcommands in the ``fpm-manual`` command by adding !> them to the manual character array and in the help/manual case as well. !> You should add the new command to the synopsis section of the ``fpm-list``, !> ``fpm-help`` and ``fpm --list`` help pages below to make sure the help output !> is complete and consistent as well. module fpm_command_line use fpm_environment , only : get_os_type , get_env , & OS_UNKNOWN , OS_LINUX , OS_MACOS , OS_WINDOWS , & OS_CYGWIN , OS_SOLARIS , OS_FREEBSD , OS_OPENBSD , OS_NAME use M_CLI2 , only : set_args , lget , sget , unnamed , remaining , specified use M_CLI2 , only : get_subcommand , CLI_RESPONSE_FILE use fpm_strings , only : lower , split , to_fortran_name , is_fortran_name , remove_characters_in_set , & string_t , glob use fpm_filesystem , only : basename , canon_path , which , run use fpm_environment , only : get_command_arguments_quoted use fpm_error , only : fpm_stop , error_t use fpm_os , only : get_current_directory use fpm_release , only : fpm_version , version_t use , intrinsic :: iso_fortran_env , only : stdin => input_unit , & & stdout => output_unit , & & stderr => error_unit implicit none private public :: fpm_cmd_settings , & fpm_build_settings , & fpm_install_settings , & fpm_export_settings , & fpm_new_settings , & fpm_run_settings , & fpm_test_settings , & fpm_update_settings , & fpm_clean_settings , & fpm_publish_settings , & get_command_line_settings , & get_fpm_env type , abstract :: fpm_cmd_settings character ( len = :), allocatable :: working_dir character ( len = :), allocatable :: path_to_config logical :: verbose = . true . end type integer , parameter :: ibug = 4096 type , extends ( fpm_cmd_settings ) :: fpm_new_settings character ( len = :), allocatable :: name logical :: with_executable = . false . logical :: with_test = . false . logical :: with_lib = . true . logical :: with_example = . false . logical :: with_full = . false . logical :: with_bare = . false . logical :: backfill = . true . end type type , extends ( fpm_cmd_settings ) :: fpm_build_settings logical :: list = . false . logical :: show_model = . false . logical :: build_tests = . false . logical :: prune = . true . character ( len = :), allocatable :: dump character ( len = :), allocatable :: compiler character ( len = :), allocatable :: c_compiler character ( len = :), allocatable :: cxx_compiler character ( len = :), allocatable :: archiver character ( len = :), allocatable :: profile character ( len = :), allocatable :: flag character ( len = :), allocatable :: cflag character ( len = :), allocatable :: cxxflag character ( len = :), allocatable :: ldflag end type type , extends ( fpm_build_settings ) :: fpm_run_settings character ( len = ibug ), allocatable :: name (:) character ( len = :), allocatable :: args ! passed to the app character ( len = :), allocatable :: runner character ( len = :), allocatable :: runner_args ! passed to the runner logical :: example contains procedure :: runner_command procedure :: name_ID end type type , extends ( fpm_run_settings ) :: fpm_test_settings end type type , extends ( fpm_build_settings ) :: fpm_install_settings character ( len = :), allocatable :: prefix character ( len = :), allocatable :: bindir character ( len = :), allocatable :: libdir character ( len = :), allocatable :: testdir character ( len = :), allocatable :: includedir logical :: no_rebuild end type !> Settings for interacting and updating with project dependencies type , extends ( fpm_cmd_settings ) :: fpm_update_settings character ( len = ibug ), allocatable :: name (:) character ( len = :), allocatable :: dump logical :: fetch_only logical :: clean end type !> Settings for exporting model data type , extends ( fpm_build_settings ) :: fpm_export_settings character ( len = :), allocatable :: dump_manifest character ( len = :), allocatable :: dump_dependencies character ( len = :), allocatable :: dump_model end type type , extends ( fpm_cmd_settings ) :: fpm_clean_settings logical :: clean_skip = . false . logical :: clean_all = . false . logical :: registry_cache = . false . end type type , extends ( fpm_build_settings ) :: fpm_publish_settings logical :: show_package_version = . false . logical :: show_upload_data = . false . logical :: is_dry_run = . false . character ( len = :), allocatable :: token end type character ( len = :), allocatable :: name character ( len = :), allocatable :: os_type character ( len = ibug ), allocatable :: names (:) character ( len = :), allocatable :: tnames (:) character ( len = :), allocatable :: version_text (:) character ( len = :), allocatable :: help_new (:), help_fpm (:), help_run (:), & & help_test (:), help_build (:), help_usage (:), help_runner (:), & & help_text (:), help_install (:), help_help (:), help_update (:), & & help_list (:), help_list_dash (:), help_list_nodash (:), & & help_clean (:), help_publish (:) character ( len = 20 ), parameter :: manual ( * ) = [ character ( len = 20 ) :: & & ' ' , 'fpm' , 'new' , 'build' , 'run' , 'clean' , & & 'test' , 'runner' , 'install' , 'update' , 'list' , 'help' , 'version' , 'publish' ] character ( len = :), allocatable :: val_runner , val_compiler , val_flag , val_cflag , val_cxxflag , val_ldflag , & val_profile , val_runner_args , val_dump ! '12345678901234567890123456789012345678901234567890123456789012345678901234567890',& character ( len = 80 ), parameter :: help_text_build_common ( * ) = [ character ( len = 80 ) :: & ' --profile PROF Selects the compilation profile for the build. ' ,& ' Currently available profiles are \"release\" for ' ,& ' high optimization and \"debug\" for full debug options. ' ,& ' If --flag is not specified the \"debug\" flags are the ' ,& ' default. ' ,& ' --no-prune Disable tree-shaking/pruning of unused module dependencies ' & ] ! '12345678901234567890123456789012345678901234567890123456789012345678901234567890',& character ( len = 80 ), parameter :: help_text_compiler ( * ) = [ character ( len = 80 ) :: & ' --compiler NAME Specify a compiler name. The default is \"gfortran\" ' ,& ' unless set by the environment variable FPM_FC. ' ,& ' --c-compiler NAME Specify the C compiler name. Automatically determined by ' ,& ' default unless set by the environment variable FPM_CC. ' ,& ' --cxx-compiler NAME Specify the C++ compiler name. Automatically determined by' ,& ' default unless set by the environment variable FPM_CXX. ' ,& ' --archiver NAME Specify the archiver name. Automatically determined by ' ,& ' default unless set by the environment variable FPM_AR. ' & ] ! '12345678901234567890123456789012345678901234567890123456789012345678901234567890',& character ( len = 80 ), parameter :: help_text_flag ( * ) = [ character ( len = 80 ) :: & ' --flag FFLAGS selects compile arguments for the build, the default value is' ,& ' set by the FPM_FFLAGS environment variable. These are added ' ,& ' to the profile options if --profile is specified, else these ' ,& ' are added to the defaults. To override the defaults, use the ' ,& ' keyword [fortran] in the manifest. Note object and .mod ' ,& ' directory locations are always built in. ' ,& ' --c-flag CFLAGS selects compile arguments specific for C source in the build.' ,& ' The default value is set by the FPM_CFLAGS environment ' ,& ' variable. ' ,& ' --cxx-flag CFLAGS selects compile arguments specific for C++ source in the ' ,& ' build. The default value is set by the FPM_CXXFLAGS ' ,& ' environment variable. ' ,& ' --link-flag LDFLAGS select arguments passed to the linker for the build. The ' ,& ' default value is set by the FPM_LDFLAGS environment variable.' & ] character ( len = 80 ), parameter :: help_text_environment ( * ) = [ character ( len = 80 ) :: & 'ENVIRONMENT VARIABLES' ,& ' FPM_FC sets the path to the Fortran compiler used for the build,' , & ' will be overwritten by --compiler command line option' , & '' , & ' FPM_FFLAGS sets the arguments for the Fortran compiler' , & ' will be overwritten by --flag command line option' , & '' , & ' FPM_CC sets the path to the C compiler used for the build,' , & ' will be overwritten by --c-compiler command line option' , & '' , & ' FPM_CFLAGS sets the arguments for the C compiler' , & ' will be overwritten by --c-flag command line option' , & '' , & ' FPM_CXX sets the path to the C++ compiler used for the build,' , & ' will be overwritten by --cxx-compiler command line option' , & '' , & ' FPM_CXXFLAGS sets the arguments for the C++ compiler' , & ' will be overwritten by --cxx-flag command line option' , & '' , & ' FPM_AR sets the path to the archiver used for the build,' , & ' will be overwritten by --archiver command line option' , & '' , & ' FPM_LDFLAGS sets additional link arguments for creating executables' , & ' will be overwritten by --link-flag command line option' & ] contains subroutine get_command_line_settings ( cmd_settings ) class ( fpm_cmd_settings ), allocatable , intent ( out ) :: cmd_settings integer , parameter :: widest = 256 character ( len = 4096 ) :: cmdarg integer :: i integer :: os type ( fpm_install_settings ), allocatable :: install_settings type ( fpm_publish_settings ), allocatable :: publish_settings type ( fpm_export_settings ) , allocatable :: export_settings type ( version_t ) :: version character ( len = :), allocatable :: common_args , compiler_args , run_args , working_dir , & & c_compiler , cxx_compiler , archiver , version_s , token_s , config_file character ( len =* ), parameter :: fc_env = \"FC\" , cc_env = \"CC\" , ar_env = \"AR\" , & & fflags_env = \"FFLAGS\" , cflags_env = \"CFLAGS\" , cxxflags_env = \"CXXFLAGS\" , ldflags_env = \"LDFLAGS\" , & & fc_default = \"gfortran\" , cc_default = \" \" , ar_default = \" \" , flags_default = \" \" , & & cxx_env = \"CXX\" , cxx_default = \" \" type ( error_t ), allocatable :: error call set_help () os = get_os_type () ! text for --version switch, select case ( os ) case ( OS_LINUX ); os_type = \"OS Type: Linux\" case ( OS_MACOS ); os_type = \"OS Type: macOS\" case ( OS_WINDOWS ); os_type = \"OS Type: Windows\" case ( OS_CYGWIN ); os_type = \"OS Type: Cygwin\" case ( OS_SOLARIS ); os_type = \"OS Type: Solaris\" case ( OS_FREEBSD ); os_type = \"OS Type: FreeBSD\" case ( OS_OPENBSD ); os_type = \"OS Type: OpenBSD\" case ( OS_UNKNOWN ); os_type = \"OS Type: Unknown\" case default ; os_type = \"OS Type: UNKNOWN\" end select ! Get current release version version = fpm_version () version_s = version % s () version_text = [ character ( len = 80 ) :: & & 'Version: ' // trim ( version_s ) // ', alpha' , & & 'Program: fpm(1)' , & & 'Description: A Fortran package manager and build system' , & & 'Home Page: https://github.com/fortran-lang/fpm' , & & 'License: MIT' , & & os_type ] ! find the subcommand name by looking for first word on command ! not starting with dash CLI_RESPONSE_FILE = . true . cmdarg = get_subcommand () common_args = & ' --directory:C \" \"' // & ' --verbose F' run_args = & ' --target \" \"' // & ' --list F' // & ' --runner \" \"' // & ' --runner-args \" \"' compiler_args = & ' --profile \" \"' // & ' --no-prune F' // & ' --compiler \"' // get_fpm_env ( fc_env , fc_default ) // '\"' // & ' --c-compiler \"' // get_fpm_env ( cc_env , cc_default ) // '\"' // & ' --cxx-compiler \"' // get_fpm_env ( cxx_env , cxx_default ) // '\"' // & ' --archiver \"' // get_fpm_env ( ar_env , ar_default ) // '\"' // & ' --flag:: \"' // get_fpm_env ( fflags_env , flags_default ) // '\"' // & ' --c-flag:: \"' // get_fpm_env ( cflags_env , flags_default ) // '\"' // & ' --cxx-flag:: \"' // get_fpm_env ( cxxflags_env , flags_default ) // '\"' // & ' --link-flag:: \"' // get_fpm_env ( ldflags_env , flags_default ) // '\"' ! now set subcommand-specific help text and process commandline ! arguments. Then call subcommand routine select case ( trim ( cmdarg )) case ( 'run' ) call set_args ( common_args // compiler_args // run_args // '& & --all F & & --example F & & --config-file \" \" & & --' , help_run , version_text ) call check_build_vals () if ( size ( unnamed ) > 1 ) then names = unnamed ( 2 :) else names = [ character ( len = len ( names )) :: ] endif if ( specified ( 'target' ) ) then call split ( sget ( 'target' ), tnames , delimiters = ' ,:' ) names = [ character ( len = max ( len ( names ), len ( tnames ))) :: names , tnames ] endif ! convert --all to '*' if ( lget ( 'all' )) then names = [ character ( len = max ( len ( names ), 1 )) :: names , '*' ] endif ! convert special string '..' to equivalent (shorter) '*' ! to allow for a string that does not require shift-key and quoting do i = 1 , size ( names ) if ( names ( i ) == '..' ) names ( i ) = '*' enddo ! If there are additional command-line arguments, remove the additional ! double quotes which have been added by M_CLI2 val_runner_args = sget ( 'runner-args' ) call remove_characters_in_set ( val_runner_args , set = '\"' ) c_compiler = sget ( 'c-compiler' ) cxx_compiler = sget ( 'cxx-compiler' ) archiver = sget ( 'archiver' ) config_file = sget ( 'config-file' ) allocate ( fpm_run_settings :: cmd_settings ) val_runner = sget ( 'runner' ) if ( specified ( 'runner' ) . and . val_runner == '' ) val_runner = 'echo' cmd_settings = fpm_run_settings (& & args = remaining ,& & profile = val_profile ,& & prune = . not . lget ( 'no-prune' ), & & compiler = val_compiler , & & c_compiler = c_compiler , & & cxx_compiler = cxx_compiler , & & archiver = archiver , & & path_to_config = config_file , & & flag = val_flag , & & cflag = val_cflag , & & cxxflag = val_cxxflag , & & ldflag = val_ldflag , & & example = lget ( 'example' ), & & list = lget ( 'list' ),& & build_tests = . false .,& & name = names ,& & runner = val_runner ,& & runner_args = val_runner_args , & & verbose = lget ( 'verbose' ) ) case ( 'build' ) call set_args ( common_args // compiler_args // '& & --list F & & --show-model F & & --dump \" \" & & --tests F & & --config-file \" \" & & --' , help_build , version_text ) call check_build_vals () c_compiler = sget ( 'c-compiler' ) cxx_compiler = sget ( 'cxx-compiler' ) archiver = sget ( 'archiver' ) config_file = sget ( 'config-file' ) val_dump = sget ( 'dump' ) if ( specified ( 'dump' ) . and . val_dump == '' ) val_dump = 'fpm_model.toml' allocate ( fpm_build_settings :: cmd_settings ) cmd_settings = fpm_build_settings ( & & profile = val_profile ,& & dump = val_dump ,& & prune = . not . lget ( 'no-prune' ), & & compiler = val_compiler , & & c_compiler = c_compiler , & & cxx_compiler = cxx_compiler , & & archiver = archiver , & & path_to_config = config_file , & & flag = val_flag , & & cflag = val_cflag , & & cxxflag = val_cxxflag , & & ldflag = val_ldflag , & & list = lget ( 'list' ),& & show_model = lget ( 'show-model' ),& & build_tests = lget ( 'tests' ),& & verbose = lget ( 'verbose' ) ) case ( 'new' ) call set_args ( common_args // '& & --src F & & --lib F & & --app F & & --test F & & --example F & & --backfill F & & --full F & & --bare F & &' , help_new , version_text ) select case ( size ( unnamed )) case ( 1 ) if ( lget ( 'backfill' )) then name = '.' else write ( stderr , '(*(7x,g0,/))' ) & & ' fpm new NAME [[--lib|--src] [--app] [--test] [--example]]|[--full|--bare] [--backfill]' call fpm_stop ( 1 , 'directory name required' ) endif case ( 2 ) name = trim ( unnamed ( 2 )) case default write ( stderr , '(7x,g0)' ) & & ' fpm new NAME [[--lib|--src] [--app] [--test] [--example]]| [--full|--bare] [--backfill]' call fpm_stop ( 2 , 'only one directory name allowed' ) end select !*! canon_path is not converting \".\", etc. if ( name == '.' ) then call get_current_directory ( name , error ) if ( allocated ( error )) then write ( stderr , '(\"[Error]\", 1x, a)' ) error % message stop 1 endif endif name = canon_path ( name ) if ( . not . is_fortran_name ( to_fortran_name ( basename ( name ))) ) then write ( stderr , '(g0)' ) [ character ( len = 72 ) :: & & ' the fpm project name must be made of up to 63 ASCII letters,' , & & ' numbers, underscores, or hyphens, and start with a letter.' ] call fpm_stop ( 4 , ' ' ) endif allocate ( fpm_new_settings :: cmd_settings ) if ( any ( specified ([ character ( len = 10 ) :: 'src' , 'lib' , 'app' , 'test' , 'example' , 'bare' ])) & & . and . lget ( 'full' ) ) then write ( stderr , '(*(a))' )& & ' --full and any of [--src|--lib,--app,--test,--example,--bare]' , & & ' are mutually exclusive.' call fpm_stop ( 5 , ' ' ) elseif ( any ( specified ([ character ( len = 10 ) :: 'src' , 'lib' , 'app' , 'test' , 'example' , 'full' ])) & & . and . lget ( 'bare' ) ) then write ( stderr , '(*(a))' )& & ' --bare and any of [--src|--lib,--app,--test,--example,--full]' , & & ' are mutually exclusive.' call fpm_stop ( 3 , ' ' ) elseif ( any ( specified ([ character ( len = 10 ) :: 'src' , 'lib' , 'app' , 'test' , 'example' ]) ) ) then cmd_settings = fpm_new_settings (& & backfill = lget ( 'backfill' ), & & name = name , & & with_executable = lget ( 'app' ), & & with_lib = any ([ lget ( 'lib' ), lget ( 'src' )]), & & with_test = lget ( 'test' ), & & with_example = lget ( 'example' ), & & verbose = lget ( 'verbose' ) ) else ! default if no specific directories are requested cmd_settings = fpm_new_settings (& & backfill = lget ( 'backfill' ) , & & name = name , & & with_executable = . true ., & & with_lib = . true ., & & with_test = . true ., & & with_example = lget ( 'full' ), & & with_full = lget ( 'full' ), & & with_bare = lget ( 'bare' ), & & verbose = lget ( 'verbose' ) ) endif case ( 'help' , 'manual' ) call set_args ( common_args , help_help , version_text ) if ( size ( unnamed ) < 2 ) then if ( unnamed ( 1 ) == 'help' ) then unnamed = [ ' ' , 'fpm' ] else unnamed = manual endif elseif ( unnamed ( 2 ) == 'manual' ) then unnamed = manual endif allocate ( character ( len = widest ) :: help_text ( 0 )) do i = 2 , size ( unnamed ) select case ( unnamed ( i )) case ( ' ' ) case ( 'fpm ' ) help_text = [ character ( len = widest ) :: help_text , help_fpm ] case ( 'new ' ) help_text = [ character ( len = widest ) :: help_text , help_new ] case ( 'build ' ) help_text = [ character ( len = widest ) :: help_text , help_build ] case ( 'install' ) help_text = [ character ( len = widest ) :: help_text , help_install ] case ( 'run ' ) help_text = [ character ( len = widest ) :: help_text , help_run ] case ( 'test ' ) help_text = [ character ( len = widest ) :: help_text , help_test ] case ( 'runner' ) help_text = [ character ( len = widest ) :: help_text , help_runner ] case ( 'list ' ) help_text = [ character ( len = widest ) :: help_text , help_list ] case ( 'update ' ) help_text = [ character ( len = widest ) :: help_text , help_update ] case ( 'help ' ) help_text = [ character ( len = widest ) :: help_text , help_help ] case ( 'version' ) help_text = [ character ( len = widest ) :: help_text , version_text ] case ( 'clean' ) help_text = [ character ( len = widest ) :: help_text , help_clean ] case ( 'publish' ) help_text = [ character ( len = widest ) :: help_text , help_publish ] case default help_text = [ character ( len = widest ) :: help_text , & & ' unknown help topic \"' // trim ( unnamed ( i )) // '\"' ] !!& ' unknown help topic \"'//trim(unnamed(i)).'not found in:',manual] end select enddo call printhelp ( help_text ) case ( 'install' ) call set_args ( common_args // compiler_args // '& & --no-rebuild F & & --prefix \" \" & & --list F & & --test F & & --libdir \"lib\" & & --bindir \"bin\" & & --testdir \"test\" & & --includedir \"include\" & & --config-file \" \" & &' , help_install , version_text ) call check_build_vals () c_compiler = sget ( 'c-compiler' ) cxx_compiler = sget ( 'cxx-compiler' ) archiver = sget ( 'archiver' ) config_file = sget ( 'config-file' ) allocate ( install_settings , source = fpm_install_settings (& list = lget ( 'list' ), & build_tests = lget ( 'test' ), & profile = val_profile ,& prune = . not . lget ( 'no-prune' ), & compiler = val_compiler , & c_compiler = c_compiler , & cxx_compiler = cxx_compiler , & archiver = archiver , & path_to_config = config_file , & flag = val_flag , & cflag = val_cflag , & cxxflag = val_cxxflag , & ldflag = val_ldflag , & no_rebuild = lget ( 'no-rebuild' ), & verbose = lget ( 'verbose' ))) call get_char_arg ( install_settings % prefix , 'prefix' ) call get_char_arg ( install_settings % libdir , 'libdir' ) call get_char_arg ( install_settings % testdir , 'testdir' ) call get_char_arg ( install_settings % bindir , 'bindir' ) call get_char_arg ( install_settings % includedir , 'includedir' ) call move_alloc ( install_settings , cmd_settings ) case ( 'list' ) call set_args ( common_args // '& & --list F & &' , help_list , version_text ) if ( lget ( 'list' )) then help_text = [ character ( widest ) :: help_list_nodash , help_list_dash ] else help_text = help_list_nodash endif call printhelp ( help_text ) case ( 'test' ) call set_args ( common_args // compiler_args // run_args // '& & --config-file \" \" & & -- ' , help_test , version_text ) call check_build_vals () if ( size ( unnamed ) > 1 ) then names = unnamed ( 2 :) else names = [ character ( len = len ( names )) :: ] endif if ( specified ( 'target' ) ) then call split ( sget ( 'target' ), tnames , delimiters = ' ,:' ) names = [ character ( len = max ( len ( names ), len ( tnames ))) :: names , tnames ] endif ! convert special string '..' to equivalent (shorter) '*' ! to allow for a string that does not require shift-key and quoting do i = 1 , size ( names ) if ( names ( i ) == '..' ) names ( i ) = '*' enddo ! If there are additional command-line arguments, remove the additional ! double quotes which have been added by M_CLI2 val_runner_args = sget ( 'runner-args' ) call remove_characters_in_set ( val_runner_args , set = '\"' ) c_compiler = sget ( 'c-compiler' ) cxx_compiler = sget ( 'cxx-compiler' ) archiver = sget ( 'archiver' ) config_file = sget ( 'config-file' ) allocate ( fpm_test_settings :: cmd_settings ) val_runner = sget ( 'runner' ) if ( specified ( 'runner' ) . and . val_runner == '' ) val_runner = 'echo' cmd_settings = fpm_test_settings (& & args = remaining , & & profile = val_profile , & & prune = . not . lget ( 'no-prune' ), & & compiler = val_compiler , & & c_compiler = c_compiler , & & cxx_compiler = cxx_compiler , & & archiver = archiver , & & path_to_config = config_file , & & flag = val_flag , & & cflag = val_cflag , & & cxxflag = val_cxxflag , & & ldflag = val_ldflag , & & example = . false ., & & list = lget ( 'list' ), & & build_tests = . true ., & & name = names , & & runner = val_runner , & & runner_args = val_runner_args , & & verbose = lget ( 'verbose' )) case ( 'update' ) call set_args ( common_args // '& & --fetch-only F & & --clean F & & --dump \" \" & & --config-file \" \" & &' , help_update , version_text ) if ( size ( unnamed ) > 1 ) then names = unnamed ( 2 :) else names = [ character ( len = len ( names )) :: ] endif config_file = sget ( 'config-file' ) val_dump = sget ( 'dump' ) if ( specified ( 'dump' ) . and . val_dump == '' ) val_dump = 'fpm_dependencies.toml' allocate ( fpm_update_settings :: cmd_settings ) cmd_settings = fpm_update_settings ( name = names , & & fetch_only = lget ( 'fetch-only' ), & & dump = val_dump , & & verbose = lget ( 'verbose' ), & & path_to_config = config_file , & & clean = lget ( 'clean' )) case ( 'export' ) call set_args ( common_args // compiler_args // '& & --manifest \"filename\" & & --model \"filename\" & & --dependencies \"filename\" ' , & help_build , version_text ) call check_build_vals () c_compiler = sget ( 'c-compiler' ) cxx_compiler = sget ( 'cxx-compiler' ) archiver = sget ( 'archiver' ) allocate ( export_settings , source = fpm_export_settings (& profile = val_profile ,& prune = . not . lget ( 'no-prune' ), & compiler = val_compiler , & c_compiler = c_compiler , & cxx_compiler = cxx_compiler , & archiver = archiver , & flag = val_flag , & cflag = val_cflag , & show_model = . true ., & cxxflag = val_cxxflag , & ldflag = val_ldflag , & verbose = lget ( 'verbose' ))) call get_char_arg ( export_settings % dump_model , 'model' ) call get_char_arg ( export_settings % dump_manifest , 'manifest' ) call get_char_arg ( export_settings % dump_dependencies , 'dependencies' ) call move_alloc ( export_settings , cmd_settings ) case ( 'clean' ) call set_args ( common_args // & & ' --registry-cache' // & & ' --skip' // & & ' --all' // & & ' --config-file \"\"' , help_clean , version_text ) block logical :: skip , clean_all skip = lget ( 'skip' ) clean_all = lget ( 'all' ) config_file = sget ( 'config-file' ) if ( all ([ skip , clean_all ])) then call fpm_stop ( 6 , 'Do not specify both --skip and --all options on the clean subcommand.' ) end if allocate ( fpm_clean_settings :: cmd_settings ) call get_current_directory ( working_dir , error ) cmd_settings = fpm_clean_settings ( & & working_dir = working_dir , & & clean_skip = skip , & & registry_cache = lget ( 'registry-cache' ), & & clean_all = clean_all , & & path_to_config = config_file ) end block case ( 'publish' ) call set_args ( common_args // compiler_args // '& & --show-package-version F & & --show-upload-data F & & --dry-run F & & --token \" \" & & --list F & & --show-model F & & --tests F & & --config-file \" \" & & --' , help_publish , version_text ) call check_build_vals () c_compiler = sget ( 'c-compiler' ) cxx_compiler = sget ( 'cxx-compiler' ) archiver = sget ( 'archiver' ) config_file = sget ( 'config-file' ) token_s = sget ( 'token' ) allocate ( fpm_publish_settings :: cmd_settings ) cmd_settings = fpm_publish_settings ( & & show_package_version = lget ( 'show-package-version' ), & & show_upload_data = lget ( 'show-upload-data' ), & & is_dry_run = lget ( 'dry-run' ), & & profile = val_profile ,& & prune = . not . lget ( 'no-prune' ), & & compiler = val_compiler , & & c_compiler = c_compiler , & & cxx_compiler = cxx_compiler , & & archiver = archiver , & & flag = val_flag , & & cflag = val_cflag , & & cxxflag = val_cxxflag , & & ldflag = val_ldflag , & & list = lget ( 'list' ),& & show_model = lget ( 'show-model' ),& & build_tests = lget ( 'tests' ),& & path_to_config = config_file , & & verbose = lget ( 'verbose' ),& & token = token_s ) case default if ( cmdarg . ne . '' . and . which ( 'fpm-' // cmdarg ). ne . '' ) then call run ( 'fpm-' // trim ( cmdarg ) // ' ' // get_command_arguments_quoted (),. false .) stop else call set_args ( '& & --list F& &' , help_fpm , version_text ) ! Note: will not get here if --version or --usage or --help ! is present on commandline if ( lget ( 'list' )) then help_text = help_list_dash elseif ( len_trim ( cmdarg ) == 0 ) then write ( stdout , '(*(a))' ) 'Fortran Package Manager:' write ( stdout , '(*(a))' ) ' ' help_text = [ character ( widest ) :: help_list_nodash , help_usage ] else write ( stderr , '(*(a))' ) ' unknown subcommand [' , & & trim ( cmdarg ), ']' help_text = [ character ( widest ) :: help_list_dash , help_usage ] endif call printhelp ( help_text ) endif end select if ( allocated ( cmd_settings )) then working_dir = sget ( \"directory\" ) call move_alloc ( working_dir , cmd_settings % working_dir ) end if contains subroutine check_build_vals () val_compiler = sget ( 'compiler' ) if ( val_compiler == '' ) val_compiler = 'gfortran' val_flag = \" \" // sget ( 'flag' ) val_cflag = \" \" // sget ( 'c-flag' ) val_cxxflag = \" \" // sget ( 'cxx-flag' ) val_ldflag = \" \" // sget ( 'link-flag' ) val_profile = sget ( 'profile' ) end subroutine check_build_vals !> Print help text and stop subroutine printhelp ( lines ) character ( len = :), intent ( in ), allocatable :: lines (:) integer :: iii , ii if ( allocated ( lines )) then ii = size ( lines ) if ( ii > 0 . and . len ( lines ) > 0 ) then write ( stdout , '(g0)' )( trim ( lines ( iii )), iii = 1 , ii ) else write ( stdout , '(a)' ) ' *printhelp* output requested is empty' endif endif stop end subroutine printhelp end subroutine get_command_line_settings subroutine set_help () help_list_nodash = [ character ( len = 80 ) :: & 'USAGE: fpm [ SUBCOMMAND [SUBCOMMAND_OPTIONS] ]|[--list|--help|--version]' , & ' where SUBCOMMAND is commonly new|build|run|test ' , & ' ' , & ' subcommand may be one of ' , & ' ' , & ' build Compile the package placing results in the \"build\" directory' , & ' help Display help ' , & ' list Display this list of subcommand descriptions ' , & ' new Create a new Fortran package directory with sample files ' , & ' run Run the local package application programs ' , & ' test Run the test programs ' , & ' update Update and manage project dependencies ' , & ' install Install project ' , & ' clean Delete the build ' , & ' publish Publish package to the registry ' , & ' ' , & ' Enter \"fpm --list\" for a brief list of subcommand options. Enter ' , & ' \"fpm --help\" or \"fpm SUBCOMMAND --help\" for detailed descriptions. ' , & ' ' ] help_list_dash = [ character ( len = 80 ) :: & ' ' , & ' build [--compiler COMPILER_NAME] [--profile PROF] [--flag FFLAGS] [--list] ' , & ' [--tests] [--no-prune] [--dump [FILENAME]] [--config-file PATH] ' , & ' help [NAME(s)] ' , & ' new NAME [[--lib|--src] [--app] [--test] [--example]]| ' , & ' [--full|--bare][--backfill] ' , & ' update [NAME(s)] [--fetch-only] [--clean] [--verbose] [--dump [FILENAME]] ' , & ' list [--list] ' , & ' run [[--target] NAME(s) [--example] [--profile PROF] [--flag FFLAGS] [--all] ' , & ' [--runner \"CMD\"] [--compiler COMPILER_NAME] [--list] [-- ARGS] ' , & ' [--config-file PATH] ' , & ' test [[--target] NAME(s)] [--profile PROF] [--flag FFLAGS] [--runner \"CMD\"] ' , & ' [--list] [--compiler COMPILER_NAME] [--config-file PATH] [-- ARGS] ' , & ' install [--profile PROF] [--flag FFLAGS] [--no-rebuild] [--prefix PATH] ' , & ' [--config-file PATH] [--registry-cache] [options] ' , & ' clean [--skip] [--all] [--config-file PATH] [--registry-cache] ' , & ' publish [--token TOKEN] [--show-package-version] [--show-upload-data] ' , & ' [--dry-run] [--verbose] [--config-file PATH] ' , & ' ' ] help_usage = [ character ( len = 80 ) :: & '' ] help_runner = [ character ( len = 80 ) :: & 'NAME ' , & ' --runner(1) - a shared option for specifying an application to launch ' , & ' executables. ' , & ' ' , & 'SYNOPSIS ' , & ' fpm run|test --runner CMD ... --runner-args ARGS -- SUFFIX_OPTIONS ' , & ' ' , & 'DESCRIPTION ' , & ' The --runner option allows specifying a program to launch ' , & ' executables selected via the fpm(1) subcommands \"run\" and \"test\". This ' , & ' gives easy recourse to utilities such as debuggers and other tools ' , & ' that wrap other executables. ' , & ' ' , & ' These external commands are not part of fpm(1) itself as they vary ' , & ' from platform to platform or require independent installation. ' , & ' ' , & 'OPTION ' , & ' --runner ''CMD'' quoted command used to launch the fpm(1) executables. ' , & ' Available for both the \"run\" and \"test\" subcommands. ' , & ' If the keyword is specified without a value the default command ' , & ' is \"echo\". ' , & ' --runner-args \"args\" an additional option to pass command-line arguments ' , & ' to the runner command, instead of to the fpm app. ' , & ' -- SUFFIX_OPTIONS additional options to suffix the command CMD and executable ' , & ' file names with. These options are passed as command-line ' , & ' arguments to the app. ' , & 'EXAMPLES ' , & ' Use cases for ''fpm run|test --runner \"CMD\"'' include employing ' , & ' the following common GNU/Linux and Unix commands: ' , & ' ' , & ' INTERROGATE ' , & ' + nm - list symbols from object files ' , & ' + size - list section sizes and total size. ' , & ' + ldd - print shared object dependencies ' , & ' + ls - list directory contents ' , & ' + stat - display file or file system status ' , & ' + file - determine file type ' , & ' PERFORMANCE AND DEBUGGING ' , & ' + gdb - The GNU Debugger ' , & ' + valgrind - a suite of tools for debugging and profiling ' , & ' + time - time a simple command or give resource usage ' , & ' + timeout - run a command with a time limit ' , & ' COPY ' , & ' + install - copy files and set attributes ' , & ' + tar - an archiving utility ' , & ' ALTER ' , & ' + rm - remove files or directories ' , & ' + chmod - change permissions of a file ' , & ' + strip - remove unnecessary information from strippable files ' , & ' ' , & ' For example ' , & ' ' , & ' fpm test --runner gdb ' , & ' fpm run --runner \"tar cvfz $HOME/bundle.tgz\" ' , & ' fpm run --runner \"mpiexec\" --runner-args \"-np 12\" ' , & ' fpm run --runner ldd ' , & ' fpm run --runner strip ' , & ' fpm run --runner ''cp -t /usr/local/bin'' ' , & ' ' , & ' # options after executable name can be specified after the -- option ' , & ' fpm --runner cp run -- /usr/local/bin/ ' , & ' # generates commands of the form \"cp $FILENAME /usr/local/bin/\" ' , & ' ' , & ' # bash(1) alias example: ' , & ' alias fpm-install=\\ ' , & ' \"fpm run --profile release --runner ''install -vbp -m 0711 -t ~/.local/bin''\" ' , & ' fpm-install ' , & '' ] help_fpm = [ character ( len = 80 ) :: & 'NAME ' , & ' fpm(1) - A Fortran package manager and build system ' , & ' ' , & 'SYNOPSIS ' , & ' fpm SUBCOMMAND [SUBCOMMAND_OPTIONS] ' , & ' ' , & ' fpm --help|--version|--list ' , & ' ' , & 'DESCRIPTION ' , & ' fpm(1) is a package manager that helps you create Fortran projects ' , & ' from source -- it automatically determines dependencies! ' , & ' ' , & ' Most significantly fpm(1) lets you draw upon other fpm(1) packages ' , & ' in distributed git(1) repositories as if the packages were a basic ' , & ' part of your default programming environment, as well as letting ' , & ' you share your projects with others in a similar manner. ' , & ' ' , & ' All output goes into the directory \"build/\" which can generally be ' , & ' removed and rebuilt if required. Note that if external packages are ' , & ' being used you need network connectivity to rebuild from scratch. ' , & ' ' , & 'SUBCOMMANDS ' , & ' Valid fpm(1) subcommands are: ' , & ' ' , & ' + build Compile the packages into the \"build/\" directory. ' , & ' + new Create a new Fortran package directory with sample files. ' , & ' + update Update the project dependencies. ' , & ' + run Run the local package binaries. Defaults to all binaries ' , & ' for that release. ' , & ' + test Run the tests. ' , & ' + help Alternate to the --help switch for displaying help text. ' , & ' + list Display brief descriptions of all subcommands. ' , & ' + install Install project. ' , & ' + clean Delete directories in the \"build/\" directory, except ' , & ' dependencies. Prompts for confirmation to delete. ' , & ' + publish Publish package to the registry. ' , & ' ' , & ' Their syntax is ' , & ' ' , & ' build [--profile PROF] [--flag FFLAGS] [--list] [--compiler COMPILER_NAME] ' , & ' [--tests] [--no-prune] [--config-file PATH] ' , & ' [--dump [FILENAME]] ' , & ' new NAME [[--lib|--src] [--app] [--test] [--example]]| ' , & ' [--full|--bare][--backfill] ' , & ' update [NAME(s)] [--fetch-only] [--clean] [--config-file PATH] [--dump [FILENAME]]' , & ' run [[--target] NAME(s)] [--profile PROF] [--flag FFLAGS] [--list] [--all] ' , & ' [--example] [--runner \"CMD\"] [--compiler COMPILER_NAME] ' , & ' [--no-prune] [-- ARGS] [--config-file PATH] ' , & ' test [[--target] NAME(s)] [--profile PROF] [--flag FFLAGS] [--list] ' , & ' [--runner \"CMD\"] [--compiler COMPILER_NAME] [--no-prune] [-- ARGS] ' , & ' [--config-file PATH] ' , & ' help [NAME(s)] ' , & ' list [--list] ' , & ' install [--profile PROF] [--flag FFLAGS] [--no-rebuild] [--prefix PATH] ' , & ' [options] [--config-file PATH] [--registry-cache] ' , & ' clean [--skip] [--all] [--config-file PATH] [--registry-cache] ' , & ' publish [--token TOKEN] [--show-package-version] [--show-upload-data] ' , & ' [--dry-run] [--verbose] [--config-file PATH] ' , & ' ' , & 'SUBCOMMAND OPTIONS ' , & ' -C, --directory PATH' , & ' Change working directory to PATH before running any command' , & help_text_build_common , & help_text_compiler , & help_text_flag , & ' --list List candidates instead of building or running them. On ' , & ' the fpm(1) command this shows a brief list of subcommands.' , & ' --runner CMD Provides a command to prefix program execution paths. ' , & ' -- ARGS Arguments to pass to executables. ' , & ' --skip Delete directories in the build/ directory without ' , & ' prompting, but skip dependencies. Cannot be used together ' , & ' with --all. ' , & ' --all Delete directories in the build/ directory without ' , & ' prompting, including dependencies. Cannot be used together' , & ' with --skip. ' , & ' --registry-cache Delete registry cache. ' , & ' ' , & 'VALID FOR ALL SUBCOMMANDS ' , & ' --help Show help text and exit ' , & ' --verbose Display additional information when available ' , & ' --version Show version information and exit. ' , & ' ' , & '@file ' , & ' You may replace the default options for the fpm(1) command from a ' , & ' file if your first options begin with @file. Initial options will ' , & ' then be read from the \"response file\" \"file.rsp\" in the current ' , & ' directory. ' , & ' ' , & ' If \"file\" does not exist or cannot be read, then an error occurs and' , & ' the program stops. Each line of the file is prefixed with \"options\" ' , & ' and interpreted as a separate argument. The file itself may not ' , & ' contain @file arguments. That is, it is not processed recursively. ' , & ' ' , & ' For more information on response files see ' , & ' ' , & ' https://urbanjost.github.io/M_CLI2/set_args.3m_cli2.html ' , & ' ' , & ' The basic functionality described here will remain the same, but ' , & ' other features described at the above reference may change. ' , & ' ' , & ' An example file: ' , & ' ' , & ' # my build options ' , & ' options build ' , & ' options --compiler gfortran ' , & ' options --flag \"-pg -static -pthread -Wunreachable-code -Wunused ' , & ' -Wuninitialized -g -O -fbacktrace -fdump-core -fno-underscoring ' , & ' -frecord-marker=4 -L/usr/X11R6/lib -L/usr/X11R6/lib64 -lX11\" ' , & ' ' , & ' Note --flag would have to be on one line as response files do not ' , & ' (currently) allow for continued lines or multiple specifications of ' , & ' the same option. ' , & ' ' , & help_text_environment , & ' ' , & 'EXAMPLES ' , & ' sample commands: ' , & ' ' , & ' fpm new mypackage --app --test ' , & ' fpm build ' , & ' fpm test ' , & ' fpm run ' , & ' fpm run --example ' , & ' fpm new --help ' , & ' fpm run myprogram --profile release -- -x 10 -y 20 --title \"my title\" ' , & ' fpm install --prefix ~/.local ' , & ' fpm clean --all ' , & ' ' , & 'SEE ALSO ' , & ' ' , & ' + The fpm(1) home page is at https://github.com/fortran-lang/fpm ' , & ' + Registered fpm(1) packages are at https://fortran-lang.org/packages ' , & ' + The fpm(1) TOML file format is described at ' , & ' https://fpm.fortran-lang.org/spec/manifest.html ' , & '' ] help_list = [ character ( len = 80 ) :: & 'NAME ' , & ' list(1) - list summary of fpm(1) subcommands ' , & ' ' , & 'SYNOPSIS ' , & ' fpm list ' , & ' ' , & ' fpm list --help|--version ' , & ' ' , & 'DESCRIPTION ' , & ' Display a short description for each fpm(1) subcommand. ' , & ' ' , & 'OPTIONS ' , & ' --list display a list of command options as well. This is the ' , & ' same output as generated by \"fpm --list\". ' , & ' ' , & 'EXAMPLES ' , & ' display a short list of fpm(1) subcommands ' , & ' ' , & ' fpm list ' , & ' fpm --list ' , & '' ] help_run = [ character ( len = 80 ) :: & 'NAME ' , & ' run(1) - the fpm(1) subcommand to run project applications ' , & ' ' , & 'SYNOPSIS ' , & ' fpm run [[--target] NAME(s)] [--profile PROF] [--flag FFLAGS]' , & ' [--compiler COMPILER_NAME] [--runner \"CMD\"] [--example]' , & ' [--list] [--all] [--config-file PATH] [-- ARGS]' , & ' ' , & ' fpm run --help|--version ' , & ' ' , & 'DESCRIPTION ' , & ' Run the applications in your fpm(1) package. By default applications ' , & ' in /app or specified as \"executable\" in your \"fpm.toml\" manifest are ' , & ' used. Alternatively demonstration programs in example/ or specified in' , & ' the \"example\" section in \"fpm.toml\" can be executed. The applications ' , & ' are automatically rebuilt before being run if they are out of date. ' , & ' ' , & 'OPTIONS ' , & ' --target NAME(s) list of application names to execute. No name is ' , & ' required if only one target exists. If no name is ' , & ' supplied and more than one candidate exists or a ' , & ' name has no match a list is produced and fpm(1) ' , & ' exits. ' , & ' ' , & ' Basic \"globbing\" is supported where \"?\" represents ' , & ' any single character and \"*\" represents any string. ' , & ' Note The glob string normally needs quoted to ' , & ' the special characters from shell expansion. ' , & ' --all Run all examples or applications. An alias for --target ''*''. ' , & ' --example Run example programs instead of applications. ' , & ' --config-file PATH Custom location of the global config file. ' , & help_text_build_common , & help_text_compiler , & help_text_flag , & ' --runner CMD A command to prefix the program execution paths with. ' , & ' see \"fpm help runner\" for further details. ' , & ' --list list basenames of candidates instead of running them. Note ' , & ' out-of-date candidates will still be rebuilt before being ' , & ' listed. ' , & ' -- ARGS optional arguments to pass to the program(s). The same ' , & ' arguments are passed to all program names specified. ' , & ' ' , & help_text_environment , & ' ' , & 'EXAMPLES ' , & ' fpm(1) - run or display project applications: ' , & ' ' , & ' fpm run # run a target when only one exists or list targets ' , & ' fpm run --list # list basename of all targets, running nothing. ' , & ' fpm run \"demo*\" --list # list target basenames starting with \"demo*\".' , & ' fpm run \"psi*\" --runner # list target pathnames starting with \"psi*\".' , & ' fpm run --all # run all targets, no matter how many there are. ' , & ' ' , & ' # run default program built or to be built with the compiler command ' , & ' # \"f90\". If more than one app exists a list displays and target names' , & ' # are required. ' , & ' fpm run --compiler f90 ' , & ' ' , & ' # run example programs instead of the application programs. ' , & ' fpm run --example \"*\" ' , & ' ' , & ' # run a specific program and pass arguments to the command ' , & ' fpm run myprog -- -x 10 -y 20 --title \"my title line\" ' , & ' ' , & ' # run production version of two applications ' , & ' fpm run --target prg1,prg2 --profile release ' , & ' ' , & ' # install executables in directory (assuming install(1) exists) ' , & ' fpm run --runner ''install -b -m 0711 -p -t /usr/local/bin'' ' , & '' ] help_build = [ character ( len = 80 ) :: & 'NAME ' , & ' build(1) - the fpm(1) subcommand to build a project ' , & ' ' , & 'SYNOPSIS ' , & ' fpm build [--profile PROF] [--flag FFLAGS] [--compiler COMPILER_NAME] ' , & ' [--list] [--tests] [--config-file PATH] [--dump [FILENAME]] ' , & ' ' , & ' fpm build --help|--version ' , & ' ' , & 'DESCRIPTION ' , & ' The \"fpm build\" command ' , & ' o Fetches any dependencies ' , & ' o Scans your sources ' , & ' o Builds them in the proper order ' , & ' ' , & ' The Fortran source files are assumed by default to be in ' , & ' o src/ for modules and procedure source ' , & ' o app/ main program(s) for applications ' , & ' o test/ main program(s) and support files for project tests ' , & ' o example/ main program(s) for example programs ' , & ' Changed or new files found are rebuilt. The results are placed in ' , & ' the build/ directory. ' , & ' ' , & ' Non-default pathnames and remote dependencies are used if ' , & ' specified in the \"fpm.toml\" file. ' , & ' ' , & 'OPTIONS ' , & help_text_build_common ,& help_text_compiler , & help_text_flag , & ' --list list candidates instead of building or running them. ' , & ' all dependencies are downloaded, and the build sequence ' , & ' is saved to `build/compile_commands.json`. ' , & ' --tests build all tests (otherwise only if needed) ' , & ' --show-model show the model and exit (do not build) ' , & ' --dump [FILENAME] save model representation to file. use JSON format ' , & ' if file name is *.json; use TOML format otherwise ' , & ' (default file name: model.toml) ' , & ' --help print this help and exit ' , & ' --version print program version information and exit ' , & ' --config-file PATH custom location of the global config file ' , & ' ' , & help_text_environment , & ' ' , & 'EXAMPLES ' , & ' Sample commands: ' , & ' ' , & ' fpm build # build with debug options ' , & ' fpm build --profile release # build with high optimization ' , & '' ] help_help = [ character ( len = 80 ) :: & 'NAME ' , & ' help(1) - the fpm(1) subcommand to display help ' , & ' ' , & 'SYNOPSIS ' , & ' fpm help [fpm] [new] [build] [run] [test] [help] [version] [manual] ' , & ' [runner] ' , & ' ' , & 'DESCRIPTION ' , & ' The \"fpm help\" command is an alternative to the --help parameter ' , & ' on the fpm(1) command and its subcommands. ' , & ' ' , & 'OPTIONS ' , & ' NAME(s) A list of topic names to display. All the subcommands ' , & ' have their own page (new, build, run, test, ...). ' , & ' ' , & ' The special name \"manual\" displays all the fpm(1) ' , & ' built-in documentation. ' , & ' ' , & ' The default is to display help for the fpm(1) command ' , & ' itself. ' , & ' ' , & 'EXAMPLES ' , & ' Sample usage: ' , & ' ' , & ' fpm help # general fpm(1) command help ' , & ' fpm help version # show program version ' , & ' fpm help new # display help for \"new\" subcommand ' , & ' fpm help manual # All fpm(1) built-in documentation ' , & ' ' , & '' ] help_new = [ character ( len = 80 ) :: & 'NAME ' , & ' new(1) - the fpm(1) subcommand to initialize a new project ' , & ' ' , & 'SYNOPSIS ' , & ' fpm new NAME [[--lib|--src] [--app] [--test] [--example]]| ' , & ' [--full|--bare][--backfill] ' , & ' fpm new --help|--version ' , & ' ' , & 'DESCRIPTION ' , & ' \"fpm new\" creates and populates a new programming project directory. ' , & ' ' , & ' It ' , & ' o creates a directory with the specified name ' , & ' o runs the command \"git init\" in that directory ' , & ' o populates the directory with the default project directories ' , & ' o adds sample Fortran source files ' , & ' ' , & ' The default file structure (that will be automatically scanned) is ' , & ' ' , & ' NAME/ ' , & ' fpm.toml ' , & ' src/ ' , & ' NAME.f90 ' , & ' app/ ' , & ' main.f90 ' , & ' test/ ' , & ' check.f90 ' , & ' example/ ' , & ' demo.f90 ' , & ' ' , & ' Using this file structure is highly encouraged, particularly for ' , & ' small packages primarily intended to be used as dependencies. ' , & ' ' , & ' If you find this restrictive and need to customize the package ' , & ' structure you will find using the --full switch creates a ' , & ' heavily annotated manifest file with references to documentation ' , & ' to aid in constructing complex package structures. ' , & ' ' , & ' Remember to update the information in the sample \"fpm.toml\" ' , & ' file with your name and e-mail address. ' , & ' ' , & 'OPTIONS ' , & ' NAME the name of the project directory to create. The name ' , & ' must be made of up to 63 ASCII letters, digits, underscores, ' , & ' or hyphens, and start with a letter. ' , & ' ' , & ' The default is to create the src/, app/, and test/ directories. ' , & ' If any of the following options are specified then only the ' , & ' selected subdirectories are generated: ' , & ' ' , & ' --lib,--src create directory src/ and a placeholder module ' , & ' named \"NAME.f90\" for use with subcommand \"build\". ' , & ' --app create directory app/ and a placeholder main ' , & ' program for use with subcommand \"run\". ' , & ' --test create directory test/ and a placeholder program ' , & ' for use with the subcommand \"test\". Note that sans ' , & ' \"--lib\" it really does not have anything to test. ' , & ' --example create directory example/ and a placeholder program ' , & ' for use with the subcommand \"run --example\". ' , & ' It is only created by default if \"--full is\" specified. ' , & ' ' , & ' So the default is equivalent to ' ,& ' ' , & ' fpm NAME --lib --app --test ' , & ' ' , & ' --backfill By default the directory must not exist. If this ' , & ' option is present the directory may pre-exist and ' , & ' only subdirectories and files that do not ' , & ' already exist will be created. For example, if you ' , & ' previously entered \"fpm new myname --lib\" entering ' , & ' \"fpm new myname -full --backfill\" will create any missing' , & ' app/, example/, and test/ directories and programs. ' , & ' ' , & ' --full By default a minimal manifest file (\"fpm.toml\") is ' , & ' created that depends on auto-discovery. With this ' , & ' option a much more extensive manifest sample is written ' , & ' and the example/ directory is created and populated. ' , & ' It is designed to facilitate creating projects that ' , & ' depend extensively on non-default build options. ' , & ' ' , & ' --bare A minimal manifest file (\"fpm.toml\") is created and ' , & ' \"README.md\" file is created but no directories or ' , & ' sample Fortran are generated. ' , & ' ' , & ' --help print this help and exit ' , & ' --version print program version information and exit ' , & ' ' , & 'EXAMPLES ' , & ' Sample use ' , & ' ' , & ' fpm new myproject # create new project directory and seed it ' , & ' cd myproject # Enter the new directory ' , & ' # and run commands such as ' , & ' fpm build ' , & ' fpm run # run lone example application program ' , & ' fpm test # run example test program(s) ' , & ' fpm run --example # run lone example program ' , & ' ' , & ' fpm new A --full # create example/ and an annotated fpm.toml as well' , & ' fpm new A --bare # create no directories ' , & ' create any missing files in current directory ' , & ' fpm new --full --backfill ' , & '' ] help_test = [ character ( len = 80 ) :: & 'NAME ' , & ' test(1) - the fpm(1) subcommand to run project tests ' , & ' ' , & 'SYNOPSIS ' , & ' fpm test [[--target] NAME(s)] [--profile PROF] [--flag FFLAGS] ' , & ' [--compiler COMPILER_NAME ] [--runner \"CMD\"] [--list] ' , & ' [-- ARGS] [--config-file PATH] ' , & ' ' , & ' fpm test --help|--version ' , & ' ' , & 'DESCRIPTION ' , & ' Run applications you have built to test your project. ' , & ' ' , & 'OPTIONS ' , & ' --target NAME(s) optional list of specific test names to execute. ' , & ' The default is to run all the tests in test/ ' , & ' or the tests listed in the \"fpm.toml\" file. ' , & ' ' , & ' Basic \"globbing\" is supported where \"?\" represents ' , & ' any single character and \"*\" represents any string. ' , & ' Note The glob string normally needs quoted to ' , & ' protect the special characters from shell expansion.' , & help_text_build_common ,& help_text_compiler , & help_text_flag , & ' --runner CMD A command to prefix the program execution paths with. ' , & ' see \"fpm help runner\" for further details. ' , & ' --list list candidate basenames instead of running them. Note they' , & ' --list will still be built if not currently up to date. ' , & ' --config-file PATH Custom location of the global config file. ' , & ' -- ARGS optional arguments to pass to the test program(s). ' , & ' The same arguments are passed to all test names ' , & ' specified. ' , & ' ' , & help_text_environment , & ' ' , & 'EXAMPLES ' , & 'run tests ' , & ' ' , & ' # run default tests in /test or as specified in \"fpm.toml\" ' , & ' fpm test ' , & ' ' , & ' # run using compiler command \"f90\" ' , & ' fpm test --compiler f90 ' , & ' ' , & ' # run a specific test and pass arguments to the command ' , & ' fpm test mytest -- -x 10 -y 20 --title \"my title line\" ' , & ' ' , & ' fpm test tst1 tst2 --profile PROF # run production version of two tests' , & '' ] help_update = [ character ( len = 80 ) :: & 'NAME' , & ' update(1) - manage project dependencies' , & '' , & 'SYNOPSIS' , & ' fpm update [--fetch-only] [--clean] [--verbose] [--dump [FILENAME]] [NAME(s)]' , & ' [--config-file PATH] ' , & '' , & 'DESCRIPTION' , & ' Manage and update project dependencies. If no dependency names are' , & ' provided all the dependencies are updated automatically.' , & '' , & 'OPTIONS' , & ' --fetch-only Only fetch dependencies, do not update existing projects' , & ' --clean Do not use previous dependency cache' , & ' --config-file PATH Custom location of the global config file' , & ' --verbose Show additional printout' , & ' --dump [FILENAME] Dump updated dependency tree to file. use JSON format ' , & ' if file name is *.json; use TOML format otherwise ' , & ' (default file name: fpm_dependencies.toml) ' , & '' , & 'SEE ALSO' , & ' The fpm(1) home page at https://github.com/fortran-lang/fpm' , & '' ] help_install = [ character ( len = 80 ) :: & 'NAME' , & ' install(1) - install fpm projects' , & '' , & 'SYNOPSIS' , & ' fpm install [--profile PROF] [--flag FFLAGS] [--list] [--no-rebuild]' , & ' [--prefix DIR] [--bindir DIR] [--libdir DIR] [--includedir DIR]' , & ' [--verbose] [--config-file PATH]' , & '' , & 'DESCRIPTION' , & ' Subcommand to install fpm projects. Running install will export the' , & ' current project to the selected prefix, this will by default install all' , & ' executables (tests and examples are excluded) which are part of the projects.' , & ' Libraries and module files are only installed for projects requiring the' , & ' installation of those components in the package manifest.' , & '' , & 'OPTIONS' , & ' --list list all installable targets for this project,' , & ' but do not install any of them' , & help_text_build_common ,& help_text_flag , & ' --no-rebuild do not rebuild project before installation' , & ' --test also install test programs' , & ' --prefix DIR path to installation directory (requires write access),' , & ' the default prefix on Unix systems is $HOME/.local' , & ' and %APPDATA%\\local on Windows' , & ' --bindir DIR subdirectory to place executables in (default: bin)' , & ' --libdir DIR subdirectory to place libraries and archives in' , & ' (default: lib)' , & ' --includedir DIR subdirectory to place headers and module files in' , & ' (default: include)' , & ' --testdir DIR subdirectory to place test programs in (default: test)' , & ' --config-file PATH custom location of the global config file' , & ' --verbose print more information' , & '' , & help_text_environment , & '' , & 'EXAMPLES' , & ' 1. Install release version of project:' , & '' , & ' fpm install --profile release' , & '' , & ' 2. Install the project without rebuilding the executables:' , & '' , & ' fpm install --no-rebuild' , & '' , & ' 3. Install executables to a custom prefix into the exe directory:' , & '' , & ' fpm install --prefix $PWD --bindir exe' , & ' 4. Install executables and test programs into the same \"exe\" directory:' , & '' , & ' fpm install --prefix $PWD --test --bindir exe --testdir exe' , & '' ] help_clean = [ character ( len = 80 ) :: & 'NAME' , & ' clean(1) - delete the build' , & '' , & 'SYNOPSIS' , & ' fpm clean' , & '' , & 'DESCRIPTION' , & ' Prompts the user to confirm deletion of the build. If affirmative,' , & ' directories in the build/ directory are deleted, except dependencies.' , & ' Use the --registry-cache option to delete the registry cache.' , & '' , & 'OPTIONS' , & ' --skip Delete the build without prompting but skip dependencies.' , & ' --all Delete the build without prompting including dependencies.' , & ' --config-file PATH Custom location of the global config file.' , & ' --registry-cache Delete registry cache.' , & '' ] help_publish = [ character ( len = 80 ) :: & 'NAME' , & ' publish(1) - publish package to the registry' , & '' , & 'SYNOPSIS' , & ' fpm publish [--token TOKEN] [--show-package-version] [--show-upload-data]' , & ' [--dry-run] [--verbose] [--config-file PATH]' , & '' , & ' fpm publish --help|--version' , & '' , & 'DESCRIPTION' , & ' Follow the steps to create a tarball and upload a package to the registry:' , & '' , & ' 1. Register on the website (https://registry-phi.vercel.app/).' , & ' 2. Create a namespace. Uploaded packages must be assigned to a unique' , & ' namespace to avoid conflicts among packages with similar names. A' , & ' namespace can accommodate multiple packages.' , & ' 3. Create a token for that namespace. A token is linked to your username' , & ' and is used to authenticate you during the upload process. Do not share' , & ' the token with others.' , & ' 4. Run fpm publish --token TOKEN to upload the package to the registry.' , & ' But be aware that the upload is permanent. An uploaded package cannot be' , & ' deleted.' , & '' , & ' See documentation for more information regarding package upload and usage:' , & '' , & ' Package upload:' , & ' https://fpm.fortran-lang.org/spec/publish.html' , & '' , & ' Package usage:' , & ' https://fpm.fortran-lang.org/spec/manifest.html#dependencies-from-a-registry' , & '' , & 'OPTIONS' , & ' --show-package-version show package version without publishing' , & ' --show-upload-data show upload data without publishing' , & ' --dry-run perform dry run without publishing' , & ' --help print this help and exit' , & ' --version print program version information and exit' , & ' --config-file PATH custom location of the global config file' , & ' --verbose print more information' , & '' , & 'EXAMPLES' , & '' , & ' fpm publish --show-package-version # show package version without publishing' , & ' fpm publish --show-upload-data # show upload data without publishing' , & ' fpm publish --token TOKEN --dry-run # perform dry run without publishing' , & ' fpm publish --token TOKEN # upload package to the registry' , & '' ] end subroutine set_help subroutine get_char_arg ( var , arg ) character ( len = :), allocatable , intent ( out ) :: var character ( len =* ), intent ( in ) :: arg var = sget ( arg ) if ( len_trim ( var ) == 0 ) deallocate ( var ) end subroutine get_char_arg !> Get an environment variable for fpm, this routine ensures that every variable !> used by fpm is prefixed with FPM_. function get_fpm_env ( env , default ) result ( val ) character ( len =* ), intent ( in ) :: env character ( len =* ), intent ( in ) :: default character ( len = :), allocatable :: val character ( len =* ), parameter :: fpm_prefix = \"FPM_\" val = get_env ( fpm_prefix // env , default ) end function get_fpm_env !> Build a full runner command (executable + command-line arguments) function runner_command ( cmd ) result ( run_cmd ) class ( fpm_run_settings ), intent ( in ) :: cmd character ( len = :), allocatable :: run_cmd !> Get executable if ( len_trim ( cmd % runner ) > 0 ) then run_cmd = trim ( cmd % runner ) else run_cmd = '' end if !> Append command-line arguments if ( len_trim ( cmd % runner_args ) > 0 ) run_cmd = run_cmd // ' ' // trim ( cmd % runner_args ) end function runner_command !> Check name in list ID. return 0 if not found integer function name_ID ( cmd , name ) class ( fpm_run_settings ), intent ( in ) :: cmd character ( * ), intent ( in ) :: name integer :: j !> Default: not found name_ID = 0 if (. not . allocated ( cmd % name )) return do j = 1 , size ( cmd % name ) if ( glob ( trim ( name ), trim ( cmd % name ( j )))) then name_ID = j return end if end do end function name_ID end module fpm_command_line","tags":"","url":"sourcefile/fpm_command_line.f90.html"},{"title":"update.f90 – Fortran-lang/fpm","text":"Source Code module fpm_cmd_update use fpm_command_line , only : fpm_update_settings use fpm_dependency , only : dependency_tree_t , new_dependency_tree use fpm_error , only : error_t , fpm_stop use fpm_filesystem , only : exists , mkdir , join_path , delete_file , filewrite use fpm_manifest , only : package_config_t , get_package_data use fpm_toml , only : name_is_json implicit none private public :: cmd_update contains !> Entry point for the update subcommand subroutine cmd_update ( settings ) !> Representation of the command line arguments type ( fpm_update_settings ), intent ( in ) :: settings type ( package_config_t ) :: package type ( dependency_tree_t ) :: deps type ( error_t ), allocatable :: error integer :: ii character ( len = :), allocatable :: cache call get_package_data ( package , \"fpm.toml\" , error , apply_defaults = . true .) call handle_error ( error ) if (. not . exists ( \"build\" )) then call mkdir ( \"build\" ) call filewrite ( join_path ( \"build\" , \".gitignore\" ),[ \"*\" ]) end if cache = join_path ( \"build\" , \"cache.toml\" ) if ( settings % clean ) call delete_file ( cache ) call new_dependency_tree ( deps , cache = cache , verbosity = merge ( 2 , 1 , settings % verbose ), & & path_to_config = settings % path_to_config ) call deps % add ( package , error ) call handle_error ( error ) ! Force-update all dependencies if `--clean` if ( settings % clean ) then do ii = 1 , deps % ndep deps % dep ( ii )% update = . true . end do end if if ( settings % fetch_only ) return if ( size ( settings % name ) == 0 ) then call deps % update ( error ) call handle_error ( error ) else do ii = 1 , size ( settings % name ) call deps % update ( trim ( settings % name ( ii )), error ) call handle_error ( error ) end do end if if ( len_trim ( settings % dump ) > 0 ) then call deps % dump ( trim ( settings % dump ), error , json = name_is_json ( trim ( settings % dump ))) call handle_error ( error ) end if end subroutine cmd_update !> Error handling for this command subroutine handle_error ( error ) !> Potential error type ( error_t ), intent ( in ), optional :: error if ( present ( error )) then call fpm_stop ( 1 , '*cmd_update* error: ' // error % message ) end if end subroutine handle_error end module fpm_cmd_update","tags":"","url":"sourcefile/update.f90.html"},{"title":"fpm_meta_stdlib.f90 – Fortran-lang/fpm","text":"Source Code module fpm_meta_stdlib use fpm_compiler , only : compiler_t use fpm_error , only : error_t , fatal_error use fpm_meta_base , only : metapackage_t , destroy use fpm_git , only : git_target_branch use fpm_manifest_metapackages , only : metapackage_request_t use fpm_strings , only : string_t use iso_fortran_env , only : stdout => output_unit implicit none private public :: init_stdlib contains !> Initialize stdlib metapackage for the current system subroutine init_stdlib ( this , compiler , all_meta , error ) class ( metapackage_t ), intent ( inout ) :: this type ( compiler_t ), intent ( in ) :: compiler type ( metapackage_request_t ), intent ( in ) :: all_meta (:) type ( error_t ), allocatable , intent ( out ) :: error integer :: i logical :: with_blas !> Cleanup call destroy ( this ) !> Set name this % name = \"stdlib\" !> Stdlib is queried as a dependency from the official repository this % has_dependencies = . true . allocate ( this % dependency ( 2 )) !> 1) Test-drive this % dependency ( 1 )% name = \"test-drive\" this % dependency ( 1 )% git = git_target_branch ( \"https://github.com/fortran-lang/test-drive\" , \"v0.4.0\" ) if (. not . allocated ( this % dependency ( 1 )% git )) then call fatal_error ( error , 'cannot initialize test-drive git dependency for stdlib metapackage' ) return end if !> 2) stdlib this % dependency ( 2 )% name = \"stdlib\" this % dependency ( 2 )% git = git_target_branch ( \"https://github.com/fortran-lang/stdlib\" , \"stdlib-fpm\" ) if (. not . allocated ( this % dependency ( 2 )% git )) then call fatal_error ( error , 'cannot initialize git repo dependency for stdlib metapackage' ) return end if !> If an external BLAS is available, deploy appropriate macros with_blas = external_blas ( all_meta ) if ( with_blas ) then allocate ( this % preprocess ) call this % preprocess % new ([ string_t ( 'STDLIB_EXTERNAL_BLAS' ), string_t ( 'STDLIB_EXTERNAL_LAPACK' )]) call this % dependency ( 2 )% add_preprocess ( this % preprocess ) end if ! Stdlib is not 100% thread safe. print a warning to the user do i = 1 , size ( all_meta ) if ( all_meta ( i )% name == \"openmp\" ) then write ( stdout , '(a)' ) ' both openmp and stdlib requested: some functions may not be thread-safe!' end if end do end subroutine init_stdlib logical function external_blas ( all_meta ) type ( metapackage_request_t ), intent ( in ) :: all_meta (:) integer :: i external_blas = . false . do i = 1 , size ( all_meta ) if ( all_meta ( i )% name == \"blas\" ) then external_blas = . true . exit end if end do end function external_blas end module fpm_meta_stdlib","tags":"","url":"sourcefile/fpm_meta_stdlib.f90.html"},{"title":"fpm.f90 – Fortran-lang/fpm","text":"Source Code module fpm use fpm_strings , only : string_t , operator (. in .), glob , join , string_cat , & lower , str_ends_with , is_fortran_name , str_begins_with_str , & is_valid_module_name , len_trim use fpm_backend , only : build_package use fpm_command_line , only : fpm_build_settings , fpm_new_settings , & fpm_run_settings , fpm_install_settings , fpm_test_settings , & fpm_clean_settings use fpm_dependency , only : new_dependency_tree use fpm_filesystem , only : is_dir , join_path , list_files , exists , & basename , filewrite , mkdir , run , os_delete_dir use fpm_model , only : fpm_model_t , srcfile_t , show_model , fortran_features_t , & FPM_SCOPE_UNKNOWN , FPM_SCOPE_LIB , FPM_SCOPE_DEP , & FPM_SCOPE_APP , FPM_SCOPE_EXAMPLE , FPM_SCOPE_TEST use fpm_compiler , only : new_compiler , new_archiver , set_cpp_preprocessor_flags use fpm_sources , only : add_executable_sources , add_sources_from_dir use fpm_targets , only : targets_from_sources , build_target_t , build_target_ptr , & FPM_TARGET_EXECUTABLE , get_library_dirs use fpm_manifest , only : get_package_data , package_config_t use fpm_meta , only : resolve_metapackages use fpm_error , only : error_t , fatal_error , fpm_stop use fpm_toml , only : name_is_json use , intrinsic :: iso_fortran_env , only : stdin => input_unit , & & stdout => output_unit , & & stderr => error_unit use iso_c_binding , only : c_char , c_ptr , c_int , c_null_char , c_associated , c_f_pointer use fpm_environment , only : os_is_unix , get_os_type , OS_WINDOWS , OS_MACOS , get_env , set_env , delete_env use fpm_settings , only : fpm_global_settings , get_global_settings implicit none private public :: cmd_build , cmd_run , cmd_clean public :: build_model , check_modules_for_duplicates contains !> Constructs a valid fpm model from command line settings and the toml manifest. subroutine build_model ( model , settings , package , error ) type ( fpm_model_t ), intent ( out ) :: model class ( fpm_build_settings ), intent ( inout ) :: settings type ( package_config_t ), intent ( inout ), target :: package type ( error_t ), allocatable , intent ( out ) :: error integer :: i , j type ( package_config_t ), target :: dependency type ( package_config_t ), pointer :: manifest character ( len = :), allocatable :: file_name , lib_dir logical :: has_cpp logical :: duplicates_found type ( string_t ) :: include_dir model % package_name = package % name allocate ( model % include_dirs ( 0 )) allocate ( model % link_libraries ( 0 )) allocate ( model % external_modules ( 0 )) call new_compiler ( model % compiler , settings % compiler , settings % c_compiler , & & settings % cxx_compiler , echo = settings % verbose , verbose = settings % verbose ) call new_archiver ( model % archiver , settings % archiver , & & echo = settings % verbose , verbose = settings % verbose ) if ( model % compiler % is_unknown ()) then write ( * , '(*(a:,1x))' ) & \"\" , \"Unknown compiler\" , model % compiler % fc , \"requested!\" , & \"Defaults for this compiler might be incorrect\" end if call new_compiler_flags ( model , settings ) model % build_prefix = join_path ( \"build\" , basename ( model % compiler % fc )) model % include_tests = settings % build_tests model % enforce_module_names = package % build % module_naming model % module_prefix = package % build % module_prefix ! Resolve meta-dependencies into the package and the model call resolve_metapackages ( model , package , settings , error ) if ( allocated ( error )) return ! Create dependencies call new_dependency_tree ( model % deps , cache = join_path ( \"build\" , \"cache.toml\" ), & & path_to_config = settings % path_to_config ) ! Build and resolve model dependencies call model % deps % add ( package , error ) if ( allocated ( error )) return ! Update dependencies where needed call model % deps % update ( error ) if ( allocated ( error )) return ! build/ directory should now exist if (. not . exists ( \"build/.gitignore\" )) then call filewrite ( join_path ( \"build\" , \".gitignore\" ),[ \"*\" ]) end if allocate ( model % packages ( model % deps % ndep )) has_cpp = . false . do i = 1 , model % deps % ndep associate ( dep => model % deps % dep ( i )) file_name = join_path ( dep % proj_dir , \"fpm.toml\" ) ! The main package manifest should not be reloaded, because it may have been ! affected by model dependencies and metapackages if ( i == 1 ) then manifest => package else call get_package_data ( dependency , file_name , error , apply_defaults = . true .) if ( allocated ( error )) exit manifest => dependency end if model % packages ( i )% name = manifest % name associate ( features => model % packages ( i )% features ) features % implicit_typing = manifest % fortran % implicit_typing features % implicit_external = manifest % fortran % implicit_external features % source_form = manifest % fortran % source_form end associate model % packages ( i )% version = package % version % s () !> Add this dependency's manifest macros if ( allocated ( manifest % preprocess )) then do j = 1 , size ( manifest % preprocess ) call model % packages ( i )% preprocess % add_config ( manifest % preprocess ( j )) end do end if !> Add this dependency's package-level macros if ( allocated ( dep % preprocess )) then do j = 1 , size ( dep % preprocess ) call model % packages ( i )% preprocess % add_config ( dep % preprocess ( j )) end do end if if ( model % packages ( i )% preprocess % is_cpp ()) has_cpp = . true . if (. not . allocated ( model % packages ( i )% sources )) allocate ( model % packages ( i )% sources ( 0 )) if ( allocated ( manifest % library )) then if ( allocated ( manifest % library % source_dir )) then lib_dir = join_path ( dep % proj_dir , manifest % library % source_dir ) if ( is_dir ( lib_dir )) then call add_sources_from_dir ( model % packages ( i )% sources , lib_dir , FPM_SCOPE_LIB , & with_f_ext = model % packages ( i )% preprocess % suffixes , error = error ) if ( allocated ( error )) exit end if end if if ( allocated ( manifest % library % include_dir )) then do j = 1 , size ( manifest % library % include_dir ) include_dir % s = join_path ( dep % proj_dir , manifest % library % include_dir ( j )% s ) if ( is_dir ( include_dir % s )) then model % include_dirs = [ model % include_dirs , include_dir ] end if end do end if end if if ( allocated ( manifest % build % link )) then model % link_libraries = [ model % link_libraries , manifest % build % link ] end if if ( allocated ( manifest % build % external_modules )) then model % external_modules = [ model % external_modules , manifest % build % external_modules ] end if ! Copy naming conventions from this dependency's manifest model % packages ( i )% enforce_module_names = manifest % build % module_naming model % packages ( i )% module_prefix = manifest % build % module_prefix end associate end do if ( allocated ( error )) return ! Add optional flags if ( has_cpp ) call set_cpp_preprocessor_flags ( model % compiler % id , model % fortran_compile_flags ) ! Add sources from executable directories if ( is_dir ( 'app' ) . and . package % build % auto_executables ) then call add_sources_from_dir ( model % packages ( 1 )% sources , 'app' , FPM_SCOPE_APP , & with_executables = . true ., with_f_ext = model % packages ( 1 )% preprocess % suffixes ,& error = error ) if ( allocated ( error )) then return end if end if if ( is_dir ( 'example' ) . and . package % build % auto_examples ) then call add_sources_from_dir ( model % packages ( 1 )% sources , 'example' , FPM_SCOPE_EXAMPLE , & with_executables = . true ., & with_f_ext = model % packages ( 1 )% preprocess % suffixes , error = error ) if ( allocated ( error )) then return end if end if if ( is_dir ( 'test' ) . and . package % build % auto_tests ) then call add_sources_from_dir ( model % packages ( 1 )% sources , 'test' , FPM_SCOPE_TEST , & with_executables = . true ., & with_f_ext = model % packages ( 1 )% preprocess % suffixes , error = error ) if ( allocated ( error )) then return endif end if if ( allocated ( package % executable )) then call add_executable_sources ( model % packages ( 1 )% sources , package % executable , FPM_SCOPE_APP , & auto_discover = package % build % auto_executables , & with_f_ext = model % packages ( 1 )% preprocess % suffixes , & error = error ) if ( allocated ( error )) then return end if end if if ( allocated ( package % example )) then call add_executable_sources ( model % packages ( 1 )% sources , package % example , FPM_SCOPE_EXAMPLE , & auto_discover = package % build % auto_examples , & with_f_ext = model % packages ( 1 )% preprocess % suffixes , & error = error ) if ( allocated ( error )) then return end if end if if ( allocated ( package % test )) then call add_executable_sources ( model % packages ( 1 )% sources , package % test , FPM_SCOPE_TEST , & auto_discover = package % build % auto_tests , & with_f_ext = model % packages ( 1 )% preprocess % suffixes , & error = error ) if ( allocated ( error )) then return endif endif if ( settings % verbose ) then write ( * , * ) ' BUILD_NAME: ' , model % build_prefix write ( * , * ) ' COMPILER: ' , model % compiler % fc write ( * , * ) ' C COMPILER: ' , model % compiler % cc write ( * , * ) ' CXX COMPILER: ' , model % compiler % cxx write ( * , * ) ' COMPILER OPTIONS: ' , model % fortran_compile_flags write ( * , * ) ' C COMPILER OPTIONS: ' , model % c_compile_flags write ( * , * ) ' CXX COMPILER OPTIONS: ' , model % cxx_compile_flags write ( * , * ) ' LINKER OPTIONS: ' , model % link_flags write ( * , * ) ' INCLUDE DIRECTORIES: [' , string_cat ( model % include_dirs , ',' ), ']' end if ! Check for invalid module names call check_module_names ( model , error ) if ( allocated ( error )) return ! Check for duplicate modules duplicates_found = . false . call check_modules_for_duplicates ( model , duplicates_found ) if ( duplicates_found ) then call fpm_stop ( 1 , '*build_model*:Error: One or more duplicate module names found.' ) end if end subroutine build_model !> Initialize model compiler flags subroutine new_compiler_flags ( model , settings ) type ( fpm_model_t ), intent ( inout ) :: model type ( fpm_build_settings ), intent ( in ) :: settings character ( len = :), allocatable :: flags , cflags , cxxflags , ldflags if ( settings % flag == '' ) then flags = model % compiler % get_default_flags ( settings % profile == \"release\" ) else flags = settings % flag select case ( settings % profile ) case ( \"release\" , \"debug\" ) flags = flags // model % compiler % get_default_flags ( settings % profile == \"release\" ) end select end if cflags = trim ( settings % cflag ) cxxflags = trim ( settings % cxxflag ) ldflags = trim ( settings % ldflag ) model % fortran_compile_flags = flags model % c_compile_flags = cflags model % cxx_compile_flags = cxxflags model % link_flags = ldflags end subroutine new_compiler_flags ! Check for duplicate modules subroutine check_modules_for_duplicates ( model , duplicates_found ) type ( fpm_model_t ), intent ( in ) :: model integer :: maxsize integer :: i , j , k , l , m , modi type ( string_t ), allocatable :: modules (:) logical :: duplicates_found ! Initialise the size of array maxsize = 0 ! Get number of modules provided by each source file of every package do i = 1 , size ( model % packages ) do j = 1 , size ( model % packages ( i )% sources ) if ( allocated ( model % packages ( i )% sources ( j )% modules_provided )) then maxsize = maxsize + size ( model % packages ( i )% sources ( j )% modules_provided ) end if end do end do ! Allocate array to contain distinct names of modules allocate ( modules ( maxsize )) ! Initialise index to point at start of the newly allocated array modi = 1 ! Loop through modules provided by each source file of every package ! Add it to the array if it is not already there ! Otherwise print out warning about duplicates do k = 1 , size ( model % packages ) do l = 1 , size ( model % packages ( k )% sources ) if ( allocated ( model % packages ( k )% sources ( l )% modules_provided )) then do m = 1 , size ( model % packages ( k )% sources ( l )% modules_provided ) if ( model % packages ( k )% sources ( l )% modules_provided ( m )% s . in . modules (: modi - 1 )) then write ( stderr , * ) \"Warning: Module \" , model % packages ( k )% sources ( l )% modules_provided ( m )% s , & \" in \" , model % packages ( k )% sources ( l )% file_name , \" is a duplicate\" duplicates_found = . true . else modules ( modi ) = model % packages ( k )% sources ( l )% modules_provided ( m ) modi = modi + 1 end if end do end if end do end do end subroutine check_modules_for_duplicates ! Check names of all modules in this package and its dependencies subroutine check_module_names ( model , error ) type ( fpm_model_t ), intent ( in ) :: model type ( error_t ), allocatable , intent ( out ) :: error integer :: k , l , m logical :: valid , errors_found , enforce_this_file type ( string_t ) :: package_name , module_name , package_prefix errors_found = . false . ! Loop through modules provided by each source file of every package ! Add it to the array if it is not already there ! Otherwise print out warning about duplicates do k = 1 , size ( model % packages ) package_name = string_t ( model % packages ( k )% name ) ! Custom prefix is taken from each dependency's manifest if ( model % packages ( k )% enforce_module_names ) then package_prefix = model % packages ( k )% module_prefix else package_prefix = string_t ( \"\" ) end if ! Warn the user if some of the dependencies have loose naming if ( model % enforce_module_names . and . . not . model % packages ( k )% enforce_module_names ) then write ( stderr , * ) \"Warning: Dependency \" , package_name % s // & \" does not enforce module naming, but project does. \" end if do l = 1 , size ( model % packages ( k )% sources ) ! Module naming is not enforced in test modules enforce_this_file = model % enforce_module_names . and . & model % packages ( k )% sources ( l )% unit_scope /= FPM_SCOPE_TEST if ( allocated ( model % packages ( k )% sources ( l )% modules_provided )) then do m = 1 , size ( model % packages ( k )% sources ( l )% modules_provided ) module_name = model % packages ( k )% sources ( l )% modules_provided ( m ) valid = is_valid_module_name ( module_name , & package_name , & package_prefix , & enforce_this_file ) if (. not . valid ) then if ( enforce_this_file ) then if ( len_trim ( package_prefix ) > 0 ) then write ( stderr , * ) \"ERROR: Module \" , module_name % s , & \" in \" , model % packages ( k )% sources ( l )% file_name , & \" does not match its package name (\" // package_name % s // & \") or custom prefix (\" // package_prefix % s // \").\" else write ( stderr , * ) \"ERROR: Module \" , module_name % s , & \" in \" , model % packages ( k )% sources ( l )% file_name , & \" does not match its package name (\" // package_name % s // \").\" endif else write ( stderr , * ) \"ERROR: Module \" , module_name % s , & \" in \" , model % packages ( k )% sources ( l )% file_name , & \" has an invalid Fortran name. \" end if errors_found = . true . end if end do end if end do end do if ( errors_found ) then if ( model % enforce_module_names ) & write ( stderr , * ) \" Hint: Try disabling module naming in the manifest: [build] module-naming=false . \" call fatal_error ( error , \"The package contains invalid module names. \" // & \"Naming conventions \" // merge ( 'are' , 'not' , model % enforce_module_names ) // & \" being requested.\" ) end if end subroutine check_module_names subroutine cmd_build ( settings ) type ( fpm_build_settings ), intent ( inout ) :: settings type ( package_config_t ) :: package type ( fpm_model_t ) :: model type ( build_target_ptr ), allocatable :: targets (:) type ( error_t ), allocatable :: error integer :: i call get_package_data ( package , \"fpm.toml\" , error , apply_defaults = . true .) if ( allocated ( error )) then call fpm_stop ( 1 , '*cmd_build* Package error: ' // error % message ) end if call build_model ( model , settings , package , error ) if ( allocated ( error )) then call fpm_stop ( 1 , '*cmd_build* Model error: ' // error % message ) end if call targets_from_sources ( targets , model , settings % prune , package % library , error ) if ( allocated ( error )) then call fpm_stop ( 1 , '*cmd_build* Target error: ' // error % message ) end if !> Dump model to file if ( len_trim ( settings % dump ) > 0 ) then call model % dump ( trim ( settings % dump ), error , json = name_is_json ( trim ( settings % dump ))) if ( allocated ( error )) call fpm_stop ( 1 , '*cmd_build* Model dump error: ' // error % message ) endif if ( settings % list ) then do i = 1 , size ( targets ) write ( stderr , * ) targets ( i )% ptr % output_file enddo endif if ( settings % show_model ) then call show_model ( model ) else call build_package ( targets , model , verbose = settings % verbose , dry_run = settings % list ) endif end subroutine cmd_build subroutine cmd_run ( settings , test ) class ( fpm_run_settings ), intent ( inout ) :: settings logical , intent ( in ) :: test integer :: i , j , col_width logical :: found ( size ( settings % name )) type ( error_t ), allocatable :: error type ( package_config_t ) :: package type ( fpm_model_t ) :: model type ( build_target_ptr ), allocatable :: targets (:) type ( string_t ) :: exe_cmd type ( string_t ), allocatable :: executables (:) type ( build_target_t ), pointer :: exe_target type ( srcfile_t ), pointer :: exe_source integer :: run_scope , firsterror integer , allocatable :: stat (:), target_ID (:) character ( len = :), allocatable :: line , run_cmd , library_path call get_package_data ( package , \"fpm.toml\" , error , apply_defaults = . true .) if ( allocated ( error )) then call fpm_stop ( 1 , '*cmd_run* Package error: ' // error % message ) end if call build_model ( model , settings , package , error ) if ( allocated ( error )) then call fpm_stop ( 1 , '*cmd_run* Model error: ' // error % message ) end if call targets_from_sources ( targets , model , settings % prune , package % library , error ) if ( allocated ( error )) then call fpm_stop ( 1 , '*cmd_run* Targets error: ' // error % message ) end if if ( test ) then run_scope = FPM_SCOPE_TEST else run_scope = merge ( FPM_SCOPE_EXAMPLE , FPM_SCOPE_APP , settings % example ) end if ! Enumerate executable targets to run col_width = - 1 found (:) = . false . allocate ( executables ( size ( targets )), target_ID ( size ( targets ))) enumerate : do i = 1 , size ( targets ) exe_target => targets ( i )% ptr if ( should_be_run ( settings , run_scope , exe_target )) then exe_source => exe_target % dependencies ( 1 )% ptr % source col_width = max ( col_width , len ( basename ( exe_target % output_file )) + 2 ) ! Priority by name ID, or 0 if no name present (run first) j = settings % name_ID ( exe_source % exe_name ) target_ID ( i ) = j if ( j > 0 ) found ( j ) = . true . exe_cmd % s = exe_target % output_file executables ( i ) = exe_cmd else target_ID ( i ) = huge ( target_ID ( i )) endif end do enumerate ! sort executables by ascending name ID, resize call sort_executables ( target_ID , executables ) ! Check if any apps/tests were found if ( col_width < 0 ) then if ( test ) then call fpm_stop ( 0 , 'No tests to run' ) else call fpm_stop ( 0 , 'No executables to run' ) end if end if ! Check all names are valid ! or no name and found more than one file if ( any (. not . found ) ) then line = join ( settings % name ) if ( line /= '.' ) then ! do not report these special strings if ( any (. not . found )) then write ( stderr , '(A)' , advance = \"no\" ) '*cmd_run*:specified names ' do j = 1 , size ( settings % name ) if (. not . found ( j )) write ( stderr , '(A)' , advance = \"no\" ) '\"' // trim ( settings % name ( j )) // '\" ' end do write ( stderr , '(A)' ) 'not found.' write ( stderr , * ) else if ( settings % verbose ) then write ( stderr , '(A)' , advance = \"yes\" ) 'when more than one executable is available' write ( stderr , '(A)' , advance = \"yes\" ) ' program names must be specified.' endif endif call compact_list_all () if ( line == '.' . or . line == ' ' ) then ! do not report these special strings call fpm_stop ( 0 , '' ) else call fpm_stop ( 1 , '' ) endif end if call build_package ( targets , model , verbose = settings % verbose , dry_run = settings % list ) if ( settings % list ) then call compact_list () else ! Save current library path and set a new one that includes the local ! dynamic library folders library_path = save_library_path () call set_library_path ( model , targets , error ) if ( allocated ( error )) call fpm_stop ( 1 , '*cmd_run* Run error: ' // error % message ) allocate ( stat ( size ( executables ))) do i = 1 , size ( executables ) if ( exists ( executables ( i )% s )) then ! Prepare command line run_cmd = executables ( i )% s if ( settings % runner /= ' ' ) run_cmd = settings % runner_command () // ' ' // run_cmd if ( allocated ( settings % args )) run_cmd = run_cmd // \" \" // settings % args ! System Integrity Protection will not propagate the .dylib environment variables ! to the child process: add paths manually if ( get_os_type () == OS_MACOS ) run_cmd = \"env DYLD_LIBRARY_PATH=\" // & get_env ( \"DYLD_LIBRARY_PATH\" , \"\" ) // & \" \" // run_cmd call run ( run_cmd , echo = settings % verbose , exitstat = stat ( i )) else call fpm_stop ( 1 , '*cmd_run*:' // executables ( i )% s // ' not found' ) end if end do if ( any ( stat /= 0 )) then do i = 1 , size ( stat ) if ( stat ( i ) /= 0 ) then write ( stderr , '(*(g0:,1x))' ) ' Execution for object \"' , basename ( executables ( i )% s ),& '\" returned exit code ' , stat ( i ) end if end do firsterror = findloc ( stat /= 0 , value = . true ., dim = 1 ) call fpm_stop ( stat ( firsterror ), '*cmd_run*:stopping due to failed executions' ) end if ! Restore original library path call restore_library_path ( library_path , error ) if ( allocated ( error )) call fpm_stop ( 1 , '*cmd_run* Environment error: ' // error % message ) end if contains subroutine compact_list_all () integer , parameter :: LINE_WIDTH = 80 integer :: ii , jj , nCol jj = 1 nCol = LINE_WIDTH / col_width write ( stderr , * ) 'Available names:' do ii = 1 , size ( targets ) exe_target => targets ( ii )% ptr if ( exe_target % target_type == FPM_TARGET_EXECUTABLE . and . & allocated ( exe_target % dependencies )) then exe_source => exe_target % dependencies ( 1 )% ptr % source if ( exe_source % unit_scope == run_scope ) then write ( stderr , '(A)' , advance = ( merge ( \"yes\" , \"no \" , modulo ( jj , nCol ) == 0 ))) & & [ character ( len = col_width ) :: basename ( exe_target % output_file , suffix = . false .)] jj = jj + 1 end if end if end do write ( stderr , * ) end subroutine compact_list_all subroutine compact_list () integer , parameter :: LINE_WIDTH = 80 integer :: ii , jj , nCol jj = 1 nCol = LINE_WIDTH / col_width write ( stderr , * ) 'Matched names:' do ii = 1 , size ( executables ) write ( stderr , '(A)' , advance = ( merge ( \"yes\" , \"no \" , modulo ( jj , nCol ) == 0 ))) & & [ character ( len = col_width ) :: basename ( executables ( ii )% s , suffix = . false .)] jj = jj + 1 end do write ( stderr , * ) end subroutine compact_list end subroutine cmd_run subroutine delete_skip ( is_unix ) !> delete directories in the build folder, skipping dependencies logical , intent ( in ) :: is_unix character ( len = :), allocatable :: dir type ( string_t ), allocatable :: files (:) integer :: i call list_files ( 'build' , files , . false .) do i = 1 , size ( files ) if ( is_dir ( files ( i )% s )) then dir = files ( i )% s if (. not . str_ends_with ( dir , 'dependencies' )) call os_delete_dir ( is_unix , dir ) end if end do end subroutine delete_skip !> Delete the build directory including or excluding dependencies. Can be used !> to clear the registry cache. subroutine cmd_clean ( settings ) !> Settings for the clean command. class ( fpm_clean_settings ), intent ( in ) :: settings character :: user_response type ( fpm_global_settings ) :: global_settings type ( error_t ), allocatable :: error ! Clear registry cache if ( settings % registry_cache ) then call get_global_settings ( global_settings , error ) if ( allocated ( error )) return call os_delete_dir ( os_is_unix (), global_settings % registry_settings % cache_path ) end if if ( is_dir ( 'build' )) then ! Remove the entire build directory if ( settings % clean_all ) then call os_delete_dir ( os_is_unix (), 'build' ); return ! Remove the build directory but skip dependencies else if ( settings % clean_skip ) then call delete_skip ( os_is_unix ()); return end if ! Prompt to remove the build directory but skip dependencies write ( stdout , '(A)' , advance = 'no' ) \"Delete build, excluding dependencies (y/n)? \" read ( stdin , '(A1)' ) user_response if ( lower ( user_response ) == 'y' ) call delete_skip ( os_is_unix ()) else write ( stdout , '(A)' ) \"fpm: No build directory found.\" end if end subroutine cmd_clean !> Sort executables by namelist ID, and trim unused values pure subroutine sort_executables ( target_ID , executables ) integer , allocatable , intent ( inout ) :: target_ID (:) type ( string_t ), allocatable , intent ( inout ) :: executables (:) integer :: i , j , n , used n = size ( target_ID ) used = 0 sort : do i = 1 , n do j = i + 1 , n if ( target_ID ( j ) < target_ID ( i )) & call swap ( target_ID ( i ), target_ID ( j ), executables ( i ), executables ( j )) end do if ( target_ID ( i ) < huge ( target_ID ( i ))) used = i end do sort if ( used > 0 . and . used < n ) then target_ID = target_ID ( 1 : used ) executables = executables ( 1 : used ) end if contains elemental subroutine swap ( t1 , t2 , e1 , e2 ) integer , intent ( inout ) :: t1 , t2 type ( string_t ), intent ( inout ) :: e1 , e2 integer :: tmp type ( string_t ) :: etmp tmp = t1 t1 = t2 t2 = tmp etmp = e1 e1 = e2 e2 = etmp end subroutine swap end subroutine sort_executables !> Check if an executable should be run logical function should_be_run ( settings , run_scope , exe_target ) class ( fpm_run_settings ), intent ( in ) :: settings integer , intent ( in ) :: run_scope type ( build_target_t ), intent ( in ) :: exe_target if ( exe_target % is_executable_target ( run_scope )) then associate ( exe_source => exe_target % dependencies ( 1 )% ptr % source ) if ( exe_source % unit_scope /= run_scope ) then ! Other scope should_be_run = . false . elseif ( size ( settings % name ) == 0 . or . settings % list ) then ! Run all or list all should_be_run = . true . else ! Is found in list should_be_run = settings % name_ID ( exe_source % exe_name ) > 0 end if end associate else !> Invalid target should_be_run = . false . endif end function should_be_run !> Save the current runtime library path (e.g., PATH or LD_LIBRARY_PATH) function save_library_path () result ( path ) character ( len = :), allocatable :: path select case ( get_os_type ()) case ( OS_WINDOWS ) path = get_env ( \"PATH\" , default = \"\" ) case ( OS_MACOS ) path = get_env ( \"DYLD_LIBRARY_PATH\" , default = \"\" ) case default ! UNIX/Linux path = get_env ( \"LD_LIBRARY_PATH\" , default = \"\" ) end select end function save_library_path !> Set the runtime library path for the current process (used for subprocesses) subroutine set_library_path ( model , targets , error ) type ( fpm_model_t ), intent ( in ) :: model type ( build_target_ptr ), intent ( inout ), target :: targets (:) type ( error_t ), allocatable , intent ( out ) :: error type ( string_t ), allocatable :: shared_lib_dirs (:) character ( len = :), allocatable :: new_path , sep , current logical :: success integer :: i ! Get library directories call get_library_dirs ( model , targets , shared_lib_dirs ) ! Select platform-specific separator select case ( get_os_type ()) case ( OS_WINDOWS ) sep = \";\" case default sep = \":\" end select ! Join the directories into a path string new_path = \"\" do i = 1 , size ( shared_lib_dirs ) if ( i > 1 ) new_path = new_path // sep new_path = new_path // shared_lib_dirs ( i )% s end do ! Get current library path current = save_library_path () ! Set the appropriate environment variable select case ( get_os_type ()) case ( OS_WINDOWS ) success = set_env ( \"PATH\" , new_path // sep // current ) case ( OS_MACOS ) success = set_env ( \"DYLD_LIBRARY_PATH\" , new_path // sep // current ) case default ! UNIX/Linux success = set_env ( \"LD_LIBRARY_PATH\" , new_path // sep // current ) end select if (. not . success ) call fatal_error ( error , \"Cannot set library path: \" // new_path ) end subroutine set_library_path !> Restore a previously saved runtime library path subroutine restore_library_path ( saved_path , error ) character ( * ), intent ( in ) :: saved_path type ( error_t ), allocatable , intent ( out ) :: error logical :: success select case ( get_os_type ()) case ( OS_WINDOWS ) success = set_env ( \"PATH\" , saved_path ) case ( OS_MACOS ) success = set_env ( \"DYLD_LIBRARY_PATH\" , saved_path ) case default ! UNIX/Linux success = set_env ( \"LD_LIBRARY_PATH\" , saved_path ) end select if (. not . success ) call fatal_error ( error , \"Cannot restore library path: \" // saved_path ) end subroutine restore_library_path end module fpm","tags":"","url":"sourcefile/fpm.f90.html"},{"title":"publish.f90 – Fortran-lang/fpm","text":"Source Code !> Upload a package to the registry using the `publish` command. !> !> To upload a package you need to provide a token that will be linked to your username and created for a namespace. !> The token can be obtained from the registry website. It can be used as `fpm publish --token `. module fpm_cmd_publish use fpm_command_line , only : fpm_publish_settings use fpm_manifest , only : package_config_t , get_package_data use fpm_model , only : fpm_model_t use fpm_error , only : error_t , fpm_stop use fpm_versioning , only : version_t use fpm_filesystem , only : exists , join_path , get_temp_filename , delete_file use fpm_git , only : git_archive use fpm_downloader , only : downloader_t use fpm_strings , only : string_t use fpm_settings , only : official_registry_base_url use fpm , only : build_model implicit none private public :: cmd_publish contains !> The `publish` command first builds the root package to obtain all the relevant information such as the !> package version. It then creates a tarball of the package and uploads it to the registry. subroutine cmd_publish ( settings ) type ( fpm_publish_settings ), intent ( inout ) :: settings type ( package_config_t ) :: package type ( fpm_model_t ) :: model type ( error_t ), allocatable :: error type ( version_t ), allocatable :: version type ( string_t ), allocatable :: upload_data (:) character ( len = :), allocatable :: tmp_file type ( downloader_t ) :: downloader integer :: i ! Get package data to determine package version. call get_package_data ( package , 'fpm.toml' , error , apply_defaults = . true .) if ( allocated ( error )) call fpm_stop ( 1 , '*cmd_build* Package error: ' // error % message ) version = package % version if ( settings % show_package_version ) then print * , version % s (); return end if !> Checks before uploading the package. if (. not . allocated ( package % license )) call fpm_stop ( 1 , 'No license specified in fpm.toml.' ) if (. not . package % build % module_naming ) call fpm_stop ( 1 , 'The package does not meet the module naming requirements. ' // & & 'Please set \"module-naming = true\" in fpm.toml [build] or specify a custom module prefix.' ) if (. not . allocated ( version )) call fpm_stop ( 1 , 'No version specified in fpm.toml.' ) if ( version % s () == '0' ) call fpm_stop ( 1 , 'Invalid version: \"' // version % s () // '\".' ) if (. not . exists ( 'fpm.toml' )) call fpm_stop ( 1 , \"Cannot find 'fpm.toml' file. Are you in the project root?\" ) ! Build model to obtain dependency tree. call build_model ( model , settings % fpm_build_settings , package , error ) if ( allocated ( error )) call fpm_stop ( 1 , '*cmd_build* Model error: ' // error % message ) ! Check if package contains git dependencies. Only publish packages without git dependencies. do i = 1 , model % deps % ndep if ( allocated ( model % deps % dep ( i )% git )) then call fpm_stop ( 1 , 'Do not publish packages containing git dependencies. ' // & & \"Please upload '\" // model % deps % dep ( i )% name // \"' to the registry first.\" ) end if end do tmp_file = get_temp_filename () call git_archive ( '.' , tmp_file , 'HEAD' , additional_files = [ 'fpm_model.json' ], verbose = settings % verbose , error = error ) if ( allocated ( error )) call fpm_stop ( 1 , '*cmd_publish* Archive error: ' // error % message ) call model % dump ( 'fpm_model.json' , error , json = . true .) if ( allocated ( error )) call fpm_stop ( 1 , '*cmd_publish* Model dump error: ' // error % message ) upload_data = [ & & string_t ( 'package_name=\"' // package % name // '\"' ), & & string_t ( 'package_license=\"' // package % license // '\"' ), & & string_t ( 'package_version=\"' // version % s () // '\"' ), & & string_t ( 'tarball=@\"' // tmp_file // '\"' ) & & ] if ( allocated ( settings % token )) upload_data = [ upload_data , string_t ( 'upload_token=\"' // settings % token // '\"' )] if ( settings % show_upload_data ) then call print_upload_data ( upload_data ); return end if ! Make sure a token is provided for publishing. if ( allocated ( settings % token )) then if ( settings % token == '' ) then call delete_file ( tmp_file ); call fpm_stop ( 1 , 'No token provided.' ) end if else call delete_file ( tmp_file ); call fpm_stop ( 1 , 'No token provided.' ) end if if ( settings % verbose ) then call print_upload_data ( upload_data ) print * , '' end if ! Perform network request and validate package, token etc. on the backend once ! https://github.com/fortran-lang/registry/issues/41 is resolved. if ( settings % is_dry_run ) then print * , 'Dry run successful. Generated tarball: ' , tmp_file ; return end if call downloader % upload_form ( official_registry_base_url // '/packages' , upload_data , settings % verbose , error ) call delete_file ( tmp_file ) if ( allocated ( error )) call fpm_stop ( 1 , '*cmd_publish* Upload error: ' // error % message ) end subroutine print_upload_data ( upload_data ) type ( string_t ), intent ( in ) :: upload_data (:) integer :: i print * , 'Upload data:' do i = 1 , size ( upload_data ) print * , upload_data ( i )% s end do end end","tags":"","url":"sourcefile/publish.f90.html"},{"title":"fpm_meta_minpack.f90 – Fortran-lang/fpm","text":"Source Code module fpm_meta_minpack use fpm_compiler , only : compiler_t use fpm_meta_base , only : metapackage_t , destroy use fpm_error , only : error_t , fatal_error use fpm_git , only : git_target_tag use fpm_manifest_metapackages , only : metapackage_request_t implicit none private public :: init_minpack contains !> Initialize minpack metapackage for the current system subroutine init_minpack ( this , compiler , all_meta , error ) class ( metapackage_t ), intent ( inout ) :: this type ( compiler_t ), intent ( in ) :: compiler type ( metapackage_request_t ), intent ( in ) :: all_meta (:) type ( error_t ), allocatable , intent ( out ) :: error !> Cleanup call destroy ( this ) !> Set name this % name = \"minpack\" !> minpack is queried as a dependency from the official repository this % has_dependencies = . true . allocate ( this % dependency ( 1 )) !> 1) minpack. There are no true releases currently. Fetch HEAD this % dependency ( 1 )% name = \"minpack\" this % dependency ( 1 )% git = git_target_tag ( \"https://github.com/fortran-lang/minpack\" , \"v2.0.0-rc.1\" ) if (. not . allocated ( this % dependency ( 1 )% git )) then call fatal_error ( error , 'cannot initialize git repo dependency for minpack metapackage' ) return end if end subroutine init_minpack end module fpm_meta_minpack","tags":"","url":"sourcefile/fpm_meta_minpack.f90.html"},{"title":"toml.f90 – Fortran-lang/fpm","text":"Source Code !># Interface to TOML processing library !> !> This module acts as a proxy to the `toml-f` public Fortran API and allows !> to selectively expose components from the library to `fpm`. !> The interaction with `toml-f` data types outside of this module should be !> limited to tables, arrays and key-lists, most of the necessary interactions !> are implemented in the building interface with the `get_value` and `set_value` !> procedures. !> !> This module allows to implement features necessary for `fpm`, which are !> not yet available in upstream `toml-f`. !> !> For more details on the library used see the !> [TOML-Fortran](https://toml-f.github.io/toml-f) developer pages. module fpm_toml use fpm_error , only : error_t , fatal_error , file_not_found_error use fpm_strings , only : string_t , str_ends_with , lower use tomlf , only : toml_table , toml_array , toml_key , toml_stat , get_value , & & set_value , toml_parse , toml_error , new_table , add_table , add_array , & & toml_serialize , len , toml_load , toml_value use tomlf_de_parser , only : parse use jonquil , only : json_serialize , json_error , json_value , json_object , json_load , & cast_to_object use iso_fortran_env , only : int64 implicit none private public :: read_package_file , toml_table , toml_array , toml_key , toml_stat , & get_value , set_value , get_list , new_table , add_table , add_array , len , & toml_error , toml_serialize , toml_load , check_keys , set_list , set_string , & name_is_json , has_list !> An abstract interface for any fpm class that should be fully serializable to/from TOML/JSON type , abstract , public :: serializable_t contains !> Dump to TOML table, unit, file procedure ( to_toml ), deferred :: dump_to_toml procedure , non_overridable , private :: dump_to_file procedure , non_overridable , private :: dump_to_unit generic :: dump => dump_to_toml , dump_to_file , dump_to_unit !> Load from TOML table, unit, file procedure ( from_toml ), deferred :: load_from_toml procedure , non_overridable , private :: load_from_file procedure , non_overridable , private :: load_from_unit generic :: load => load_from_toml , load_from_file , load_from_unit !> Serializable entities need a way to check that they're equal procedure ( is_equal ), deferred :: serializable_is_same generic :: operator ( == ) => serializable_is_same !> Test load/write roundtrip procedure , non_overridable :: test_serialization end type serializable_t !> add_table: fpm interface interface add_table module procedure add_table_fpm end interface add_table !> set_value: fpm interface interface set_value module procedure set_logical module procedure set_integer module procedure set_integer_64 end interface set_value interface set_string module procedure set_character module procedure set_string_type end interface set_string !> get_value: fpm interface interface get_value module procedure get_logical module procedure get_integer module procedure get_integer_64 module procedure get_char module procedure get_string end interface get_value abstract interface !> Write object to TOML datastructure subroutine to_toml ( self , table , error ) import serializable_t , toml_table , error_t implicit none !> Instance of the serializable object class ( serializable_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error end subroutine to_toml !> Read dependency tree from TOML data structure subroutine from_toml ( self , table , error ) import serializable_t , toml_table , error_t implicit none !> Instance of the serializable object class ( serializable_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error end subroutine from_toml !> Compare two serializable objects logical function is_equal ( this , that ) import serializable_t class ( serializable_t ), intent ( in ) :: this , that end function is_equal end interface contains !> Test serialization of a serializable object subroutine test_serialization ( self , message , error ) class ( serializable_t ), intent ( inout ) :: self character ( len =* ), intent ( in ) :: message type ( error_t ), allocatable , intent ( out ) :: error integer :: iunit , ii class ( serializable_t ), allocatable :: copy character ( len = 4 ), parameter :: formats ( 2 ) = [ 'TOML' , 'JSON' ] all_formats : do ii = 1 , 2 open ( newunit = iunit , form = 'formatted' , action = 'readwrite' , status = 'scratch' ) !> Dump to scratch file call self % dump ( iunit , error , json = ii == 2 ) if ( allocated ( error )) then error % message = formats ( ii ) // ': ' // error % message return endif !> Load from scratch file rewind ( iunit ) allocate ( copy , mold = self ) call copy % load ( iunit , error , json = ii == 2 ) if ( allocated ( error )) then error % message = formats ( ii ) // ': ' // error % message return endif close ( iunit ) !> Check same if (. not .( self == copy )) then call fatal_error ( error , 'serializable object failed ' // formats ( ii ) // & ' write/reread test: ' // trim ( message )) return end if deallocate ( copy ) end do all_formats end subroutine test_serialization !> Write serializable object to a formatted Fortran unit subroutine dump_to_unit ( self , unit , error , json ) !> Instance of the dependency tree class ( serializable_t ), intent ( inout ) :: self !> Formatted unit integer , intent ( in ) :: unit !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Optional JSON format requested? logical , optional , intent ( in ) :: json type ( toml_table ) :: table logical :: is_json is_json = . false .; if ( present ( json )) is_json = json table = toml_table () call self % dump ( table , error ) if ( is_json ) then ! !> Deactivate JSON serialization for now ! call fatal_error(error, 'JSON serialization option is not yet available') ! return write ( unit , '(a)' ) json_serialize ( table ) else write ( unit , '(a)' ) toml_serialize ( table ) end if call table % destroy () end subroutine dump_to_unit !> Write serializable object to file subroutine dump_to_file ( self , file , error , json ) !> Instance of the dependency tree class ( serializable_t ), intent ( inout ) :: self !> File name character ( len =* ), intent ( in ) :: file !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Optional JSON format logical , optional , intent ( in ) :: json integer :: unit open ( file = file , newunit = unit ) call self % dump ( unit , error , json ) close ( unit ) if ( allocated ( error )) return end subroutine dump_to_file !> Read dependency tree from file subroutine load_from_file ( self , file , error , json ) !> Instance of the dependency tree class ( serializable_t ), intent ( inout ) :: self !> File name character ( len =* ), intent ( in ) :: file !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Optional JSON format logical , optional , intent ( in ) :: json integer :: unit logical :: exist inquire ( file = file , exist = exist ) if (. not . exist ) return open ( file = file , newunit = unit ) call self % load ( unit , error , json ) close ( unit ) end subroutine load_from_file !> Read dependency tree from file subroutine load_from_unit ( self , unit , error , json ) !> Instance of the dependency tree class ( serializable_t ), intent ( inout ) :: self !> File name integer , intent ( in ) :: unit !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Optional JSON format logical , optional , intent ( in ) :: json type ( toml_error ), allocatable :: local_error type ( toml_table ), allocatable :: table type ( toml_table ), pointer :: jtable class ( toml_value ), allocatable :: object logical :: is_json is_json = . false .; if ( present ( json )) is_json = json if ( is_json ) then !> init JSON interpreter call json_load ( object , unit , error = local_error ) if ( allocated ( local_error )) then allocate ( error ) call move_alloc ( local_error % message , error % message ) return end if jtable => cast_to_object ( object ) if (. not . associated ( jtable )) then call fatal_error ( error , 'cannot initialize JSON table ' ) return end if !> Read object from TOML table call self % load ( jtable , error ) else !> use default TOML parser call toml_load ( table , unit , error = local_error ) if ( allocated ( local_error )) then allocate ( error ) call move_alloc ( local_error % message , error % message ) return end if !> Read object from TOML table call self % load ( table , error ) endif if ( allocated ( error )) return end subroutine load_from_unit !> Process the configuration file to a TOML data structure subroutine read_package_file ( table , manifest , error ) !> TOML data structure type ( toml_table ), allocatable , intent ( out ) :: table !> Name of the package configuration file character ( len =* ), intent ( in ) :: manifest !> Error status of the operation type ( error_t ), allocatable , intent ( out ) :: error type ( toml_error ), allocatable :: parse_error integer :: unit logical :: exist inquire ( file = manifest , exist = exist ) if (. not . exist ) then call file_not_found_error ( error , manifest ) return end if open ( file = manifest , newunit = unit ) call toml_load ( table , unit , error = parse_error ) close ( unit ) if ( allocated ( parse_error )) then allocate ( error ) call move_alloc ( parse_error % message , error % message ) return end if end subroutine read_package_file !> Check if an instance of the TOML data structure contains a list logical function has_list ( table , key ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Key to read from character ( len =* ), intent ( in ) :: key type ( toml_array ), pointer :: children has_list = . false . if (. not . table % has_key ( key )) return call get_value ( table , key , children , requested = . false .) ! There is an allocated list has_list = associated ( children ) end function has_list subroutine get_list ( table , key , list , error ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Key to read from character ( len =* ), intent ( in ) :: key !> List of strings to read type ( string_t ), allocatable , intent ( out ) :: list (:) !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: stat , ilist , nlist type ( toml_array ), pointer :: children character ( len = :), allocatable :: str if (. not . table % has_key ( key )) return call get_value ( table , key , children , requested = . false .) if ( associated ( children )) then nlist = len ( children ) allocate ( list ( nlist )) do ilist = 1 , nlist call get_value ( children , ilist , str , stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Entry in \" // key // \" field cannot be read\" ) exit end if call move_alloc ( str , list ( ilist )% s ) end do if ( allocated ( error )) return else call get_value ( table , key , str , stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Entry in \" // key // \" field cannot be read\" ) return end if if ( allocated ( str )) then allocate ( list ( 1 )) call move_alloc ( str , list ( 1 )% s ) end if end if end subroutine get_list ! Set string array subroutine set_list ( table , key , list , error ) !> Instance of the string array type ( string_t ), allocatable , intent ( in ) :: list (:) !> Key to save to character ( len =* ), intent ( in ) :: key !> Instance of the toml table type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Local variables integer :: stat , ilist type ( toml_array ), pointer :: children character ( len = :), allocatable :: str !> Set no key if array is not present if (. not . allocated ( list )) return !> Check the key is not empty if ( len_trim ( key ) <= 0 ) then call fatal_error ( error , 'key is empty dumping string array to TOML table' ) return end if if ( size ( list ) /= 1 ) then ! includes empty list case !> String array call add_array ( table , key , children , stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Cannot set array table in \" // key // \" field\" ) return end if do ilist = 1 , size ( list ) call set_value ( children , ilist , list ( ilist )% s , stat = stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Cannot store array entry in \" // key // \" field\" ) return end if end do else ! Single value: set string call set_value ( table , key , list ( 1 )% s , stat = stat ) if ( stat /= toml_stat % success ) & call fatal_error ( error , \"Cannot store entry in \" // key // \" field\" ) return end if end subroutine set_list !> Function wrapper to set a character(len=:), allocatable variable to a toml table subroutine set_character ( table , key , var , error , whereAt ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> List of keys to check. character ( len =* ), intent ( in ) :: key !> The character variable character ( len =* ), optional , intent ( in ) :: var !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Optional description character ( len =* ), intent ( in ), optional :: whereAt integer :: ierr !> Check the key is not empty if ( len_trim ( key ) <= 0 ) then call fatal_error ( error , 'key is empty setting character string to TOML table' ) if ( present ( whereAt )) error % message = whereAt // ': ' // error % message return end if if ( present ( var )) then call set_value ( table , key , var , ierr ) if ( ierr /= toml_stat % success ) then call fatal_error ( error , 'cannot set character key <' // key // '> in TOML table' ) if ( present ( whereAt )) error % message = whereAt // ': ' // error % message return end if endif end subroutine set_character !> Function wrapper to set a logical variable to a toml table, returning an fpm error subroutine set_logical ( table , key , var , error , whereAt ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> The key character ( len =* ), intent ( in ) :: key !> The variable logical , intent ( in ) :: var !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Optional description character ( len =* ), intent ( in ), optional :: whereAt integer :: ierr call set_value ( table , key , var , stat = ierr ) if ( ierr /= toml_stat % success ) then call fatal_error ( error , 'cannot set logical key <' // key // '> in TOML table' ) if ( present ( whereAt )) error % message = whereAt // ': ' // error % message return end if end subroutine set_logical !> Function wrapper to set a default integer variable to a toml table, returning an fpm error subroutine set_integer ( table , key , var , error , whereAt ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> The key character ( len =* ), intent ( in ) :: key !> The variable integer , intent ( in ) :: var !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Optional description character ( len =* ), intent ( in ), optional :: whereAt integer :: ierr call set_value ( table , key , var , stat = ierr ) if ( ierr /= toml_stat % success ) then call fatal_error ( error , 'cannot set integer key <' // key // '> in TOML table' ) if ( present ( whereAt )) error % message = whereAt // ': ' // error % message return end if end subroutine set_integer !> Function wrapper to set a default integer variable to a toml table, returning an fpm error subroutine set_integer_64 ( table , key , var , error , whereAt ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> The key character ( len =* ), intent ( in ) :: key !> The variable integer ( int64 ), intent ( in ) :: var !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Optional description character ( len =* ), intent ( in ), optional :: whereAt integer :: ierr call set_value ( table , key , var , stat = ierr ) if ( ierr /= toml_stat % success ) then call fatal_error ( error , 'cannot set integer(int64) key <' // key // '> in TOML table' ) if ( present ( whereAt )) error % message = whereAt // ': ' // error % message return end if end subroutine set_integer_64 !> Function wrapper to set a character(len=:), allocatable variable to a toml table subroutine set_string_type ( table , key , var , error , whereAt ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> List of keys to check. character ( len =* ), intent ( in ) :: key !> The character variable type ( string_t ), intent ( in ) :: var !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Optional description character ( len =* ), intent ( in ), optional :: whereAt call set_character ( table , key , var % s , error , whereAt ) end subroutine set_string_type !> Function wrapper to add a toml table and return an fpm error subroutine add_table_fpm ( table , key , ptr , error , whereAt ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Table key character ( len =* ), intent ( in ) :: key !> The character variable type ( toml_table ), pointer , intent ( out ) :: ptr !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Optional description character ( len =* ), intent ( in ), optional :: whereAt integer :: ierr !> Nullify pointer nullify ( ptr ) call add_table ( table , key , ptr , ierr ) if ( ierr /= toml_stat % success ) then call fatal_error ( error , 'cannot add <' // key // '> table in TOML table' ) if ( present ( whereAt )) error % message = whereAt // ': ' // error % message return end if end subroutine add_table_fpm !> Function wrapper to get a logical variable from a toml table, returning an fpm error subroutine get_logical ( table , key , var , error , whereAt ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> The key character ( len =* ), intent ( in ) :: key !> The variable logical , intent ( inout ) :: var !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Optional description character ( len =* ), intent ( in ), optional :: whereAt integer :: ierr call get_value ( table , key , var , stat = ierr ) if ( ierr /= toml_stat % success ) then call fatal_error ( error , 'cannot get logical key <' // key // '> from TOML table' ) if ( present ( whereAt )) error % message = whereAt // ': ' // error % message return end if end subroutine get_logical !> Function wrapper to get a default integer variable from a toml table, returning an fpm error subroutine get_integer ( table , key , var , error , whereAt ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> The key character ( len =* ), intent ( in ) :: key !> The variable integer , intent ( inout ) :: var !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Optional description character ( len =* ), intent ( in ), optional :: whereAt integer :: ierr call get_value ( table , key , var , stat = ierr ) if ( ierr /= toml_stat % success ) then call fatal_error ( error , 'cannot get integer key <' // key // '> from TOML table' ) if ( present ( whereAt )) error % message = whereAt // ': ' // error % message return end if end subroutine get_integer !> Function wrapper to get a default string variable from a toml table, returning an fpm error subroutine get_string ( table , key , var , error , whereAt ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> The key character ( len =* ), intent ( in ) :: key !> The variable type ( string_t ), intent ( inout ) :: var !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Optional description character ( len =* ), intent ( in ), optional :: whereAt call get_char ( table , key , var % s , error , whereAt ) end subroutine get_string !> Function wrapper to get a default character variable from a toml table, returning an fpm error subroutine get_char ( table , key , var , error , whereAt ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> The key character ( len =* ), intent ( in ) :: key !> The variable character ( len = :), allocatable , intent ( inout ) :: var !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Optional description character ( len =* ), intent ( in ), optional :: whereAt integer :: ierr call get_value ( table , key , var , stat = ierr ) if ( ierr /= toml_stat % success ) then call fatal_error ( error , 'cannot get string key <' // key // '> from TOML table' ) if ( present ( whereAt )) error % message = whereAt // ': ' // error % message return end if end subroutine get_char !> Function wrapper to get a integer(int64) variable from a toml table, returning an fpm error subroutine get_integer_64 ( table , key , var , error , whereAt ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> The key character ( len =* ), intent ( in ) :: key !> The variable integer ( int64 ), intent ( inout ) :: var !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Optional description character ( len =* ), intent ( in ), optional :: whereAt integer :: ierr call get_value ( table , key , var , stat = ierr ) if ( ierr /= toml_stat % success ) then call fatal_error ( error , 'cannot get integer(int64) key <' // key // '> from TOML table' ) if ( present ( whereAt )) error % message = whereAt // ': ' // error % message return end if end subroutine get_integer_64 !> Check if table contains only keys that are part of the list. If a key is !> found that is not part of the list, an error is allocated. subroutine check_keys ( table , valid_keys , error ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> List of keys to check. character ( len =* ), intent ( in ) :: valid_keys (:) !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_key ), allocatable :: keys (:) type ( toml_table ), pointer :: child character (:), allocatable :: name , value , valid_keys_string integer :: ikey , ivalid call table % get_key ( name ) call table % get_keys ( keys ) do ikey = 1 , size ( keys ) if (. not . any ( keys ( ikey )% key == valid_keys )) then ! Generate error message valid_keys_string = new_line ( 'a' ) // new_line ( 'a' ) do ivalid = 1 , size ( valid_keys ) valid_keys_string = valid_keys_string // trim ( valid_keys ( ivalid )) // new_line ( 'a' ) end do allocate ( error ) error % message = \"Key '\" // keys ( ikey )% key // \"' not allowed in the '\" // & & name // \"' table.\" // new_line ( 'a' ) // new_line ( 'a' ) // 'Valid keys: ' // valid_keys_string return end if ! Check if value can be mapped or else (wrong type) show error message with the error location. ! Right now, it can only be mapped to a string or to a child node, but this can be extended in the future. call get_value ( table , keys ( ikey )% key , value ) if (. not . allocated ( value )) then ! If value is not a string, check if it is a child node call get_value ( table , keys ( ikey )% key , child ) if (. not . associated ( child )) then allocate ( error ) error % message = \"'\" // name // \"' has an invalid '\" // keys ( ikey )% key // \"' entry.\" return endif end if end do end subroutine check_keys !> Choose between JSON or TOML based on a file name logical function name_is_json ( filename ) character ( * ), intent ( in ) :: filename character ( * ), parameter :: json_identifier = \".json\" name_is_json = . false . if ( len_trim ( filename ) < len ( json_identifier )) return name_is_json = str_ends_with ( lower ( filename ), json_identifier ) end function name_is_json end module fpm_toml","tags":"","url":"sourcefile/toml.f90.html"},{"title":"export.f90 – Fortran-lang/fpm","text":"Source Code module fpm_cmd_export use fpm_command_line , only : fpm_export_settings use fpm_dependency , only : dependency_tree_t , new_dependency_tree use fpm_error , only : error_t , fpm_stop use fpm_filesystem , only : join_path use fpm_manifest , only : package_config_t , get_package_data use fpm_toml , only : name_is_json use fpm_model , only : fpm_model_t use fpm , only : build_model implicit none private public :: cmd_export contains !> Entry point for the export subcommand subroutine cmd_export ( settings ) !> Representation of the command line arguments type ( fpm_export_settings ), intent ( inout ) :: settings type ( package_config_t ) :: package type ( dependency_tree_t ) :: deps type ( fpm_model_t ) :: model type ( error_t ), allocatable :: error character ( len = :), allocatable :: filename if ( len_trim ( settings % dump_manifest ) <= 0 . and . & len_trim ( settings % dump_model ) <= 0 . and . & len_trim ( settings % dump_dependencies ) <= 0 ) then call fpm_stop ( 0 , '*cmd_export* exiting: no manifest/model/dependencies keyword provided' ) end if !> Read in manifest call get_package_data ( package , \"fpm.toml\" , error , apply_defaults = . true .) call handle_error ( error ) !> Export manifest if ( len_trim ( settings % dump_manifest ) > 0 ) then filename = trim ( settings % dump_manifest ) call package % dump ( filename , error , json = name_is_json ( filename )) end if !> Export dependency tree if ( len_trim ( settings % dump_dependencies ) > 0 ) then !> Generate dependency tree filename = join_path ( \"build\" , \"cache.toml\" ) call new_dependency_tree ( deps , cache = filename , verbosity = merge ( 2 , 1 , settings % verbose )) call deps % add ( package , error ) call handle_error ( error ) !> Export dependency tree filename = settings % dump_dependencies call deps % dump ( filename , error , json = name_is_json ( filename )) call handle_error ( error ) end if !> Export full model if ( len_trim ( settings % dump_model ) > 0 ) then call build_model ( model , settings % fpm_build_settings , package , error ) if ( allocated ( error )) then call fpm_stop ( 1 , '*cmd_export* Model error: ' // error % message ) end if filename = settings % dump_model call model % dump ( filename , error , json = name_is_json ( filename )) call handle_error ( error ) end if end subroutine cmd_export !> Error handling for this command subroutine handle_error ( error ) !> Potential error type ( error_t ), intent ( in ), optional :: error if ( present ( error )) then call fpm_stop ( 1 , '*cmd_export* error: ' // error % message ) end if end subroutine handle_error end module fpm_cmd_export","tags":"","url":"sourcefile/export.f90.html"},{"title":"dependency.f90 – Fortran-lang/fpm","text":"Source Code !> Implementation of the meta data for dependencies. !> !> A dependency table can currently have the following fields !> !>```toml !>[dependencies] !>\"dep1\" = { git = \"url\" } !>\"dep2\" = { git = \"url\", branch = \"name\" } !>\"dep3\" = { git = \"url\", tag = \"name\" } !>\"dep4\" = { git = \"url\", rev = \"sha1\" } !>\"dep0\" = { path = \"path\" } !>``` !> !> To reduce the amount of boilerplate code this module provides two constructors !> for dependency types, one basic for an actual dependency (inline) table !> and another to collect all dependency objects from a dependencies table, !> which is handling the allocation of the objects and is forwarding the !> individual dependency tables to their respective constructors. !> The usual entry point should be the constructor for the super table. !> !> This objects contains a target to retrieve required `fpm` projects to !> build the target declaring the dependency. !> Resolving a dependency will result in obtaining a new package configuration !> data for the respective project. module fpm_manifest_dependency use fpm_error , only : error_t , syntax_error , fatal_error use fpm_git , only : git_target_t , git_target_tag , git_target_branch , & & git_target_revision , git_target_default , git_matches_manifest use tomlf , only : toml_table , toml_key , toml_stat use fpm_toml , only : get_value , check_keys , serializable_t , add_table , & & set_value , set_string use fpm_filesystem , only : windows_path , join_path use fpm_environment , only : get_os_type , OS_WINDOWS use fpm_manifest_metapackages , only : metapackage_config_t , is_meta_package , new_meta_config , & metapackage_request_t , new_meta_request use fpm_versioning , only : version_t , new_version use fpm_strings , only : string_t use fpm_manifest_preprocess implicit none private public :: dependency_config_t , new_dependency , new_dependencies , manifest_has_changed , & & dependency_destroy , resize !> Configuration meta data for a dependency type , extends ( serializable_t ) :: dependency_config_t !> Name of the dependency character ( len = :), allocatable :: name !> Local target character ( len = :), allocatable :: path !> Namespace which the dependency belongs to. !> Enables multiple dependencies with the same name. !> Required for dependencies that are obtained via the official registry. character ( len = :), allocatable :: namespace !> The requested version of the dependency. !> The latest version is used if not specified. type ( version_t ), allocatable :: requested_version !> Requested macros for the dependency type ( preprocess_config_t ), allocatable :: preprocess (:) !> Git descriptor type ( git_target_t ), allocatable :: git contains !> Print information on this instance procedure :: info !> Add a preprocessor configuration procedure :: add_preprocess !> Serialization interface procedure :: serializable_is_same => dependency_is_same procedure :: dump_to_toml procedure :: load_from_toml end type dependency_config_t !> Common output format for writing to the command line character ( len =* ), parameter :: out_fmt = '(\"#\", *(1x, g0))' interface resize module procedure resize_dependency_config end interface resize contains !> Construct a new dependency configuration from a TOML data structure subroutine new_dependency ( self , table , root , error ) !> Instance of the dependency configuration type ( dependency_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Root directory of the manifest character ( * ), intent ( in ), optional :: root !> Error handling type ( error_t ), allocatable , intent ( out ) :: error character ( len = :), allocatable :: uri , value , requested_version type ( toml_table ), pointer :: child call check ( table , error ) if ( allocated ( error )) return call table % get_key ( self % name ) call get_value ( table , \"namespace\" , self % namespace ) call get_value ( table , \"v\" , requested_version ) if ( allocated ( requested_version )) then if (. not . allocated ( self % requested_version )) allocate ( self % requested_version ) call new_version ( self % requested_version , requested_version , error ) if ( allocated ( error )) return end if !> Get optional preprocessor directives call get_value ( table , \"preprocess\" , child , requested = . false .) if ( associated ( child )) then call new_preprocessors ( self % preprocess , child , error ) if ( allocated ( error )) return endif call get_value ( table , \"path\" , uri ) if ( allocated ( uri )) then if ( get_os_type () == OS_WINDOWS ) uri = windows_path ( uri ) if ( present ( root )) uri = join_path ( root , uri ) ! Relative to the fpm.toml it’s written in call move_alloc ( uri , self % path ) return end if call get_value ( table , \"git\" , uri ) if ( allocated ( uri )) then call get_value ( table , \"tag\" , value ) if ( allocated ( value )) then self % git = git_target_tag ( uri , value ) end if if (. not . allocated ( self % git )) then call get_value ( table , \"branch\" , value ) if ( allocated ( value )) then self % git = git_target_branch ( uri , value ) end if end if if (. not . allocated ( self % git )) then call get_value ( table , \"rev\" , value ) if ( allocated ( value )) then self % git = git_target_revision ( uri , value ) end if end if if (. not . allocated ( self % git )) then self % git = git_target_default ( uri ) end if return end if end subroutine new_dependency !> Check local schema for allowed entries subroutine check ( table , error ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error character ( len = :), allocatable :: name type ( toml_key ), allocatable :: list (:) type ( toml_table ), pointer :: child !> List of valid keys for the dependency table. character ( * ), dimension ( * ), parameter :: valid_keys = [ character ( 24 ) :: & & \"namespace\" , & \"v\" , & \"path\" , & \"git\" , & \"tag\" , & \"branch\" , & \"rev\" , & \"preprocess\" & & ] call table % get_key ( name ) call table % get_keys ( list ) if ( size ( list ) < 1 ) then call syntax_error ( error , \"Dependency '\" // name // \"' does not provide sufficient entries\" ) return end if call check_keys ( table , valid_keys , error ) if ( allocated ( error )) return if ( table % has_key ( \"path\" ) . and . table % has_key ( \"git\" )) then call syntax_error ( error , \"Dependency '\" // name // \"' cannot have both git and path entries\" ) return end if if (( table % has_key ( \"branch\" ) . and . table % has_key ( \"rev\" )) . or . & ( table % has_key ( \"branch\" ) . and . table % has_key ( \"tag\" )) . or . & ( table % has_key ( \"rev\" ) . and . table % has_key ( \"tag\" ))) then call syntax_error ( error , \"Dependency '\" // name // \"' can only have one of branch, rev or tag present\" ) return end if if (( table % has_key ( \"branch\" ) . or . table % has_key ( \"tag\" ) . or . table % has_key ( \"rev\" )) & . and . . not . table % has_key ( \"git\" )) then call syntax_error ( error , \"Dependency '\" // name // \"' has git identifier but no git url\" ) return end if if (. not . table % has_key ( \"path\" ) . and . . not . table % has_key ( \"git\" ) & . and . . not . table % has_key ( \"namespace\" )) then call syntax_error ( error , \"Please provide a 'namespace' for dependency '\" // name // & & \"' if it is not a local path or git repository\" ) return end if if ( table % has_key ( 'v' ) . and . ( table % has_key ( 'path' ) . or . table % has_key ( 'git' ))) then call syntax_error ( error , \"Dependency '\" // name // \"' cannot have both v and git/path entries\" ) return end if ! Check preprocess key if ( table % has_key ( 'preprocess' )) then call get_value ( table , 'preprocess' , child ) if (. not . associated ( child )) then call syntax_error ( error , \"Dependency '\" // name // \"' has invalid 'preprocess' entry\" ) return end if end if end subroutine check !> Construct new dependency array from a TOML data structure subroutine new_dependencies ( deps , table , root , meta , error ) !> Instance of the dependency configuration type ( dependency_config_t ), allocatable , intent ( out ) :: deps (:) !> (optional) metapackages type ( metapackage_config_t ), optional , intent ( out ) :: meta !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Root directory of the manifest character ( * ), intent ( in ), optional :: root !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_table ), pointer :: node type ( toml_key ), allocatable :: list (:) type ( dependency_config_t ), allocatable :: all_deps (:) type ( metapackage_request_t ) :: meta_request logical , allocatable :: is_meta (:) logical :: metapackages_allowed integer :: idep , stat , ndep call table % get_keys ( list ) ! An empty table is okay if ( size ( list ) < 1 ) return !> Flag dependencies that should be treated as metapackages metapackages_allowed = present ( meta ) allocate ( is_meta ( size ( list )), source = . false .) allocate ( all_deps ( size ( list ))) !> Parse all meta- and non-metapackage dependencies do idep = 1 , size ( list ) ! Check if this is a standard dependency node call get_value ( table , list ( idep )% key , node , stat = stat ) is_standard_dependency : if ( stat /= toml_stat % success ) then ! See if it can be a valid metapackage name call new_meta_request ( meta_request , list ( idep )% key , table , error = error ) !> Neither a standard dep nor a metapackage if ( allocated ( error )) then call syntax_error ( error , \"Dependency \" // list ( idep )% key // \" is not a valid metapackage or a table entry\" ) return endif !> Valid meta dependency is_meta ( idep ) = . true . else ! Parse as a standard dependency is_meta ( idep ) = . false . call new_dependency ( all_deps ( idep ), node , root , error ) if ( allocated ( error )) return end if is_standard_dependency end do ! Non-meta dependencies ndep = count (. not . is_meta ) ! Finalize standard dependencies allocate ( deps ( ndep )) ndep = 0 do idep = 1 , size ( list ) if ( is_meta ( idep )) cycle ndep = ndep + 1 deps ( ndep ) = all_deps ( idep ) end do ! Finalize meta dependencies if ( metapackages_allowed ) call new_meta_config ( meta , table , is_meta , error ) end subroutine new_dependencies !> Write information on instance subroutine info ( self , unit , verbosity ) !> Instance of the dependency configuration class ( dependency_config_t ), intent ( in ) :: self !> Unit for IO integer , intent ( in ) :: unit !> Verbosity of the printout integer , intent ( in ), optional :: verbosity integer :: pr character ( len =* ), parameter :: fmt = '(\"#\", 1x, a, t30, a)' if ( present ( verbosity )) then pr = verbosity else pr = 1 end if write ( unit , fmt ) \"Dependency\" if ( allocated ( self % name )) then write ( unit , fmt ) \"- name\" , self % name end if if ( allocated ( self % git )) then write ( unit , fmt ) \"- kind\" , \"git\" call self % git % info ( unit , pr - 1 ) end if if ( allocated ( self % path )) then write ( unit , fmt ) \"- kind\" , \"local\" write ( unit , fmt ) \"- path\" , self % path end if end subroutine info !> Check if two dependency configurations are different logical function manifest_has_changed ( cached , manifest , verbosity , iunit ) result ( has_changed ) !> Two instances of the dependency configuration class ( dependency_config_t ), intent ( in ) :: cached , manifest !> Log verbosity integer , intent ( in ) :: verbosity , iunit has_changed = . true . !> Perform all checks if ( allocated ( cached % git ). neqv . allocated ( manifest % git )) then if ( verbosity > 1 ) write ( iunit , out_fmt ) \"GIT presence has changed. \" return endif if ( allocated ( cached % git )) then if (. not . git_matches_manifest ( cached % git , manifest % git , verbosity , iunit )) return end if !> All checks passed! The two instances are equal has_changed = . false . end function manifest_has_changed !> Clean memory elemental subroutine dependency_destroy ( self ) class ( dependency_config_t ), intent ( inout ) :: self if ( allocated ( self % name )) deallocate ( self % name ) if ( allocated ( self % path )) deallocate ( self % path ) if ( allocated ( self % namespace )) deallocate ( self % namespace ) if ( allocated ( self % requested_version )) deallocate ( self % requested_version ) if ( allocated ( self % git )) deallocate ( self % git ) end subroutine dependency_destroy !> Check that two dependency configs are equal logical function dependency_is_same ( this , that ) class ( dependency_config_t ), intent ( in ) :: this class ( serializable_t ), intent ( in ) :: that dependency_is_same = . false . select type ( other => that ) type is ( dependency_config_t ) if ( allocated ( this % name ). neqv . allocated ( other % name )) return if ( allocated ( this % name )) then if (. not .( this % name == other % name )) return endif if ( allocated ( this % path ). neqv . allocated ( other % path )) return if ( allocated ( this % path )) then if (. not .( this % path == other % path )) return endif if ( allocated ( this % namespace ). neqv . allocated ( other % namespace )) return if ( allocated ( this % namespace )) then if (. not .( this % namespace == other % namespace )) return endif if ( allocated ( this % requested_version ). neqv . allocated ( other % requested_version )) return if ( allocated ( this % requested_version )) then if (. not .( this % requested_version == other % requested_version )) return endif if (( allocated ( this % git ). neqv . allocated ( other % git ))) return if ( allocated ( this % git )) then if (. not .( this % git == other % git )) return endif class default ! Not the same type return end select !> All checks passed! dependency_is_same = . true . end function dependency_is_same !> Dump dependency to toml table subroutine dump_to_toml ( self , table , error ) !> Instance of the serializable object class ( dependency_config_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( toml_table ), pointer :: ptr type ( error_t ), allocatable , intent ( out ) :: error integer :: ierr call set_string ( table , \"name\" , self % name , error , 'dependency_config_t' ) if ( allocated ( error )) return call set_string ( table , \"path\" , self % path , error , 'dependency_config_t' ) if ( allocated ( error )) return call set_string ( table , \"namespace\" , self % namespace , error , 'dependency_config_t' ) if ( allocated ( error )) return if ( allocated ( self % requested_version )) then call set_string ( table , \"requested_version\" , self % requested_version % s (), error , 'dependency_config_t' ) if ( allocated ( error )) return endif if ( allocated ( self % git )) then call add_table ( table , \"git\" , ptr , error ) if ( allocated ( error )) return call self % git % dump_to_toml ( ptr , error ) if ( allocated ( error )) return endif end subroutine dump_to_toml !> Read dependency from toml table (no checks made at this stage) subroutine load_from_toml ( self , table , error ) !> Instance of the serializable object class ( dependency_config_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Local variables type ( toml_key ), allocatable :: list (:) type ( toml_table ), pointer :: ptr character ( len = :), allocatable :: requested_version integer :: ierr , ii call dependency_destroy ( self ) call get_value ( table , \"name\" , self % name ) call get_value ( table , \"path\" , self % path ) call get_value ( table , \"namespace\" , self % namespace ) call get_value ( table , \"requested_version\" , requested_version ) if ( allocated ( requested_version )) then allocate ( self % requested_version ) call new_version ( self % requested_version , requested_version , error ) if ( allocated ( error )) then error % message = 'dependency_config_t: version error from TOML table - ' // error % message return endif end if call table % get_keys ( list ) add_git : do ii = 1 , size ( list ) if ( list ( ii )% key == \"git\" ) then call get_value ( table , list ( ii )% key , ptr , stat = ierr ) if ( ierr /= toml_stat % success ) then call fatal_error ( error , 'dependency_config_t: cannot retrieve git from TOML table' ) exit endif allocate ( self % git ) call self % git % load_from_toml ( ptr , error ) if ( allocated ( error )) return exit add_git end if end do add_git end subroutine load_from_toml !> Reallocate a list of dependencies pure subroutine resize_dependency_config ( var , n ) !> Instance of the array to be resized type ( dependency_config_t ), allocatable , intent ( inout ) :: var (:) !> Dimension of the final array size integer , intent ( in ), optional :: n type ( dependency_config_t ), allocatable :: tmp (:) integer :: this_size , new_size integer , parameter :: initial_size = 16 if ( allocated ( var )) then this_size = size ( var , 1 ) call move_alloc ( var , tmp ) else this_size = initial_size end if if ( present ( n )) then new_size = n else new_size = this_size + this_size / 2 + 1 end if allocate ( var ( new_size )) if ( allocated ( tmp )) then this_size = min ( size ( tmp , 1 ), size ( var , 1 )) var (: this_size ) = tmp (: this_size ) deallocate ( tmp ) end if end subroutine resize_dependency_config subroutine add_preprocess ( dep , preprocess ) !> Instance of the dependency config class ( dependency_config_t ), intent ( inout ) :: dep !> Instance of the preprocessor configuration type ( preprocess_config_t ), intent ( in ) :: preprocess integer :: i , n type ( preprocess_config_t ), allocatable :: new_preprocess (:) if ( allocated ( dep % preprocess )) then n = size ( dep % preprocess ) if ( n < 1 ) then deallocate ( dep % preprocess ) allocate ( dep % preprocess ( 1 ), source = preprocess ) else find_similar : do i = 1 , n if ( dep % preprocess ( i )% name == dep % name ) then call dep % preprocess ( i )% add_config ( preprocess ) return end if end do find_similar ! Similar preprocessor config not found: add a new one allocate ( new_preprocess ( n + 1 )) new_preprocess ( 1 : n ) = dep % preprocess new_preprocess ( n + 1 ) = preprocess call move_alloc ( from = new_preprocess , to = dep % preprocess ) end if else ! Copy configuration allocate ( dep % preprocess ( 1 ), source = preprocess ) end if end subroutine add_preprocess end module fpm_manifest_dependency","tags":"","url":"sourcefile/dependency.f90~2.html"},{"title":"fpm_meta_netcdf.f90 – Fortran-lang/fpm","text":"Source Code module fpm_meta_netcdf use fpm_compiler , only : compiler_t , get_include_flag use fpm_meta_base , only : metapackage_t , destroy use fpm_meta_util , only : add_pkg_config_compile_options use fpm_pkg_config , only : assert_pkg_config , pkgcfg_has_package use fpm_strings , only : string_t use fpm_error , only : error_t , fatal_error use fpm_manifest_metapackages , only : metapackage_request_t implicit none private public :: init_netcdf contains !> Initialize NetCDF metapackage for the current system subroutine init_netcdf ( this , compiler , all_meta , error ) class ( metapackage_t ), intent ( inout ) :: this type ( compiler_t ), intent ( in ) :: compiler type ( metapackage_request_t ), intent ( in ) :: all_meta (:) type ( error_t ), allocatable , intent ( out ) :: error logical :: s character ( len = :), allocatable :: include_flag , libdir include_flag = get_include_flag ( compiler , \"\" ) !> Cleanup call destroy ( this ) allocate ( this % link_libs ( 0 ), this % incl_dirs ( 0 ), this % external_modules ( 0 )) this % link_flags = string_t ( \"\" ) this % flags = string_t ( \"\" ) !> Set name this % name = \"netcdf\" !> Assert pkg-config is installed if (. not . assert_pkg_config ()) then call fatal_error ( error , 'netcdf metapackage requires pkg-config' ) return end if if (. not . pkgcfg_has_package ( 'netcdf' )) then call fatal_error ( error , 'pkg-config could not find a suitable netcdf package.' ) return end if call add_pkg_config_compile_options ( this , 'netcdf' , include_flag , libdir , error ) if ( allocated ( error )) return if (. not . pkgcfg_has_package ( 'netcdf-fortran' )) then call fatal_error ( error , & 'pkg-config could not find a suitable netcdf-fortran package.' ) return end if call add_pkg_config_compile_options ( this , 'netcdf-fortran' , include_flag , libdir , error ) if ( allocated ( error )) return !> Add NetCDF modules as external this % has_external_modules = . true . this % external_modules = [ string_t ( 'netcdf' ), & string_t ( 'netcdf4_f03' ), & string_t ( 'netcdf4_nc_interfaces' ), & string_t ( 'netcdf4_nf_interfaces' ), & string_t ( 'netcdf_f03' ), & string_t ( 'netcdf_fortv2_c_interfaces' ), & string_t ( 'netcdf_nc_data' ), & string_t ( 'netcdf_nc_interfaces' ), & string_t ( 'netcdf_nf_data' ), & string_t ( 'netcdf_nf_interfaces' )] end subroutine init_netcdf end module fpm_meta_netcdf","tags":"","url":"sourcefile/fpm_meta_netcdf.f90.html"},{"title":"installer.f90 – Fortran-lang/fpm","text":"Source Code !> Implementation of an installer object. !> !> The installer provides a way to install objects to their respective directories !> in the installation prefix, a generic install command allows to install !> to any directory within the prefix. module fpm_installer use , intrinsic :: iso_fortran_env , only : output_unit use fpm_environment , only : get_os_type , os_is_unix , OS_WINDOWS , OS_MACOS use fpm_error , only : error_t , fatal_error use fpm_targets , only : build_target_t , FPM_TARGET_ARCHIVE , FPM_TARGET_SHARED , FPM_TARGET_NAME use fpm_filesystem , only : join_path , mkdir , exists , unix_path , windows_path , get_local_prefix , & basename implicit none private public :: installer_t , new_installer !> Declaration of the installer type type :: installer_t !> Path to installation directory character ( len = :), allocatable :: prefix !> Binary dir relative to the installation prefix character ( len = :), allocatable :: bindir !> Library directory relative to the installation prefix character ( len = :), allocatable :: libdir !> Test program directory relative to the installation prefix character ( len = :), allocatable :: testdir !> Include directory relative to the installation prefix character ( len = :), allocatable :: includedir !> Output unit for informative printout integer :: unit = output_unit !> Verbosity of the installer integer :: verbosity = 1 !> Command to copy objects into the installation prefix character ( len = :), allocatable :: copy !> Command to move objects into the installation prefix character ( len = :), allocatable :: move !> Cached operating system integer :: os contains !> Evaluate the installation path procedure :: install_destination !> Install an executable in its correct subdirectory procedure :: install_executable !> Install a library in its correct subdirectory procedure :: install_library !> Install a header/module in its correct subdirectory procedure :: install_header !> Install a test program in its correct subdirectory procedure :: install_test !> Install a generic file into a subdirectory in the installation prefix procedure :: install !> Run an installation command, type-bound for unit testing purposes procedure :: run !> Create a new directory in the prefix, type-bound for unit testing purposes procedure :: make_dir end type installer_t !> Default name of the binary subdirectory character ( len =* ), parameter :: default_bindir = \"bin\" !> Default name of the library subdirectory character ( len =* ), parameter :: default_libdir = \"lib\" !> Default name of the test subdirectory character ( len =* ), parameter :: default_testdir = \"test\" !> Default name of the include subdirectory character ( len =* ), parameter :: default_includedir = \"include\" !> Copy command on Unix platforms character ( len =* ), parameter :: default_copy_unix = \"cp\" !> Copy command on Windows platforms character ( len =* ), parameter :: default_copy_win = \"copy\" !> Copy command on Unix platforms character ( len =* ), parameter :: default_force_copy_unix = \"cp -f\" !> Copy command on Windows platforms character ( len =* ), parameter :: default_force_copy_win = \"copy /Y\" !> Move command on Unix platforms character ( len =* ), parameter :: default_move_unix = \"mv\" !> Move command on Windows platforms character ( len =* ), parameter :: default_move_win = \"move\" contains !> Create a new instance of an installer subroutine new_installer ( self , prefix , bindir , libdir , includedir , testdir , verbosity , & copy , move ) !> Instance of the installer type ( installer_t ), intent ( out ) :: self !> Path to installation directory character ( len =* ), intent ( in ), optional :: prefix !> Binary dir relative to the installation prefix character ( len =* ), intent ( in ), optional :: bindir !> Library directory relative to the installation prefix character ( len =* ), intent ( in ), optional :: libdir !> Include directory relative to the installation prefix character ( len =* ), intent ( in ), optional :: includedir !> Test directory relative to the installation prefix character ( len =* ), intent ( in ), optional :: testdir !> Verbosity of the installer integer , intent ( in ), optional :: verbosity !> Copy command character ( len =* ), intent ( in ), optional :: copy !> Move command character ( len =* ), intent ( in ), optional :: move self % os = get_os_type () ! By default, never prompt the user for overwrites if ( present ( copy )) then self % copy = copy else if ( os_is_unix ( self % os )) then self % copy = default_force_copy_unix else self % copy = default_force_copy_win end if end if if ( present ( move )) then self % move = move else if ( os_is_unix ( self % os )) then self % move = default_move_unix else self % move = default_move_win end if end if if ( present ( includedir )) then self % includedir = includedir else self % includedir = default_includedir end if if ( present ( testdir )) then self % testdir = testdir else self % testdir = default_testdir end if if ( present ( prefix )) then self % prefix = prefix else self % prefix = get_local_prefix ( self % os ) end if if ( present ( bindir )) then self % bindir = bindir else self % bindir = default_bindir end if if ( present ( libdir )) then self % libdir = libdir else self % libdir = default_libdir end if if ( present ( verbosity )) then self % verbosity = verbosity else self % verbosity = 1 end if end subroutine new_installer !> Install an executable in its correct subdirectory subroutine install_executable ( self , executable , error ) !> Instance of the installer class ( installer_t ), intent ( inout ) :: self !> Path to the executable character ( len =* ), intent ( in ) :: executable !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: ll character ( len = :), allocatable :: exe_path , cmd if (. not . os_is_unix ( self % os )) then ll = len ( executable ) if ( executable ( max ( 1 , ll - 3 ): ll ) /= \".exe\" ) then call self % install ( executable // \".exe\" , self % bindir , error ) return end if end if call self % install ( executable , self % bindir , error ) ! on MacOS, add two relative paths for search of dynamic library dependencies: add_rpath : if ( self % os == OS_MACOS ) then exe_path = join_path ( self % install_destination ( self % bindir ) , basename ( executable )) ! First path: for bin/lib/include structure cmd = \"install_name_tool -add_rpath @executable_path/../lib \" // exe_path call self % run ( cmd , error ) if ( allocated ( error )) return ! Second path: same as executable folder cmd = \"install_name_tool -add_rpath @executable_path \" // exe_path call self % run ( cmd , error ) if ( allocated ( error )) return end if add_rpath end subroutine install_executable !> Install a library in its correct subdirectory subroutine install_library ( self , library , error ) !> Instance of the installer class ( installer_t ), intent ( inout ) :: self !> Library target type ( build_target_t ), intent ( in ) :: library !> Error handling type ( error_t ), allocatable , intent ( out ) :: error character (:), allocatable :: def_file , implib_file select case ( library % target_type ) case ( FPM_TARGET_ARCHIVE ) call self % install ( library % output_file , self % libdir , error ) case ( FPM_TARGET_SHARED ) call self % install ( library % output_file , self % libdir , error ) ! Handle shared library side-files only on Windows if ( self % os == OS_WINDOWS ) then ! Try both compiler-dependent import library names implib_file = join_path ( library % output_dir , library % package_name // \".dll.a\" ) if ( exists ( implib_file )) then call self % install ( implib_file , self % libdir , error ) if ( allocated ( error )) return else implib_file = join_path ( library % output_dir , library % package_name // \".lib\" ) if ( exists ( implib_file )) call self % install ( implib_file , self % libdir , error ) if ( allocated ( error )) return endif end if case default call fatal_error ( error , \"Installer error: \" // library % package_name // \" is a \" // & FPM_TARGET_NAME ( library % target_type ) // \", not a library\" ) return end select end subroutine install_library !> Install a test program in its correct subdirectory subroutine install_test ( self , test , error ) !> Instance of the installer class ( installer_t ), intent ( inout ) :: self !> Path to the test executable character ( len =* ), intent ( in ) :: test !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: ll if (. not . os_is_unix ( self % os )) then ll = len ( test ) if ( test ( max ( 1 , ll - 3 ): ll ) /= \".exe\" ) then call self % install ( test // \".exe\" , self % testdir , error ) return end if end if call self % install ( test , self % testdir , error ) end subroutine install_test !> Install a header/module in its correct subdirectory subroutine install_header ( self , header , error ) !> Instance of the installer class ( installer_t ), intent ( inout ) :: self !> Path to the header character ( len =* ), intent ( in ) :: header !> Error handling type ( error_t ), allocatable , intent ( out ) :: error call self % install ( header , self % includedir , error ) end subroutine install_header !> Install a generic file into a subdirectory in the installation prefix subroutine install ( self , source , destination , error ) !> Instance of the installer class ( installer_t ), intent ( inout ) :: self !> Path to the original file character ( len =* ), intent ( in ) :: source !> Path to the destination inside the prefix character ( len =* ), intent ( in ) :: destination !> Error handling type ( error_t ), allocatable , intent ( out ) :: error character ( len = :), allocatable :: install_dest install_dest = self % install_destination ( destination ) call self % make_dir ( install_dest , error ) if ( allocated ( error )) return if ( self % verbosity > 0 ) then if ( exists ( install_dest )) then write ( self % unit , '(\"# Update:\", 1x, a, 1x, \"->\", 1x, a)' ) & source , install_dest else write ( self % unit , '(\"# Install:\", 1x, a, 1x, \"->\", 1x, a)' ) & source , install_dest end if end if ! Use force-copy to never prompt the user for overwrite if a package was already installed call self % run ( self % copy // ' \"' // source // '\" \"' // install_dest // '\"' , error ) if ( allocated ( error )) return end subroutine install !> Evaluate the installation path function install_destination ( self , destination ) result ( install_dest ) !> Instance of the installer class ( installer_t ), intent ( inout ) :: self !> Path to the destination inside the prefix character ( len =* ), intent ( in ) :: destination character ( len = :), allocatable :: install_dest install_dest = join_path ( self % prefix , destination ) if ( os_is_unix ( self % os )) then install_dest = unix_path ( install_dest ) else install_dest = windows_path ( install_dest ) end if end function install_destination !> Create a new directory in the prefix subroutine make_dir ( self , dir , error ) !> Instance of the installer class ( installer_t ), intent ( inout ) :: self !> Directory to be created character ( len =* ), intent ( in ) :: dir !> Error handling type ( error_t ), allocatable , intent ( out ) :: error if (. not . exists ( dir )) then if ( self % verbosity > 1 ) then write ( self % unit , '(\"# Dir:\", 1x, a)' ) dir end if call mkdir ( dir ) end if end subroutine make_dir !> Run an installation command subroutine run ( self , command , error ) !> Instance of the installer class ( installer_t ), intent ( inout ) :: self !> Command to be launched character ( len =* ), intent ( in ) :: command !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: stat if ( self % verbosity > 1 ) then write ( self % unit , '(\"# Run:\", 1x, a)' ) command end if call execute_command_line ( command , exitstat = stat ) if ( stat /= 0 ) then call fatal_error ( error , \"Failed in command: '\" // command // \"'\" ) return end if end subroutine run end module fpm_installer","tags":"","url":"sourcefile/installer.f90.html"},{"title":"profiles.f90 – Fortran-lang/fpm","text":"Source Code !> Implementation of the meta data for compiler flag profiles. !> !> A profiles table can currently have the following subtables: !> Profile names - any string, if omitted, flags are appended to all matching profiles !> Compiler - any from the following list, omitting it yields an error !> !> - \"gfortran\" !> - \"ifort\" !> - \"ifx\" !> - \"pgfortran\" !> - \"nvfortran\" !> - \"flang\" !> - \"caf\" !> - \"f95\" !> - \"lfortran\" !> - \"lfc\" !> - \"nagfor\" !> - \"crayftn\" !> - \"xlf90\" !> - \"ftn95\" !> !> OS - any from the following list, if omitted, the profile is used if and only !> if there is no profile perfectly matching the current configuration !> !> - \"linux\" !> - \"macos\" !> - \"windows\" !> - \"cygwin\" !> - \"solaris\" !> - \"freebsd\" !> - \"openbsd\" !> - \"unknown\" !> !> Each of the subtables currently supports the following fields: !>```toml !>[profiles.debug.gfortran.linux] !> flags=\"-Wall -g -Og\" !> c-flags=\"-g O1\" !> cxx-flags=\"-g O1\" !> link-time-flags=\"-xlinkopt\" !> files={\"hello_world.f90\"=\"-Wall -O3\"} !>``` !> module fpm_manifest_profile use fpm_error , only : error_t , syntax_error , fatal_error , fpm_stop use tomlf , only : toml_table , toml_key , toml_stat use fpm_toml , only : get_value , serializable_t , set_value , & set_string , add_table use fpm_strings , only : lower use fpm_environment , only : get_os_type , OS_UNKNOWN , OS_LINUX , OS_MACOS , OS_WINDOWS , & OS_CYGWIN , OS_SOLARIS , OS_FREEBSD , OS_OPENBSD , OS_NAME use fpm_filesystem , only : join_path implicit none public :: profile_config_t , new_profile , new_profiles , get_default_profiles , & & info_profile , find_profile , DEFAULT_COMPILER !> Name of the default compiler character ( len =* ), parameter :: DEFAULT_COMPILER = 'gfortran' integer , parameter :: OS_ALL = - 1 character ( len = :), allocatable :: path !> Type storing file name - file scope compiler flags pairs type , extends ( serializable_t ) :: file_scope_flag !> Name of the file character ( len = :), allocatable :: file_name !> File scope flags character ( len = :), allocatable :: flags contains !> Serialization interface procedure :: serializable_is_same => file_scope_same procedure :: dump_to_toml => file_scope_dump procedure :: load_from_toml => file_scope_load end type file_scope_flag !> Configuration meta data for a profile type , extends ( serializable_t ) :: profile_config_t !> Name of the profile character ( len = :), allocatable :: profile_name !> Name of the compiler character ( len = :), allocatable :: compiler !> Value repesenting OS integer :: os_type = OS_ALL !> Fortran compiler flags character ( len = :), allocatable :: flags !> C compiler flags character ( len = :), allocatable :: c_flags !> C++ compiler flags character ( len = :), allocatable :: cxx_flags !> Link time compiler flags character ( len = :), allocatable :: link_time_flags !> File scope flags type ( file_scope_flag ), allocatable :: file_scope_flags (:) !> Is this profile one of the built-in ones? logical :: is_built_in = . false . contains !> Print information on this instance procedure :: info !> Serialization interface procedure :: serializable_is_same => profile_same procedure :: dump_to_toml => profile_dump procedure :: load_from_toml => profile_load end type profile_config_t contains !> Construct a new profile configuration from a TOML data structure function new_profile ( profile_name , compiler , os_type , flags , c_flags , cxx_flags , & link_time_flags , file_scope_flags , is_built_in ) & & result ( profile ) !> Name of the profile character ( len =* ), intent ( in ) :: profile_name !> Name of the compiler character ( len =* ), intent ( in ) :: compiler !> Type of the OS integer , intent ( in ) :: os_type !> Fortran compiler flags character ( len =* ), optional , intent ( in ) :: flags !> C compiler flags character ( len =* ), optional , intent ( in ) :: c_flags !> C++ compiler flags character ( len =* ), optional , intent ( in ) :: cxx_flags !> Link time compiler flags character ( len =* ), optional , intent ( in ) :: link_time_flags !> File scope flags type ( file_scope_flag ), optional , intent ( in ) :: file_scope_flags (:) !> Is this profile one of the built-in ones? logical , optional , intent ( in ) :: is_built_in type ( profile_config_t ) :: profile profile % profile_name = profile_name profile % compiler = compiler profile % os_type = os_type if ( present ( flags )) then profile % flags = flags else profile % flags = \"\" end if if ( present ( c_flags )) then profile % c_flags = c_flags else profile % c_flags = \"\" end if if ( present ( cxx_flags )) then profile % cxx_flags = cxx_flags else profile % cxx_flags = \"\" end if if ( present ( link_time_flags )) then profile % link_time_flags = link_time_flags else profile % link_time_flags = \"\" end if if ( present ( file_scope_flags )) then profile % file_scope_flags = file_scope_flags end if if ( present ( is_built_in )) then profile % is_built_in = is_built_in else profile % is_built_in = . false . end if end function new_profile !> Check if compiler name is a valid compiler name subroutine validate_compiler_name ( compiler_name , is_valid ) !> Name of a compiler character ( len = :), allocatable , intent ( in ) :: compiler_name !> Boolean value of whether compiler_name is valid or not logical , intent ( out ) :: is_valid select case ( compiler_name ) case ( \"gfortran\" , \"ifort\" , \"ifx\" , \"pgfortran\" , \"nvfortran\" , \"flang\" , \"caf\" , & & \"f95\" , \"lfortran\" , \"lfc\" , \"nagfor\" , \"crayftn\" , \"xlf90\" , \"ftn95\" ) is_valid = . true . case default is_valid = . false . end select end subroutine validate_compiler_name !> Check if os_name is a valid name of a supported OS subroutine validate_os_name ( os_name , is_valid ) !> Name of an operating system character ( len = :), allocatable , intent ( in ) :: os_name !> Boolean value of whether os_name is valid or not logical , intent ( out ) :: is_valid select case ( os_name ) case ( \"linux\" , \"macos\" , \"windows\" , \"cygwin\" , \"solaris\" , \"freebsd\" , & & \"openbsd\" , \"unknown\" ) is_valid = . true . case default is_valid = . false . end select end subroutine validate_os_name !> Match os_type enum to a lowercase string with name of OS subroutine match_os_type ( os_name , os_type ) !> Name of operating system character ( len = :), allocatable , intent ( in ) :: os_name !> Enum representing type of OS integer , intent ( out ) :: os_type select case ( os_name ) case ( \"linux\" ); os_type = OS_LINUX case ( \"macos\" ); os_type = OS_MACOS case ( \"windows\" ); os_type = OS_WINDOWS case ( \"cygwin\" ); os_type = OS_CYGWIN case ( \"solaris\" ); os_type = OS_SOLARIS case ( \"freebsd\" ); os_type = OS_FREEBSD case ( \"openbsd\" ); os_type = OS_OPENBSD case ( \"all\" ); os_type = OS_ALL case default ; os_type = OS_UNKNOWN end select end subroutine match_os_type !> Match lowercase string with name of OS to os_type enum function os_type_name ( os_type ) !> Name of operating system character ( len = :), allocatable :: os_type_name !> Enum representing type of OS integer , intent ( in ) :: os_type select case ( os_type ) case ( OS_ALL ); os_type_name = \"all\" case default ; os_type_name = lower ( OS_NAME ( os_type )) end select end function os_type_name subroutine validate_profile_table ( profile_name , compiler_name , key_list , table , error , os_valid ) !> Name of profile character ( len = :), allocatable , intent ( in ) :: profile_name !> Name of compiler character ( len = :), allocatable , intent ( in ) :: compiler_name !> List of keys in the table type ( toml_key ), allocatable , intent ( in ) :: key_list (:) !> Table containing OS tables type ( toml_table ), pointer , intent ( in ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Was called with valid operating system logical , intent ( in ) :: os_valid character ( len = :), allocatable :: flags , c_flags , cxx_flags , link_time_flags , key_name , file_name , file_flags , err_message type ( toml_table ), pointer :: files type ( toml_key ), allocatable :: file_list (:) integer :: ikey , ifile , stat logical :: is_valid if ( size ( key_list ). ge . 1 ) then do ikey = 1 , size ( key_list ) key_name = key_list ( ikey )% key if ( key_name . eq . 'flags' ) then call get_value ( table , 'flags' , flags , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"flags has to be a key-value pair\" ) return end if else if ( key_name . eq . 'c-flags' ) then call get_value ( table , 'c-flags' , c_flags , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"c-flags has to be a key-value pair\" ) return end if else if ( key_name . eq . 'cxx-flags' ) then call get_value ( table , 'cxx-flags' , cxx_flags , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"cxx-flags has to be a key-value pair\" ) return end if else if ( key_name . eq . 'link-time-flags' ) then call get_value ( table , 'link-time-flags' , link_time_flags , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"link-time-flags has to be a key-value pair\" ) return end if else if ( key_name . eq . 'files' ) then call get_value ( table , 'files' , files , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"files has to be a table\" ) return end if call files % get_keys ( file_list ) do ifile = 1 , size ( file_list ) file_name = file_list ( ifile )% key call get_value ( files , file_name , file_flags , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"file scope flags has to be a key-value pair\" ) return end if end do else if (. not . os_valid ) then call validate_os_name ( key_name , is_valid ) err_message = \"Unexpected key \" // key_name // \" found in profile table \" // profile_name // \" \" // compiler_name // \".\" if (. not . is_valid ) call syntax_error ( error , err_message ) else err_message = \"Unexpected key \" // key_name // \" found in profile table \" // profile_name // \" \" // compiler_name // \".\" call syntax_error ( error , err_message ) end if end do end if if ( allocated ( error )) return end subroutine validate_profile_table !> Look for flags, c-flags, link-time-flags key-val pairs !> and files table in a given table and create new profiles subroutine get_flags ( profile_name , compiler_name , os_type , key_list , table , profiles , profindex , os_valid ) !> Name of profile character ( len = :), allocatable , intent ( in ) :: profile_name !> Name of compiler character ( len = :), allocatable , intent ( in ) :: compiler_name !> OS type integer , intent ( in ) :: os_type !> List of keys in the table type ( toml_key ), allocatable , intent ( in ) :: key_list (:) !> Table containing OS tables type ( toml_table ), pointer , intent ( in ) :: table !> List of profiles type ( profile_config_t ), allocatable , intent ( inout ) :: profiles (:) !> Index in the list of profiles integer , intent ( inout ) :: profindex !> Was called with valid operating system logical , intent ( in ) :: os_valid character ( len = :), allocatable :: flags , c_flags , cxx_flags , link_time_flags , key_name , file_name , file_flags , err_message type ( toml_table ), pointer :: files type ( toml_key ), allocatable :: file_list (:) type ( file_scope_flag ), allocatable :: file_scope_flags (:) integer :: ikey , ifile , stat logical :: is_valid call get_value ( table , 'flags' , flags ) call get_value ( table , 'c-flags' , c_flags ) call get_value ( table , 'cxx-flags' , cxx_flags ) call get_value ( table , 'link-time-flags' , link_time_flags ) call get_value ( table , 'files' , files ) if ( associated ( files )) then call files % get_keys ( file_list ) allocate ( file_scope_flags ( size ( file_list ))) do ifile = 1 , size ( file_list ) file_name = file_list ( ifile )% key call get_value ( files , file_name , file_flags ) associate ( cur_file => file_scope_flags ( ifile )) if (. not .( path . eq . \"\" )) file_name = join_path ( path , file_name ) cur_file % file_name = file_name cur_file % flags = file_flags end associate end do end if profiles ( profindex ) = new_profile ( profile_name , compiler_name , os_type , & & flags , c_flags , cxx_flags , link_time_flags , file_scope_flags ) profindex = profindex + 1 end subroutine get_flags !> Traverse operating system tables to obtain number of profiles subroutine traverse_oss_for_size ( profile_name , compiler_name , os_list , table , profiles_size , error ) !> Name of profile character ( len = :), allocatable , intent ( in ) :: profile_name !> Name of compiler character ( len = :), allocatable , intent ( in ) :: compiler_name !> List of OSs in table with profile name and compiler name given type ( toml_key ), allocatable , intent ( in ) :: os_list (:) !> Table containing OS tables type ( toml_table ), pointer , intent ( in ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Number of profiles in list of profiles integer , intent ( inout ) :: profiles_size type ( toml_key ), allocatable :: key_list (:) character ( len = :), allocatable :: os_name , l_os_name type ( toml_table ), pointer :: os_node integer :: ios , stat logical :: is_valid , key_val_added , is_key_val if ( size ( os_list ) < 1 ) return key_val_added = . false . do ios = 1 , size ( os_list ) os_name = os_list ( ios )% key call validate_os_name ( os_name , is_valid ) if ( is_valid ) then call get_value ( table , os_name , os_node , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"os \" // os_name // \" has to be a table\" ) return end if call os_node % get_keys ( key_list ) profiles_size = profiles_size + 1 call validate_profile_table ( profile_name , compiler_name , key_list , os_node , error , . true .) else ! Not lowercase OS name l_os_name = lower ( os_name ) call validate_os_name ( l_os_name , is_valid ) if ( is_valid ) then call fatal_error ( error , '*traverse_oss*:Error: Name of the operating system must be a lowercase string.' ) end if if ( allocated ( error )) return ! Missing OS name is_key_val = . false . os_name = os_list ( ios )% key call get_value ( table , os_name , os_node , stat = stat ) if ( stat /= toml_stat % success ) then is_key_val = . true . end if os_node => table if ( is_key_val . and .. not . key_val_added ) then key_val_added = . true . is_key_val = . false . profiles_size = profiles_size + 1 else if (. not . is_key_val ) then profiles_size = profiles_size + 1 end if call validate_profile_table ( profile_name , compiler_name , os_list , os_node , error , . false .) end if end do end subroutine traverse_oss_for_size !> Traverse operating system tables to obtain profiles subroutine traverse_oss ( profile_name , compiler_name , os_list , table , profiles , profindex , error ) !> Name of profile character ( len = :), allocatable , intent ( in ) :: profile_name !> Name of compiler character ( len = :), allocatable , intent ( in ) :: compiler_name !> List of OSs in table with profile name and compiler name given type ( toml_key ), allocatable , intent ( in ) :: os_list (:) !> Table containing OS tables type ( toml_table ), pointer , intent ( in ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> List of profiles type ( profile_config_t ), allocatable , intent ( inout ) :: profiles (:) !> Index in the list of profiles integer , intent ( inout ) :: profindex type ( toml_key ), allocatable :: key_list (:) character ( len = :), allocatable :: os_name , l_os_name type ( toml_table ), pointer :: os_node integer :: ios , stat , os_type logical :: is_valid , is_key_val if ( size ( os_list ) < 1 ) return do ios = 1 , size ( os_list ) os_name = os_list ( ios )% key call validate_os_name ( os_name , is_valid ) if ( is_valid ) then call get_value ( table , os_name , os_node , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"os \" // os_name // \" has to be a table\" ) return end if call os_node % get_keys ( key_list ) call match_os_type ( os_name , os_type ) call get_flags ( profile_name , compiler_name , os_type , key_list , os_node , profiles , profindex , . true .) else ! Not lowercase OS name l_os_name = lower ( os_name ) call validate_os_name ( l_os_name , is_valid ) if ( is_valid ) then call fatal_error ( error , '*traverse_oss*:Error: Name of the operating system must be a lowercase string.' ) end if if ( allocated ( error )) return ! Missing OS name is_key_val = . false . os_name = os_list ( ios )% key call get_value ( table , os_name , os_node , stat = stat ) if ( stat /= toml_stat % success ) then is_key_val = . true . end if os_node => table os_type = OS_ALL call get_flags ( profile_name , compiler_name , os_type , os_list , os_node , profiles , profindex , . false .) end if end do end subroutine traverse_oss !> Traverse compiler tables subroutine traverse_compilers ( profile_name , comp_list , table , error , profiles_size , profiles , profindex ) !> Name of profile character ( len = :), allocatable , intent ( in ) :: profile_name !> List of OSs in table with profile name given type ( toml_key ), allocatable , intent ( in ) :: comp_list (:) !> Table containing compiler tables type ( toml_table ), pointer , intent ( in ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Number of profiles in list of profiles integer , intent ( inout ), optional :: profiles_size !> List of profiles type ( profile_config_t ), allocatable , intent ( inout ), optional :: profiles (:) !> Index in the list of profiles integer , intent ( inout ), optional :: profindex character ( len = :), allocatable :: compiler_name type ( toml_table ), pointer :: comp_node type ( toml_key ), allocatable :: os_list (:) integer :: icomp , stat logical :: is_valid if ( size ( comp_list ) < 1 ) return do icomp = 1 , size ( comp_list ) call validate_compiler_name ( comp_list ( icomp )% key , is_valid ) if ( is_valid ) then compiler_name = comp_list ( icomp )% key call get_value ( table , compiler_name , comp_node , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"Compiler \" // comp_list ( icomp )% key // \" must be a table entry\" ) exit end if call comp_node % get_keys ( os_list ) if ( present ( profiles_size )) then call traverse_oss_for_size ( profile_name , compiler_name , os_list , comp_node , profiles_size , error ) if ( allocated ( error )) return else if (. not .( present ( profiles ). and . present ( profindex ))) then call fatal_error ( error , \"Both profiles and profindex have to be present\" ) return end if call traverse_oss ( profile_name , compiler_name , os_list , comp_node , & & profiles , profindex , error ) if ( allocated ( error )) return end if else call fatal_error ( error , '*traverse_compilers*:Error: Compiler name not specified or invalid.' ) end if end do end subroutine traverse_compilers !> Construct new profiles array from a TOML data structure subroutine new_profiles ( profiles , table , error ) !> Instance of the dependency configuration type ( profile_config_t ), allocatable , intent ( out ) :: profiles (:) !> Instance of the TOML data structure type ( toml_table ), target , intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_table ), pointer :: prof_node type ( toml_key ), allocatable :: prof_list (:) type ( toml_key ), allocatable :: comp_list (:) type ( toml_key ), allocatable :: os_list (:) character ( len = :), allocatable :: profile_name , compiler_name integer :: profiles_size , iprof , stat , profindex logical :: is_valid type ( profile_config_t ), allocatable :: default_profiles (:) path = '' default_profiles = get_default_profiles ( error ) if ( allocated ( error )) return call table % get_keys ( prof_list ) if ( size ( prof_list ) < 1 ) return profiles_size = 0 do iprof = 1 , size ( prof_list ) profile_name = prof_list ( iprof )% key call validate_compiler_name ( profile_name , is_valid ) if ( is_valid ) then profile_name = \"all\" comp_list = prof_list ( iprof : iprof ) prof_node => table call traverse_compilers ( profile_name , comp_list , prof_node , error , profiles_size = profiles_size ) if ( allocated ( error )) return else call validate_os_name ( profile_name , is_valid ) if ( is_valid ) then os_list = prof_list ( iprof : iprof ) profile_name = 'all' compiler_name = DEFAULT_COMPILER call traverse_oss_for_size ( profile_name , compiler_name , os_list , table , profiles_size , error ) if ( allocated ( error )) return else call get_value ( table , profile_name , prof_node , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"Profile \" // prof_list ( iprof )% key // \" must be a table entry\" ) exit end if call prof_node % get_keys ( comp_list ) call traverse_compilers ( profile_name , comp_list , prof_node , error , profiles_size = profiles_size ) if ( allocated ( error )) return end if end if end do profiles_size = profiles_size + size ( default_profiles ) allocate ( profiles ( profiles_size )) do profindex = 1 , size ( default_profiles ) profiles ( profindex ) = default_profiles ( profindex ) end do do iprof = 1 , size ( prof_list ) profile_name = prof_list ( iprof )% key call validate_compiler_name ( profile_name , is_valid ) if ( is_valid ) then profile_name = \"all\" comp_list = prof_list ( iprof : iprof ) prof_node => table call traverse_compilers ( profile_name , comp_list , prof_node , error , profiles = profiles , profindex = profindex ) if ( allocated ( error )) return else call validate_os_name ( profile_name , is_valid ) if ( is_valid ) then os_list = prof_list ( iprof : iprof ) profile_name = 'all' compiler_name = DEFAULT_COMPILER prof_node => table call traverse_oss ( profile_name , compiler_name , os_list , prof_node , profiles , profindex , error ) if ( allocated ( error )) return else call get_value ( table , profile_name , prof_node , stat = stat ) call prof_node % get_keys ( comp_list ) call traverse_compilers ( profile_name , comp_list , prof_node , error , profiles = profiles , profindex = profindex ) if ( allocated ( error )) return end if end if end do ! Apply profiles with profile name 'all' to matching profiles do iprof = 1 , size ( profiles ) if ( profiles ( iprof )% profile_name . eq . 'all' ) then do profindex = 1 , size ( profiles ) if (. not .( profiles ( profindex )% profile_name . eq . 'all' ) & & . and .( profiles ( profindex )% compiler . eq . profiles ( iprof )% compiler ) & & . and .( profiles ( profindex )% os_type . eq . profiles ( iprof )% os_type )) then profiles ( profindex )% flags = profiles ( profindex )% flags // & & \" \" // profiles ( iprof )% flags profiles ( profindex )% c_flags = profiles ( profindex )% c_flags // & & \" \" // profiles ( iprof )% c_flags profiles ( profindex )% cxx_flags = profiles ( profindex )% cxx_flags // & & \" \" // profiles ( iprof )% cxx_flags profiles ( profindex )% link_time_flags = profiles ( profindex )% link_time_flags // & & \" \" // profiles ( iprof )% link_time_flags end if end do end if end do end subroutine new_profiles !> Construct an array of built-in profiles function get_default_profiles ( error ) result ( default_profiles ) !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( profile_config_t ), allocatable :: default_profiles (:) default_profiles = [ & & new_profile ( 'release' , & & 'caf' , & & OS_ALL , & & flags = ' -O3 -Wimplicit-interface -fPIC -fmax-errors=1 -funroll-loops' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'gfortran' , & & OS_ALL , & & flags = ' -O3 -Wimplicit-interface -fPIC -fmax-errors=1 -funroll-loops -fcoarray=single' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'f95' , & & OS_ALL , & & flags = ' -O3 -Wimplicit-interface -fPIC -fmax-errors=1 -ffast-math -funroll-loops' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'nvfortran' , & & OS_ALL , & & flags = ' -Mbackslash' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'ifort' , & & OS_ALL , & & flags = ' -fp-model precise -pc64 -align all -error-limit 1 -reentrancy& & threaded -nogen-interfaces -assume byterecl' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'ifort' , & & OS_WINDOWS , & & flags = ' /fp:precise /align:all /error-limit:1 /reentrancy:threaded& & /nogen-interfaces /assume:byterecl' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'ifx' , & & OS_ALL , & & flags = ' -fp-model=precise -pc64 -align all -error-limit 1 -reentrancy& & threaded -nogen-interfaces -assume byterecl' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'ifx' , & & OS_WINDOWS , & & flags = ' /fp:precise /align:all /error-limit:1 /reentrancy:threaded& & /nogen-interfaces /assume:byterecl' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'nagfor' , & & OS_ALL , & & flags = ' -O4 -coarray=single -PIC' , & & is_built_in = . true .), & & new_profile ( 'release' , & & 'lfortran' , & & OS_ALL , & & flags = ' flag_lfortran_opt' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'caf' , & & OS_ALL , & & flags = ' -Wall -Wextra -Wimplicit-interface -fPIC -fmax-errors=1 -g -fcheck=bounds& & -fcheck=array-temps -fbacktrace' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'gfortran' , & & OS_ALL , & & flags = ' -Wall -Wextra -Wimplicit-interface -fPIC -fmax-errors=1 -g -fcheck=bounds& & -fcheck=array-temps -fbacktrace -fcoarray=single' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'f95' , & & OS_ALL , & & flags = ' -Wall -Wextra -Wimplicit-interface -fPIC -fmax-errors=1 -g -fcheck=bounds& & -fcheck=array-temps -Wno-maybe-uninitialized -Wno-uninitialized -fbacktrace' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'nvfortran' , & & OS_ALL , & & flags = ' -Minform=inform -Mbackslash -g -Mbounds -Mchkptr -Mchkstk -traceback' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'ifort' , & & OS_ALL , & & flags = ' -warn all -check all -error-limit 1 -O0 -g -assume byterecl -traceback' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'ifort' , & & OS_WINDOWS , & & flags = ' /warn:all /check:all /error-limit:1& & /Od /Z7 /assume:byterecl /traceback' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'ifx' , & & OS_ALL , & & flags = ' -warn all -check all -error-limit 1 -O0 -g -assume byterecl -traceback' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'ifx' , & & OS_WINDOWS , & & flags = ' /warn:all /check:all /error-limit:1 /Od /Z7 /assume:byterecl' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'ifx' , & & OS_WINDOWS , & & flags = ' /warn:all /check:all /error-limit:1 /Od /Z7 /assume:byterecl' , & & is_built_in = . true .), & & new_profile ( 'debug' , & & 'lfortran' , & & OS_ALL , & & flags = '' , & & is_built_in = . true .) & &] end function get_default_profiles !> Write information on instance subroutine info ( self , unit , verbosity ) !> Instance of the profile configuration class ( profile_config_t ), intent ( in ) :: self !> Unit for IO integer , intent ( in ) :: unit !> Verbosity of the printout integer , intent ( in ), optional :: verbosity integer :: pr character ( len =* ), parameter :: fmt = '(\"#\", 1x, a, t30, a)' if ( present ( verbosity )) then pr = verbosity else pr = 1 end if write ( unit , fmt ) \"Profile\" if ( allocated ( self % profile_name )) then write ( unit , fmt ) \"- profile name\" , self % profile_name end if if ( allocated ( self % compiler )) then write ( unit , fmt ) \"- compiler\" , self % compiler end if write ( unit , fmt ) \"- os\" , os_type_name ( self % os_type ) if ( allocated ( self % flags )) then write ( unit , fmt ) \"- compiler flags\" , self % flags end if end subroutine info !> Print a representation of profile_config_t function info_profile ( profile ) result ( s ) !> Profile to be represented type ( profile_config_t ), intent ( in ) :: profile !> String representation of given profile character (:), allocatable :: s integer :: i s = \"profile_config_t(\" s = s // 'profile_name=\"' // profile % profile_name // '\"' s = s // ', compiler=\"' // profile % compiler // '\"' s = s // \", os_type=\" select case ( profile % os_type ) case ( OS_UNKNOWN ) s = s // \"OS_UNKNOWN\" case ( OS_LINUX ) s = s // \"OS_LINUX\" case ( OS_MACOS ) s = s // \"OS_MACOS\" case ( OS_WINDOWS ) s = s // \"OS_WINDOWS\" case ( OS_CYGWIN ) s = s // \"OS_CYGWIN\" case ( OS_SOLARIS ) s = s // \"OS_SOLARIS\" case ( OS_FREEBSD ) s = s // \"OS_FREEBSD\" case ( OS_OPENBSD ) s = s // \"OS_OPENBSD\" case ( OS_ALL ) s = s // \"OS_ALL\" case default s = s // \"INVALID\" end select if ( allocated ( profile % flags )) s = s // ', flags=\"' // profile % flags // '\"' if ( allocated ( profile % c_flags )) s = s // ', c_flags=\"' // profile % c_flags // '\"' if ( allocated ( profile % cxx_flags )) s = s // ', cxx_flags=\"' // profile % cxx_flags // '\"' if ( allocated ( profile % link_time_flags )) s = s // ', link_time_flags=\"' // profile % link_time_flags // '\"' if ( allocated ( profile % file_scope_flags )) then do i = 1 , size ( profile % file_scope_flags ) s = s // ', flags for ' // profile % file_scope_flags ( i )% file_name // & & ' =\"' // profile % file_scope_flags ( i )% flags // '\"' end do end if s = s // \")\" end function info_profile !> Look for profile with given configuration in array profiles subroutine find_profile ( profiles , profile_name , compiler , os_type , found_matching , chosen_profile ) !> Array of profiles type ( profile_config_t ), allocatable , intent ( in ) :: profiles (:) !> Name of profile character (:), allocatable , intent ( in ) :: profile_name !> Name of compiler character (:), allocatable , intent ( in ) :: compiler !> Type of operating system (enum) integer , intent ( in ) :: os_type !> Boolean value containing true if matching profile was found logical , intent ( out ) :: found_matching !> Last matching profile in the profiles array type ( profile_config_t ), intent ( out ) :: chosen_profile character (:), allocatable :: curr_profile_name character (:), allocatable :: curr_compiler integer :: curr_os integer :: i , priority , curr_priority found_matching = . false . if ( size ( profiles ) < 1 ) return ! Try to find profile with matching OS type do i = 1 , size ( profiles ) curr_profile_name = profiles ( i )% profile_name curr_compiler = profiles ( i )% compiler curr_os = profiles ( i )% os_type if ( curr_profile_name . eq . profile_name ) then if ( curr_compiler . eq . compiler ) then if ( curr_os . eq . os_type ) then chosen_profile = profiles ( i ) found_matching = . true . end if end if end if end do ! Try to find profile with OS type 'all' if (. not . found_matching ) then do i = 1 , size ( profiles ) curr_profile_name = profiles ( i )% profile_name curr_compiler = profiles ( i )% compiler curr_os = profiles ( i )% os_type if ( curr_profile_name . eq . profile_name ) then if ( curr_compiler . eq . compiler ) then if ( curr_os . eq . OS_ALL ) then chosen_profile = profiles ( i ) found_matching = . true . end if end if end if end do end if end subroutine find_profile logical function file_scope_same ( this , that ) class ( file_scope_flag ), intent ( in ) :: this class ( serializable_t ), intent ( in ) :: that file_scope_same = . false . select type ( other => that ) type is ( file_scope_flag ) if ( allocated ( this % file_name ). neqv . allocated ( other % file_name )) return if ( allocated ( this % file_name )) then if (. not .( this % file_name == other % file_name )) return endif if ( allocated ( this % flags ). neqv . allocated ( other % flags )) return if ( allocated ( this % flags )) then if (. not .( this % flags == other % flags )) return endif class default ! Not the same type return end select !> All checks passed! file_scope_same = . true . end function file_scope_same !> Dump to toml table subroutine file_scope_dump ( self , table , error ) !> Instance of the serializable object class ( file_scope_flag ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error call set_string ( table , \"file-name\" , self % file_name , error ) if ( allocated ( error )) return call set_string ( table , \"flags\" , self % flags , error ) if ( allocated ( error )) return end subroutine file_scope_dump !> Read from toml table (no checks made at this stage) subroutine file_scope_load ( self , table , error ) !> Instance of the serializable object class ( file_scope_flag ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error call get_value ( table , \"file-name\" , self % file_name ) call get_value ( table , \"flags\" , self % flags ) end subroutine file_scope_load logical function profile_same ( this , that ) class ( profile_config_t ), intent ( in ) :: this class ( serializable_t ), intent ( in ) :: that integer :: ii profile_same = . false . select type ( other => that ) type is ( profile_config_t ) if ( allocated ( this % profile_name ). neqv . allocated ( other % profile_name )) return if ( allocated ( this % profile_name )) then if (. not .( this % profile_name == other % profile_name )) return endif if ( allocated ( this % compiler ). neqv . allocated ( other % compiler )) return if ( allocated ( this % compiler )) then if (. not .( this % compiler == other % compiler )) return endif if ( this % os_type /= other % os_type ) return if ( allocated ( this % flags ). neqv . allocated ( other % flags )) return if ( allocated ( this % flags )) then if (. not .( this % flags == other % flags )) return endif if ( allocated ( this % c_flags ). neqv . allocated ( other % c_flags )) return if ( allocated ( this % c_flags )) then if (. not .( this % c_flags == other % c_flags )) return endif if ( allocated ( this % cxx_flags ). neqv . allocated ( other % cxx_flags )) return if ( allocated ( this % cxx_flags )) then if (. not .( this % cxx_flags == other % cxx_flags )) return endif if ( allocated ( this % link_time_flags ). neqv . allocated ( other % link_time_flags )) return if ( allocated ( this % link_time_flags )) then if (. not .( this % link_time_flags == other % link_time_flags )) return endif if ( allocated ( this % file_scope_flags ). neqv . allocated ( other % file_scope_flags )) return if ( allocated ( this % file_scope_flags )) then if (. not . size ( this % file_scope_flags ) == size ( other % file_scope_flags )) return do ii = 1 , size ( this % file_scope_flags ) print * , 'check ii-th file scope: ' , ii if (. not . this % file_scope_flags ( ii ) == other % file_scope_flags ( ii )) return end do endif if ( this % is_built_in . neqv . other % is_built_in ) return class default ! Not the same type return end select !> All checks passed! profile_same = . true . end function profile_same !> Dump to toml table subroutine profile_dump ( self , table , error ) !> Instance of the serializable object class ( profile_config_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Local variables integer :: ierr , ii type ( toml_table ), pointer :: ptr_deps , ptr character ( len = 30 ) :: unnamed call set_string ( table , \"profile-name\" , self % profile_name , error ) if ( allocated ( error )) return call set_string ( table , \"compiler\" , self % compiler , error ) if ( allocated ( error )) return call set_string ( table , \"os-type\" , os_type_name ( self % os_type ), error , 'profile_config_t' ) if ( allocated ( error )) return call set_string ( table , \"flags\" , self % flags , error ) if ( allocated ( error )) return call set_string ( table , \"c-flags\" , self % c_flags , error ) if ( allocated ( error )) return call set_string ( table , \"cxx-flags\" , self % cxx_flags , error ) if ( allocated ( error )) return call set_string ( table , \"link-time-flags\" , self % link_time_flags , error ) if ( allocated ( error )) return if ( allocated ( self % file_scope_flags )) then ! Create dependency table call add_table ( table , \"file-scope-flags\" , ptr_deps ) if (. not . associated ( ptr_deps )) then call fatal_error ( error , \"profile_config_t cannot create file scope table \" ) return end if do ii = 1 , size ( self % file_scope_flags ) associate ( dep => self % file_scope_flags ( ii )) !> Because files need a name, fallback if this has no name if ( len_trim ( dep % file_name ) == 0 ) then write ( unnamed , 1 ) ii call add_table ( ptr_deps , trim ( unnamed ), ptr ) else call add_table ( ptr_deps , dep % file_name , ptr ) end if if (. not . associated ( ptr )) then call fatal_error ( error , \"profile_config_t cannot create entry for file \" // dep % file_name ) return end if call dep % dump_to_toml ( ptr , error ) if ( allocated ( error )) return end associate end do endif call set_value ( table , \"is-built-in\" , self % is_built_in , error , 'profile_config_t' ) if ( allocated ( error )) return 1 format ( 'UNNAMED_FILE_' , i0 ) end subroutine profile_dump !> Read from toml table (no checks made at this stage) subroutine profile_load ( self , table , error ) !> Instance of the serializable object class ( profile_config_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Local variables character ( len = :), allocatable :: flag integer :: ii , jj type ( toml_table ), pointer :: ptr_dep , ptr type ( toml_key ), allocatable :: keys (:), dep_keys (:) call table % get_keys ( keys ) call get_value ( table , \"profile-name\" , self % profile_name ) call get_value ( table , \"compiler\" , self % compiler ) call get_value ( table , \"os-type\" , flag ) call match_os_type ( flag , self % os_type ) call get_value ( table , \"flags\" , self % flags ) call get_value ( table , \"c-flags\" , self % c_flags ) call get_value ( table , \"cxx-flags\" , self % cxx_flags ) call get_value ( table , \"link-time-flags\" , self % link_time_flags ) call get_value ( table , \"is-built-in\" , self % is_built_in , error , 'profile_config_t' ) if ( allocated ( error )) return if ( allocated ( self % file_scope_flags )) deallocate ( self % file_scope_flags ) sub_deps : do ii = 1 , size ( keys ) select case ( keys ( ii )% key ) case ( \"file-scope-flags\" ) call get_value ( table , keys ( ii ), ptr ) if (. not . associated ( ptr )) then call fatal_error ( error , 'profile_config_t: error retrieving file_scope_flags table' ) return end if !> Read all packages call ptr % get_keys ( dep_keys ) allocate ( self % file_scope_flags ( size ( dep_keys ))) do jj = 1 , size ( dep_keys ) call get_value ( ptr , dep_keys ( jj ), ptr_dep ) call self % file_scope_flags ( jj )% load_from_toml ( ptr_dep , error ) if ( allocated ( error )) return end do end select end do sub_deps end subroutine profile_load end module fpm_manifest_profile","tags":"","url":"sourcefile/profiles.f90.html"},{"title":"fpm_meta_util.f90 – Fortran-lang/fpm","text":"Source Code module fpm_meta_util use fpm_meta_base , only : metapackage_t , destroy use fpm_filesystem , only : join_path use fpm_strings , only : split , string_t , str_begins_with_str use fpm_error , only : error_t use fpm_versioning , only : new_version use fpm_pkg_config , only : pkgcfg_get_libs , pkgcfg_get_build_flags , pkgcfg_get_version implicit none private public :: add_pkg_config_compile_options , lib_get_trailing contains !> Add pkgconfig compile options to a metapackage subroutine add_pkg_config_compile_options ( this , name , include_flag , libdir , error ) class ( metapackage_t ), intent ( inout ) :: this character ( len =* ), intent ( in ) :: name character ( len =* ), intent ( in ) :: include_flag type ( error_t ), allocatable , intent ( out ) :: error character ( len = :), allocatable :: libdir type ( string_t ) :: log , current_include_dir , current_lib type ( string_t ), allocatable :: libs (:), flags (:) integer :: i !> Get version if (. not . allocated ( this % version )) then log = pkgcfg_get_version ( name , error ) if ( allocated ( error )) return allocate ( this % version ) call new_version ( this % version , log % s , error ) if ( allocated ( error )) return end if !> Get libraries libs = pkgcfg_get_libs ( name , error ) if ( allocated ( error )) return libdir = \"\" do i = 1 , size ( libs ) if ( str_begins_with_str ( libs ( i )% s , '-l' )) then current_lib = string_t ( libs ( i )% s ( 3 :)) if ( len_trim ( current_lib % s ) == 0 ) cycle this % has_link_libraries = . true . this % link_libs = [ this % link_libs , current_lib ] else ! -L and others: concatenate this % has_link_flags = . true . this % link_flags = string_t ( trim ( this % link_flags % s ) // ' ' // libs ( i )% s ) ! Also save library dir if ( str_begins_with_str ( libs ( i )% s , '-L' )) then libdir = libs ( i )% s ( 3 :) elseif ( str_begins_with_str ( libs ( i )% s , '/LIBPATH' )) then libdir = libs ( i )% s ( 9 :) end if end if end do !> Get compiler flags flags = pkgcfg_get_build_flags ( name , . true ., error ) if ( allocated ( error )) return do i = 1 , size ( flags ) if ( str_begins_with_str ( flags ( i )% s , include_flag )) then current_include_dir = string_t ( flags ( i )% s ( len ( include_flag ) + 1 :)) if ( len_trim ( current_include_dir % s ) == 0 ) cycle this % has_include_dirs = . true . this % incl_dirs = [ this % incl_dirs , current_include_dir ] else this % has_build_flags = . true . this % flags = string_t ( trim ( this % flags % s ) // ' ' // flags ( i )% s ) end if end do end subroutine add_pkg_config_compile_options !> Given a library name and folder, find extension and prefix subroutine lib_get_trailing ( lib_name , lib_dir , prefix , suffix , found ) character ( * ), intent ( in ) :: lib_name , lib_dir character (:), allocatable , intent ( out ) :: prefix , suffix logical , intent ( out ) :: found character ( * ), parameter :: extensions ( * ) = [ character ( 11 ) :: '.dll.a' , '.a' , '.dylib' , '.dll' ] logical :: is_file character (:), allocatable :: noext , tokens (:), path integer :: l , k ! Extract name with no extension call split ( lib_name , tokens , '.' ) noext = trim ( tokens ( 1 )) ! Get library extension: find file name: NAME.a, NAME.dll.a, NAME.dylib, libNAME.a, etc. found = . false . suffix = \"\" prefix = \"\" with_pref : do l = 1 , 2 if ( l == 2 ) then prefix = \"lib\" else prefix = \"\" end if find_ext : do k = 1 , size ( extensions ) path = join_path ( lib_dir , prefix // noext // trim ( extensions ( k ))) inquire ( file = path , exist = is_file ) if ( is_file ) then suffix = trim ( extensions ( k )) found = . true . exit with_pref end if end do find_ext end do with_pref if (. not . found ) then prefix = \"\" suffix = \"\" end if end subroutine lib_get_trailing end module fpm_meta_util","tags":"","url":"sourcefile/fpm_meta_util.f90.html"},{"title":"fpm_backend.F90 – Fortran-lang/fpm","text":"Source Code !># Build backend !> Uses a list of `[[build_target_ptr]]` and a valid `[[fpm_model]]` instance !> to schedule and execute the compilation and linking of package targets. !> !> The package build process (`[[build_package]]`) comprises three steps: !> !> 1. __Target sorting:__ topological sort of the target dependency graph (`[[sort_target]]`) !> 2. __Target scheduling:__ group targets into schedule regions based on the sorting (`[[schedule_targets]]`) !> 3. __Target building:__ generate targets by compilation or linking !> !> @note If compiled with OpenMP, targets will be build in parallel where possible. !> !>### Incremental compilation !> The backend process supports *incremental* compilation whereby targets are not !> re-compiled if their corresponding dependencies have not been modified. !> !> - Source-based targets (*i.e.* objects) are not re-compiled if the corresponding source !> file is unmodified AND all of the target dependencies are not marked for re-compilation !> !> - Link targets (*i.e.* executables and libraries) are not re-compiled if the !> target output file already exists AND all of the target dependencies are not marked for !> re-compilation !> !> Source file modification is determined by a file digest (hash) which is calculated during !> the source parsing phase ([[fpm_source_parsing]]) and cached to disk after a target is !> successfully generated. !> module fpm_backend use , intrinsic :: iso_fortran_env , only : stdin => input_unit , stdout => output_unit , stderr => error_unit use fpm_error , only : fpm_stop , error_t use fpm_filesystem , only : basename , dirname , join_path , exists , mkdir , run , getline use fpm_model , only : fpm_model_t use fpm_strings , only : string_t , operator (. in .) use fpm_targets , only : build_target_t , build_target_ptr , FPM_TARGET_OBJECT , & FPM_TARGET_C_OBJECT , FPM_TARGET_ARCHIVE , FPM_TARGET_EXECUTABLE , & FPM_TARGET_CPP_OBJECT , FPM_TARGET_SHARED use fpm_backend_output use fpm_compile_commands , only : compile_command_table_t implicit none private public :: build_package , sort_target , schedule_targets #ifndef FPM_BOOTSTRAP interface function c_isatty () bind ( C , name = 'c_isatty' ) use , intrinsic :: iso_c_binding , only : c_int integer ( c_int ) :: c_isatty end function end interface #endif contains !> Top-level routine to build package described by `model` subroutine build_package ( targets , model , verbose , dry_run ) type ( build_target_ptr ), intent ( inout ) :: targets (:) type ( fpm_model_t ), intent ( in ) :: model logical , intent ( in ) :: verbose !> If dry_run, the build process is only mocked, but the list of compile_commands !> is still created logical , intent ( in ) :: dry_run integer :: i , j type ( build_target_ptr ), allocatable :: queue (:) integer , allocatable :: schedule_ptr (:), stat (:) logical :: build_failed , skip_current type ( string_t ), allocatable :: build_dirs (:) type ( string_t ) :: temp type ( error_t ), allocatable :: error type ( build_progress_t ) :: progress logical :: plain_output ! Need to make output directory for include (mod) files allocate ( build_dirs ( 0 )) do i = 1 , size ( targets ) associate ( target => targets ( i )% ptr ) if ( target % output_dir . in . build_dirs ) cycle temp % s = target % output_dir build_dirs = [ build_dirs , temp ] end associate end do do i = 1 , size ( build_dirs ) if (. not . dry_run ) call mkdir ( build_dirs ( i )% s , verbose ) end do ! Perform depth-first topological sort of targets do i = 1 , size ( targets ) call sort_target ( targets ( i )% ptr , dry_run ) end do ! Construct build schedule queue call schedule_targets ( queue , schedule_ptr , targets ) ! Check if queue is empty if (. not . verbose . and . size ( queue ) < 1 . and . . not . dry_run ) then write ( stderr , '(a)' ) 'Project is up to date' return end if ! Initialise build status flags allocate ( stat ( size ( queue )), source = 0 ) build_failed = . false . ! Set output mode #ifndef FPM_BOOTSTRAP plain_output = (. not .( c_isatty () == 1 )) . or . verbose #else plain_output = . true . #endif progress = build_progress_t ( queue , plain_output ) ! Loop over parallel schedule regions do i = 1 , size ( schedule_ptr ) - 1 ! Build targets in schedule region i !$omp parallel do default(shared) private(skip_current) schedule(dynamic,1) do j = schedule_ptr ( i ),( schedule_ptr ( i + 1 ) - 1 ) ! Check if build already failed !$omp atomic read skip_current = build_failed if (. not . skip_current ) then if (. not . dry_run ) call progress % compiling_status ( j ) call build_target ( model , queue ( j )% ptr , verbose , dry_run , & progress % compile_commands , stat ( j )) if (. not . dry_run ) call progress % completed_status ( j , stat ( j )) end if ! Set global flag if this target failed to build if ( stat ( j ) /= 0 ) then !$omp atomic write build_failed = . true . end if end do ! Check if this schedule region failed: exit with message if failed if ( build_failed ) then write ( * , * ) do j = 1 , size ( stat ) if ( stat ( j ) /= 0 ) Then call print_build_log ( queue ( j )% ptr ) end if end do do j = 1 , size ( stat ) if ( stat ( j ) /= 0 ) then write ( stderr , '(*(g0:,1x))' ) ' Compilation failed for object \"' , basename ( queue ( j )% ptr % output_file ), '\"' end if end do call fpm_stop ( 1 , 'stopping due to failed compilation' ) end if end do if (. not . dry_run ) call progress % success () call progress % dump_commands ( error ) if ( allocated ( error )) call fpm_stop ( 1 , 'error writing compile_commands.json: ' // trim ( error % message )) end subroutine build_package !> Topologically sort a target for scheduling by !> recursing over its dependencies. !> !> Checks disk-cached source hashes to determine if objects are !> up-to-date. Up-to-date sources are tagged as skipped. !> !> On completion, `target` should either be marked as !> sorted (`target%sorted=.true.`) or skipped (`target%skip=.true.`) !> !> If `target` is marked as sorted, `target%schedule` should be an !> integer greater than zero indicating the region for scheduling !> recursive subroutine sort_target ( target , mock ) type ( build_target_t ), intent ( inout ), target :: target !> Optionally sort ALL targets if this is a dry run logical , optional , intent ( in ) :: mock integer :: i , fh , stat logical :: dry_run dry_run = . false . if ( present ( mock )) dry_run = mock ! Check if target has already been processed (as a dependency) if ( target % sorted . or . target % skip ) return ! Check for a circular dependency ! (If target has been touched but not processed) if ( target % touched ) then call fpm_stop ( 1 , '(!) Circular dependency found with: ' // target % output_file ) else target % touched = . true . ! Set touched flag end if ! Load cached source file digest if present if (. not . allocated ( target % digest_cached ) . and . & exists ( target % output_file ) . and . & exists ( target % output_file // '.digest' ) . and . & (. not . dry_run )) then allocate ( target % digest_cached ) open ( newunit = fh , file = target % output_file // '.digest' , status = 'old' ) read ( fh , * , iostat = stat ) target % digest_cached close ( fh ) ! Cached digest is not recognized if ( stat /= 0 ) deallocate ( target % digest_cached ) end if if ( dry_run ) then target % skip = . false . elseif ( allocated ( target % source )) then ! Skip if target is source-based and source file is unmodified if ( allocated ( target % digest_cached )) then if ( target % digest_cached == target % source % digest ) target % skip = . true . end if elseif ( exists ( target % output_file )) then ! Skip if target is not source-based and already exists target % skip = . true . end if ! Loop over target dependencies target % schedule = 1 do i = 1 , size ( target % dependencies ) ! Sort dependency call sort_target ( target % dependencies ( i )% ptr , dry_run ) if (. not . target % dependencies ( i )% ptr % skip ) then ! Can't skip target if any dependency is not skipped target % skip = . false . ! Set target schedule after all of its dependencies target % schedule = max ( target % schedule , target % dependencies ( i )% ptr % schedule + 1 ) end if end do ! Mark flag as processed: either sorted or skipped target % sorted = . not . target % skip end subroutine sort_target !> Construct a build schedule from the sorted targets. !> !> The schedule is broken into regions, described by `schedule_ptr`, !> where targets in each region can be compiled in parallel. !> subroutine schedule_targets ( queue , schedule_ptr , targets ) type ( build_target_ptr ), allocatable , intent ( out ) :: queue (:) integer , allocatable :: schedule_ptr (:) type ( build_target_ptr ), intent ( in ) :: targets (:) integer :: i , j integer :: n_schedule , n_sorted n_schedule = 0 ! Number of schedule regions n_sorted = 0 ! Total number of targets to build do i = 1 , size ( targets ) if ( targets ( i )% ptr % sorted ) then n_sorted = n_sorted + 1 end if n_schedule = max ( n_schedule , targets ( i )% ptr % schedule ) end do allocate ( queue ( n_sorted )) allocate ( schedule_ptr ( n_schedule + 1 )) ! Construct the target queue and schedule region pointer n_sorted = 1 schedule_ptr ( n_sorted ) = 1 do i = 1 , n_schedule do j = 1 , size ( targets ) if ( targets ( j )% ptr % sorted ) then if ( targets ( j )% ptr % schedule == i ) then queue ( n_sorted )% ptr => targets ( j )% ptr n_sorted = n_sorted + 1 end if end if end do schedule_ptr ( i + 1 ) = n_sorted end do end subroutine schedule_targets !> Call compile/link command for a single target. !> !> If successful, also caches the source file digest to disk. !> subroutine build_target ( model , target , verbose , dry_run , table , stat ) type ( fpm_model_t ), intent ( in ) :: model type ( build_target_t ), intent ( in ), target :: target logical , intent ( in ) :: verbose !> If dry_run, the build process is only mocked, but compile_commands are still created logical , intent ( in ) :: dry_run type ( compile_command_table_t ), intent ( inout ) :: table integer , intent ( out ) :: stat integer :: fh !$omp critical if (. not . exists ( dirname ( target % output_file )) . and . . not . dry_run ) then call mkdir ( dirname ( target % output_file ), verbose ) end if !$omp end critical select case ( target % target_type ) case ( FPM_TARGET_OBJECT ) call model % compiler % compile_fortran ( target % source % file_name , target % output_file , & & target % compile_flags , target % output_log_file , stat , table , dry_run ) case ( FPM_TARGET_C_OBJECT ) call model % compiler % compile_c ( target % source % file_name , target % output_file , & & target % compile_flags , target % output_log_file , stat , table , dry_run ) case ( FPM_TARGET_CPP_OBJECT ) call model % compiler % compile_cpp ( target % source % file_name , target % output_file , & & target % compile_flags , target % output_log_file , stat , table , dry_run ) case ( FPM_TARGET_EXECUTABLE ) call model % compiler % link ( target % output_file , & & target % compile_flags // \" \" // target % link_flags , target % output_log_file , stat , dry_run ) case ( FPM_TARGET_ARCHIVE ) call model % archiver % make_archive ( target % output_file , target % link_objects , & & target % output_log_file , stat , dry_run ) case ( FPM_TARGET_SHARED ) call model % compiler % link_shared ( target % output_file , target % link_flags , & & target % output_log_file , stat , dry_run ) end select if ( stat == 0 . and . allocated ( target % source ) . and . . not . dry_run ) then open ( newunit = fh , file = target % output_file // '.digest' , status = 'unknown' ) write ( fh , * ) target % source % digest close ( fh ) end if end subroutine build_target !> Read and print the build log for target !> subroutine print_build_log ( target ) type ( build_target_t ), intent ( in ), target :: target integer :: fh , ios character (:), allocatable :: line if ( exists ( target % output_log_file )) then open ( newunit = fh , file = target % output_log_file , status = 'old' ) do call getline ( fh , line , ios ) if ( ios /= 0 ) exit write ( * , '(A)' ) trim ( line ) end do close ( fh ) else write ( stderr , '(*(g0:,1x))' ) ' Unable to find build log \"' , basename ( target % output_log_file ), '\"' end if end subroutine print_build_log end module fpm_backend","tags":"","url":"sourcefile/fpm_backend.f90.html"},{"title":"fpm_strings.f90 – Fortran-lang/fpm","text":"Source Code !> This module defines general procedures for **string operations** for both CHARACTER and !! TYPE(STRING_T) variables ! !>## general routines for performing __string operations__ !! !!### Types !! - **TYPE(STRING_T)** define a type to contain strings of variable length !!### Type Conversions !! - [[F_STRING]] return Fortran **CHARACTER** variable when given a C-like array of !! single characters terminated with a C_NULL_CHAR **CHARACTER** !! - [[STR]] Converts **INTEGER** or** LOGICAL** to **CHARACTER** string !!### Case !! - [[LOWER]] Changes a string to lowercase over optional specified column range !!### Parsing and joining !! - [[SPLIT]] parse string on delimiter characters and store tokens into an allocatable array !! - [[SPLIT_FIRST_LAST]] Computes the first and last indices of tokens in input string, delimited by the characters in set, !! and stores them into first and last output arrays. !! - [[STRING_CAT]] Concatenate an array of **type(string_t)** into a single **CHARACTER** variable !! - [[JOIN]] append an array of **CHARACTER** variables into a single **CHARACTER** variable !!### Testing !! - [[STR_ENDS_WITH]] test if a **CHARACTER** string or array ends with a specified suffix !! - [[STRING_ARRAY_CONTAINS]] Check if array of **TYPE(STRING_T)** matches a particular **CHARACTER** string !! - **OPERATOR(.IN.)** Check if array of **TYPE(STRING_T)** matches a particular **CHARACTER** string !! - [[GLOB]] function compares text strings, one of which can have wildcards ('*' or '?'). !! - [[IS_FORTRAN_NAME]] determine whether a string is an acceptable Fortran entity name !! - [[TO_FORTRAN_NAME]] replace allowed special but unusuable characters in names with underscore !!### Whitespace !! - [[NOTABS]] subroutine to expand tab characters assuming a tab space every eight characters !! - [[DILATE]] function to expand tab characters assuming a tab space every eight characters !! - [[LEN_TRIM]] Determine total trimmed length of **STRING_T** array !!### Miscellaneous !! - [[FNV_1A]] Hash a **CHARACTER(*)** string of default kind or a **TYPE(STRING_T)** array !! - [[REPLACE]] Returns string with characters in charset replaced with target_char. !! - [[RESIZE]] increase the size of a **TYPE(STRING_T)** array by N elements !! module fpm_strings use iso_fortran_env , only : int64 use , intrinsic :: iso_fortran_env , only : stdin => input_unit , & & stdout => output_unit , & & stderr => error_unit use iso_c_binding , only : c_char , c_ptr , c_int , c_null_char , c_associated , c_f_pointer , c_size_t implicit none private public :: f_string , lower , upper , split , split_first_last , split_lines_first_last , str_ends_with , string_t , str_begins_with_str public :: to_fortran_name , is_fortran_name public :: string_array_contains , string_cat , len_trim , operator (. in .), fnv_1a public :: replace , resize , str , join , glob public :: notabs , dilate , remove_newline_characters , remove_characters_in_set public :: operator ( == ) !> Module naming public :: is_valid_module_name , is_valid_module_prefix , & has_valid_custom_prefix , has_valid_standard_prefix , & module_prefix_template , module_prefix_type type string_t character ( len = :), allocatable :: s end type interface len_trim module procedure :: string_len_trim module procedure :: strings_len_trim end interface len_trim interface resize module procedure :: resize_string end interface interface operator (. in .) module procedure string_array_contains end interface interface fnv_1a procedure :: fnv_1a_char procedure :: fnv_1a_string_t end interface fnv_1a interface str_ends_with procedure :: str_ends_with_str procedure :: str_ends_with_any procedure :: str_ends_with_any_string end interface str_ends_with interface str module procedure str_int , str_int64 , str_logical end interface interface string_t module procedure new_string_t end interface string_t interface f_string module procedure f_string , f_string_cptr , f_string_cptr_n end interface f_string interface operator ( == ) module procedure string_is_same module procedure string_arrays_same end interface contains !> test if a CHARACTER string ends with a specified suffix pure logical function str_ends_with_str ( s , e ) result ( r ) character ( * ), intent ( in ) :: s , e integer :: n1 , n2 n1 = len ( s ) - len ( e ) + 1 n2 = len ( s ) if ( n1 < 1 ) then r = . false . else r = ( s ( n1 : n2 ) == e ) end if end function str_ends_with_str !> test if a CHARACTER string ends with any of an array of suffixs pure logical function str_ends_with_any ( s , e ) result ( r ) character ( * ), intent ( in ) :: s character ( * ), intent ( in ) :: e (:) integer :: i r = . true . do i = 1 , size ( e ) if ( str_ends_with ( s , trim ( e ( i )))) return end do r = . false . end function str_ends_with_any !> Test if a CHARACTER string ends with any of an array of string suffixs pure logical function str_ends_with_any_string ( s , e ) result ( r ) character ( * ), intent ( in ) :: s type ( string_t ), intent ( in ) :: e (:) integer :: i r = . true . do i = 1 , size ( e ) if ( str_ends_with ( s , trim ( e ( i )% s ))) return end do r = . false . end function str_ends_with_any_string !> test if a CHARACTER string begins with a specified prefix pure logical function str_begins_with_str ( s , e , case_sensitive ) result ( r ) character ( * ), intent ( in ) :: s , e logical , optional , intent ( in ) :: case_sensitive ! Default option: case sensitive integer :: n1 , n2 logical :: lower_case ! Check if case sensitive if ( present ( case_sensitive )) then lower_case = . not . case_sensitive else lower_case = . false . end if n1 = 1 n2 = 1 + len ( e ) - 1 if ( n2 > len ( s )) then r = . false . elseif ( lower_case ) then r = lower ( s ( n1 : n2 )) == lower ( e ) else r = ( s ( n1 : n2 ) == e ) end if end function str_begins_with_str !> return Fortran character variable when given a C-like array of !! single characters terminated with a C_NULL_CHAR character function f_string ( c_string ) use iso_c_binding character ( len = 1 ), intent ( in ) :: c_string (:) character (:), allocatable :: f_string integer :: i , n i = 0 do while ( c_string ( i + 1 ) /= C_NULL_CHAR ) i = i + 1 end do n = i allocate ( character ( n ) :: f_string ) do i = 1 , n f_string ( i : i ) = c_string ( i ) end do end function f_string !> return Fortran character variable when given a null-terminated c_ptr function f_string_cptr ( cptr ) result ( s ) type ( c_ptr ), intent ( in ), value :: cptr character ( len = :, kind = c_char ), allocatable :: s interface function c_strlen ( s ) result ( r ) bind ( c , name = \"strlen\" ) import c_size_t , c_ptr type ( c_ptr ), intent ( in ), value :: s integer ( kind = c_size_t ) :: r end function end interface s = f_string_cptr_n ( cptr , c_strlen ( cptr )) end function !> return Fortran character variable when given a null-terminated c_ptr and its length function f_string_cptr_n ( cptr , n ) result ( s ) type ( c_ptr ), intent ( in ), value :: cptr integer ( kind = c_size_t ), intent ( in ) :: n character ( len = n , kind = c_char ) :: s character ( len = n , kind = c_char ), pointer :: sptr call c_f_pointer ( cptr , sptr ) s = sptr end function !> Hash a character(*) string of default kind pure function fnv_1a_char ( input , seed ) result ( hash ) character ( * ), intent ( in ) :: input integer ( int64 ), intent ( in ), optional :: seed integer ( int64 ) :: hash integer :: i integer ( int64 ), parameter :: FNV_OFFSET_32 = 2166136261_int64 integer ( int64 ), parameter :: FNV_PRIME_32 = 16777619_int64 if ( present ( seed )) then hash = seed else hash = FNV_OFFSET_32 end if do i = 1 , len ( input ) hash = ieor ( hash , iachar ( input ( i : i ), int64 )) * FNV_PRIME_32 end do end function fnv_1a_char !> Hash a string_t array of default kind pure function fnv_1a_string_t ( input , seed ) result ( hash ) type ( string_t ), intent ( in ) :: input (:) integer ( int64 ), intent ( in ), optional :: seed integer ( int64 ) :: hash integer :: i hash = fnv_1a ( input ( 1 )% s , seed ) do i = 2 , size ( input ) hash = fnv_1a ( input ( i )% s , hash ) end do end function fnv_1a_string_t !>Author: John S. Urban !!License: Public Domain !! Changes a string to lowercase over optional specified column range elemental pure function lower ( str , begin , end ) result ( string ) character ( * ), intent ( In ) :: str character ( len ( str )) :: string integer , intent ( in ), optional :: begin , end integer :: i integer :: ibegin , iend string = str ibegin = 1 if ( present ( begin )) then ibegin = max ( ibegin , begin ) endif iend = len_trim ( str ) if ( present ( end )) then iend = min ( iend , end ) endif do i = ibegin , iend ! step thru each letter in the string in specified range select case ( str ( i : i )) case ( 'A' : 'Z' ) string ( i : i ) = char ( iachar ( str ( i : i )) + 32 ) ! change letter to miniscule case default end select end do end function lower !!License: Public Domain !! Changes a string to upprtcase over optional specified column range elemental pure function upper ( str , begin , end ) result ( string ) character ( * ), intent ( In ) :: str character ( len ( str )) :: string integer , intent ( in ), optional :: begin , end integer :: i integer :: ibegin , iend string = str ibegin = 1 if ( present ( begin )) then ibegin = max ( ibegin , begin ) endif iend = len_trim ( str ) if ( present ( end )) then iend = min ( iend , end ) endif do i = ibegin , iend ! step thru each letter in the string in specified range select case ( str ( i : i )) case ( 'a' : 'z' ) string ( i : i ) = char ( iachar ( str ( i : i )) - 32 ) ! change letter to capitalized case default end select end do end function upper !> Helper function to generate a new string_t instance !> (Required due to the allocatable component) function new_string_t ( s ) result ( string ) character ( * ), intent ( in ) :: s type ( string_t ) :: string string % s = s end function new_string_t !> Check if array of TYPE(STRING_T) matches a particular CHARACTER string !! logical function string_array_contains ( search_string , array ) character ( * ), intent ( in ) :: search_string type ( string_t ), intent ( in ) :: array (:) integer :: i string_array_contains = any ([( array ( i )% s == search_string , & i = 1 , size ( array ))]) end function string_array_contains !> Concatenate an array of type(string_t) into !> a single CHARACTER variable function string_cat ( strings , delim ) result ( cat ) type ( string_t ), intent ( in ) :: strings (:) character ( * ), intent ( in ), optional :: delim character (:), allocatable :: cat integer :: i character (:), allocatable :: delim_str if ( size ( strings ) < 1 ) then cat = '' return end if if ( present ( delim )) then delim_str = delim else delim_str = '' end if cat = strings ( 1 )% s do i = 2 , size ( strings ) cat = cat // delim_str // strings ( i )% s end do end function string_cat !> Determine total trimmed length of `string_t` array pure function strings_len_trim ( strings ) result ( n ) type ( string_t ), intent ( in ) :: strings (:) integer :: i , n n = 0 do i = 1 , size ( strings ) n = n + len_trim ( strings ( i )% s ) end do end function strings_len_trim !> Determine total trimmed length of `string_t` array elemental integer function string_len_trim ( string ) result ( n ) type ( string_t ), intent ( in ) :: string if ( allocated ( string % s )) then n = len_trim ( string % s ) else n = 0 end if end function string_len_trim !>Author: John S. Urban !!License: Public Domain !! parse string on delimiter characters and store tokens into an allocatable array subroutine split ( input_line , array , delimiters , order , nulls ) !! given a line of structure \" par1 par2 par3 ... parn \" store each par(n) into a separate variable in array. !! !! * by default adjacent delimiters in the input string do not create an empty string in the output array !! * no quoting of delimiters is supported character ( len =* ), intent ( in ) :: input_line !! input string to tokenize character ( len =* ), optional , intent ( in ) :: delimiters !! list of delimiter characters character ( len =* ), optional , intent ( in ) :: order !! order of output array sequential|[reverse|right] character ( len =* ), optional , intent ( in ) :: nulls !! return strings composed of delimiters or not ignore|return|ignoreend character ( len = :), allocatable , intent ( out ) :: array (:) !! output array of tokens integer :: n ! max number of strings INPUT_LINE could split into if all delimiter integer , allocatable :: ibegin (:) ! positions in input string where tokens start integer , allocatable :: iterm (:) ! positions in input string where tokens end character ( len = :), allocatable :: dlim ! string containing delimiter characters character ( len = :), allocatable :: ordr ! string containing order keyword character ( len = :), allocatable :: nlls ! string containing nulls keyword integer :: ii , iiii ! loop parameters used to control print order integer :: icount ! number of tokens found integer :: ilen ! length of input string with trailing spaces trimmed integer :: i10 , i20 , i30 ! loop counters integer :: icol ! pointer into input string as it is being parsed integer :: idlim ! number of delimiter characters integer :: ifound ! where next delimiter character is found in remaining input string data integer :: inotnull ! count strings not composed of delimiters integer :: ireturn ! number of tokens returned integer :: imax ! length of longest token ! decide on value for optional DELIMITERS parameter if ( present ( delimiters )) then ! optional delimiter list was present if ( delimiters /= '' ) then ! if DELIMITERS was specified and not null use it dlim = delimiters else ! DELIMITERS was specified on call as empty string dlim = ' ' // char ( 9 ) // char ( 10 ) // char ( 11 ) // char ( 12 ) // char ( 13 ) // char ( 0 ) ! use default delimiter when not specified endif else ! no delimiter value was specified dlim = ' ' // char ( 9 ) // char ( 10 ) // char ( 11 ) // char ( 12 ) // char ( 13 ) // char ( 0 ) ! use default delimiter when not specified endif idlim = len ( dlim ) ! dlim a lot of blanks on some machines if dlim is a big string if ( present ( order )) then ; ordr = lower ( adjustl ( order )); else ; ordr = 'sequential' ; endif ! decide on value for optional ORDER parameter if ( present ( nulls )) then ; nlls = lower ( adjustl ( nulls )); else ; nlls = 'ignore' ; endif ! optional parameter n = len ( input_line ) + 1 ! max number of strings INPUT_LINE could split into if all delimiter allocate ( ibegin ( n )) ! allocate enough space to hold starting location of tokens if string all tokens allocate ( iterm ( n )) ! allocate enough space to hold ending location of tokens if string all tokens ibegin (:) = 1 iterm (:) = 1 ilen = len ( input_line ) ! ILEN is the column position of the last non-blank character icount = 0 ! how many tokens found inotnull = 0 ! how many tokens found not composed of delimiters imax = 0 ! length of longest token found select case ( ilen ) case ( 0 ) ! command was totally blank case default ! there is at least one non-delimiter in INPUT_LINE if get here icol = 1 ! initialize pointer into input line INFINITE : do i30 = 1 , ilen , 1 ! store into each array element ibegin ( i30 ) = icol ! assume start new token on the character if ( index ( dlim ( 1 : idlim ), input_line ( icol : icol )) == 0 ) then ! if current character is not a delimiter iterm ( i30 ) = ilen ! initially assume no more tokens do i10 = 1 , idlim ! search for next delimiter ifound = index ( input_line ( ibegin ( i30 ): ilen ), dlim ( i10 : i10 )) IF ( ifound > 0 ) then iterm ( i30 ) = min ( iterm ( i30 ), ifound + ibegin ( i30 ) - 2 ) endif enddo icol = iterm ( i30 ) + 2 ! next place to look as found end of this token inotnull = inotnull + 1 ! increment count of number of tokens not composed of delimiters else ! character is a delimiter for a null string iterm ( i30 ) = icol - 1 ! record assumed end of string. Will be less than beginning icol = icol + 1 ! advance pointer into input string endif imax = max ( imax , iterm ( i30 ) - ibegin ( i30 ) + 1 ) icount = i30 ! increment count of number of tokens found if ( icol > ilen ) then ! no text left exit INFINITE endif enddo INFINITE end select select case ( trim ( adjustl ( nlls ))) case ( 'ignore' , '' , 'ignoreend' ) ireturn = inotnull case default ireturn = icount end select allocate ( character ( len = imax ) :: array ( ireturn )) ! allocate the array to return !allocate(array(ireturn)) ! allocate the array to turn select case ( trim ( adjustl ( ordr ))) ! decide which order to store tokens case ( 'reverse' , 'right' ) ; ii = ireturn ; iiii =- 1 ! last to first case default ; ii = 1 ; iiii = 1 ! first to last end select do i20 = 1 , icount ! fill the array with the tokens that were found if ( iterm ( i20 ) < ibegin ( i20 )) then select case ( trim ( adjustl ( nlls ))) case ( 'ignore' , '' , 'ignoreend' ) case default array ( ii ) = ' ' ii = ii + iiii end select else array ( ii ) = input_line ( ibegin ( i20 ): iterm ( i20 )) ii = ii + iiii endif enddo end subroutine split !! Author: Milan Curcic !! Computes the first and last indices of tokens in input string, delimited !! by the characters in set, and stores them into first and last output !! arrays. pure subroutine split_first_last ( string , set , first , last ) character ( * ), intent ( in ) :: string character ( * ), intent ( in ) :: set integer , allocatable , intent ( out ) :: first (:) integer , allocatable , intent ( out ) :: last (:) integer , dimension ( len ( string ) + 1 ) :: istart , iend integer :: p , n , slen slen = len ( string ) n = 0 if ( slen > 0 ) then p = 0 do while ( p < slen ) n = n + 1 istart ( n ) = min ( p + 1 , slen ) call split_pos ( string , set , p ) iend ( n ) = p - 1 end do end if first = istart (: n ) last = iend (: n ) end subroutine split_first_last !! Author: Federico Perini !! Computes the first and last indices of lines in input string, delimited !! by either CR, LF, or CRLF, and stores them into first and last output !! arrays. pure subroutine split_lines_first_last ( string , first , last ) character ( * ), intent ( in ) :: string integer , allocatable , intent ( out ) :: first (:) integer , allocatable , intent ( out ) :: last (:) integer , dimension ( len ( string ) + 1 ) :: istart , iend integer :: p , n , slen character , parameter :: CR = achar ( 13 ) character , parameter :: LF = new_line ( 'A' ) slen = len ( string ) n = 0 if ( slen > 0 ) then p = 1 do while ( p <= slen ) if ( index ( CR // LF , string ( p : p )) == 0 ) then n = n + 1 istart ( n ) = p do while ( p <= slen ) if ( index ( CR // LF , string ( p : p )) /= 0 ) exit p = p + 1 end do iend ( n ) = p - 1 end if ! Handle Windows CRLF by skipping LF after CR if ( p < slen ) then if ( string ( p : p ) == CR . and . string ( p + 1 : p + 1 ) == LF ) p = p + 1 endif p = p + 1 end do end if first = istart (: n ) last = iend (: n ) end subroutine split_lines_first_last !! Author: Milan Curcic !! If back is absent, computes the leftmost token delimiter in string whose !! position is > pos. If back is present and true, computes the rightmost !! token delimiter in string whose position is < pos. The result is stored !! in pos. pure subroutine split_pos ( string , set , pos , back ) character ( * ), intent ( in ) :: string character ( * ), intent ( in ) :: set integer , intent ( in out ) :: pos logical , intent ( in ), optional :: back logical :: backward integer :: result_pos , bound if ( len ( string ) == 0 ) then pos = 1 return end if !TODO use optval when implemented in stdlib !backward = optval(back, .false.) backward = . false . if ( present ( back )) backward = back if ( backward ) then bound = min ( len ( string ), max ( pos - 1 , 0 )) result_pos = scan ( string (: bound ), set , back = . true .) else result_pos = scan ( string ( min ( pos + 1 , len ( string )):), set ) + pos if ( result_pos < pos + 1 ) result_pos = len ( string ) + 1 end if pos = result_pos end subroutine split_pos !> Returns string with characters in charset replaced with target_char. pure function replace ( string , charset , target_char ) result ( res ) character ( * ), intent ( in ) :: string character , intent ( in ) :: charset (:), target_char character ( len ( string )) :: res integer :: n res = string do n = 1 , len ( string ) if ( any ( string ( n : n ) == charset )) then res ( n : n ) = target_char end if end do end function replace !> increase the size of a TYPE(STRING_T) array by N elements subroutine resize_string ( list , n ) !> Instance of the array to be resized type ( string_t ), allocatable , intent ( inout ) :: list (:) !> Dimension of the final array size integer , intent ( in ), optional :: n type ( string_t ), allocatable :: tmp (:) integer :: this_size , new_size , i integer , parameter :: initial_size = 16 if ( allocated ( list )) then this_size = size ( list , 1 ) call move_alloc ( list , tmp ) else this_size = initial_size end if if ( present ( n )) then new_size = n else new_size = this_size + this_size / 2 + 1 end if allocate ( list ( new_size )) if ( allocated ( tmp )) then this_size = min ( size ( tmp , 1 ), size ( list , 1 )) do i = 1 , this_size call move_alloc ( tmp ( i )% s , list ( i )% s ) end do deallocate ( tmp ) end if end subroutine resize_string !>AUTHOR: John S. Urban !!LICENSE: Public Domain !> !!##NAME !! join(3f) - [M_strings:EDITING] append CHARACTER variable array into !! a single CHARACTER variable with specified separator !! (LICENSE:PD) !! !!##SYNOPSIS !! !! pure function join(str,sep,trm,left,right,start,end) result (string) !! !! character(len=*),intent(in) :: str(:) !! character(len=*),intent(in),optional :: sep !! logical,intent(in),optional :: trm !! character(len=*),intent(in),optional :: right !! character(len=*),intent(in),optional :: left !! character(len=*),intent(in),optional :: start !! character(len=*),intent(in),optional :: end !! character(len=:),allocatable :: string !! !!##DESCRIPTION !! JOIN(3f) appends the elements of a CHARACTER array into a single !! CHARACTER variable, with elements 1 to N joined from left to right. !! By default each element is trimmed of trailing spaces and the !! default separator is a null string. !! !!##OPTIONS !! STR(:) array of CHARACTER variables to be joined !! SEP separator string to place between each variable. defaults !! to a null string. !! LEFT string to place at left of each element !! RIGHT string to place at right of each element !! START prefix string !! END suffix string !! TRM option to trim each element of STR of trailing !! spaces. Defaults to .TRUE. !! !!##RESULT !! STRING CHARACTER variable composed of all of the elements of STR() !! appended together with the optional separator SEP placed !! between the elements. !! !!##EXAMPLE !! !! Sample program: !! !! program demo_join !! use M_strings, only: join !! implicit none !! character(len=:),allocatable :: s(:) !! character(len=:),allocatable :: out !! integer :: i !! s=[character(len=10) :: 'United',' we',' stand,', & !! & ' divided',' we fall.'] !! out=join(s) !! write(*,'(a)') out !! write(*,'(a)') join(s,trm=.false.) !! write(*,'(a)') (join(s,trm=.false.,sep='|'),i=1,3) !! write(*,'(a)') join(s,sep='<>') !! write(*,'(a)') join(s,sep=';',left='[',right=']') !! write(*,'(a)') join(s,left='[',right=']') !! write(*,'(a)') join(s,left='>>') !! end program demo_join !! !! Expected output: !! !! United we stand, divided we fall. !! United we stand, divided we fall. !! United | we | stand, | divided | we fall. !! United | we | stand, | divided | we fall. !! United | we | stand, | divided | we fall. !! United<> we<> stand,<> divided<> we fall. !! [United];[ we];[ stand,];[ divided];[ we fall.] !! [United][ we][ stand,][ divided][ we fall.] !! >>United>> we>> stand,>> divided>> we fall. pure function join ( str , sep , trm , left , right , start , end ) result ( string ) ! @(#)M_strings::join(3f): merge string array into a single CHARACTER value adding specified separators, caps, prefix and suffix character ( len =* ), intent ( in ) :: str (:) character ( len =* ), intent ( in ), optional :: sep , right , left , start , end logical , intent ( in ), optional :: trm character ( len = :), allocatable :: sep_local , left_local , right_local character ( len = :), allocatable :: string logical :: trm_local integer :: i if ( present ( sep )) then ; sep_local = sep ; else ; sep_local = '' ; endif if ( present ( trm )) then ; trm_local = trm ; else ; trm_local = . true . ; endif if ( present ( left )) then ; left_local = left ; else ; left_local = '' ; endif if ( present ( right )) then ; right_local = right ; else ; right_local = '' ; endif string = '' if ( size ( str ) == 0 ) then string = string // left_local // right_local else do i = 1 , size ( str ) - 1 if ( trm_local ) then string = string // left_local // trim ( str ( i )) // right_local // sep_local else string = string // left_local // str ( i ) // right_local // sep_local endif enddo if ( trm_local ) then string = string // left_local // trim ( str ( i )) // right_local else string = string // left_local // str ( i ) // right_local endif endif if ( present ( start )) string = start // string if ( present ( end )) string = string // end end function join !>AUTHOR: John S. Urban !!LICENSE: Public Domain !> !!## NAME !! glob(3f) - [fpm_strings:COMPARE] compare given string for match to !! pattern which may contain wildcard characters !! (LICENSE:PD) !! !!## SYNOPSIS !! !! logical function glob(string, pattern ) !! !! character(len=*),intent(in) :: string !! character(len=*),intent(in) :: pattern !! !!## DESCRIPTION !! glob(3f) compares given STRING for match to PATTERN which may !! contain wildcard characters. !! !! In this version to get a match the entire string must be described !! by PATTERN. Trailing whitespace is significant, so trim the input !! string to have trailing whitespace ignored. !! !!## OPTIONS !! string the input string to test to see if it contains the pattern. !! pattern the following simple globbing options are available !! !! o \"?\" matching any one character !! o \"*\" matching zero or more characters. !! Do NOT use adjacent asterisks. !! o Both strings may have trailing spaces which !! are ignored. !! o There is no escape character, so matching strings with !! literal question mark and asterisk is problematic. !! !!## EXAMPLES !! !! Example program !! !! program demo_glob !! implicit none !! ! This main() routine passes a bunch of test strings !! ! into the above code. In performance comparison mode, !! ! it does that over and over. Otherwise, it does it just !! ! once. Either way, it outputs a passed/failed result. !! ! !! integer :: nReps !! logical :: allpassed !! integer :: i !! allpassed = .true. !! !! nReps = 10000 !! ! Can choose as many repetitions as you're expecting !! ! in the real world. !! nReps = 1 !! !! do i=1,nReps !! ! Cases with repeating character sequences. !! allpassed=allpassed .and. test(\"a*abab\", \"a*b\", .true.) !! !!cycle !! allpassed=allpassed .and. test(\"ab\", \"*?\", .true.) !! allpassed=allpassed .and. test(\"abc\", \"*?\", .true.) !! allpassed=allpassed .and. test(\"abcccd\", \"*ccd\", .true.) !! allpassed=allpassed .and. test(\"bLah\", \"bLaH\", .false.) !! allpassed=allpassed .and. test(\"mississippi\", \"*sip*\", .true.) !! allpassed=allpassed .and. & !! & test(\"xxxx*zzzzzzzzy*f\", \"xxx*zzy*f\", .true.) !! allpassed=allpassed .and. & !! & test(\"xxxx*zzzzzzzzy*f\", \"xxxx*zzy*fffff\", .false.) !! allpassed=allpassed .and. & !! & test(\"mississipissippi\", \"*issip*ss*\", .true.) !! allpassed=allpassed .and. & !! & test(\"xxxxzzzzzzzzyf\", \"xxxx*zzy*fffff\", .false.) !! allpassed=allpassed .and. & !! & test(\"xxxxzzzzzzzzyf\", \"xxxx*zzy*f\", .true.) !! allpassed=allpassed .and. test(\"xyxyxyzyxyz\", \"xy*z*xyz\", .true.) !! allpassed=allpassed .and. test(\"xyxyxyxyz\", \"xy*xyz\", .true.) !! allpassed=allpassed .and. test(\"mississippi\", \"mi*sip*\", .true.) !! allpassed=allpassed .and. test(\"ababac\", \"*abac*\", .true.) !! allpassed=allpassed .and. test(\"aaazz\", \"a*zz*\", .true.) !! allpassed=allpassed .and. test(\"a12b12\", \"*12*23\", .false.) !! allpassed=allpassed .and. test(\"a12b12\", \"a12b\", .false.) !! allpassed=allpassed .and. test(\"a12b12\", \"*12*12*\", .true.) !! !! ! Additional cases where the '*' char appears in the tame string. !! allpassed=allpassed .and. test(\"*\", \"*\", .true.) !! allpassed=allpassed .and. test(\"a*r\", \"a*\", .true.) !! allpassed=allpassed .and. test(\"a*ar\", \"a*aar\", .false.) !! !! ! More double wildcard scenarios. !! allpassed=allpassed .and. test(\"XYXYXYZYXYz\", \"XY*Z*XYz\", .true.) !! allpassed=allpassed .and. test(\"missisSIPpi\", \"*SIP*\", .true.) !! allpassed=allpassed .and. test(\"mississipPI\", \"*issip*PI\", .true.) !! allpassed=allpassed .and. test(\"xyxyxyxyz\", \"xy*xyz\", .true.) !! allpassed=allpassed .and. test(\"miSsissippi\", \"mi*sip*\", .true.) !! allpassed=allpassed .and. test(\"miSsissippi\", \"mi*Sip*\", .false.) !! allpassed=allpassed .and. test(\"abAbac\", \"*Abac*\", .true.) !! allpassed=allpassed .and. test(\"aAazz\", \"a*zz*\", .true.) !! allpassed=allpassed .and. test(\"A12b12\", \"*12*23\", .false.) !! allpassed=allpassed .and. test(\"a12B12\", \"*12*12*\", .true.) !! allpassed=allpassed .and. test(\"oWn\", \"*oWn*\", .true.) !! !! ! Completely tame (no wildcards) cases. !! allpassed=allpassed .and. test(\"bLah\", \"bLah\", .true.) !! !! ! Simple mixed wildcard tests suggested by IBMer Marlin Deckert. !! allpassed=allpassed .and. test(\"a\", \"*?\", .true.) !! !! ! More mixed wildcard tests including coverage for false positives. !! allpassed=allpassed .and. test(\"a\", \"??\", .false.) !! allpassed=allpassed .and. test(\"ab\", \"?*?\", .true.) !! allpassed=allpassed .and. test(\"ab\", \"*?*?*\", .true.) !! allpassed=allpassed .and. test(\"abc\", \"?**?*?\", .true.) !! allpassed=allpassed .and. test(\"abc\", \"?**?*&?\", .false.) !! allpassed=allpassed .and. test(\"abcd\", \"?b*??\", .true.) !! allpassed=allpassed .and. test(\"abcd\", \"?a*??\", .false.) !! allpassed=allpassed .and. test(\"abcd\", \"?**?c?\", .true.) !! allpassed=allpassed .and. test(\"abcd\", \"?**?d?\", .false.) !! allpassed=allpassed .and. test(\"abcde\", \"?*b*?*d*?\", .true.) !! !! ! Single-character-match cases. !! allpassed=allpassed .and. test(\"bLah\", \"bL?h\", .true.) !! allpassed=allpassed .and. test(\"bLaaa\", \"bLa?\", .false.) !! allpassed=allpassed .and. test(\"bLah\", \"bLa?\", .true.) !! allpassed=allpassed .and. test(\"bLaH\", \"?Lah\", .false.) !! allpassed=allpassed .and. test(\"bLaH\", \"?LaH\", .true.) !! !! ! Many-wildcard scenarios. !! allpassed=allpassed .and. test(& !! &\"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa& !! &aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab\",& !! &\"a*a*a*a*a*a*aa*aaa*a*a*b\",& !! &.true.) !! allpassed=allpassed .and. test(& !! &\"abababababababababababababababababababaacacacacacacac& !! &adaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab\",& !! &\"*a*b*ba*ca*a*aa*aaa*fa*ga*b*\",& !! &.true.) !! allpassed=allpassed .and. test(& !! &\"abababababababababababababababababababaacacacacacaca& !! &cadaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab\",& !! &\"*a*b*ba*ca*a*x*aaa*fa*ga*b*\",& !! &.false.) !! allpassed=allpassed .and. test(& !! &\"abababababababababababababababababababaacacacacacacacad& !! &aeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab\",& !! &\"*a*b*ba*ca*aaaa*fa*ga*gggg*b*\",& !! &.false.) !! allpassed=allpassed .and. test(& !! &\"abababababababababababababababababababaacacacacacacacad& !! &aeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab\",& !! &\"*a*b*ba*ca*aaaa*fa*ga*ggg*b*\",& !! &.true.) !! allpassed=allpassed .and. test(\"aaabbaabbaab\", \"*aabbaa*a*\", .true.) !! allpassed=allpassed .and. & !! test(\"a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*\",& !! &\"a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*\", .true.) !! allpassed=allpassed .and. test(\"aaaaaaaaaaaaaaaaa\",& !! &\"*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*\", .true.) !! allpassed=allpassed .and. test(\"aaaaaaaaaaaaaaaa\",& !! &\"*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*\", .false.) !! allpassed=allpassed .and. test(& !! &\"abc*abcd*abcde*abcdef*abcdefg*abcdefgh*abcdefghi*abcdefghij& !! &*abcdefghijk*abcdefghijkl*abcdefghijklm*abcdefghijklmn\",& !! & \"abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc& !! &*abc*abc*abc*\",& !! &.false.) !! allpassed=allpassed .and. test(& !! &\"abc*abcd*abcde*abcdef*abcdefg*abcdefgh*abcdefghi*abcdefghij& !! &*abcdefghijk*abcdefghijkl*abcdefghijklm*abcdefghijklmn\",& !! &\"abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*\",& !! &.true.) !! allpassed=allpassed .and. test(\"abc*abcd*abcd*abc*abcd\",& !! &\"abc*abc*abc*abc*abc\", .false.) !! allpassed=allpassed .and. test( \"abc*abcd*abcd*abc*abcd*abcd& !! &*abc*abcd*abc*abc*abcd\", & !! &\"abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abcd\",& !! &.true.) !! allpassed=allpassed .and. test(\"abc\",& !! &\"********a********b********c********\", .true.) !! allpassed=allpassed .and.& !! &test(\"********a********b********c********\", \"abc\", .false.) !! allpassed=allpassed .and. & !! &test(\"abc\", \"********a********b********b********\", .false.) !! allpassed=allpassed .and. test(\"*abc*\", \"***a*b*c***\", .true.) !! !! ! A case-insensitive algorithm test. !! ! allpassed=allpassed .and. test(\"mississippi\", \"*issip*PI\", .true.) !! enddo !! !! if (allpassed)then !! write(*,'(a)')\"Passed\",nReps !! else !! write(*,'(a)')\"Failed\" !! endif !! contains !! ! This is a test program for wildcard matching routines. !! ! It can be used either to test a single routine for correctness, !! ! or to compare the timings of two (or more) different wildcard !! ! matching routines. !! ! !! function test(tame, wild, bExpectedResult) result(bpassed) !! use fpm_strings, only : glob !! character(len=*) :: tame !! character(len=*) :: wild !! logical :: bExpectedResult !! logical :: bResult !! logical :: bPassed !! bResult = .true. ! We'll do \"&=\" cumulative checking. !! bPassed = .false. ! Assume the worst. !! write(*,*)repeat('=',79) !! bResult = glob(tame, wild) ! Call a wildcard matching routine. !! !! ! To assist correctness checking, output the two strings in any !! ! failing scenarios. !! if (bExpectedResult .eqv. bResult) then !! bPassed = .true. !! if(nReps == 1) write(*,*)\"Passed match on \",tame,\" vs. \", wild !! else !! if(nReps == 1) write(*,*)\"Failed match on \",tame,\" vs. \", wild !! endif !! !! end function test !! end program demo_glob !! !! Expected output !! !! !!## REFERENCE !! The article \"Matching Wildcards: An Empirical Way to Tame an Algorithm\" !! in Dr Dobb's Journal, By Kirk J. Krauss, October 07, 2014 !! function glob ( tame , wild ) ! @(#)fpm_strings::glob(3f): function compares text strings, one of which can have wildcards ('*' or '?'). logical :: glob !! result of test character ( len =* ) :: tame !! A string without wildcards to compare to the globbing expression character ( len =* ) :: wild !! A (potentially) corresponding string with wildcards character ( len = len ( tame ) + 1 ) :: tametext character ( len = len ( wild ) + 1 ) :: wildtext character ( len = 1 ), parameter :: NULL = char ( 0 ) integer :: wlen integer :: ti , wi integer :: i character ( len = :), allocatable :: tbookmark , wbookmark ! These two values are set when we observe a wildcard character. They ! represent the locations, in the two strings, from which we start once we've observed it. tametext = tame // NULL wildtext = wild // NULL tbookmark = NULL wbookmark = NULL wlen = len ( wild ) wi = 1 ti = 1 do ! Walk the text strings one character at a time. if ( wildtext ( wi : wi ) == '*' ) then ! How do you match a unique text string? do i = wi , wlen ! Easy: unique up on it! if ( wildtext ( wi : wi ) == '*' ) then wi = wi + 1 else exit endif enddo if ( wildtext ( wi : wi ) == NULL ) then ! \"x\" matches \"*\" glob = . true . return endif if ( wildtext ( wi : wi ) /= '?' ) then ! Fast-forward to next possible match. do while ( tametext ( ti : ti ) /= wildtext ( wi : wi )) ti = ti + 1 if ( tametext ( ti : ti ) == NULL ) then glob = . false . return ! \"x\" doesn't match \"*y*\" endif enddo endif wbookmark = wildtext ( wi :) tbookmark = tametext ( ti :) elseif ( tametext ( ti : ti ) /= wildtext ( wi : wi ) . and . wildtext ( wi : wi ) /= '?' ) then ! Got a non-match. If we've set our bookmarks, back up to one or both of them and retry. if ( wbookmark /= NULL ) then if ( wildtext ( wi :) /= wbookmark ) then wildtext = wbookmark ; wlen = len_trim ( wbookmark ) wi = 1 ! Don't go this far back again. if ( tametext ( ti : ti ) /= wildtext ( wi : wi )) then tbookmark = tbookmark ( 2 :) tametext = tbookmark ti = 1 cycle ! \"xy\" matches \"*y\" else wi = wi + 1 endif endif if ( tametext ( ti : ti ) /= NULL ) then ti = ti + 1 cycle ! \"mississippi\" matches \"*sip*\" endif endif glob = . false . return ! \"xy\" doesn't match \"x\" endif ti = ti + 1 wi = wi + 1 if ( tametext ( ti : ti ) == NULL ) then ! How do you match a tame text string? if ( wildtext ( wi : wi ) /= NULL ) then do while ( wildtext ( wi : wi ) == '*' ) ! The tame way: unique up on it! wi = wi + 1 ! \"x\" matches \"x*\" if ( wildtext ( wi : wi ) == NULL ) exit enddo endif if ( wildtext ( wi : wi ) == NULL ) then glob = . true . return ! \"x\" matches \"x\" endif glob = . false . return ! \"x\" doesn't match \"xy\" endif enddo end function glob !> Returns the length of the string representation of 'i' pure integer function str_int_len ( i ) result ( sz ) integer , intent ( in ) :: i integer , parameter :: MAX_STR = 100 character ( MAX_STR ) :: s ! If 's' is too short (MAX_STR too small), Fortran will abort with: ! \"Fortran runtime error: End of record\" write ( s , '(i0)' ) i sz = len_trim ( s ) end function !> Converts integer \"i\" to string pure function str_int ( i ) result ( s ) integer , intent ( in ) :: i character ( len = str_int_len ( i )) :: s write ( s , '(i0)' ) i end function !> Returns the length of the string representation of 'i' pure integer function str_int64_len ( i ) result ( sz ) integer ( int64 ), intent ( in ) :: i integer , parameter :: MAX_STR = 100 character ( MAX_STR ) :: s ! If 's' is too short (MAX_STR too small), Fortran will abort with: ! \"Fortran runtime error: End of record\" write ( s , '(i0)' ) i sz = len_trim ( s ) end function !> Converts integer \"i\" to string pure function str_int64 ( i ) result ( s ) integer ( int64 ), intent ( in ) :: i character ( len = str_int64_len ( i )) :: s write ( s , '(i0)' ) i end function !> Returns the length of the string representation of 'l' pure integer function str_logical_len ( l ) result ( sz ) logical , intent ( in ) :: l if ( l ) then sz = 6 else sz = 7 end if end function !> Converts logical \"l\" to string pure function str_logical ( l ) result ( s ) logical , intent ( in ) :: l character ( len = str_logical_len ( l )) :: s if ( l ) then s = \".true.\" else s = \".false.\" end if end function !> Returns string with special characters replaced with an underscore. !! For now, only a hyphen is treated as a special character, but this can be !! expanded to other characters if needed. pure function to_fortran_name ( string ) result ( res ) character ( * ), intent ( in ) :: string character ( len ( string )) :: res character , parameter :: SPECIAL_CHARACTERS ( * ) = [ '-' ] res = replace ( string , SPECIAL_CHARACTERS , '_' ) end function to_fortran_name elemental function is_fortran_name ( line ) result ( lout ) ! determine if a string is a valid Fortran name ignoring trailing spaces ! (but not leading spaces) character ( len =* ), parameter :: int = '0123456789' character ( len =* ), parameter :: lower = 'abcdefghijklmnopqrstuvwxyz' character ( len =* ), parameter :: upper = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' character ( len =* ), parameter :: allowed = upper // lower // int // '_' character ( len =* ), intent ( in ) :: line character ( len = :), allocatable :: name logical :: lout name = trim ( line ) if ( len ( name ) /= 0 ) then lout = . true . & & . and . verify ( name ( 1 : 1 ), lower // upper ) == 0 & & . and . verify ( name , allowed ) == 0 & & . and . len ( name ) <= 63 else lout = . false . endif end function is_fortran_name !> Check that a module name fits the current naming rules: !> 1) It must be a valid FORTRAN name (<=63 chars, begin with letter, \"_\" is only allowed non-alphanumeric) !> 2) It must begin with the package name !> 3) If longer, package name must be followed by default separator plus at least one char logical function is_valid_module_name ( module_name , package_name , custom_prefix , enforce_module_names ) result ( valid ) type ( string_t ), intent ( in ) :: module_name type ( string_t ), intent ( in ) :: package_name type ( string_t ), intent ( in ) :: custom_prefix logical , intent ( in ) :: enforce_module_names !> Basic check: check the name is Fortran-compliant valid = is_fortran_name ( module_name % s ); if (. not . valid ) return !> FPM package enforcing: check that the module name begins with the package name if ( enforce_module_names ) then ! Default prefixing is always valid valid = has_valid_standard_prefix ( module_name , package_name ) ! If a custom prefix was validated, it provides additional naming options ! Because they never overlap with the default prefix, the former is always an option if ( len_trim ( custom_prefix ) > 0 . and . . not . valid ) & valid = has_valid_custom_prefix ( module_name , custom_prefix ) end if end function is_valid_module_name !> Check that a custom module prefix fits the current naming rules: !> 1) Only alphanumeric characters (no spaces, dashes, underscores or other characters) !> 2) Does not begin with a number (Fortran-compatible syntax) logical function is_valid_module_prefix ( module_prefix ) result ( valid ) type ( string_t ), intent ( in ) :: module_prefix character ( len =* ), parameter :: num = '0123456789' character ( len =* ), parameter :: lower = 'abcdefghijklmnopqrstuvwxyz' character ( len =* ), parameter :: upper = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' character ( len =* ), parameter :: alpha = upper // lower character ( len =* ), parameter :: allowed = alpha // num character ( len = :), allocatable :: name name = trim ( module_prefix % s ) if ( len ( name ) > 0 . and . len ( name ) <= 63 ) then valid = verify ( name ( 1 : 1 ), alpha ) == 0 . and . & verify ( name , allowed ) == 0 else valid = . false . endif end function is_valid_module_prefix type ( string_t ) function module_prefix_template ( project_name , custom_prefix ) result ( prefix ) type ( string_t ), intent ( in ) :: project_name type ( string_t ), intent ( in ) :: custom_prefix if ( is_valid_module_prefix ( custom_prefix )) then prefix = string_t ( trim ( custom_prefix % s ) // \"_\" ) else prefix = string_t ( to_fortran_name ( project_name % s ) // \"__\" ) end if end function module_prefix_template type ( string_t ) function module_prefix_type ( project_name , custom_prefix ) result ( ptype ) type ( string_t ), intent ( in ) :: project_name type ( string_t ), intent ( in ) :: custom_prefix if ( is_valid_module_prefix ( custom_prefix )) then ptype = string_t ( \"custom\" ) else ptype = string_t ( \"default\" ) end if end function module_prefix_type !> Check that a module name is prefixed with a custom prefix: !> 1) It must be a valid FORTRAN name subset (<=63 chars, begin with letter, only alphanumeric allowed) !> 2) It must begin with the prefix !> 3) If longer, package name must be followed by default separator (\"_\") plus at least one char logical function has_valid_custom_prefix ( module_name , custom_prefix ) result ( valid ) type ( string_t ), intent ( in ) :: module_name type ( string_t ), intent ( in ) :: custom_prefix !> custom_module separator: single underscore character ( * ), parameter :: SEP = \"_\" logical :: is_same , has_separator , same_beginning integer :: lpkg , lmod , lsep !> Basic check: check that both names are individually valid valid = is_fortran_name ( module_name % s ) . and . & is_valid_module_prefix ( custom_prefix ) !> FPM package enforcing: check that the module name begins with the custom prefix if ( valid ) then !> Query string lengths lpkg = len_trim ( custom_prefix ) lmod = len_trim ( module_name ) lsep = len_trim ( SEP ) same_beginning = str_begins_with_str ( module_name % s , custom_prefix % s , case_sensitive = . false .) is_same = lpkg == lmod . and . same_beginning if ( lmod >= lpkg + lsep ) then has_separator = str_begins_with_str ( module_name % s ( lpkg + 1 : lpkg + lsep ), SEP ) else has_separator = . false . endif !> 2) It must begin with the package name. !> 3) It can be equal to the package name, or, if longer, must be followed by the ! default separator plus at least one character !> 4) Package name must not end with an underscore valid = same_beginning . and . ( is_same . or . ( lmod > lpkg + lsep . and . has_separator )) end if end function has_valid_custom_prefix !> Check that a module name is prefixed with the default package prefix: !> 1) It must be a valid FORTRAN name (<=63 chars, begin with letter, \"_\" is only allowed non-alphanumeric) !> 2) It must begin with the package name !> 3) If longer, package name must be followed by default separator plus at least one char logical function has_valid_standard_prefix ( module_name , package_name ) result ( valid ) type ( string_t ), intent ( in ) :: module_name type ( string_t ), intent ( in ) :: package_name !> Default package__module separator: two underscores character ( * ), parameter :: SEP = \"__\" character ( len = :), allocatable :: fortranized_pkg logical :: is_same , has_separator , same_beginning integer :: lpkg , lmod , lsep !> Basic check: check the name is Fortran-compliant valid = is_fortran_name ( module_name % s ) !> FPM package enforcing: check that the module name begins with the package name if ( valid ) then fortranized_pkg = to_fortran_name ( package_name % s ) !> Query string lengths lpkg = len_trim ( fortranized_pkg ) lmod = len_trim ( module_name ) lsep = len_trim ( SEP ) same_beginning = str_begins_with_str ( module_name % s , fortranized_pkg , case_sensitive = . false .) is_same = lpkg == lmod . and . same_beginning if ( lmod >= lpkg + lsep ) then has_separator = str_begins_with_str ( module_name % s ( lpkg + 1 : lpkg + lsep ), SEP ) else has_separator = . false . endif !> 2) It must begin with the package name. !> 3) It can be equal to the package name, or, if longer, must be followed by the ! default separator plus at least one character !> 4) Package name must not end with an underscore valid = is_fortran_name ( fortranized_pkg ) . and . & fortranized_pkg ( lpkg : lpkg ) /= '_' . and . & ( same_beginning . and . ( is_same . or . ( lmod > lpkg + lsep . and . has_separator ))) end if end function has_valid_standard_prefix !> Check that two string _objects_ are exactly identical pure logical function string_is_same ( this , that ) !> two strings to be compared type ( string_t ), intent ( in ) :: this , that integer :: i string_is_same = . false . if ( allocated ( this % s ). neqv . allocated ( that % s )) return if ( allocated ( this % s )) then if (. not . len ( this % s ) == len ( that % s )) return if (. not . len_trim ( this % s ) == len_trim ( that % s )) return do i = 1 , len_trim ( this % s ) if (. not .( this % s ( i : i ) == that % s ( i : i ))) return end do end if ! All checks passed string_is_same = . true . end function string_is_same !> Check that two allocatable string _object_ arrays are exactly identical pure logical function string_arrays_same ( this , that ) !> two string arrays to be compared type ( string_t ), allocatable , intent ( in ) :: this (:), that (:) integer :: i string_arrays_same = . false . if ( allocated ( this ). neqv . allocated ( that )) return if ( allocated ( this )) then if (. not .( size ( this ) == size ( that ))) return if (. not .( ubound ( this , 1 ) == ubound ( that , 1 ))) return if (. not .( lbound ( this , 1 ) == lbound ( that , 1 ))) return do i = lbound ( this , 1 ), ubound ( this , 1 ) if (. not . string_is_same ( this ( i ), that ( i ))) return end do end if ! All checks passed string_arrays_same = . true . end function string_arrays_same ! Remove all characters from a set from a string subroutine remove_characters_in_set ( string , set , replace_with ) character ( len = :), allocatable , intent ( inout ) :: string character ( * ), intent ( in ) :: set character , optional , intent ( in ) :: replace_with ! Replace with this character instead of removing integer :: feed , length if (. not . allocated ( string )) return if ( len ( set ) <= 0 ) return length = len ( string ) feed = scan ( string , set ) do while ( length > 0 . and . feed > 0 ) ! Remove heading if ( length == 1 ) then string = \"\" elseif ( feed == 1 ) then string = string ( 2 : length ) ! Remove trailing elseif ( feed == length ) then string = string ( 1 : length - 1 ) ! In between: replace with given character elseif ( present ( replace_with )) then string ( feed : feed ) = replace_with ! Or just remove else string = string ( 1 : feed - 1 ) // string ( feed + 1 : length ) end if length = len ( string ) feed = scan ( string , set ) end do end subroutine remove_characters_in_set ! Remove all new line characters from the current string, replace them with spaces subroutine remove_newline_characters ( string ) type ( string_t ), intent ( inout ) :: string integer :: feed , length character ( * ), parameter :: CRLF = achar ( 13 ) // new_line ( 'a' ) character ( * ), parameter :: SPACE = ' ' call remove_characters_in_set ( string % s , set = CRLF , replace_with = SPACE ) end subroutine remove_newline_characters !>AUTHOR: John S. Urban !!LICENSE: Public Domain !> !!### NAME !! notabs(3f) - [fpm_strings:NONALPHA] expand tab characters !! (LICENSE:PD) !! !!### SYNOPSIS !! !! subroutine notabs(INSTR,OUTSTR,ILEN) !! !! character(len=*),intent=(in) :: INSTR !! character(len=*),intent=(out) :: OUTSTR !! integer,intent=(out) :: ILEN !! !!### DESCRIPTION !! NOTABS() converts tabs in INSTR to spaces in OUTSTR while maintaining !! columns. It assumes a tab is set every 8 characters. Trailing spaces !! are removed. !! !! In addition, trailing carriage returns and line feeds are removed !! (they are usually a problem created by going to and from MSWindows). !! !! What are some reasons for removing tab characters from an input line? !! Some Fortran compilers have problems with tabs, as tabs are not !! part of the Fortran character set. Some editors and printers will !! have problems with tabs. It is often useful to expand tabs in input !! files to simplify further processing such as tokenizing an input line. !! !!### OPTIONS !! instr Input line to remove tabs from !! !!### RESULTS !! outstr Output string with tabs expanded. Assumed to be of sufficient !! length !! ilen Significant length of returned string !! !!### EXAMPLES !! !! Sample program: !! !! program demo_notabs !! !! ! test filter to remove tabs and trailing white space from input !! ! on files up to 1024 characters wide !! use fpm_strings, only : notabs !! character(len=1024) :: in,out !! integer :: ios,iout !! do !! read(*,'(A)',iostat=ios)in !! if(ios /= 0) exit !! call notabs(in,out,iout) !! write(*,'(a)')out(:iout) !! enddo !! end program demo_notabs !! !!### SEE ALSO !! GNU/Unix commands expand(1) and unexpand(1) !! elemental impure subroutine notabs ( instr , outstr , ilen ) ! ident_31=\"@(#)fpm_strings::notabs(3f): convert tabs to spaces while maintaining columns, remove CRLF chars\" character ( len =* ), intent ( in ) :: instr ! input line to scan for tab characters character ( len =* ), intent ( out ) :: outstr ! tab-expanded version of INSTR produced integer , intent ( out ) :: ilen ! column position of last character put into output string ! that is, ILEN holds the position of the last non-blank character in OUTSTR integer , parameter :: tabsize = 8 ! assume a tab stop is set every 8th column integer :: ipos ! position in OUTSTR to put next character of INSTR integer :: lenin ! length of input string trimmed of trailing spaces integer :: lenout ! number of characters output string can hold integer :: istep ! counter that advances thru input string INSTR one character at a time character ( len = 1 ) :: c ! character in input line being processed integer :: iade ! ADE (ASCII Decimal Equivalent) of character being tested ipos = 1 ! where to put next character in output string OUTSTR lenin = len_trim ( instr ( 1 : len ( instr ) )) ! length of INSTR trimmed of trailing spaces lenout = len ( outstr ) ! number of characters output string OUTSTR can hold outstr = \" \" ! this SHOULD blank-fill string, a buggy machine required a loop to set all characters SCAN_LINE : do istep = 1 , lenin ! look through input string one character at a time c = instr ( istep : istep ) ! get next character iade = ichar ( c ) ! get ADE of the character EXPAND_TABS : select case ( iade ) ! take different actions depending on which character was found case ( 9 ) ! test if character is a tab and move pointer out to appropriate column ipos = ipos + ( tabsize - ( mod ( ipos - 1 , tabsize ))) case ( 10 , 13 ) ! convert carriage-return and new-line to space ,typically to handle DOS-format files ipos = ipos + 1 case default ! c is anything else other than a tab,newline,or return insert it in output string if ( ipos > lenout ) then write ( stderr , * ) \"*notabs* output string overflow\" exit else outstr ( ipos : ipos ) = c ipos = ipos + 1 endif end select EXPAND_TABS enddo SCAN_LINE ipos = min ( ipos , lenout ) ! tabs or newline or return characters or last character might have gone too far ilen = len_trim ( outstr (: ipos )) ! trim trailing spaces end subroutine notabs !>AUTHOR: John S. Urban !!LICENSE: Public Domain !> !!##NAME !! dilate(3f) - [M_strings:NONALPHA] expand tab characters !! (LICENSE:PD) !! !!##SYNOPSIS !! !! function dilate(INSTR) result(OUTSTR) !! !! character(len=*),intent=(in) :: INSTR !! character(len=:),allocatable :: OUTSTR !! !!##DESCRIPTION !! dilate() converts tabs in INSTR to spaces in OUTSTR. It assumes a !! tab is set every 8 characters. Trailing spaces are removed. !! !! In addition, trailing carriage returns and line feeds are removed !! (they are usually a problem created by going to and from MSWindows). !! !!##OPTIONS !! instr Input line to remove tabs from !! !!##RESULTS !! outstr Output string with tabs expanded. !! !!##EXAMPLES !! !! Sample program: !! !! program demo_dilate !! !! use M_strings, only : dilate !! implicit none !! character(len=:),allocatable :: in !! integer :: i !! in=' this is my string ' !! ! change spaces to tabs to make a sample input !! do i=1,len(in) !! if(in(i:i) == ' ')in(i:i)=char(9) !! enddo !! write(*,'(a)')in,dilate(in) !! end program demo_dilate !! function dilate ( instr ) result ( outstr ) character ( len =* ), intent ( in ) :: instr ! input line to scan for tab characters character ( len = :), allocatable :: outstr ! tab-expanded version of INSTR produced integer :: i integer :: icount integer :: lgth icount = 0 do i = 1 , len ( instr ) if ( instr ( i : i ) == char ( 9 )) icount = icount + 1 end do allocate ( character ( len = ( len ( instr ) + 8 * icount )) :: outstr ) call notabs ( instr , outstr , lgth ) outstr = outstr (: lgth ) end function dilate end module fpm_strings","tags":"","url":"sourcefile/fpm_strings.f90.html"},{"title":"versioning.f90 – Fortran-lang/fpm","text":"Source Code !> Implementation of versioning data for comparing packages module fpm_versioning use fpm_error , only : error_t , syntax_error use fpm_strings , only : string_t use regex_module , only : regex implicit none private public :: version_t , new_version public :: regex_version_from_text type :: version_t private !> Version numbers found integer , allocatable :: num (:) contains generic :: operator ( == ) => equals procedure , private :: equals generic :: operator ( /= ) => not_equals procedure , private :: not_equals generic :: operator ( > ) => greater procedure , private :: greater generic :: operator ( < ) => less procedure , private :: less generic :: operator ( >= ) => greater_equals procedure , private :: greater_equals generic :: operator ( <= ) => less_equals procedure , private :: less_equals !> Compare a version against a version constraint (x.x.0 <= v < x.x.HUGE) generic :: operator (. match .) => match procedure , private :: match !> Create a printable string from a version data type procedure :: s end type version_t !> Arbitrary internal limit of the version parser integer , parameter :: max_limit = 3 interface new_version module procedure :: new_version_from_string module procedure :: new_version_from_int end interface new_version contains !> Create a new version from a string subroutine new_version_from_int ( self , num ) !> Instance of the versioning data type ( version_t ), intent ( out ) :: self !> Subversion numbers to define version data integer , intent ( in ) :: num (:) self % num = num end subroutine new_version_from_int !> Create a new version from a string subroutine new_version_from_string ( self , string , error ) !> Instance of the versioning data type ( version_t ), intent ( out ) :: self !> String describing the version information character ( len =* ), intent ( in ) :: string !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: istart , iend , stat , nn integer :: num ( max_limit ) logical :: is_number nn = 0 iend = 0 istart = 0 is_number = . false . do while ( iend < len ( string )) call next ( string , istart , iend , is_number , error ) if ( allocated ( error )) exit if ( is_number ) then if ( nn >= max_limit ) then call token_error ( error , string , istart , iend , & & \"Too many subversions found\" ) exit end if nn = nn + 1 read ( string ( istart : iend ), * , iostat = stat ) num ( nn ) if ( stat /= 0 ) then call token_error ( error , string , istart , iend , & & \"Failed to parse version number\" ) exit end if end if end do if ( allocated ( error )) return if (. not . is_number ) then call token_error ( error , string , istart , iend , & & \"Expected version number, but no characters are left\" ) return end if call new_version ( self , num (: nn )) end subroutine new_version_from_string !> Tokenize a version string subroutine next ( string , istart , iend , is_number , error ) !> String describing the version information character ( len =* ), intent ( in ) :: string !> Start of last token, start of next token on exit integer , intent ( inout ) :: istart !> End of last token on entry, end of next token on exit integer , intent ( inout ) :: iend !> Token produced is a number logical , intent ( inout ) :: is_number !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: ii , nn logical :: was_number character :: tok was_number = is_number nn = len ( string ) if ( iend >= nn ) then istart = nn iend = nn return end if ii = min ( iend + 1 , nn ) tok = string ( ii : ii ) is_number = tok /= '.' if ( is_number . eqv . was_number ) then call token_error ( error , string , istart , ii , & & \"Unexpected token found\" ) return end if if (. not . is_number ) then is_number = . false . istart = ii iend = ii return end if istart = ii do ii = min ( iend + 1 , nn ), nn tok = string ( ii : ii ) select case ( tok ) case default call token_error ( error , string , istart , ii , & & \"Invalid character in version number\" ) exit case ( '.' ) exit case ( '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' ) iend = ii cycle end select end do end subroutine next !> Create an error on an invalid token, provide some visual context as well subroutine token_error ( error , string , istart , iend , message ) !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> String describing the version information character ( len =* ), intent ( in ) :: string !> Start of last token, start of next token on exit integer , intent ( in ) :: istart !> End of last token on entry, end of next token on exit integer , intent ( in ) :: iend !> Error message character ( len =* ), intent ( in ) :: message character ( len =* ), parameter :: nl = new_line ( 'a' ) allocate ( error ) error % message = message // nl // \" | \" // string // nl // & & \" |\" // repeat ( '-' , istart ) // repeat ( '^' , iend - istart + 1 ) end subroutine token_error pure function s ( self ) result ( string ) !> Version number class ( version_t ), intent ( in ) :: self !> Character representation of the version character ( len = :), allocatable :: string integer , parameter :: buffersize = 64 character ( len = buffersize ) :: buffer integer :: ii do ii = 1 , ndigits ( self ) if ( allocated ( string )) then write ( buffer , '(\".\", i0)' ) self % num ( ii ) string = string // trim ( buffer ) else write ( buffer , '(i0)' ) self % num ( ii ) string = trim ( buffer ) end if end do if (. not . allocated ( string )) then string = '0' end if end function s !> Check to version numbers for equality elemental function equals ( lhs , rhs ) result ( is_equal ) !> First version number class ( version_t ), intent ( in ) :: lhs !> Second version number class ( version_t ), intent ( in ) :: rhs !> Version match logical :: is_equal is_equal = . not .( lhs > rhs ) if ( is_equal ) then is_equal = . not .( rhs > lhs ) end if end function equals !> Check two versions for inequality elemental function not_equals ( lhs , rhs ) result ( not_equal ) !> First version number class ( version_t ), intent ( in ) :: lhs !> Second version number class ( version_t ), intent ( in ) :: rhs !> Version mismatch logical :: not_equal not_equal = lhs > rhs if (. not . not_equal ) then not_equal = rhs > lhs end if end function not_equals !> Relative comparison of two versions elemental function greater ( lhs , rhs ) result ( is_greater ) !> First version number class ( version_t ), intent ( in ) :: lhs !> Second version number class ( version_t ), intent ( in ) :: rhs !> First version is greater logical :: is_greater integer :: ii , lhs_size , rhs_size do ii = 1 , min ( ndigits ( lhs ), ndigits ( rhs )) if ( lhs % num ( ii ) /= rhs % num ( ii )) then is_greater = lhs % num ( ii ) > rhs % num ( ii ) return end if end do is_greater = ndigits ( lhs ) > ndigits ( rhs ) if ( is_greater ) then do ii = ndigits ( rhs ) + 1 , ndigits ( lhs ) is_greater = lhs % num ( ii ) > 0 if ( is_greater ) return end do end if end function greater !> Relative comparison of two versions elemental function less ( lhs , rhs ) result ( is_less ) !> First version number class ( version_t ), intent ( in ) :: lhs !> Second version number class ( version_t ), intent ( in ) :: rhs !> First version is less logical :: is_less is_less = rhs > lhs end function less !> Relative comparison of two versions elemental function greater_equals ( lhs , rhs ) result ( is_greater_equal ) !> First version number class ( version_t ), intent ( in ) :: lhs !> Second version number class ( version_t ), intent ( in ) :: rhs !> First version is greater or equal logical :: is_greater_equal is_greater_equal = . not . ( rhs > lhs ) end function greater_equals !> Relative comparison of two versions elemental function less_equals ( lhs , rhs ) result ( is_less_equal ) !> First version number class ( version_t ), intent ( in ) :: lhs !> Second version number class ( version_t ), intent ( in ) :: rhs !> First version is less or equal logical :: is_less_equal is_less_equal = . not . ( lhs > rhs ) end function less_equals !> Try to match first version against second version elemental function match ( lhs , rhs ) !> First version number class ( version_t ), intent ( in ) :: lhs !> Second version number class ( version_t ), intent ( in ) :: rhs !> Version match following semantic versioning rules logical :: match type ( version_t ) :: tmp match = . not .( rhs > lhs ) if ( match ) then tmp % num = rhs % num tmp % num ( size ( tmp % num )) = tmp % num ( size ( tmp % num )) + 1 match = tmp > lhs end if end function match !> Number of digits elemental integer function ndigits ( self ) class ( version_t ), intent ( in ) :: self if ( allocated ( self % num )) then ndigits = size ( self % num ) else ndigits = 0 end if end function ndigits ! Extract canonical version flags \"1.0.0\" or \"1.0\" as the first instance inside a text ! (whatever long) using regex type ( string_t ) function regex_version_from_text ( text , what , error ) result ( ver ) character ( * ), intent ( in ) :: text character ( * ), intent ( in ) :: what type ( error_t ), allocatable , intent ( out ) :: error integer :: ire , length if ( len_trim ( text ) <= 0 ) then call syntax_error ( error , 'cannot retrieve ' // what // ' version: empty input string' ) return end if ! Extract 3-sized version \"1.0.4\" ire = regex ( text , '\\d+\\.\\d+\\.\\d+' , length = length ) if ( ire > 0 . and . length > 0 ) then ! Parse version into the object (this should always work) ver = string_t ( text ( ire : ire + length - 1 )) else ! Try 2-sized version \"1.0\" ire = regex ( text , '\\d+\\.\\d+' , length = length ) if ( ire > 0 . and . length > 0 ) then ver = string_t ( text ( ire : ire + length - 1 )) else call syntax_error ( error , 'cannot retrieve ' // what // ' version.' ) end if end if end function regex_version_from_text end module fpm_versioning","tags":"","url":"sourcefile/versioning.f90.html"},{"title":"main.f90 – Fortran-lang/fpm","text":"Source Code program main use , intrinsic :: iso_fortran_env , only : error_unit , output_unit use fpm_command_line , only : & fpm_cmd_settings , & fpm_new_settings , & fpm_build_settings , & fpm_export_settings , & fpm_run_settings , & fpm_test_settings , & fpm_install_settings , & fpm_update_settings , & fpm_clean_settings , & fpm_publish_settings , & get_command_line_settings use fpm_error , only : error_t use fpm_filesystem , only : exists , parent_dir , join_path use fpm , only : cmd_build , cmd_run , cmd_clean use fpm_cmd_install , only : cmd_install use fpm_cmd_export , only : cmd_export use fpm_cmd_new , only : cmd_new use fpm_cmd_update , only : cmd_update use fpm_cmd_publish , only : cmd_publish use fpm_os , only : change_directory , get_current_directory implicit none class ( fpm_cmd_settings ), allocatable :: cmd_settings type ( error_t ), allocatable :: error character ( len = :), allocatable :: pwd_start , pwd_working , working_dir , project_root call get_command_line_settings ( cmd_settings ) call get_current_directory ( pwd_start , error ) call handle_error ( error ) call get_working_dir ( cmd_settings , working_dir ) if ( allocated ( working_dir )) then ! Change working directory if requested if ( len_trim ( working_dir ) > 0 ) then call change_directory ( working_dir , error ) call handle_error ( error ) call get_current_directory ( pwd_working , error ) call handle_error ( error ) write ( output_unit , '(*(a))' ) \"fpm: Entering directory '\" // pwd_working // \"'\" else pwd_working = pwd_start end if else pwd_working = pwd_start end if select type ( settings => cmd_settings ) type is ( fpm_new_settings ) class default if (. not . has_manifest ( pwd_working )) then project_root = pwd_working do while (. not . has_manifest ( project_root )) working_dir = parent_dir ( project_root ) if ( len ( working_dir ) == 0 ) exit project_root = working_dir end do if ( has_manifest ( project_root )) then call change_directory ( project_root , error ) call handle_error ( error ) write ( output_unit , '(*(a))' ) \"fpm: Entering directory '\" // project_root // \"'\" end if end if end select select type ( settings => cmd_settings ) type is ( fpm_new_settings ) call cmd_new ( settings ) type is ( fpm_build_settings ) call cmd_build ( settings ) type is ( fpm_run_settings ) call cmd_run ( settings , test = . false .) type is ( fpm_test_settings ) call cmd_run ( settings , test = . true .) type is ( fpm_export_settings ) call cmd_export ( settings ) type is ( fpm_install_settings ) call cmd_install ( settings ) type is ( fpm_update_settings ) call cmd_update ( settings ) type is ( fpm_clean_settings ) call cmd_clean ( settings ) type is ( fpm_publish_settings ) call cmd_publish ( settings ) end select if ( allocated ( project_root )) then write ( output_unit , '(*(a))' ) \"fpm: Leaving directory '\" // project_root // \"'\" end if if ( pwd_start /= pwd_working ) then write ( output_unit , '(*(a))' ) \"fpm: Leaving directory '\" // pwd_working // \"'\" end if contains function has_manifest ( dir ) character ( len =* ), intent ( in ) :: dir logical :: has_manifest has_manifest = exists ( join_path ( dir , \"fpm.toml\" )) end function has_manifest subroutine handle_error ( error_ ) type ( error_t ), optional , intent ( in ) :: error_ if ( present ( error_ )) then write ( error_unit , '(\"[Error]\", 1x, a)' ) error_ % message stop 1 end if end subroutine handle_error !> Save access to working directory in settings, in case setting have not been allocated subroutine get_working_dir ( settings , working_dir_ ) class ( fpm_cmd_settings ), optional , intent ( in ) :: settings character ( len = :), allocatable , intent ( out ) :: working_dir_ if ( present ( settings )) then working_dir_ = settings % working_dir end if end subroutine get_working_dir end program main","tags":"","url":"sourcefile/main.f90.html"},{"title":"fpm_targets.f90 – Fortran-lang/fpm","text":"Source Code !># Build target handling !> !> This module handles the construction of the build target list !> from the sources list (`[[targets_from_sources]]`), the !> resolution of module-dependencies between build targets !> (`[[resolve_module_dependencies]]`), and the enumeration of !> objects required for link targets (`[[resolve_target_linking]]`). !> !> A build target (`[[build_target_t]]`) is a file to be generated !> by the backend (compilation and linking). !> !> @note The current implementation is ignorant to the existence of !> module files (`.mod`,`.smod`). Dependencies arising from modules !> are based on the corresponding object files (`.o`) only. !> !> For more information, please read the documentation for the procedures: !> !> - `[[build_target_list]]` !> - `[[resolve_module_dependencies]]` !> !>### Enumerations !> !> __Target type:__ `FPM_TARGET_*` !> Describes the type of build target — determines backend build rules !> module fpm_targets use iso_fortran_env , only : int64 , stdout => output_unit use fpm_error , only : error_t , fatal_error , fpm_stop use fpm_model use fpm_compiler , only : compiler_t use fpm_environment , only : get_os_type , OS_WINDOWS , OS_MACOS , library_filename use fpm_filesystem , only : dirname , join_path , canon_path use fpm_strings , only : string_t , operator (. in .), string_cat , fnv_1a , resize , lower , str_ends_with use fpm_compiler , only : get_macros use fpm_sources , only : get_exe_name_with_suffix use fpm_manifest_library , only : library_config_t use fpm_manifest_preprocess , only : preprocess_config_t implicit none private public FPM_TARGET_UNKNOWN , FPM_TARGET_EXECUTABLE , & FPM_TARGET_ARCHIVE , FPM_TARGET_OBJECT , & FPM_TARGET_C_OBJECT , FPM_TARGET_CPP_OBJECT , & FPM_TARGET_SHARED , FPM_TARGET_NAME public build_target_t , build_target_ptr public targets_from_sources , resolve_module_dependencies public add_target , new_target , add_dependency , get_library_dirs public filter_library_targets , filter_executable_targets , filter_modules !> Target type is unknown (ignored) integer , parameter :: FPM_TARGET_UNKNOWN = - 1 !> Target type is executable integer , parameter :: FPM_TARGET_EXECUTABLE = 1 !> Target type is library archive integer , parameter :: FPM_TARGET_ARCHIVE = 2 !> Target type is compiled object integer , parameter :: FPM_TARGET_OBJECT = 3 !> Target type is c compiled object integer , parameter :: FPM_TARGET_C_OBJECT = 4 !> Target type is cpp compiled object integer , parameter :: FPM_TARGET_CPP_OBJECT = 5 !> Target type is a shared library integer , parameter :: FPM_TARGET_SHARED = 6 !> Wrapper type for constructing arrays of `[[build_target_t]]` pointers type build_target_ptr type ( build_target_t ), pointer :: ptr => null () end type build_target_ptr !> Type describing a generated build target type build_target_t !> File path of build target object relative to cwd character (:), allocatable :: output_file !> File path of build target object relative to output_dir character (:), allocatable :: output_name !> File path of output directory character (:), allocatable :: output_dir !> File path of build log file relative to cwd character (:), allocatable :: output_log_file !> Name of parent package character (:), allocatable :: package_name !> Primary source for this build target type ( srcfile_t ), allocatable :: source !> Resolved build dependencies type ( build_target_ptr ), allocatable :: dependencies (:) !> Target type integer :: target_type = FPM_TARGET_UNKNOWN !> Native libraries to link against type ( string_t ), allocatable :: link_libraries (:) !> Objects needed to link this target type ( string_t ), allocatable :: link_objects (:) !> Link flags for this build target character (:), allocatable :: link_flags !> Compile flags for this build target character (:), allocatable :: compile_flags !> Flag set when first visited to check for circular dependencies logical :: touched = . false . !> Flag set if build target is sorted for building logical :: sorted = . false . !> Flag set if build target will be skipped (not built) logical :: skip = . false . !> Language features type ( fortran_features_t ) :: features !> Targets in the same schedule group are guaranteed to be independent integer :: schedule = - 1 !> Previous source file hash integer ( int64 ), allocatable :: digest_cached !> List of macros type ( string_t ), allocatable :: macros (:) !> Version number character (:), allocatable :: version contains !> Print information on this instance procedure :: info !> Set output directory procedure :: set_output_dir procedure :: is_executable_target end type build_target_t interface add_target module procedure add_new_target module procedure add_old_target module procedure add_old_targets end interface contains !> Target type name pure function FPM_TARGET_NAME ( type ) result ( msg ) integer , intent ( in ) :: type character (:), allocatable :: msg select case ( type ) case ( FPM_TARGET_ARCHIVE ); msg = 'Archive' case ( FPM_TARGET_SHARED ); msg = 'Shared library' case ( FPM_TARGET_CPP_OBJECT ); msg = 'C++ object' case ( FPM_TARGET_C_OBJECT ); msg = 'C Object' case ( FPM_TARGET_EXECUTABLE ); msg = 'Executable' case ( FPM_TARGET_OBJECT ); msg = 'Object' case default ; msg = 'Unknown' end select end function FPM_TARGET_NAME !> Write information on a build target subroutine info ( self , unit , verbosity ) class ( build_target_t ), intent ( in ) :: self integer , intent ( in ) :: unit integer , intent ( in ), optional :: verbosity integer :: pr character ( len =* ), parameter :: fmt = '(\"#\", 1x, a, t30, a)' character ( len =* ), parameter :: fmt_list = '(\"#\", 1x, a, t30, a, \" (\", i0, \" items)\")' if ( present ( verbosity )) then pr = verbosity else pr = 1 end if if ( pr < 1 ) return write ( unit , fmt ) \"Build target\" write ( unit , fmt ) \"- output file\" , self % output_file write ( unit , fmt ) \"- output name\" , self % output_name write ( unit , fmt ) \"- output directory\" , self % output_dir write ( unit , fmt ) \"- log file\" , self % output_log_file write ( unit , fmt ) \"- package\" , self % package_name write ( unit , fmt ) \"- type\" , FPM_TARGET_NAME ( self % target_type ) if ( allocated ( self % source )) then write ( unit , fmt ) \"- source file\" , self % source % file_name end if if ( allocated ( self % dependencies )) then write ( unit , fmt_list ) \"- dependencies\" , \"\" , size ( self % dependencies ) end if if ( allocated ( self % link_objects )) then write ( unit , fmt_list ) \"- link objects\" , \"\" , size ( self % link_objects ) end if if ( allocated ( self % link_libraries )) then write ( unit , fmt_list ) \"- link libraries\" , \"\" , size ( self % link_libraries ) end if if ( allocated ( self % compile_flags )) then write ( unit , fmt ) \"- compile flags\" , self % compile_flags end if if ( allocated ( self % link_flags )) then write ( unit , fmt ) \"- link flags\" , self % link_flags end if if ( allocated ( self % version )) then write ( unit , fmt ) \"- version\" , self % version end if if ( allocated ( self % macros )) then write ( unit , fmt_list ) \"- macros\" , \"\" , size ( self % macros ) end if write ( unit , fmt ) \"- skip\" , merge ( \"yes\" , \"no \" , self % skip ) write ( unit , fmt ) \"- schedule\" , trim ( adjustl ( to_string ( self % schedule ))) contains pure function to_string ( i ) result ( s ) integer , intent ( in ) :: i character ( len = 32 ) :: s write ( s , '(i0)' ) i end function to_string end subroutine info !> High-level wrapper to generate build target information subroutine targets_from_sources ( targets , model , prune , library , error ) !> The generated list of build targets type ( build_target_ptr ), intent ( out ), allocatable :: targets (:) !> The package model from which to construct the target list type ( fpm_model_t ), intent ( inout ), target :: model !> Library build configuration type ( library_config_t ), intent ( in ), optional :: library !> Enable tree-shaking/pruning of module dependencies logical , intent ( in ) :: prune !> Error structure type ( error_t ), intent ( out ), allocatable :: error logical :: should_prune call build_target_list ( targets , model , library ) call collect_exe_link_dependencies ( targets ) call resolve_module_dependencies ( targets , model % external_modules , error ) if ( allocated ( error )) return ! Prune unused source files, unless we're building shared libraries that need ! all sources to be distributable should_prune = prune if ( present ( library )) should_prune = should_prune . and . library % monolithic () call prune_build_targets ( targets , model % packages ( 1 ), should_prune ) call resolve_target_linking ( targets , model , library , error ) if ( allocated ( error )) return end subroutine targets_from_sources !> Constructs a list of build targets from a list of source files !> !>### Source-target mapping !> !> One compiled object target (`FPM_TARGET_OBJECT`) is generated for each !> non-executable source file (`FPM_UNIT_MODULE`,`FPM_UNIT_SUBMODULE`, !> `FPM_UNIT_SUBPROGRAM`,`FPM_UNIT_CSOURCE`). !> !> If any source file has scope `FPM_SCOPE_LIB` (*i.e.* there are library sources) !> then the first target in the target list will be a library archive target !> (`FPM_TARGET_ARCHIVE`). The archive target will have a dependency on every !> compiled object target corresponding to a library source file. !> !> One compiled object target (`FPM_TARGET_OBJECT`) and one executable target (`FPM_TARGET_EXECUTABLE`) is !> generated for each exectuable source file (`FPM_UNIT_PROGRAM`). The exectuble target !> always has a dependency on the corresponding compiled object target. If there !> is a library, then the executable target has an additional dependency on the library !> archive target. !> subroutine build_target_list ( targets , model , library ) !> The generated list of build targets type ( build_target_ptr ), intent ( out ), allocatable :: targets (:) !> The package model from which to construct the target list type ( fpm_model_t ), intent ( inout ), target :: model !> The optional model library configuration type ( library_config_t ), optional , intent ( in ) :: library integer :: i , j , k , n_source , exe_type character (:), allocatable :: exe_dir , compile_flags , lib_name logical :: with_lib , monolithic , shared_lib , static_lib ! Initialize targets allocate ( targets ( 0 )) ! Check for empty build (e.g. header-only lib) n_source = sum ([( size ( model % packages ( j )% sources ), & j = 1 , size ( model % packages ))]) if ( n_source < 1 ) return with_lib = any ( model % packages % has_library ()) if ( with_lib . and . present ( library )) then shared_lib = library % shared () static_lib = library % static () monolithic = library % monolithic () else monolithic = with_lib shared_lib = . false . static_lib = . false . end if ! For a static object archive, everything from this package or all its dependencies is ! put into the same file. For a shared library configuration, each package has its own ! dynamic library file to avoid dependency collisions if ( monolithic ) then lib_name = join_path ( model % package_name , & library_filename ( model % packages ( 1 )% name ,. false .,. false ., get_os_type ())) call add_target ( targets , package = model % package_name , & type = FPM_TARGET_ARCHIVE , output_name = lib_name ) elseif ( shared_lib . or . static_lib ) then ! Individual package libraries are built. ! Create as many targets as the packages in the dependency tree do j = 1 , size ( model % packages ) lib_name = library_filename ( model % packages ( j )% name , shared_lib ,. false ., get_os_type ()) call add_target ( targets , package = model % packages ( j )% name , & type = merge ( FPM_TARGET_SHARED , FPM_TARGET_ARCHIVE , shared_lib ), & output_name = lib_name ) end do endif do j = 1 , size ( model % packages ) associate ( sources => model % packages ( j )% sources ) do i = 1 , size ( sources ) if (. not . model % include_tests ) then if ( sources ( i )% unit_scope == FPM_SCOPE_TEST ) cycle end if select case ( sources ( i )% unit_type ) case ( FPM_UNIT_MODULE , FPM_UNIT_SUBMODULE , FPM_UNIT_SUBPROGRAM , FPM_UNIT_CSOURCE ) call add_target ( targets , package = model % packages ( j )% name , source = sources ( i ), & type = merge ( FPM_TARGET_C_OBJECT , FPM_TARGET_OBJECT ,& sources ( i )% unit_type == FPM_UNIT_CSOURCE ), & output_name = get_object_name ( sources ( i )), & features = model % packages ( j )% features , & preprocess = model % packages ( j )% preprocess , & version = model % packages ( j )% version ) if ( with_lib . and . sources ( i )% unit_scope == FPM_SCOPE_LIB ) then ! Archive depends on object call add_dependency ( targets ( merge ( 1 , j , monolithic ))% ptr , targets ( size ( targets ))% ptr ) end if case ( FPM_UNIT_CPPSOURCE ) call add_target ( targets , package = model % packages ( j )% name , source = sources ( i ), & type = FPM_TARGET_CPP_OBJECT , & output_name = get_object_name ( sources ( i )), & preprocess = model % packages ( j )% preprocess , & version = model % packages ( j )% version ) if ( with_lib . and . sources ( i )% unit_scope == FPM_SCOPE_LIB ) then ! Archive depends on object call add_dependency ( targets ( merge ( 1 , j , monolithic ))% ptr , targets ( size ( targets ))% ptr ) end if !> Add stdc++ as a linker flag. If not already there. if (. not . ( \"stdc++\" . in . model % link_libraries )) then if ( get_os_type () == OS_MACOS ) then model % link_libraries = [ model % link_libraries , string_t ( \"c++\" )] else model % link_libraries = [ model % link_libraries , string_t ( \"stdc++\" )] end if end if case ( FPM_UNIT_PROGRAM ) if ( str_ends_with ( lower ( sources ( i )% file_name ), [ \".c\" ])) then exe_type = FPM_TARGET_C_OBJECT else if ( str_ends_with ( lower ( sources ( i )% file_name ), [ \".cpp\" , \".cc \" ])) then exe_type = FPM_TARGET_CPP_OBJECT else ! Default to a Fortran object exe_type = FPM_TARGET_OBJECT end if call add_target ( targets , package = model % packages ( j )% name , type = exe_type ,& output_name = get_object_name ( sources ( i )), & source = sources ( i ), & features = model % packages ( j )% features , & preprocess = model % packages ( j )% preprocess & ) if ( sources ( i )% unit_scope == FPM_SCOPE_APP ) then exe_dir = 'app' else if ( sources ( i )% unit_scope == FPM_SCOPE_EXAMPLE ) then exe_dir = 'example' else exe_dir = 'test' end if call add_target ( targets , package = model % packages ( j )% name , type = FPM_TARGET_EXECUTABLE ,& link_libraries = sources ( i )% link_libraries , & output_name = join_path ( exe_dir , get_exe_name_with_suffix ( sources ( i )))) associate ( target => targets ( size ( targets ))% ptr ) ! Linker-only flags are necessary on some compilers for codes with non-Fortran main select case ( exe_type ) case ( FPM_TARGET_C_OBJECT ) call model % compiler % get_main_flags ( \"c\" , compile_flags ) case ( FPM_TARGET_CPP_OBJECT ) call model % compiler % get_main_flags ( \"c++\" , compile_flags ) case default compile_flags = \"\" end select target % compile_flags = target % compile_flags // ' ' // compile_flags ! Executable depends on object call add_dependency ( target , targets ( size ( targets ) - 1 )% ptr ) if ( with_lib ) then ! Executable depends on library file(s) do k = 1 , merge ( 1 , size ( model % packages ), monolithic ) call add_dependency ( target , targets ( k )% ptr ) end do end if endassociate end select end do end associate end do contains function get_object_name ( source ) result ( object_file ) ! Generate object target path from source name and model params ! ! type ( srcfile_t ), intent ( in ) :: source character (:), allocatable :: object_file integer :: i character ( 1 ), parameter :: filesep = '/' object_file = canon_path ( source % file_name ) ! Convert any remaining directory separators to underscores i = index ( object_file , filesep ) do while ( i > 0 ) object_file ( i : i ) = '_' i = index ( object_file , filesep ) end do object_file = join_path ( model % package_name , object_file ) // '.o' end function get_object_name end subroutine build_target_list !> Add non-library non-module dependencies for executable targets !> !> Executable targets will link to any non-program non-module source files that !> are in the same directory or in a subdirectory. !> !> (Note: Fortran module dependencies are handled separately in !> `resolve_module_dependencies` and `resolve_target_linking`.) !> subroutine collect_exe_link_dependencies ( targets ) type ( build_target_ptr ), intent ( inout ) :: targets (:) integer :: i , j character (:), allocatable :: exe_source_dir ! Add non-module dependencies for executables do j = 1 , size ( targets ) if ( targets ( j )% ptr % target_type == FPM_TARGET_EXECUTABLE ) then do i = 1 , size ( targets ) if ( i == j ) cycle associate ( exe => targets ( j )% ptr , dep => targets ( i )% ptr ) exe_source_dir = dirname ( exe % dependencies ( 1 )% ptr % source % file_name ) if ( allocated ( dep % source )) then if ( dep % source % unit_scope /= FPM_SCOPE_LIB . and . & dep % source % unit_type /= FPM_UNIT_PROGRAM . and . & dep % source % unit_type /= FPM_UNIT_MODULE . and . & index ( dirname ( dep % source % file_name ), exe_source_dir ) == 1 ) then call add_dependency ( exe , dep ) end if end if end associate end do end if end do end subroutine collect_exe_link_dependencies !> Allocate a new target type ( build_target_ptr ) function new_target ( package , type , output_name , source , link_libraries , & & features , preprocess , version , output_dir ) character ( * ), intent ( in ) :: package integer , intent ( in ) :: type character ( * ), intent ( in ) :: output_name type ( srcfile_t ), intent ( in ), optional :: source type ( string_t ), intent ( in ), optional :: link_libraries (:) type ( fortran_features_t ), intent ( in ), optional :: features type ( preprocess_config_t ), intent ( in ), optional :: preprocess character ( * ), intent ( in ), optional :: version character ( * ), intent ( in ), optional :: output_dir allocate ( new_target % ptr ) associate ( target => new_target % ptr ) target % target_type = type target % output_name = output_name target % package_name = package if ( present ( source )) target % source = source if ( present ( link_libraries )) target % link_libraries = link_libraries if ( present ( features )) target % features = features if ( present ( preprocess )) then if ( allocated ( preprocess % macros )) target % macros = preprocess % macros endif if ( present ( version )) target % version = version allocate ( target % dependencies ( 0 )) call target % set_output_dir ( output_dir ) endassociate end function new_target !> Allocate a new target and append to target list subroutine add_new_target ( targets , package , type , output_name , source , link_libraries , & & features , preprocess , version , output_dir ) type ( build_target_ptr ), allocatable , intent ( inout ) :: targets (:) character ( * ), intent ( in ) :: package integer , intent ( in ) :: type character ( * ), intent ( in ) :: output_name type ( srcfile_t ), intent ( in ), optional :: source type ( string_t ), intent ( in ), optional :: link_libraries (:) type ( fortran_features_t ), intent ( in ), optional :: features type ( preprocess_config_t ), intent ( in ), optional :: preprocess character ( * ), intent ( in ), optional :: version character ( * ), intent ( in ), optional :: output_dir type ( build_target_ptr ) :: added if (. not . allocated ( targets )) allocate ( targets ( 0 )) ! Create new target added = new_target ( package , type , output_name , source , link_libraries , features , preprocess ,& version , output_dir ) call add_old_target ( targets , added ) end subroutine add_new_target subroutine add_old_targets ( targets , add_targets ) type ( build_target_ptr ), allocatable , intent ( inout ) :: targets (:) type ( build_target_ptr ), intent ( in ) :: add_targets (:) integer :: i , j if (. not . allocated ( targets )) allocate ( targets ( 0 )) ! Check for duplicate outputs do j = 1 , size ( add_targets ) associate ( added => add_targets ( j )% ptr ) do i = 1 , size ( targets ) if ( targets ( i )% ptr % output_name == added % output_name ) then write ( * , * ) 'Error while building target list: duplicate output object \"' ,& added % output_name , '\"' if ( allocated ( added % source )) write ( * , * ) ' Source file: \"' , added % source % file_name , '\"' call fpm_stop ( 1 , ' ' ) end if end do endassociate end do targets = [ targets , add_targets ] end subroutine add_old_targets subroutine add_old_target ( targets , add_target ) type ( build_target_ptr ), allocatable , intent ( inout ) :: targets (:) type ( build_target_ptr ), intent ( in ) :: add_target call add_old_targets ( targets , [ add_target ]) end subroutine add_old_target !> Add pointer to dependeny in target%dependencies subroutine add_dependency ( target , dependency ) type ( build_target_t ), intent ( inout ) :: target type ( build_target_t ) , intent ( in ), target :: dependency target % dependencies = [ target % dependencies , build_target_ptr ( dependency )] end subroutine add_dependency !> Add dependencies to source-based targets (`FPM_TARGET_OBJECT`) !> based on any modules used by the corresponding source file. !> !>### Source file scoping !> !> Source files are assigned a scope of either `FPM_SCOPE_LIB`, !> `FPM_SCOPE_APP` or `FPM_SCOPE_TEST`. The scope controls which !> modules may be used by the source file: !> !> - Library sources (`FPM_SCOPE_LIB`) may only use modules !> also with library scope. This includes library modules !> from dependencies. !> !> - Executable sources (`FPM_SCOPE_APP`,`FPM_SCOPE_TEST`) may use !> library modules (including dependencies) as well as any modules !> corresponding to source files in the same directory or a !> subdirectory of the executable source file. !> !> @warning If a module used by a source file cannot be resolved to !> a source file in the package of the correct scope, then a __fatal error__ !> is returned by the procedure and model construction fails. !> subroutine resolve_module_dependencies ( targets , external_modules , error ) type ( build_target_ptr ), intent ( inout ), target :: targets (:) type ( string_t ), intent ( in ) :: external_modules (:) type ( error_t ), allocatable , intent ( out ) :: error type ( build_target_ptr ) :: dep integer :: i , j do i = 1 , size ( targets ) if (. not . allocated ( targets ( i )% ptr % source )) cycle do j = 1 , size ( targets ( i )% ptr % source % modules_used ) if ( targets ( i )% ptr % source % modules_used ( j )% s . in . targets ( i )% ptr % source % modules_provided ) then ! Dependency satisfied in same file, skip cycle end if if ( targets ( i )% ptr % source % modules_used ( j )% s . in . external_modules ) then ! Dependency satisfied in system-installed module cycle end if if ( any ( targets ( i )% ptr % source % unit_scope == & [ FPM_SCOPE_APP , FPM_SCOPE_EXAMPLE , FPM_SCOPE_TEST ])) then dep % ptr => & find_module_dependency ( targets , targets ( i )% ptr % source % modules_used ( j )% s , & include_dir = dirname ( targets ( i )% ptr % source % file_name )) else dep % ptr => & find_module_dependency ( targets , targets ( i )% ptr % source % modules_used ( j )% s ) end if if (. not . associated ( dep % ptr )) then call fatal_error ( error , & 'Unable to find source for module dependency: \"' // & targets ( i )% ptr % source % modules_used ( j )% s // & '\" used by \"' // targets ( i )% ptr % source % file_name // '\"' ) return end if call add_dependency ( targets ( i )% ptr , dep % ptr ) end do end do end subroutine resolve_module_dependencies function find_module_dependency ( targets , module_name , include_dir ) result ( target_ptr ) ! Find a module dependency in the library or a dependency library ! ! 'include_dir' specifies an allowable non-library search directory ! (Used for executable dependencies) ! type ( build_target_ptr ), intent ( in ), target :: targets (:) character ( * ), intent ( in ) :: module_name character ( * ), intent ( in ), optional :: include_dir type ( build_target_t ), pointer :: target_ptr integer :: k , l target_ptr => NULL () do k = 1 , size ( targets ) if (. not . allocated ( targets ( k )% ptr % source )) cycle do l = 1 , size ( targets ( k )% ptr % source % modules_provided ) if ( module_name == targets ( k )% ptr % source % modules_provided ( l )% s ) then select case ( targets ( k )% ptr % source % unit_scope ) case ( FPM_SCOPE_LIB , FPM_SCOPE_DEP ) target_ptr => targets ( k )% ptr exit case default if ( present ( include_dir )) then if ( index ( dirname ( targets ( k )% ptr % source % file_name ), include_dir ) == 1 ) then ! source file is within the include_dir or a subdirectory target_ptr => targets ( k )% ptr exit end if end if end select end if end do end do end function find_module_dependency !> Perform tree-shaking to remove unused module targets subroutine prune_build_targets ( targets , root_package , prune_unused_objects ) !> Build target list to prune type ( build_target_ptr ), intent ( inout ), allocatable :: targets (:) !> Root package type ( package_t ), intent ( in ) :: root_package !> Whether unused objects should be pruned logical , intent ( in ) :: prune_unused_objects integer :: i , j , nexec type ( string_t ), allocatable :: modules_used (:) logical :: exclude_target ( size ( targets )) logical , allocatable :: exclude_from_archive (:) if ( size ( targets ) < 1 ) then return end if nexec = 0 allocate ( modules_used ( 0 )) ! Enumerate modules used by executables, non-module subprograms and their dependencies do i = 1 , size ( targets ) if ( targets ( i )% ptr % target_type == FPM_TARGET_EXECUTABLE ) then nexec = nexec + 1 call collect_used_modules ( targets ( i )% ptr ) elseif ( allocated ( targets ( i )% ptr % source )) then if ( targets ( i )% ptr % source % unit_type == FPM_UNIT_SUBPROGRAM ) then call collect_used_modules ( targets ( i )% ptr ) end if end if end do ! If there aren't any executables, then prune ! based on modules used in root package if ( nexec < 1 ) then do i = 1 , size ( targets ) if ( targets ( i )% ptr % package_name == root_package % name . and . & all ( targets ( i )% ptr % target_type /= [ FPM_TARGET_ARCHIVE , FPM_TARGET_SHARED ])) then call collect_used_modules ( targets ( i )% ptr ) end if end do end if call reset_target_flags ( targets ) exclude_target = . false . ! Exclude purely module targets if they are not used anywhere do i = 1 , size ( targets ) associate ( target => targets ( i )% ptr ) if ( allocated ( target % source )) then if ( target % source % unit_type == FPM_UNIT_MODULE ) then exclude_target ( i ) = prune_unused_objects target % skip = prune_unused_objects do j = 1 , size ( target % source % modules_provided ) if ( target % source % modules_provided ( j )% s . in . modules_used ) then exclude_target ( i ) = . false . target % skip = . false . end if end do elseif ( target % source % unit_type == FPM_UNIT_SUBMODULE ) then ! Remove submodules if their parents are not used exclude_target ( i ) = prune_unused_objects target % skip = prune_unused_objects do j = 1 , size ( target % source % parent_modules ) if ( target % source % parent_modules ( j )% s . in . modules_used ) then exclude_target ( i ) = . false . target % skip = . false . end if end do end if elseif ( any ( target % target_type == [ FPM_TARGET_ARCHIVE , FPM_TARGET_SHARED ])) then ! Remove empty library files if ( size ( target % dependencies ) == 0 ) then exclude_target ( i ) = . true . target % skip = . true . endif end if ! (If there aren't any executables then we only prune modules from dependencies, ! unless the root package is also empty) if ( nexec < 1 . and . target % package_name == root_package % name ) then exclude_target ( i ) = . not . root_package % has_library () target % skip = exclude_target ( i ) end if end associate end do targets = pack ( targets ,. not . exclude_target ) ! Remove unused targets from library dependency list do j = 1 , size ( targets ) associate ( archive => targets ( j )% ptr ) if ( any ( archive % target_type == [ FPM_TARGET_ARCHIVE , FPM_TARGET_OBJECT ])) then allocate ( exclude_from_archive ( size ( archive % dependencies )), source = . false .) do i = 1 , size ( archive % dependencies ) if ( archive % dependencies ( i )% ptr % skip ) then exclude_from_archive ( i ) = . true . end if end do archive % dependencies = pack ( archive % dependencies ,. not . exclude_from_archive ) deallocate ( exclude_from_archive ) endif end associate end do contains !> Recursively collect which modules are actually used recursive subroutine collect_used_modules ( target ) type ( build_target_t ), intent ( inout ) :: target integer :: j , k if ( target % touched ) then return else target % touched = . true . end if if ( allocated ( target % source )) then ! Add modules from this target and from any of it's children submodules do j = 1 , size ( target % source % modules_provided ) if (. not .( target % source % modules_provided ( j )% s . in . modules_used )) then modules_used = [ modules_used , target % source % modules_provided ( j )] end if ! Recurse into child submodules do k = 1 , size ( targets ) if ( allocated ( targets ( k )% ptr % source )) then if ( targets ( k )% ptr % source % unit_type == FPM_UNIT_SUBMODULE ) then if ( target % source % modules_provided ( j )% s . in . targets ( k )% ptr % source % parent_modules ) then call collect_used_modules ( targets ( k )% ptr ) end if end if end if end do end do end if ! Recurse into dependencies do j = 1 , size ( target % dependencies ) if ( target % dependencies ( j )% ptr % target_type /= FPM_TARGET_ARCHIVE ) then call collect_used_modules ( target % dependencies ( j )% ptr ) end if end do end subroutine collect_used_modules !> Reset target flags after recursive search subroutine reset_target_flags ( targets ) type ( build_target_ptr ), intent ( inout ) :: targets (:) integer :: i do i = 1 , size ( targets ) targets ( i )% ptr % touched = . false . end do end subroutine reset_target_flags end subroutine prune_build_targets !> Construct the linker flags string for each target !> `target%link_flags` includes non-library objects and library flags !> subroutine resolve_target_linking ( targets , model , library , error ) type ( build_target_ptr ), intent ( inout ), target :: targets (:) type ( fpm_model_t ), intent ( in ) :: model type ( library_config_t ), intent ( in ), optional :: library type ( error_t ), allocatable , intent ( out ) :: error integer :: i , j logical :: shared , static , monolithic , has_self_lib integer , allocatable :: package_deps (:), dep_target_ID (:) character (:), allocatable :: global_link_flags , local_link_flags character (:), allocatable :: global_include_flags , shared_lib_paths if ( size ( targets ) == 0 ) return global_link_flags = \"\" if ( allocated ( model % link_libraries )) then if ( size ( model % link_libraries ) > 0 ) then global_link_flags = model % compiler % enumerate_libraries ( global_link_flags , model % link_libraries ) end if end if allocate ( character ( 0 ) :: global_include_flags ) if ( allocated ( model % include_dirs )) then if ( size ( model % include_dirs ) > 0 ) then global_include_flags = global_include_flags // & & \" -I\" // string_cat ( model % include_dirs , \" -I\" ) end if end if if ( present ( library )) then shared = library % shared () static = library % static () monolithic = library % monolithic () else shared = . false . static = . false . monolithic = . true . end if do i = 1 , size ( targets ) associate ( target => targets ( i )% ptr ) ! If the main program is a C/C++ one, some compilers require additional linking flags, see ! https://stackoverflow.com/questions/36221612/p3dfft-compilation-ifort-compiler-error-multiple-definiton-of-main ! In this case, compile_flags were already allocated if (. not . allocated ( target % compile_flags )) allocate ( character ( len = 0 ) :: target % compile_flags ) target % compile_flags = target % compile_flags // ' ' select case ( target % target_type ) case ( FPM_TARGET_C_OBJECT ) target % compile_flags = target % compile_flags // model % c_compile_flags case ( FPM_TARGET_CPP_OBJECT ) target % compile_flags = target % compile_flags // model % cxx_compile_flags case default target % compile_flags = target % compile_flags // model % fortran_compile_flags & & // get_feature_flags ( model % compiler , target % features ) end select !> Get macros as flags. target % compile_flags = target % compile_flags // get_macros ( model % compiler % id , & target % macros , & target % version ) if ( len ( global_include_flags ) > 0 ) then target % compile_flags = target % compile_flags // global_include_flags end if call target % set_output_dir ( get_output_dir ( model % build_prefix , target % compile_flags )) end associate end do call add_include_build_dirs ( model , targets ) call add_library_link_dirs ( model , targets , shared_lib_paths ) call library_targets_to_deps ( model , targets , dep_target_ID ) do i = 1 , size ( targets ) associate ( target => targets ( i )% ptr ) allocate ( target % link_objects ( 0 )) select case ( target % target_type ) case ( FPM_TARGET_ARCHIVE ) ! This adds the monolithic archive to the link flags if ( monolithic ) global_link_flags = \" \" // target % output_file // global_link_flags call get_link_objects ( target % link_objects , target , is_exe = . false .) allocate ( character ( 0 ) :: target % link_flags ) case ( FPM_TARGET_SHARED ) ! Gather object files from this package only call get_link_objects ( target % link_objects , target , is_exe = . false .) ! Build link flags target % link_flags = string_cat ( target % link_objects , \" \" ) target % link_flags = target % link_flags // shared_lib_paths ! Add dependencies' shared libraries (excluding self) target % link_flags = model % get_package_libraries_link ( target % package_name , & target % link_flags , & exclude_self = . true ., & dep_IDs = package_deps , & error = error ) if ( allocated ( error )) return ! Now that they're available, add these dependencies to the targets if ( size ( package_deps ) > 0 ) then do j = 1 , size ( package_deps ) if ( dep_target_ID ( package_deps ( j )) <= 0 ) cycle call add_dependency ( target , targets ( dep_target_ID ( package_deps ( j )))% ptr ) end do end if ! Add any per-target libraries (e.g., `target%link_libraries`) if ( allocated ( target % link_libraries )) then if ( size ( target % link_libraries ) > 0 ) then target % link_flags = model % compiler % enumerate_libraries ( target % link_flags , & target % link_libraries ) end if end if ! Add shared library exports (import library + .def) target % link_flags = target % link_flags // \" \" // & model % compiler % get_export_flags ( target % output_dir , target % package_name ) ! Add install_name flag (macOS only) target % link_flags = target % link_flags // \" \" // & model % compiler % get_install_name_flags ( target % output_dir , target % package_name ) ! Add global link flags (e.g., system-wide libraries) target % link_flags = target % link_flags // \" \" // global_link_flags case ( FPM_TARGET_EXECUTABLE ) local_link_flags = \"\" if ( allocated ( model % link_flags )) local_link_flags = model % link_flags call get_link_objects ( target % link_objects , target , is_exe = . true .) target % link_flags = model % link_flags // \" \" // string_cat ( target % link_objects , \" \" ) ! Add shared libs if (. not . monolithic ) then target % link_flags = target % link_flags // shared_lib_paths ! Check if there's a library with this name (maybe not, if it is a ! single-file app with only external dependencies) has_self_lib = . false . find_self : do j = 1 , size ( targets ) associate ( target_loop => targets ( j )% ptr ) if ( any ( target_loop % target_type == [ FPM_TARGET_SHARED , FPM_TARGET_ARCHIVE ]) & . and . target_loop % package_name == target % package_name ) then has_self_lib = . true . exit find_self end if end associate end do find_self ! Add dependencies' shared libraries (including self if there is a library) target % link_flags = model % get_package_libraries_link ( target % package_name , & target % link_flags , & error = error , & exclude_self = . not . has_self_lib ) ! On macOS, add room for 2 install_name_tool paths target % link_flags = target % link_flags // model % compiler % get_headerpad_flags () end if if ( allocated ( target % link_libraries )) then if ( size ( target % link_libraries ) > 0 ) then target % link_flags = model % compiler % enumerate_libraries ( target % link_flags , target % link_libraries ) local_link_flags = model % compiler % enumerate_libraries ( local_link_flags , target % link_libraries ) end if end if target % link_flags = target % link_flags // \" \" // global_link_flags end select end associate end do contains !> Wrapper to build link object list !> !> For libraries: just list dependency objects of lib target !> !> For executables: need to recursively discover non-library !> dependency objects. (i.e. modules in same dir as program) !> recursive subroutine get_link_objects ( link_objects , target , is_exe ) type ( string_t ), intent ( inout ), allocatable :: link_objects (:) type ( build_target_t ), intent ( in ) :: target logical , intent ( in ) :: is_exe integer :: i type ( string_t ) :: temp_str if (. not . allocated ( target % dependencies )) return do i = 1 , size ( target % dependencies ) associate ( dep => target % dependencies ( i )% ptr ) if (. not . allocated ( dep % source )) cycle ! Skip library dependencies for executable targets ! since the library archive will always be linked if ( is_exe . and .( dep % source % unit_scope == FPM_SCOPE_LIB )) cycle ! Skip if dependency object already listed if ( dep % output_file . in . link_objects ) cycle ! Add dependency object file to link object list temp_str % s = dep % output_file link_objects = [ link_objects , temp_str ] ! For executable objects, also need to include non-library ! dependencies from dependencies (recurse) if ( is_exe ) call get_link_objects ( link_objects , dep , is_exe = . true .) end associate end do end subroutine get_link_objects end subroutine resolve_target_linking subroutine add_include_build_dirs ( model , targets ) type ( fpm_model_t ), intent ( in ) :: model type ( build_target_ptr ), intent ( inout ), target :: targets (:) integer :: i type ( string_t ), allocatable :: build_dirs (:) type ( string_t ) :: temp allocate ( build_dirs ( 0 )) do i = 1 , size ( targets ) associate ( target => targets ( i )% ptr ) if ( target % target_type /= FPM_TARGET_OBJECT ) cycle if ( target % output_dir . in . build_dirs ) cycle temp % s = target % output_dir build_dirs = [ build_dirs , temp ] end associate end do do i = 1 , size ( targets ) associate ( target => targets ( i )% ptr ) if ( target % target_type /= FPM_TARGET_OBJECT ) cycle target % compile_flags = target % compile_flags // & \" \" // model % compiler % get_module_flag ( target % output_dir ) // & \" -I\" // string_cat ( build_dirs , \" -I\" ) end associate end do end subroutine add_include_build_dirs !> Add link directories for all shared libraries in the dependency graph subroutine get_library_dirs ( model , targets , shared_lib_dirs ) type ( fpm_model_t ), intent ( in ) :: model type ( build_target_ptr ), intent ( inout ), target :: targets (:) type ( string_t ), allocatable , intent ( out ) :: shared_lib_dirs (:) integer :: i type ( string_t ) :: temp allocate ( shared_lib_dirs ( 0 )) do i = 1 , size ( targets ) associate ( target => targets ( i )% ptr ) if ( all ( target % target_type /= [ FPM_TARGET_SHARED , FPM_TARGET_ARCHIVE ])) cycle if ( target % output_dir . in . shared_lib_dirs ) cycle temp = string_t ( target % output_dir ) shared_lib_dirs = [ shared_lib_dirs , temp ] end associate end do end subroutine get_library_dirs !> Add link directories for all shared libraries in the dependency graph subroutine add_library_link_dirs ( model , targets , shared_lib_path ) type ( fpm_model_t ), intent ( in ) :: model type ( build_target_ptr ), intent ( inout ), target :: targets (:) character (:), allocatable , intent ( out ) :: shared_lib_path type ( string_t ), allocatable :: shared_lib_dirs (:) call get_library_dirs ( model , targets , shared_lib_dirs ) shared_lib_path = \" -L\" // string_cat ( shared_lib_dirs , \" -L\" ) end subroutine add_library_link_dirs function get_output_dir ( build_prefix , args ) result ( path ) character ( len =* ), intent ( in ) :: build_prefix character ( len =* ), intent ( in ) :: args character ( len = :), allocatable :: path character ( len = 16 ) :: build_hash write ( build_hash , '(z16.16)' ) fnv_1a ( args ) path = build_prefix // \"_\" // build_hash end function get_output_dir !> Returns pointers to all library targets subroutine filter_library_targets ( targets , list ) type ( build_target_ptr ), intent ( in ) :: targets (:) type ( build_target_ptr ), allocatable , intent ( out ) :: list (:) integer :: i , n n = 0 do i = 1 , size ( targets ) if ( any ( targets ( i )% ptr % target_type == [ FPM_TARGET_ARCHIVE , FPM_TARGET_SHARED ])) then n = n + 1 end if end do allocate ( list ( n )) n = 0 do i = 1 , size ( targets ) if ( any ( targets ( i )% ptr % target_type == [ FPM_TARGET_ARCHIVE , FPM_TARGET_SHARED ])) then n = n + 1 list ( n )% ptr => targets ( i )% ptr end if end do end subroutine filter_library_targets subroutine filter_executable_targets ( targets , scope , list ) type ( build_target_ptr ), intent ( in ) :: targets (:) integer , intent ( in ) :: scope type ( string_t ), allocatable , intent ( out ) :: list (:) integer :: i , n n = 0 call resize ( list ) do i = 1 , size ( targets ) if ( is_executable_target ( targets ( i )% ptr , scope )) then if ( n >= size ( list )) call resize ( list ) n = n + 1 list ( n )% s = targets ( i )% ptr % output_file end if end do call resize ( list , n ) end subroutine filter_executable_targets elemental function is_executable_target ( target_ptr , scope ) result ( is_exe ) class ( build_target_t ), intent ( in ) :: target_ptr integer , intent ( in ) :: scope logical :: is_exe is_exe = target_ptr % target_type == FPM_TARGET_EXECUTABLE . and . & allocated ( target_ptr % dependencies ) if ( is_exe ) then is_exe = target_ptr % dependencies ( 1 )% ptr % source % unit_scope == scope end if end function is_executable_target subroutine filter_modules ( targets , list ) type ( build_target_ptr ), intent ( in ) :: targets (:) type ( string_t ), allocatable , intent ( out ) :: list (:) integer :: i , j , n n = 0 call resize ( list ) do i = 1 , size ( targets ) associate ( target => targets ( i )% ptr ) if (. not . allocated ( target % source )) cycle if ( target % source % unit_type == FPM_UNIT_SUBMODULE ) cycle if ( n + size ( target % source % modules_provided ) >= size ( list )) call resize ( list ) do j = 1 , size ( target % source % modules_provided ) n = n + 1 list ( n )% s = join_path ( target % output_dir , & target % source % modules_provided ( j )% s ) end do end associate end do call resize ( list , n ) end subroutine filter_modules function get_feature_flags ( compiler , features ) result ( flags ) type ( compiler_t ), intent ( in ) :: compiler type ( fortran_features_t ), intent ( in ) :: features character (:), allocatable :: flags flags = \"\" if ( features % implicit_typing ) then flags = flags // compiler % get_feature_flag ( \"implicit-typing\" ) else flags = flags // compiler % get_feature_flag ( \"no-implicit-typing\" ) end if if ( features % implicit_external ) then flags = flags // compiler % get_feature_flag ( \"implicit-external\" ) else flags = flags // compiler % get_feature_flag ( \"no-implicit-external\" ) end if if ( allocated ( features % source_form )) then flags = flags // compiler % get_feature_flag ( features % source_form // \"-form\" ) end if end function get_feature_flags !> Helper function: update output directory of a target subroutine set_output_dir ( self , output_dir ) class ( build_target_t ), intent ( inout ) :: self character ( * ), optional , intent ( in ) :: output_dir character (:), allocatable :: outdir ! Normalize: if output_dir is empty, use no path outdir = \"\" if ( present ( output_dir )) outdir = trim ( output_dir ) self % output_dir = outdir self % output_file = join_path ( outdir , self % output_name ) self % output_log_file = self % output_file // \".log\" end subroutine set_output_dir !> Build a lookup table mapping each package dependency to its corresponding !> shared or archive build target in the targets list. !> !> This mapping is essential when model%deps%dep(i) indices do not match !> the pruned or reordered targets(:) array. subroutine library_targets_to_deps ( model , targets , target_ID ) class ( fpm_model_t ), intent ( in ) :: model type ( build_target_ptr ), intent ( in ) :: targets (:) !> For each package (by dependency index), gives the index of the corresponding target integer , allocatable , intent ( out ) :: target_ID (:) integer :: it , ip , n n = size ( model % deps % dep ) allocate ( target_ID ( n ), source = 0 ) do it = 1 , size ( targets ) associate ( target => targets ( it )% ptr ) ! Only shared libraries and archives are mapped if ( all ( target % target_type /= [ FPM_TARGET_ARCHIVE , FPM_TARGET_SHARED ])) cycle ! Get the dependency graph index of this package ip = model % deps % find ( target % package_name ) if ( ip > 0 ) target_ID ( ip ) = it end associate end do end subroutine library_targets_to_deps end module fpm_targets","tags":"","url":"sourcefile/fpm_targets.f90.html"},{"title":"preprocess.f90 – Fortran-lang/fpm","text":"Source Code !> Implementation of the meta data for preprocessing. !> !> A preprocess table can currently have the following fields !> !> ```toml !> [preprocess] !> [preprocess.cpp] !> suffixes = [\"F90\", \"f90\"] !> directories = [\"src/feature1\", \"src/models\"] !> macros = [] !> ``` module fpm_manifest_preprocess use fpm_error , only : error_t , syntax_error use fpm_strings , only : string_t , operator ( == ) use tomlf , only : toml_table , toml_key , toml_stat use fpm_toml , only : get_value , get_list , serializable_t , set_value , set_list , & set_string use , intrinsic :: iso_fortran_env , only : stderr => error_unit implicit none private public :: preprocess_config_t , new_preprocessors , operator ( == ) !> Configuration meta data for a preprocessor type , extends ( serializable_t ) :: preprocess_config_t !> Name of the preprocessor character ( len = :), allocatable :: name !> Suffixes of the files to be preprocessed type ( string_t ), allocatable :: suffixes (:) !> Directories to search for files to be preprocessed type ( string_t ), allocatable :: directories (:) !> Macros to be defined for the preprocessor type ( string_t ), allocatable :: macros (:) contains !> Print information on this instance procedure :: info !> Initialization procedure , private :: new_cpp_config_with_macros procedure , private :: new_preprocess_config generic :: new => new_cpp_config_with_macros , new_preprocess_config !> Serialization interface procedure :: serializable_is_same => preprocess_is_same procedure :: dump_to_toml procedure :: load_from_toml !> Operations procedure :: destroy procedure :: add_config !> Properties procedure :: is_cpp procedure :: is_fypp end type preprocess_config_t character ( * ), parameter , private :: class_name = 'preprocess_config_t' contains !> Construct a new cpp preprocessor configuration with a list of macros subroutine new_cpp_config_with_macros ( self , macros ) !> Instance of the preprocess configuration class ( preprocess_config_t ), intent ( out ) :: self !> List of macros type ( string_t ), intent ( in ) :: macros (:) call self % destroy () !> Set cpp self % name = \"cpp\" !> Set macros if ( size ( macros ) <= 0 ) then allocate ( self % macros ( 0 )) else allocate ( self % macros , source = macros ) end if end subroutine new_cpp_config_with_macros !> Construct a new preprocess configuration from TOML data structure subroutine new_preprocess_config ( self , table , error ) !> Instance of the preprocess configuration class ( preprocess_config_t ), intent ( out ) :: self !> Instance of the TOML data structure. type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error call check ( table , error ) if ( allocated ( error )) return call table % get_key ( self % name ) call get_list ( table , \"suffixes\" , self % suffixes , error ) if ( allocated ( error )) return call get_list ( table , \"directories\" , self % directories , error ) if ( allocated ( error )) return call get_list ( table , \"macros\" , self % macros , error ) if ( allocated ( error )) return end subroutine new_preprocess_config !> Check local schema for allowed entries subroutine check ( table , error ) !> Instance of the TOML data structure. type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( inout ) :: error character ( len = :), allocatable :: name type ( toml_key ), allocatable :: list (:) integer :: ikey call table % get_key ( name ) call table % get_keys ( list ) do ikey = 1 , size ( list ) select case ( list ( ikey )% key ) !> Valid keys. case ( \"suffixes\" , \"directories\" , \"macros\" ) case default call syntax_error ( error , \"Key '\" // list ( ikey )% key // \"' not allowed in preprocessor '\" // name // \"'.\" ); exit end select end do end subroutine check !> Construct new preprocess array from a TOML data structure. subroutine new_preprocessors ( preprocessors , table , error ) !> Instance of the preprocess configuration type ( preprocess_config_t ), allocatable , intent ( out ) :: preprocessors (:) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_table ), pointer :: node type ( toml_key ), allocatable :: list (:) integer :: iprep , stat call table % get_keys ( list ) ! An empty table is not allowed if ( size ( list ) == 0 ) then call syntax_error ( error , \"No preprocessors defined\" ) end if allocate ( preprocessors ( size ( list ))) do iprep = 1 , size ( list ) call get_value ( table , list ( iprep )% key , node , stat = stat ) if ( stat /= toml_stat % success ) then call syntax_error ( error , \"Preprocessor \" // list ( iprep )% key // \" must be a table entry\" ) exit end if call preprocessors ( iprep )% new ( node , error ) if ( allocated ( error )) exit end do end subroutine new_preprocessors !> Write information on this instance subroutine info ( self , unit , verbosity ) !> Instance of the preprocess configuration class ( preprocess_config_t ), intent ( in ) :: self !> Unit for IO integer , intent ( in ) :: unit !> Verbosity of the printout integer , intent ( in ), optional :: verbosity integer :: pr , ilink character ( len =* ), parameter :: fmt = '(\"#\", 1x, a, t30, a)' if ( present ( verbosity )) then pr = verbosity else pr = 1 end if if ( pr < 1 ) return write ( unit , fmt ) \"Preprocessor\" if ( allocated ( self % name )) then write ( unit , fmt ) \"- name\" , self % name end if if ( allocated ( self % suffixes )) then write ( unit , fmt ) \" - suffixes\" do ilink = 1 , size ( self % suffixes ) write ( unit , fmt ) \" - \" // self % suffixes ( ilink )% s end do end if if ( allocated ( self % directories )) then write ( unit , fmt ) \" - directories\" do ilink = 1 , size ( self % directories ) write ( unit , fmt ) \" - \" // self % directories ( ilink )% s end do end if if ( allocated ( self % macros )) then write ( unit , fmt ) \" - macros\" do ilink = 1 , size ( self % macros ) write ( unit , fmt ) \" - \" // self % macros ( ilink )% s end do end if end subroutine info logical function preprocess_is_same ( this , that ) class ( preprocess_config_t ), intent ( in ) :: this class ( serializable_t ), intent ( in ) :: that integer :: istr preprocess_is_same = . false . select type ( other => that ) type is ( preprocess_config_t ) if ( allocated ( this % name ). neqv . allocated ( other % name )) return if ( allocated ( this % name )) then if (. not .( this % name == other % name )) return endif if (. not .( this % suffixes == other % suffixes )) return if (. not .( this % directories == other % directories )) return if (. not .( this % macros == other % macros )) return class default ! Not the same type return end select !> All checks passed! preprocess_is_same = . true . end function preprocess_is_same !> Dump install config to toml table subroutine dump_to_toml ( self , table , error ) !> Instance of the serializable object class ( preprocess_config_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error call set_string ( table , \"name\" , self % name , error ) if ( allocated ( error )) return call set_list ( table , \"suffixes\" , self % suffixes , error ) if ( allocated ( error )) return call set_list ( table , \"directories\" , self % directories , error ) if ( allocated ( error )) return call set_list ( table , \"macros\" , self % macros , error ) if ( allocated ( error )) return end subroutine dump_to_toml !> Read install config from toml table (no checks made at this stage) subroutine load_from_toml ( self , table , error ) !> Instance of the serializable object class ( preprocess_config_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error call get_value ( table , \"name\" , self % name ) call get_list ( table , \"suffixes\" , self % suffixes , error ) if ( allocated ( error )) return call get_list ( table , \"directories\" , self % directories , error ) if ( allocated ( error )) return call get_list ( table , \"macros\" , self % macros , error ) if ( allocated ( error )) return end subroutine load_from_toml !> Clean preprocessor structure elemental subroutine destroy ( this ) class ( preprocess_config_t ), intent ( inout ) :: this if ( allocated ( this % name )) deallocate ( this % name ) if ( allocated ( this % suffixes )) deallocate ( this % suffixes ) if ( allocated ( this % directories )) deallocate ( this % directories ) if ( allocated ( this % macros )) deallocate ( this % macros ) end subroutine destroy !> Add preprocessor settings subroutine add_config ( this , that ) class ( preprocess_config_t ), intent ( inout ) :: this type ( preprocess_config_t ), intent ( in ) :: that if (. not . that % is_cpp ()) then write ( stderr , '(a)' ) 'Warning: Preprocessor ' // that % name // & ' is not supported; will ignore it' return end if if (. not . allocated ( this % name )) this % name = that % name ! Add macros if ( allocated ( that % macros )) then if ( allocated ( this % macros )) then this % macros = [ this % macros , that % macros ] else allocate ( this % macros , source = that % macros ) end if endif ! Add suffixes if ( allocated ( that % suffixes )) then if ( allocated ( this % suffixes )) then this % suffixes = [ this % suffixes , that % suffixes ] else allocate ( this % suffixes , source = that % suffixes ) end if endif ! Add directories if ( allocated ( that % directories )) then if ( allocated ( this % directories )) then this % directories = [ this % directories , that % directories ] else allocate ( this % directories , source = that % directories ) end if endif end subroutine add_config ! Check cpp logical function is_cpp ( this ) class ( preprocess_config_t ), intent ( in ) :: this is_cpp = . false . if ( allocated ( this % name )) is_cpp = this % name == \"cpp\" end function is_cpp ! Check cpp logical function is_fypp ( this ) class ( preprocess_config_t ), intent ( in ) :: this is_fypp = . false . if ( allocated ( this % name )) is_fypp = this % name == \"fypp\" end function is_fypp end module fpm_manifest_preprocess","tags":"","url":"sourcefile/preprocess.f90.html"},{"title":"fpm_compile_commands.F90 – Fortran-lang/fpm","text":"Source Code !># Store compiler commands in a `compile_commands.json` table module fpm_compile_commands use fpm_toml , only : serializable_t , set_string , set_list , get_value , get_list , add_table , & toml_array , add_array , toml_stat , len use tomlf , only : toml_table use jonquil , only : json_serialize , json_ser_config use fpm_strings , only : string_t , operator ( == ) use fpm_error , only : error_t , syntax_error , fatal_error use fpm_os , only : get_current_directory use fpm_environment , only : get_os_type , OS_WINDOWS use shlex_module , only : sh_split => split , ms_split implicit none !> Definition of a build command type , extends ( serializable_t ) :: compile_command_t type ( string_t ) :: directory type ( string_t ), allocatable :: arguments (:) type ( string_t ) :: file contains !> Operation procedure :: destroy => compile_command_destroy !> Serialization interface procedure :: serializable_is_same => compile_command_is_same procedure :: dump_to_toml => compile_command_dump_toml procedure :: load_from_toml => compile_command_load_toml end type compile_command_t type , extends ( serializable_t ) :: compile_command_table_t type ( compile_command_t ), allocatable :: command (:) contains !> Operation procedure :: destroy => cct_destroy procedure :: write => cct_write procedure , private :: cct_register procedure , private :: cct_register_object generic :: register => cct_register , & cct_register_object !> Serialization interface procedure :: serializable_is_same => cct_is_same procedure :: dump_to_toml => cct_dump_toml procedure :: load_from_toml => cct_load_toml end type compile_command_table_t interface compile_command_t module procedure cct_new end interface compile_command_t contains !> Override default initializer (GCC 15 bug) type ( compile_command_t ) function cct_new ( directory , arguments , file ) result ( cct ) character ( len =* ), intent ( in ) :: directory , file character ( len =* ), optional , intent ( in ) :: arguments (:) integer :: i , n cct % directory = string_t ( trim ( directory )) cct % file = string_t ( trim ( file )) if ( present ( arguments )) then n = size ( arguments ) else n = 0 endif allocate ( cct % arguments ( n )) do i = 1 , n cct % arguments ( i ) = string_t ( trim ( arguments ( i ))) end do end function cct_new !> Cleanup compile command elemental subroutine compile_command_destroy ( self ) !> Instance of the serializable object class ( compile_command_t ), intent ( inout ) :: self if ( allocated ( self % directory % s )) deallocate ( self % directory % s ) if ( allocated ( self % arguments )) deallocate ( self % arguments ) if ( allocated ( self % file % s )) deallocate ( self % file % s ) end subroutine compile_command_destroy !> Dump compile_command_t to toml table subroutine compile_command_dump_toml ( self , table , error ) !> Instance of the serializable object class ( compile_command_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error call set_list ( table , \"arguments\" , self % arguments , error ) if ( allocated ( error )) return call set_string ( table , \"directory\" , self % directory , error , 'compile_command_t' ) if ( allocated ( error )) return call set_string ( table , \"file\" , self % file , error , 'compile_command_t' ) if ( allocated ( error )) return end subroutine compile_command_dump_toml !> Read compile_command_t from toml table (no checks made at this stage) subroutine compile_command_load_toml ( self , table , error ) !> Instance of the serializable object class ( compile_command_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error call self % destroy () call get_list ( table , \"arguments\" , self % arguments , error ) if ( allocated ( error )) return ! Return unallocated value if not present call get_value ( table , \"directory\" , self % directory % s ) call get_value ( table , \"file\" , self % file % s ) end subroutine compile_command_load_toml !> Check that two compile_command_t objects are equal logical function compile_command_is_same ( this , that ) class ( compile_command_t ), intent ( in ) :: this class ( serializable_t ), intent ( in ) :: that compile_command_is_same = . false . select type ( other => that ) type is ( compile_command_t ) if (. not . this % directory == other % directory ) return if (. not . this % arguments == other % arguments ) return if (. not . this % file == other % file ) return class default ! Not the same type return end select !> All checks passed! compile_command_is_same = . true . end function compile_command_is_same !> Dump compile_command_table_t to a toml array subroutine cct_dump_array ( self , array , error ) !> Instance of the serializable object class ( compile_command_table_t ), intent ( inout ) :: self !> Data structure type ( toml_array ), intent ( inout ) :: array !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: ii , stat type ( toml_table ), pointer :: item if (. not . allocated ( self % command )) return do ii = 1 , size ( self % command ) associate ( cmd => self % command ( ii )) ! Set node for this command call add_table ( array , item , stat ) if ( stat /= toml_stat % success ) then call fatal_error ( error , \"Cannot store entry in compile_command_table_t array\" ) return end if call cmd % dump_to_toml ( item , error ) if ( allocated ( error )) return endassociate end do end subroutine cct_dump_array !> Write compile_commands.json file. Because Jonquil does not support non-named arrays, !> create a custom json here. subroutine cct_write ( self , filename , error ) !> Instance of the serializable object class ( compile_command_table_t ), intent ( inout ) :: self !> The file name character ( * ), intent ( in ) :: filename !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_array ) :: array type ( json_ser_config ) :: cfg integer :: stat , lun ! Init array array = toml_array () ! Dump information to the array call cct_dump_array ( self , array , error ) if ( allocated ( error )) return ! Open file and write to it open ( newunit = lun , file = filename , form = 'formatted' , action = 'write' , status = 'replace' , iostat = stat ) if ( stat /= 0 ) then call fatal_error ( error , 'cannot open file ' // filename // ' for writing' ) return end if ! Ensure the array has no key if ( allocated ( array % key )) deallocate ( array % key ) cfg % indent = repeat ( ' ' , 3 ) write ( lun , '(A)' , iostat = stat , err = 1 ) json_serialize ( array , cfg ) close ( lun , iostat = stat ) 1 if ( stat /= 0 ) then call fatal_error ( error , 'cannot close file ' // filename // ' after writing' ) return end if end subroutine cct_write !> Cleanup a compile command table elemental subroutine cct_destroy ( self ) !> Instance of the serializable object class ( compile_command_table_t ), intent ( inout ) :: self if ( allocated ( self % command )) deallocate ( self % command ) end subroutine cct_destroy !> Register a new compile command subroutine cct_register ( self , command , target_os , error ) !> Instance of the serializable object class ( compile_command_table_t ), intent ( inout ) :: self !> Data structure character ( len =* ), intent ( in ) :: command !> The target OS of the compile_commands.json (may be cross-compiling) integer , intent ( in ) :: target_os !> Error handling type ( error_t ), allocatable , intent ( out ) :: error ! Local variables type ( compile_command_t ) :: cmd character ( len = :), allocatable :: args (:), cwd , source_file logical :: sh_success integer :: i , n ! Early check if ( len_trim ( command ) <= 0 ) then call syntax_error ( error , \"compile_command_table_t trying to register an empty command\" ) return end if ! Tokenize the input command into args(:) if ( target_os == OS_WINDOWS ) then args = ms_split ( command , ucrt = . true ., success = sh_success ) else args = sh_split ( command , join_spaced = . false ., keep_quotes = . true ., success = sh_success ) end if n = size ( args ) if ( n == 0 . or . . not . sh_success ) then call syntax_error ( error , \"compile_command_table_t failed tokenizing: <\" // command // \">\" ) return end if ! Get current working directory call get_current_directory ( cwd , error ) if ( allocated ( error )) return ! Try to find the source file allocate ( character ( len = 0 ) :: source_file ) find_source_file : do i = 1 , n - 1 if ( args ( i ) == \"-c\" ) then source_file = trim ( args ( i + 1 )) exit find_source_file end if end do find_source_file ! Fallback: use last argument if not found if ( len_trim ( source_file ) == 0 ) source_file = trim ( args ( n )) ! Fill in the compile_command_t. ! Use non-default initializer due to gcc 15 bug cmd = compile_command_t ( cwd , args , source_file ) ! Add it to the structure !$omp critical (command_update) call cct_register_object ( self , cmd , error ) !$omp end critical (command_update) end subroutine cct_register pure subroutine cct_register_object ( self , command , error ) !> Instance of the serializable object class ( compile_command_table_t ), intent ( inout ) :: self !> Data structure type ( compile_command_t ), intent ( in ) :: command !> Error handling type ( error_t ), allocatable , intent ( out ) :: error if ( allocated ( self % command )) then self % command = [ self % command , command ] else allocate ( self % command ( 1 ), source = command ) end if end subroutine cct_register_object !> Dump compile_command_table_t to toml table subroutine cct_dump_toml ( self , table , error ) !> Instance of the serializable object class ( compile_command_table_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: stat , ii type ( toml_array ), pointer :: array ! Create array call add_array ( table , 'compile_commands' , array , stat = stat ) if ( stat /= toml_stat % success . or . . not . associated ( array )) then call fatal_error ( error , \"compile_command_table_t cannot create entry\" ) return end if ! Dump to it call cct_dump_array ( self , array , error ) end subroutine cct_dump_toml !> Read compile_command_table_t from toml table (no checks made at this stage) subroutine cct_load_toml ( self , table , error ) !> Instance of the serializable object class ( compile_command_table_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: stat , i , n type ( toml_array ), pointer :: array type ( toml_table ), pointer :: elem call self % destroy () call get_value ( table , key = 'compile_commands' , ptr = array , requested = . true ., stat = stat ) if ( stat /= toml_stat % success . or . . not . associated ( array )) then call fatal_error ( error , \"TOML table has no 'compile_commands' key\" ) return else n = len ( array ) if ( n <= 0 ) return allocate ( self % command ( n )) do i = 1 , n call get_value ( array , pos = i , ptr = elem , stat = stat ) if ( stat /= toml_stat % success . or . . not . associated ( elem )) then call fatal_error ( error , \"Entry in 'compile_commands' field cannot be read\" ) return end if call self % command ( i )% load ( elem , error ) if ( allocated ( error )) return end do end if end subroutine cct_load_toml !> Check that two compile_command_table_t objects are equal logical function cct_is_same ( this , that ) class ( compile_command_table_t ), intent ( in ) :: this class ( serializable_t ), intent ( in ) :: that integer :: i cct_is_same = . false . select type ( other => that ) type is ( compile_command_table_t ) if ( allocated ( this % command ). neqv . allocated ( other % command )) return if ( allocated ( this % command )) then if (. not .( size ( this % command ) == size ( other % command ))) return if (. not .( ubound ( this % command , 1 ) == ubound ( other % command , 1 ))) return if (. not .( lbound ( this % command , 1 ) == lbound ( other % command , 1 ))) return do i = lbound ( this % command , 1 ), ubound ( this % command , 1 ) if (. not . this % command ( i ) == other % command ( i )) return end do end if class default ! Not the same type return end select !> All checks passed! cct_is_same = . true . end function cct_is_same end module fpm_compile_commands","tags":"","url":"sourcefile/fpm_compile_commands.f90.html"},{"title":"fpm_backend_output.f90 – Fortran-lang/fpm","text":"Source Code !># Build Backend Progress Output !> This module provides a derived type `build_progress_t` for printing build status !> and progress messages to the console while the backend is building the package. !> !> The `build_progress_t` type supports two modes: `normal` and `plain` !> where the former does 'pretty' output and the latter does not. !> The `normal` mode is intended for typical interactive usage whereas !> 'plain' mode is used with the `--verbose` flag or when `stdout` is not attached !> to a terminal (e.g. when piping or redirecting `stdout`). In these cases, !> the pretty output must be suppressed to avoid control codes being output. module fpm_backend_output use iso_fortran_env , only : stdout => output_unit use fpm_error , only : error_t use fpm_filesystem , only : basename , join_path use fpm_targets , only : build_target_ptr use fpm_backend_console , only : console_t , LINE_RESET , COLOR_RED , COLOR_GREEN , COLOR_YELLOW , COLOR_RESET use fpm_compile_commands , only : compile_command_t , compile_command_table_t implicit none private public build_progress_t !> Build progress object type build_progress_t !> Console object for updating console lines type ( console_t ) :: console !> Number of completed targets integer :: n_complete !> Total number of targets scheduled integer :: n_target !> 'Plain' output (no colors or updating) logical :: plain_mode = . true . !> Store needed when updating previous console lines integer , allocatable :: output_lines (:) !> Queue of scheduled build targets type ( build_target_ptr ), pointer :: target_queue (:) !> The compile_commands.json table type ( compile_command_table_t ) :: compile_commands contains !> Output 'compiling' status for build target procedure :: compiling_status => output_status_compiling !> Output 'complete' status for build target procedure :: completed_status => output_status_complete !> Output finished status for whole package procedure :: success => output_progress_success !> Output 'compile_commands.json' to build/ folder procedure :: dump_commands => output_write_compile_commands end type build_progress_t !> Constructor for build_progress_t interface build_progress_t procedure :: new_build_progress end interface build_progress_t contains !> Initialise a new build progress object function new_build_progress ( target_queue , plain_mode ) result ( progress ) !> The queue of scheduled targets type ( build_target_ptr ), intent ( in ), target :: target_queue (:) !> Enable 'plain' output for progress object logical , intent ( in ), optional :: plain_mode !> Progress object to initialise type ( build_progress_t ) :: progress call progress % compile_commands % destroy () progress % n_target = size ( target_queue , 1 ) progress % target_queue => target_queue progress % plain_mode = plain_mode progress % n_complete = 0 allocate ( progress % output_lines ( progress % n_target )) end function new_build_progress !> Output 'compiling' status for build target and overall percentage progress subroutine output_status_compiling ( progress , queue_index ) !> Progress object class ( build_progress_t ), intent ( inout ) :: progress !> Index of build target in the target queue integer , intent ( in ) :: queue_index character (:), allocatable :: target_name character ( 100 ) :: output_string character ( 7 ) :: overall_progress associate ( target => progress % target_queue ( queue_index )% ptr ) if ( allocated ( target % source )) then target_name = basename ( target % source % file_name ) else target_name = basename ( target % output_file ) end if write ( overall_progress , '(A,I3,A)' ) '[' , 100 * progress % n_complete / progress % n_target , '%] ' if ( progress % plain_mode ) then ! Plain output !$omp critical write ( * , '(A7,A30)' ) overall_progress , target_name !$omp end critical else ! Pretty output write ( output_string , '(A,T40,A,A)' ) target_name , COLOR_YELLOW // 'compiling...' // COLOR_RESET call progress % console % write_line ( trim ( output_string ), progress % output_lines ( queue_index )) call progress % console % write_line ( overall_progress // 'Compiling...' , advance = . false .) end if end associate end subroutine output_status_compiling !> Output 'complete' status for build target and update overall percentage progress subroutine output_status_complete ( progress , queue_index , build_stat ) !> Progress object class ( build_progress_t ), intent ( inout ) :: progress !> Index of build target in the target queue integer , intent ( in ) :: queue_index !> Build status flag integer , intent ( in ) :: build_stat character (:), allocatable :: target_name character ( 100 ) :: output_string character ( 7 ) :: overall_progress !$omp critical progress % n_complete = progress % n_complete + 1 !$omp end critical associate ( target => progress % target_queue ( queue_index )% ptr ) if ( allocated ( target % source )) then target_name = basename ( target % source % file_name ) else target_name = basename ( target % output_file ) end if if ( build_stat == 0 ) then write ( output_string , '(A,T40,A,A)' ) target_name , COLOR_GREEN // 'done.' // COLOR_RESET else write ( output_string , '(A,T40,A,A)' ) target_name , COLOR_RED // 'failed.' // COLOR_RESET end if write ( overall_progress , '(A,I3,A)' ) '[' , 100 * progress % n_complete / progress % n_target , '%] ' if ( progress % plain_mode ) then ! Plain output !$omp critical write ( * , '(A7,A30,A7)' ) overall_progress , target_name , 'done.' !$omp end critical else ! Pretty output call progress % console % update_line ( progress % output_lines ( queue_index ), trim ( output_string )) call progress % console % write_line ( overall_progress // 'Compiling...' , advance = . false .) end if end associate end subroutine output_status_complete !> Output finished status for whole package subroutine output_progress_success ( progress ) class ( build_progress_t ), intent ( inout ) :: progress if ( progress % plain_mode ) then ! Plain output write ( * , '(A)' ) '[100%] Project compiled successfully.' else ! Pretty output write ( * , '(A)' ) LINE_RESET // COLOR_GREEN // '[100%] Project compiled successfully.' // COLOR_RESET end if end subroutine output_progress_success !> Write compile commands table subroutine output_write_compile_commands ( progress , error ) class ( build_progress_t ), intent ( inout ) :: progress character (:), allocatable :: path type ( error_t ), allocatable :: error ! Write compile commands path = join_path ( 'build' , 'compile_commands.json' ) call progress % compile_commands % write ( filename = path , error = error ) end subroutine output_write_compile_commands end module fpm_backend_output","tags":"","url":"sourcefile/fpm_backend_output.f90.html"},{"title":"fpm_release.F90 – Fortran-lang/fpm","text":"Source Code !># Release parameters !> Module fpm_release contains public constants storing this build's unique version IDs module fpm_release use fpm_versioning , only : version_t , new_version use fpm_error , only : error_t , fpm_stop implicit none private public :: fpm_version public :: version_t contains !> Return the current fpm version from fpm_version_ID as a version type type ( version_t ) function fpm_version () type ( error_t ), allocatable :: error ! Fallback to last known version in case of undefined macro #ifndef FPM_RELEASE_VERSION # define FPM_RELEASE_VERSION 0.12.0 #endif ! Accept solution from https://stackoverflow.com/questions/31649691/stringify-macro-with-gnu-gfortran ! which provides the \"easiest\" way to pass a macro to a string in Fortran complying with both ! gfortran's \"traditional\" cpp and the standard cpp syntaxes #ifdef __GFORTRAN__ /* traditional-cpp stringification */ # define STRINGIFY_START(X) \"& # define STRINGIFY_END(X) &X\" #else /* default stringification */ # define STRINGIFY_(X) #X # define STRINGIFY_START(X) & # define STRINGIFY_END(X) STRINGIFY_(X) #endif character ( len = :), allocatable :: ver_string ver_string = STRINGIFY_START ( FPM_RELEASE_VERSION ) STRINGIFY_END ( FPM_RELEASE_VERSION ) call new_version ( fpm_version , ver_string , error ) if ( allocated ( error )) call fpm_stop ( 1 , '*fpm*:internal error: cannot get version - ' // error % message ) end function fpm_version end module fpm_release","tags":"","url":"sourcefile/fpm_release.f90.html"},{"title":"manifest.f90 – Fortran-lang/fpm","text":"Source Code !> Package configuration data. !> !> This module provides the necessary procedure to translate a TOML document !> to the corresponding Fortran type, while verifying it with respect to !> its schema. !> !> Additionally, the required data types for users of this module are reexported !> to hide the actual implementation details. module fpm_manifest use fpm_manifest_example , only : example_config_t use fpm_manifest_executable , only : executable_config_t use fpm_manifest_dependency , only : dependency_config_t use fpm_manifest_library , only : library_config_t use fpm_manifest_preprocess , only : preprocess_config_t use fpm_manifest_package , only : package_config_t , new_package use fpm_error , only : error_t , fatal_error use tomlf , only : toml_table use fpm_toml , only : read_package_file use fpm_manifest_test , only : test_config_t use fpm_filesystem , only : join_path , exists , dirname , is_dir use fpm_environment , only : os_is_unix use fpm_strings , only : string_t implicit none private public :: get_package_data , default_executable , default_library , default_test public :: get_package_dependencies public :: default_example public :: package_config_t , dependency_config_t , preprocess_config_t contains !> Populate library in case we find the default src directory subroutine default_library ( self ) !> Instance of the library meta data type ( library_config_t ), intent ( out ) :: self self % source_dir = \"src\" self % include_dir = [ string_t ( \"include\" )] end subroutine default_library !> Populate executable in case we find the default app directory subroutine default_executable ( self , name ) !> Instance of the executable meta data type ( executable_config_t ), intent ( out ) :: self !> Name of the package character ( len =* ), intent ( in ) :: name self % name = name self % source_dir = \"app\" self % main = \"main.f90\" end subroutine default_executable !> Populate test in case we find the default example/ directory subroutine default_example ( self , name ) !> Instance of the executable meta data type ( example_config_t ), intent ( out ) :: self !> Name of the package character ( len =* ), intent ( in ) :: name self % name = name // \"-demo\" self % source_dir = \"example\" self % main = \"main.f90\" end subroutine default_example !> Populate test in case we find the default test/ directory subroutine default_test ( self , name ) !> Instance of the executable meta data type ( test_config_t ), intent ( out ) :: self !> Name of the package character ( len =* ), intent ( in ) :: name self % name = name // \"-test\" self % source_dir = \"test\" self % main = \"main.f90\" end subroutine default_test !> Obtain package meta data from a configuation file subroutine get_package_data ( package , file , error , apply_defaults ) !> Parsed package meta data type ( package_config_t ), intent ( out ) :: package !> Name of the package configuration file character ( len =* ), intent ( in ) :: file !> Error status of the operation type ( error_t ), allocatable , intent ( out ) :: error !> Apply package defaults (uses file system operations) logical , intent ( in ), optional :: apply_defaults type ( toml_table ), allocatable :: table character ( len = :), allocatable :: root call read_package_file ( table , file , error ) if ( allocated ( error )) return if (. not . allocated ( table )) then call fatal_error ( error , \"Unclassified error while reading: '\" // file // \"'\" ) return end if call new_package ( package , table , dirname ( file ), error ) if ( allocated ( error )) return if ( present ( apply_defaults )) then if ( apply_defaults ) then root = dirname ( file ) if ( len_trim ( root ) == 0 ) root = \".\" call package_defaults ( package , root , error ) if ( allocated ( error )) return end if end if end subroutine get_package_data !> Apply package defaults subroutine package_defaults ( package , root , error ) !> Parsed package meta data type ( package_config_t ), intent ( inout ) :: package !> Current working directory character ( len =* ), intent ( in ) :: root !> Error status of the operation type ( error_t ), allocatable , intent ( out ) :: error ! Populate library in case we find the default src directory if (. not . allocated ( package % library ) . and . & & ( is_dir ( join_path ( root , \"src\" )) . or . & & is_dir ( join_path ( root , \"include\" )))) then allocate ( package % library ) call default_library ( package % library ) end if ! Populate executable in case we find the default app if (. not . allocated ( package % executable ) . and . & & exists ( join_path ( root , \"app\" , \"main.f90\" ))) then allocate ( package % executable ( 1 )) call default_executable ( package % executable ( 1 ), package % name ) end if ! Populate example in case we find the default example directory if (. not . allocated ( package % example ) . and . & & exists ( join_path ( root , \"example\" , \"main.f90\" ))) then allocate ( package % example ( 1 )) call default_example ( package % example ( 1 ), package % name ) endif ! Populate test in case we find the default test directory if (. not . allocated ( package % test ) . and . & & exists ( join_path ( root , \"test\" , \"main.f90\" ))) then allocate ( package % test ( 1 )) call default_test ( package % test ( 1 ), package % name ) endif if (. not .( allocated ( package % library ) & & . or . allocated ( package % executable ) & & . or . allocated ( package % example ) & & . or . allocated ( package % test ))) then call fatal_error ( error , \"Neither library nor executable found, there is nothing to do\" ) return end if end subroutine package_defaults ! Return an array of all dependencies in the manifest subroutine get_package_dependencies ( package , main , deps ) !> Parsed package meta data type ( package_config_t ), intent ( in ) :: package !> Is the main project logical , intent ( in ) :: main !> Unprocessed list of all dependencies listed in this manifest type ( dependency_config_t ), allocatable , intent ( out ) :: deps (:) integer :: ndeps , k ndeps = 0 if ( allocated ( package % dependency )) & ndeps = ndeps + size ( package % dependency ) if ( main ) then if ( allocated ( package % dev_dependency )) & ndeps = ndeps + size ( package % dev_dependency ) if ( allocated ( package % example )) then do k = 1 , size ( package % example ) if ( allocated ( package % example ( k )% dependency )) & ndeps = ndeps + size ( package % example ( k )% dependency ) end do end if if ( allocated ( package % executable )) then do k = 1 , size ( package % executable ) if ( allocated ( package % executable ( k )% dependency )) & ndeps = ndeps + size ( package % executable ( k )% dependency ) end do end if if ( allocated ( package % test )) then do k = 1 , size ( package % test ) if ( allocated ( package % test ( k )% dependency )) & ndeps = ndeps + size ( package % test ( k )% dependency ) end do end if endif allocate ( deps ( ndeps )) if ( ndeps > 0 ) then ndeps = 0 if ( allocated ( package % dependency )) & call collect ( deps , ndeps , package % dependency ) if ( main ) then if ( allocated ( package % dev_dependency )) & call collect ( deps , ndeps , package % dev_dependency ) if ( allocated ( package % example )) then do k = 1 , size ( package % example ) if ( allocated ( package % example ( k )% dependency )) & call collect ( deps , ndeps , package % example ( k )% dependency ) end do end if if ( allocated ( package % executable )) then do k = 1 , size ( package % executable ) if ( allocated ( package % executable ( k )% dependency )) & call collect ( deps , ndeps , package % executable ( k )% dependency ) end do end if if ( allocated ( package % test )) then do k = 1 , size ( package % test ) if ( allocated ( package % test ( k )% dependency )) & call collect ( deps , ndeps , package % test ( k )% dependency ) end do end if endif endif contains ! Add dependencies to the list pure subroutine collect ( list , nreq , new_deps ) type ( dependency_config_t ), intent ( inout ) :: list (:) integer , intent ( inout ) :: nreq type ( dependency_config_t ), intent ( in ) :: new_deps (:) integer :: i do i = 1 , size ( new_deps ) nreq = nreq + 1 list ( nreq ) = new_deps ( i ) end do end subroutine collect end subroutine get_package_dependencies end module fpm_manifest","tags":"","url":"sourcefile/manifest.f90.html"},{"title":"fpm_filesystem.F90 – Fortran-lang/fpm","text":"Source Code !> This module contains general routines for interacting with the file system !! module fpm_filesystem use , intrinsic :: iso_fortran_env , only : stdin => input_unit , stdout => output_unit , stderr => error_unit use , intrinsic :: iso_c_binding , only : c_new_line use fpm_environment , only : get_os_type , & OS_UNKNOWN , OS_LINUX , OS_MACOS , OS_WINDOWS , & OS_CYGWIN , OS_SOLARIS , OS_FREEBSD , OS_OPENBSD use fpm_environment , only : separator , get_env , os_is_unix use fpm_strings , only : f_string , replace , string_t , split , split_lines_first_last , dilate , str_begins_with_str use iso_c_binding , only : c_char , c_ptr , c_int , c_null_char , c_associated , c_f_pointer use fpm_error , only : fpm_stop , error_t , fatal_error implicit none private public :: basename , canon_path , dirname , is_dir , join_path , number_of_rows , list_files , get_local_prefix , & mkdir , exists , get_temp_filename , windows_path , unix_path , getline , delete_file , fileopen , fileclose , & filewrite , warnwrite , parent_dir , is_hidden_file , read_lines , read_lines_expanded , which , run , & os_delete_dir , is_absolute_path , get_home , execute_and_read_output , get_dos_path #ifndef FPM_BOOTSTRAP interface function c_opendir ( dir ) result ( r ) bind ( c , name = \"c_opendir\" ) import c_char , c_ptr character ( kind = c_char ), intent ( in ) :: dir ( * ) type ( c_ptr ) :: r end function c_opendir function c_readdir ( dir ) result ( r ) bind ( c , name = \"c_readdir\" ) import c_ptr type ( c_ptr ), intent ( in ), value :: dir type ( c_ptr ) :: r end function c_readdir function c_closedir ( dir ) result ( r ) bind ( c , name = \"closedir\" ) import c_ptr , c_int type ( c_ptr ), intent ( in ), value :: dir integer ( kind = c_int ) :: r end function c_closedir function c_get_d_name ( dir ) result ( r ) bind ( c , name = \"get_d_name\" ) import c_ptr type ( c_ptr ), intent ( in ), value :: dir type ( c_ptr ) :: r end function c_get_d_name function c_is_dir ( path ) result ( r ) bind ( c , name = \"c_is_dir\" ) import c_char , c_int character ( kind = c_char ), intent ( in ) :: path ( * ) integer ( kind = c_int ) :: r end function c_is_dir end interface #endif contains !> Extract filename from path with/without suffix function basename ( path , suffix ) result ( base ) character ( * ), intent ( In ) :: path logical , intent ( in ), optional :: suffix character (:), allocatable :: base character (:), allocatable :: file_parts (:) logical :: with_suffix if (. not . present ( suffix )) then with_suffix = . true . else with_suffix = suffix end if call split ( path , file_parts , delimiters = '\\/' ) if ( size ( file_parts ) > 0 ) then base = trim ( file_parts ( size ( file_parts ))) else base = '' endif if (. not . with_suffix ) then call split ( base , file_parts , delimiters = '.' ) if ( size ( file_parts ) >= 2 ) then base = trim ( file_parts ( size ( file_parts ) - 1 )) endif endif end function basename !> Canonicalize path for comparison !! * Handles path string redundancies !! * Does not test existence of path !! !! To be replaced by realpath/_fullname in stdlib_os !! !! FIXME: Lot's of ugly hacks following here function canon_path ( path ) character ( len =* ), intent ( in ) :: path character ( len = :), allocatable :: canon_path character ( len = :), allocatable :: nixpath integer :: istart , iend , nn , last logical :: is_path , absolute nixpath = unix_path ( path ) istart = 0 nn = 0 iend = 0 absolute = nixpath ( 1 : 1 ) == \"/\" if ( absolute ) then canon_path = \"/\" else canon_path = \"\" end if do while ( iend < len ( nixpath )) call next ( nixpath , istart , iend , is_path ) if ( is_path ) then select case ( nixpath ( istart : iend )) case ( \".\" , \"\" ) ! always drop empty paths case ( \"..\" ) if ( nn > 0 ) then last = scan ( canon_path (: len ( canon_path ) - 1 ), \"/\" , back = . true .) canon_path = canon_path (: last ) nn = nn - 1 else if (. not . absolute ) then canon_path = canon_path // nixpath ( istart : iend ) // \"/\" end if end if case default nn = nn + 1 canon_path = canon_path // nixpath ( istart : iend ) // \"/\" end select end if end do if ( len ( canon_path ) == 0 ) canon_path = \".\" if ( len ( canon_path ) > 1 . and . canon_path ( len ( canon_path ):) == \"/\" ) then canon_path = canon_path (: len ( canon_path ) - 1 ) end if contains subroutine next ( string , istart , iend , is_path ) character ( len =* ), intent ( in ) :: string integer , intent ( inout ) :: istart integer , intent ( inout ) :: iend logical , intent ( inout ) :: is_path integer :: ii , nn character :: tok nn = len ( string ) if ( iend >= nn ) then istart = nn iend = nn return end if ii = min ( iend + 1 , nn ) tok = string ( ii : ii ) is_path = tok /= '/' if (. not . is_path ) then is_path = . false . istart = ii iend = ii return end if istart = ii do ii = min ( iend + 1 , nn ), nn tok = string ( ii : ii ) select case ( tok ) case ( '/' ) exit case default iend = ii cycle end select end do end subroutine next end function canon_path !> Extract dirname from path function dirname ( path ) result ( dir ) character ( * ), intent ( in ) :: path character (:), allocatable :: dir dir = path ( 1 : scan ( path , '/\\',back=.true.)) end function dirname !> Extract dirname from path function parent_dir(path) result (dir) character(*), intent(in) :: path character(:), allocatable :: dir dir = path(1:scan(path,' / \\ ',back=.true.)-1) end function parent_dir !> test if a name matches an existing directory path logical function is_dir(dir) character(*), intent(in) :: dir integer :: stat select case (get_os_type()) case (OS_UNKNOWN, OS_LINUX, OS_MACOS, OS_CYGWIN, OS_SOLARIS, OS_FREEBSD, OS_OPENBSD) call run( \"test -d \" // dir , & & exitstat=stat,echo=.false.,verbose=.false.) case (OS_WINDOWS) call run(' cmd / c \"if not exist ' // windows_path(dir) // '\\ exit /B 1\" ', & & exitstat=stat,echo=.false.,verbose=.false.) end select is_dir = (stat == 0) end function is_dir !> test if a file is hidden logical function is_hidden_file(file_basename) result(r) character(*), intent(in) :: file_basename if (len(file_basename) <= 2) then r = .false. else r = str_begins_with_str(file_basename, ' . ') end if end function is_hidden_file !> Construct path by joining strings with os file separator function join_path(a1,a2,a3,a4,a5) result(path) character(len=*), intent(in) :: a1, a2 character(len=*), intent(in), optional :: a3, a4, a5 character(len=:), allocatable :: path character(len=1) :: filesep logical, save :: has_cache = .false. character(len=1), save :: cache = ' / ' !$omp threadprivate(has_cache, cache) if (has_cache) then filesep = cache else select case (get_os_type()) case default filesep = ' / ' case (OS_WINDOWS) filesep = ' \\ ' end select cache = filesep has_cache = .true. end if if (a1 == \"\") then path = a2 else path = a1 // filesep // a2 end if if (present(a3)) then path = path // filesep // a3 else return end if if (present(a4)) then path = path // filesep // a4 else return end if if (present(a5)) then path = path // filesep // a5 else return end if end function join_path !> Determine number or rows in a file given a LUN integer function number_of_rows(s) result(nrows) integer,intent(in)::s integer :: ios rewind(s) nrows = 0 do read(s, *, iostat=ios) if (ios /= 0) exit nrows = nrows + 1 end do rewind(s) end function number_of_rows !> read lines into an array of TYPE(STRING_T) variables expanding tabs function read_lines_expanded(filename) result(lines) character(len=*), intent(in) :: filename type(string_t), allocatable :: lines(:) integer :: i character(len=:), allocatable :: content integer, allocatable :: first(:), last(:) content = read_text_file(filename) if (len(content) == 0) then allocate (lines(0)) return end if call split_lines_first_last(content, first, last) ! allocate lines from file content string allocate (lines(size(first))) do i = 1, size(first) allocate(lines(i)%s, source=dilate(content(first(i):last(i)))) end do end function read_lines_expanded !> read lines into an array of TYPE(STRING_T) variables function read_lines(filename) result(lines) character(len=*), intent(in) :: filename type(string_t), allocatable :: lines(:) integer :: i character(len=:), allocatable :: content integer, allocatable :: first(:), last(:) content = read_text_file(filename) if (len(content) == 0) then allocate (lines(0)) return end if call split_lines_first_last(content, first, last) ! allocate lines from file content string allocate (lines(size(first))) do i = 1, size(first) allocate(lines(i)%s, source=content(first(i):last(i))) end do end function read_lines !> read text file into a string function read_text_file(filename) result(string) character(len=*), intent(in) :: filename character(len=:), allocatable :: string integer :: fh, length open (newunit=fh, file=filename, status=' old ', action=' read ', & access=' stream ', form=' unformatted ') inquire (fh, size=length) allocate (character(len=length) :: string) if (length == 0) return read (fh) string close (fh) end function read_text_file !> Create a directory. Create subdirectories as needed subroutine mkdir(dir, echo) character(len=*), intent(in) :: dir logical, intent(in), optional :: echo integer :: stat if (is_dir(dir)) return select case (get_os_type()) case (OS_UNKNOWN, OS_LINUX, OS_MACOS, OS_CYGWIN, OS_SOLARIS, OS_FREEBSD, OS_OPENBSD) call run(' mkdir - p ' // dir, exitstat=stat,echo=echo,verbose=.false.) case (OS_WINDOWS) call run(\"mkdir \" // windows_path(dir), & & echo=echo, exitstat=stat,verbose=.false.) end select if (stat /= 0) then call fpm_stop(1, ' * mkdir * : directory creation failed ') end if end subroutine mkdir #ifndef FPM_BOOTSTRAP !> Get file & directory names in directory `dir` using iso_c_binding. !! !! - File/directory names return are relative to cwd, ie. preprended with `dir` !! - Includes files starting with `.` except current directory and parent directory !! recursive subroutine list_files(dir, files, recurse) character(len=*), intent(in) :: dir type(string_t), allocatable, intent(out) :: files(:) logical, intent(in), optional :: recurse integer :: i type(string_t), allocatable :: dir_files(:) type(string_t), allocatable :: sub_dir_files(:) type(c_ptr) :: dir_handle type(c_ptr) :: dir_entry_c character(len=:,kind=c_char), allocatable :: fortran_name character(len=:), allocatable :: string_fortran integer, parameter :: N_MAX = 256 type(string_t) :: files_tmp(N_MAX) integer(kind=c_int) :: r if (c_is_dir(dir(1:len_trim(dir))//c_null_char) == 0) then allocate (files(0)) return end if dir_handle = c_opendir(dir(1:len_trim(dir))//c_null_char) if (.not. c_associated(dir_handle)) then print *, ' c_opendir () failed ' error stop end if i = 0 allocate(files(0)) do dir_entry_c = c_readdir(dir_handle) if (.not. c_associated(dir_entry_c)) then exit else string_fortran = f_string(c_get_d_name(dir_entry_c)) if ((string_fortran == ' . ' .or. string_fortran == ' .. ')) then cycle end if i = i + 1 if (i > N_MAX) then files = [files, files_tmp] i = 1 end if files_tmp(i)%s = join_path(dir, string_fortran) end if end do r = c_closedir(dir_handle) if (r /= 0) then print *, ' c_closedir () failed ' error stop end if if (i > 0) then files = [files, files_tmp(1:i)] end if if (present(recurse)) then if (recurse) then allocate(sub_dir_files(0)) do i=1,size(files) if (c_is_dir(files(i)%s//c_null_char) /= 0) then call list_files(files(i)%s, dir_files, recurse=.true.) sub_dir_files = [sub_dir_files, dir_files] end if end do files = [files, sub_dir_files] end if end if end subroutine list_files #else !> Get file & directory names in directory `dir`. !! !! - File/directory names return are relative to cwd, ie. preprended with `dir` !! - Includes files starting with `.` except current directory and parent directory !! recursive subroutine list_files(dir, files, recurse) character(len=*), intent(in) :: dir type(string_t), allocatable, intent(out) :: files(:) logical, intent(in), optional :: recurse integer :: stat, fh, i character(:), allocatable :: temp_file type(string_t), allocatable :: dir_files(:) type(string_t), allocatable :: sub_dir_files(:) if (.not. is_dir(dir)) then allocate (files(0)) return end if allocate (temp_file, source=get_temp_filename()) select case (get_os_type()) case (OS_UNKNOWN, OS_LINUX, OS_MACOS, OS_CYGWIN, OS_SOLARIS, OS_FREEBSD, OS_OPENBSD) call run(' ls - A ' // dir , & & redirect=temp_file, exitstat=stat,echo=.false.,verbose=.false.) case (OS_WINDOWS) call run(' dir / b ' // windows_path(dir), & & redirect=temp_file, exitstat=stat,echo=.false.,verbose=.false.) end select if (stat /= 0) then call fpm_stop(2,' * list_files * : directory listing failed ') end if files = read_lines(temp_file) call delete_file(temp_file) do i=1,size(files) files(i)%s = join_path(dir,files(i)%s) end do if (present(recurse)) then if (recurse) then allocate(sub_dir_files(0)) do i=1,size(files) if (is_dir(files(i)%s)) then call list_files(files(i)%s, dir_files, recurse=.true.) sub_dir_files = [sub_dir_files, dir_files] end if end do files = [files, sub_dir_files] end if end if end subroutine list_files #endif !> test if pathname already exists logical function exists(filename) result(r) character(len=*), intent(in) :: filename inquire(file=filename, exist=r) !> Directories are not files for the Intel compilers. If so, also use this compiler-dependent extension #if defined(__INTEL_COMPILER) if (.not.r) inquire(directory=filename, exist=r) #endif end function !> Get a unused temporary filename !! Calls posix ' tempnam ' - not recommended, but !! we have no security concerns for this application !! and use here is temporary. !! Works with MinGW function get_temp_filename() result(tempfile) ! use iso_c_binding, only: c_ptr, C_NULL_PTR, c_f_pointer integer, parameter :: MAX_FILENAME_LENGTH = 32768 character(:), allocatable :: tempfile type(c_ptr) :: c_tempfile_ptr character(len=1), pointer :: c_tempfile(:) interface function c_tempnam(dir,pfx) result(tmp) bind(c,name=\"tempnam\") import type(c_ptr), intent(in), value :: dir type(c_ptr), intent(in), value :: pfx type(c_ptr) :: tmp end function c_tempnam subroutine c_free(ptr) BIND(C,name=\"free\") import type(c_ptr), value :: ptr end subroutine c_free end interface c_tempfile_ptr = c_tempnam(C_NULL_PTR, C_NULL_PTR) call c_f_pointer(c_tempfile_ptr,c_tempfile,[MAX_FILENAME_LENGTH]) tempfile = f_string(c_tempfile) call c_free(c_tempfile_ptr) end function get_temp_filename !> Replace file system separators for windows function windows_path(path) result(winpath) character(*), intent(in) :: path character(:), allocatable :: winpath integer :: idx winpath = path idx = index(winpath,' / ') do while(idx > 0) winpath(idx:idx) = ' \\ ' idx = index(winpath,' / ') end do end function windows_path !> Replace file system separators for unix function unix_path(path) result(nixpath) character(*), intent(in) :: path character(:), allocatable :: nixpath integer :: idx nixpath = path idx = index(nixpath,' \\ ') do while(idx > 0) nixpath(idx:idx) = ' / ' idx = index(nixpath,' \\ ') end do end function unix_path !>AUTHOR: fpm(1) contributors !!LICENSE: MIT !> !!##NAME !! getline(3f) - [M_io:READ] read a line of arbintrary length from specified !! LUN into allocatable string (up to system line length limit) !! (LICENSE:PD) !! !!##SYNTAX !! subroutine getline(unit,line,iostat,iomsg) !! !! integer,intent(in) :: unit !! character(len=:),allocatable,intent(out) :: line !! integer,intent(out) :: iostat !! character(len=:), allocatable, optional :: iomsg !! !!##DESCRIPTION !! Read a line of any length up to programming environment maximum !! line length. Requires Fortran 2003+. !! !! It is primarily expected to be used when reading input which will !! then be parsed or echoed. !! !! The input file must have a PAD attribute of YES for the function !! to work properly, which is typically true. !! !! The simple use of a loop that repeatedly re-allocates a character !! variable in addition to reading the input file one buffer at a !! time could (depending on the programming environment used) be !! inefficient, as it could reallocate and allocate memory used for !! the output string with each buffer read. !! !!##OPTIONS !! LINE The line read when IOSTAT returns as zero. !! LUN LUN (Fortran logical I/O unit) number of file open and ready !! to read. !! IOSTAT status returned by READ(IOSTAT=IOS). If not zero, an error !! occurred or an end-of-file or end-of-record was encountered. !! IOMSG error message returned by system when IOSTAT is not zero. !! !!##EXAMPLE !! !! Sample program: !! !! program demo_getline !! use,intrinsic :: iso_fortran_env, only : stdin=>input_unit !! use,intrinsic :: iso_fortran_env, only : iostat_end !! use FPM_filesystem, only : getline !! implicit none !! integer :: iostat !! character(len=:),allocatable :: line, iomsg !! open(unit=stdin,pad=' yes ') !! INFINITE: do !! call getline(stdin,line,iostat,iomsg) !! if(iostat /= 0) exit INFINITE !! write(*,' ( a ) ')' [ '//line//' ] ' !! enddo INFINITE !! if(iostat /= iostat_end)then !! write(*,*)' error reading input : ',iomsg !! endif !! end program demo_getline !! subroutine getline(unit, line, iostat, iomsg) !> Formatted IO unit integer, intent(in) :: unit !> Line to read character(len=:), allocatable, intent(out) :: line !> Status of operation integer, intent(out) :: iostat !> Error message character(len=:), allocatable, optional :: iomsg integer, parameter :: BUFFER_SIZE = 1024 character(len=BUFFER_SIZE) :: buffer character(len=256) :: msg integer :: size integer :: stat allocate(character(len=0) :: line) do read(unit, ' ( a ) ', advance=' no ', iostat=stat, iomsg=msg, size=size) & & buffer if (stat > 0) exit line = line // buffer(:size) if (stat < 0) then if (is_iostat_eor(stat)) then stat = 0 end if exit end if end do if (stat /= 0) then if (present(iomsg)) iomsg = trim(msg) end if iostat = stat end subroutine getline !> delete a file by filename subroutine delete_file(file) character(len=*), intent(in) :: file logical :: exist integer :: unit inquire(file=file, exist=exist) if (exist) then open(file=file, newunit=unit) close(unit, status=\"delete\") end if end subroutine delete_file !> write trimmed character data to a file if it does not exist subroutine warnwrite(fname,data) character(len=*),intent(in) :: fname character(len=*),intent(in) :: data(:) if(.not.exists(fname))then call filewrite(fname,data) else write(stderr,' ( * ( g0 , 1 x )) ')' < INFO > ',fname,& & ' already exists . Not overwriting ' endif end subroutine warnwrite !> procedure to open filename as a sequential \"text\" file subroutine fileopen(filename,lun,ier) character(len=*),intent(in) :: filename integer,intent(out) :: lun integer,intent(out),optional :: ier integer :: ios character(len=256) :: message message=' ' ios=0 if(filename/=' ')then open(file=filename, & & newunit=lun, & & form=' formatted ', & ! FORM = FORMATTED | UNFORMATTED & access=' sequential ', & ! ACCESS = SEQUENTIAL| DIRECT | STREAM & action=' write ', & ! ACTION = READ|WRITE| READWRITE & position=' rewind ', & ! POSITION= ASIS | REWIND | APPEND & status=' new ', & ! STATUS = NEW| REPLACE| OLD| SCRATCH| UNKNOWN & iostat=ios, & & iomsg=message) else lun=stdout ios=0 endif if(ios/=0)then lun=-1 if(present(ier))then ier=ios else call fpm_stop(3,' * fileopen * : '//filename//' : '//trim(message)) endif endif end subroutine fileopen !> simple close of a LUN. On error show message and stop (by default) subroutine fileclose(lun,ier) integer,intent(in) :: lun integer,intent(out),optional :: ier character(len=256) :: message integer :: ios if(lun/=-1)then close(unit=lun,iostat=ios,iomsg=message) if(ios/=0)then if(present(ier))then ier=ios else call fpm_stop(4,' * fileclose * : '//trim(message)) endif endif endif end subroutine fileclose !> procedure to write filedata to file filename subroutine filewrite(filename,filedata) character(len=*),intent(in) :: filename character(len=*),intent(in) :: filedata(:) integer :: lun, i, ios character(len=256) :: message call fileopen(filename,lun) if(lun/=-1)then ! program currently stops on error on open, but might ! want it to continue so -1 (unallowed LUN) indicates error ! write file do i=1,size(filedata) write(lun,' ( a ) ',iostat=ios,iomsg=message)trim(filedata(i)) if(ios/=0)then call fpm_stop(5,' * filewrite * : '//filename//' : '//trim(message)) endif enddo endif ! close file call fileclose(lun) end subroutine filewrite !>AUTHOR: John S. Urban !!LICENSE: Public Domain !> !!##Name !! which(3f) - [M_io:ENVIRONMENT] given a command name find the pathname by searching !! the directories in the environment variable $PATH !! (LICENSE:PD) !! !!##Syntax !! function which(command) result(pathname) !! !! character(len=*),intent(in) :: command !! character(len=:),allocatable :: pathname !! !!##Description !! Given a command name find the first file with that name in the directories !! specified by the environment variable $PATH. !! !!##options !! COMMAND the command to search for !! !!##Returns !! PATHNAME the first pathname found in the current user path. Returns blank !! if the command is not found. !! !!##Example !! !! Sample program: !! !! Checking the error message and counting lines: !! !! program demo_which !! use M_io, only : which !! implicit none !! write(*,*)' ls is ',which(' ls ') !! write(*,*)' dir is ',which(' dir ') !! write(*,*)' install is ',which(' install ') !! end program demo_which !! function which(command) result(pathname) character(len=*),intent(in) :: command character(len=:),allocatable :: pathname, checkon, paths(:), exts(:) integer :: i, j pathname='' call split(get_env(' PATH '),paths,delimiters=merge(' ; ',' : ',separator()==' \\ ')) SEARCH: do i=1,size(paths) checkon=trim(join_path(trim(paths(i)),command)) select case(separator()) case(' / ') if(exists(checkon))then pathname=checkon exit SEARCH endif case(' \\ ') if(exists(checkon))then pathname=checkon exit SEARCH endif if(exists(checkon//' . bat '))then pathname=checkon//' . bat ' exit SEARCH endif if(exists(checkon//' . exe '))then pathname=checkon//' . exe ' exit SEARCH endif call split(get_env(' PATHEXT '),exts,delimiters=' ; ') do j=1,size(exts) if(exists(checkon//' . '//trim(exts(j))))then pathname=checkon//' . '//trim(exts(j)) exit SEARCH endif enddo end select enddo SEARCH end function which !>AUTHOR: fpm(1) contributors !!LICENSE: MIT !> !!##Name !! run(3f) - execute specified system command and selectively echo !! command and output to a file and/or stdout. !! (LICENSE:MIT) !! !!##Syntax !! subroutine run(cmd,echo,exitstat,verbose,redirect) !! !! character(len=*), intent(in) :: cmd !! logical,intent(in),optional :: echo !! integer, intent(out),optional :: exitstat !! logical, intent(in), optional :: verbose !! character(*), intent(in), optional :: redirect !! !!##Description !! Execute the specified system command. Optionally !! !! + echo the command before execution !! + return the system exit status of the command. !! + redirect the output of the command to a file. !! + echo command output to stdout !! !! Calling run(3f) is preferred to direct calls to !! execute_command_line(3f) in the fpm(1) source to provide a standard !! interface where output modes can be specified. !! !!##Options !! CMD System command to execute !! ECHO Whether to echo the command being executed or not !! Defaults to .TRUE. . !! VERBOSE Whether to redirect the command output to a null device or not !! Defaults to .TRUE. . !! REDIRECT Filename to redirect stdout and stderr of the command into. !! If generated it is closed before run(3f) returns. !! EXITSTAT The system exit status of the command when supported by !! the system. If not present and a non-zero status is !! generated program termination occurs. !! !!##Example !! !! Sample program: !! !! Checking the error message and counting lines: !! !! program demo_run !! use fpm_filesystem, only : run !! implicit none !! logical,parameter :: T=.true., F=.false. !! integer :: exitstat !! character(len=:),allocatable :: cmd !! cmd=' ls - ltrasd * . md ' !! call run(cmd) !! call run(cmd,exitstat=exitstat) !! call run(cmd,echo=F) !! call run(cmd,verbose=F) !! end program demo_run !! subroutine run(cmd,echo,exitstat,verbose,redirect) character(len=*), intent(in) :: cmd logical,intent(in),optional :: echo integer, intent(out),optional :: exitstat logical, intent(in), optional :: verbose character(*), intent(in), optional :: redirect integer :: cmdstat character(len=256) :: cmdmsg, iomsg logical :: echo_local, verbose_local character(:), allocatable :: redirect_str character(:), allocatable :: line integer :: stat, fh, iostat if(present(echo))then echo_local=echo else echo_local=.true. end if if(present(verbose))then verbose_local=verbose else verbose_local=.true. end if if (present(redirect)) then if(redirect /= '')then redirect_str = \">\"//redirect//\" 2>&1\" else redirect_str = \"\" endif else if(verbose_local)then ! No redirection but verbose output redirect_str = \"\" else ! No redirection and non-verbose output if (os_is_unix()) then redirect_str = \" >/dev/null 2>&1\" else redirect_str = \" >NUL 2>&1\" end if end if end if if(echo_local) print *, ' + ', cmd !//redirect_str call execute_command_line(cmd//redirect_str, exitstat=stat,cmdstat=cmdstat,cmdmsg=cmdmsg) if(cmdstat /= 0)then write(*,' ( a ) ')' < ERROR > : failed command '//cmd//redirect_str call fpm_stop(1,' * run * : '//trim(cmdmsg)) endif if (verbose_local.and.present(redirect)) then open(newunit=fh,file=redirect,status=' old ',iostat=iostat,iomsg=iomsg) if(iostat == 0)then do call getline(fh, line, iostat) if (iostat /= 0) exit write(*,' ( A ) ') trim(line) end do else write(*,' ( A ) ') trim(iomsg) endif close(fh) end if if (present(exitstat)) then exitstat = stat elseif (stat /= 0) then call fpm_stop(stat,' * run * : Command '//cmd//redirect_str//' returned a non - zero status code ') end if end subroutine run !> Delete directory using system OS remove directory commands subroutine os_delete_dir(is_unix, dir, echo) logical, intent(in) :: is_unix character(len=*), intent(in) :: dir logical, intent(in), optional :: echo if (is_unix) then call run(' rm - rf ' // dir, echo=echo,verbose=.false.) else call run(' rmdir / s / q ' // dir, echo=echo,verbose=.false.) end if end subroutine os_delete_dir !> Determine the path prefix to the local folder. Used for installation, registry etc. function get_local_prefix(os) result(prefix) !> Installation prefix character(len=:), allocatable :: prefix !> Platform identifier integer, intent(in), optional :: os !> Default installation prefix on Unix platforms character(len=*), parameter :: default_prefix_unix = \"/usr/local\" !> Default installation prefix on Windows platforms character(len=*), parameter :: default_prefix_win = \"C:\\\" character(len=:), allocatable :: home if (os_is_unix(os)) then home=get_env(' HOME ','') if (home /= '' ) then prefix = join_path(home, \".local\") else prefix = default_prefix_unix end if else home=get_env(' APPDATA ','') if (home /= '' ) then prefix = join_path(home, \"local\") else prefix = default_prefix_win end if end if end function get_local_prefix !> Returns .true. if provided path is absolute. !> !> `~` not treated as absolute. logical function is_absolute_path(path, is_unix) character(len=*), intent(in) :: path logical, optional, intent(in):: is_unix character(len=*), parameter :: letters = ' ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz ' logical :: is_unix_os if (present(is_unix)) then is_unix_os = is_unix else is_unix_os = os_is_unix() end if if (is_unix_os) then is_absolute_path = path(1:1) == ' / ' else if (len(path) < 2) then is_absolute_path = .false. return end if is_absolute_path = index(letters, path(1:1)) /= 0 .and. path(2:2) == ' : ' end if end function is_absolute_path !> Get the HOME directory on Unix and the %USERPROFILE% directory on Windows. subroutine get_home(home, error) character(len=:), allocatable, intent(out) :: home type(error_t), allocatable, intent(out) :: error if (os_is_unix()) then home=get_env(' HOME ','') if ( home == '' ) then call fatal_error(error, \"Couldn' t retrieve 'HOME' variable \") return end if else home=get_env('USERPROFILE','') if ( home == '' ) then call fatal_error(error, \" Couldn 't retrieve ' % USERPROFILE % ' variable\") return end if end if end subroutine get_home !> Execute command line and return output as a string. subroutine execute_and_read_output(cmd, output, error, verbose) !> Command to execute. character(len=*), intent(in) :: cmd !> Command line output. character(len=:), allocatable, intent(out) :: output !> Error to handle. type(error_t), allocatable, intent(out) :: error !> Print additional information if true. logical, intent(in), optional :: verbose integer :: exitstat, unit, stat character(len=:), allocatable :: cmdmsg, tmp_file, output_line logical :: is_verbose if (present(verbose)) then is_verbose = verbose else is_verbose = .false. end if tmp_file = get_temp_filename() call run(cmd//' > '//tmp_file, exitstat=exitstat, echo=is_verbose) if (exitstat /= 0) call fatal_error(error, ' * run * : '//\"Command failed: ' \"//cmd//\" '. Message: ' \"//trim(cmdmsg)//\" '.\") open(newunit=unit, file=tmp_file, action=' read ', status=' old ') output = '' do call getline(unit, output_line, stat) if (stat /= 0) exit output = output//output_line//' ' end do if (is_verbose) print *, output close(unit, status=' delete ') end !> Ensure a windows path is converted to an 8.3 DOS path if it contains spaces function get_dos_path(path,error) character(len=*), intent(in) :: path type(error_t), allocatable, intent(out) :: error character(len=:), allocatable :: get_dos_path character(:), allocatable :: redirect,screen_output,line integer :: stat,cmdstat,iunit,last ! Non-Windows OS if (get_os_type()/=OS_WINDOWS) then get_dos_path = path return end if ! Trim path first get_dos_path = trim(path) !> No need to convert if there are no spaces has_spaces: if (scan(get_dos_path,' ')>0) then redirect = get_temp_filename() call execute_command_line(' cmd / c for % A in ( \"'//path//'\" ) do @ echo % ~ sA > '//redirect//' 2 > & 1 ',& exitstat=stat,cmdstat=cmdstat) !> Read screen output command_OK: if (cmdstat==0 .and. stat==0) then allocate(character(len=0) :: screen_output) open(newunit=iunit,file=redirect,status=' old ',iostat=stat) if (stat == 0)then do call getline(iunit, line, stat) if (stat /= 0) exit screen_output = screen_output//line//' ' end do ! Close and delete file close(iunit,status=' delete ') else call fatal_error(error,' cannot read temporary file from successful DOS path evaluation ') return endif else command_OK call fatal_error(error,' unsuccessful Windows -> DOS path command ') return end if command_OK get_dos_path = trim(adjustl(screen_output)) endif has_spaces !> Ensure there are no trailing slashes last = len_trim(get_dos_path) if (last>1 .and. get_dos_path(last:last)==' / ' .or. get_dos_path(last:last)==' \\' ) get_dos_path = get_dos_path ( 1 : last - 1 ) end function get_dos_path end module fpm_filesystem","tags":"","url":"sourcefile/fpm_filesystem.f90.html"},{"title":"example.f90 – Fortran-lang/fpm","text":"Source Code !> Implementation of the meta data for an example. !> !> The example data structure is effectively a decorated version of an executable !> and shares most of its properties, except for the defaults and can be !> handled under most circumstances just like any other executable. !> !> A example table can currently have the following fields !> !>```toml !>[[ example ]] !>name = \"string\" !>source-dir = \"path\" !>main = \"file\" !>link = [\"lib\"] !>[example.dependencies] !>``` module fpm_manifest_example use fpm_manifest_dependency , only : dependency_config_t , new_dependencies use fpm_manifest_executable , only : executable_config_t use fpm_error , only : error_t , syntax_error , bad_name_error use tomlf , only : toml_table , toml_key , toml_stat use fpm_toml , only : get_value , get_list implicit none private public :: example_config_t , new_example !> Configuation meta data for an example type , extends ( executable_config_t ) :: example_config_t contains !> Print information on this instance procedure :: info end type example_config_t contains !> Construct a new example configuration from a TOML data structure subroutine new_example ( self , table , error ) !> Instance of the example configuration type ( example_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_table ), pointer :: child call check ( table , error ) if ( allocated ( error )) return call get_value ( table , \"name\" , self % name ) if (. not . allocated ( self % name )) then call syntax_error ( error , \"Could not retrieve example name\" ) return end if if ( bad_name_error ( error , 'example' , self % name )) then return endif call get_value ( table , \"source-dir\" , self % source_dir , \"example\" ) call get_value ( table , \"main\" , self % main , \"main.f90\" ) call get_value ( table , \"dependencies\" , child , requested = . false .) if ( associated ( child )) then call new_dependencies ( self % dependency , child , error = error ) if ( allocated ( error )) return end if call get_list ( table , \"link\" , self % link , error ) if ( allocated ( error )) return end subroutine new_example !> Check local schema for allowed entries subroutine check ( table , error ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_key ), allocatable :: list (:) logical :: name_present integer :: ikey name_present = . false . call table % get_keys ( list ) if ( size ( list ) < 1 ) then call syntax_error ( error , \"Example section does not provide sufficient entries\" ) return end if do ikey = 1 , size ( list ) select case ( list ( ikey )% key ) case default call syntax_error ( error , \"Key \" // list ( ikey )% key // \" is not allowed in example entry\" ) exit case ( \"name\" ) name_present = . true . case ( \"source-dir\" , \"main\" , \"dependencies\" , \"link\" ) continue end select end do if ( allocated ( error )) return if (. not . name_present ) then call syntax_error ( error , \"Example name is not provided, please add a name entry\" ) end if end subroutine check !> Write information on instance subroutine info ( self , unit , verbosity ) !> Instance of the example configuration class ( example_config_t ), intent ( in ) :: self !> Unit for IO integer , intent ( in ) :: unit !> Verbosity of the printout integer , intent ( in ), optional :: verbosity integer :: pr , ii character ( len =* ), parameter :: fmt = '(\"#\", 1x, a, t30, a)' , & & fmti = '(\"#\", 1x, a, t30, i0)' if ( present ( verbosity )) then pr = verbosity else pr = 1 end if if ( pr < 1 ) return write ( unit , fmt ) \"Example target\" if ( allocated ( self % name )) then write ( unit , fmt ) \"- name\" , self % name end if if ( allocated ( self % source_dir )) then if ( self % source_dir /= \"example\" . or . pr > 2 ) then write ( unit , fmt ) \"- source directory\" , self % source_dir end if end if if ( allocated ( self % main )) then if ( self % main /= \"main.f90\" . or . pr > 2 ) then write ( unit , fmt ) \"- example source\" , self % main end if end if if ( allocated ( self % dependency )) then if ( size ( self % dependency ) > 1 . or . pr > 2 ) then write ( unit , fmti ) \"- dependencies\" , size ( self % dependency ) end if do ii = 1 , size ( self % dependency ) call self % dependency ( ii )% info ( unit , pr - 1 ) end do end if end subroutine info end module fpm_manifest_example","tags":"","url":"sourcefile/example.f90.html"},{"title":"fpm_compiler.F90 – Fortran-lang/fpm","text":"Source Code !># Define compiler command options !! !! This module defines compiler options to use for the debug and release builds. ! vendor Fortran C Module output Module include OpenMP Free for OSS ! compiler compiler directory directory ! Gnu gfortran gcc -J -I -fopenmp X ! Intel ifort icc -module -I -qopenmp X ! Intel(Windows) ifort icc /module:path /I /Qopenmp X ! Intel oneAPI ifx icx -module -I -qopenmp X ! PGI pgfortran pgcc -module -I -mp X ! NVIDIA nvfortran nvc -module -I -mp X ! LLVM flang flang clang -module -I -mp X ! LFortran lfortran --- -J -I --openmp X ! Lahey/Futjitsu lfc ? -M -I -openmp ? ! NAG nagfor ? -mdir -I -openmp x ! Cray crayftn craycc -J -I -homp ? ! IBM xlf90 ? -qmoddir -I -qsmp X ! Oracle/Sun ? ? -moddir= -M -xopenmp ? ! Silverfrost FTN95 ftn95 ? ? /MOD_PATH ? ? ! Elbrus ? lcc -J -I -fopenmp ? ! Hewlett Packard ? ? ? ? ? discontinued ! Watcom ? ? ? ? ? discontinued ! PathScale ? ? -module -I -mp discontinued ! G95 ? ? -fmod= -I -fopenmp discontinued ! Open64 ? ? -module -I -mp discontinued ! Unisys ? ? ? ? ? discontinued module fpm_compiler use , intrinsic :: iso_fortran_env , only : stderr => error_unit use fpm_environment , only : & get_os_type , & OS_LINUX , & OS_MACOS , & OS_WINDOWS , & OS_CYGWIN , & OS_SOLARIS , & OS_FREEBSD , & OS_OPENBSD , & OS_UNKNOWN , & library_filename use fpm_filesystem , only : join_path , basename , get_temp_filename , delete_file , unix_path , & & getline , run use fpm_strings , only : split , string_cat , string_t , str_ends_with , str_begins_with_str , & & string_array_contains use fpm_manifest , only : package_config_t use fpm_error , only : error_t , fatal_error use tomlf , only : toml_table use fpm_toml , only : serializable_t , set_string , set_value , toml_stat , get_value use fpm_compile_commands , only : compile_command_t , compile_command_table_t use shlex_module , only : sh_split => split , ms_split , quote => ms_quote implicit none public :: compiler_t , new_compiler , archiver_t , new_archiver , get_macros public :: append_clean_flags , append_clean_flags_array public :: debug enum , bind ( C ) enumerator :: & id_unknown , & id_gcc , & id_f95 , & id_caf , & id_intel_classic_nix , & id_intel_classic_mac , & id_intel_classic_windows , & id_intel_llvm_nix , & id_intel_llvm_windows , & id_intel_llvm_unknown , & id_pgi , & id_nvhpc , & id_nag , & id_flang , & id_flang_new , & id_f18 , & id_ibmxl , & id_cray , & id_lahey , & id_lfortran end enum integer , parameter :: compiler_enum = kind ( id_unknown ) !> Definition of compiler object type , extends ( serializable_t ) :: compiler_t !> Identifier of the compiler integer ( compiler_enum ) :: id = id_unknown !> Path to the Fortran compiler character ( len = :), allocatable :: fc !> Path to the C compiler character ( len = :), allocatable :: cc !> Path to the C++ compiler character ( len = :), allocatable :: cxx !> Print all commands logical :: echo = . true . !> Verbose output of command logical :: verbose = . true . contains !> Get default compiler flags procedure :: get_default_flags !> Get flag for module output directories procedure :: get_module_flag !> Get flag for include directories procedure :: get_include_flag !> Get feature flag procedure :: get_feature_flag !> Get flags for the main linking command procedure :: get_main_flags !> Get library export flags procedure :: get_export_flags !> Get library install name flags procedure :: get_install_name_flags !> Generate header padding flags for macOS executables procedure :: get_headerpad_flags !> Compile a Fortran object procedure :: compile_fortran !> Compile a C object procedure :: compile_c !> Compile a CPP object procedure :: compile_cpp !> Link a shared library procedure :: link_shared !> Link executable procedure :: link => link_executable !> Check whether compiler is recognized procedure :: is_unknown !> Check whether this is an Intel compiler procedure :: is_intel !> Check whether this is a GNU compiler procedure :: is_gnu !> Enumerate libraries, based on compiler and platform procedure :: enumerate_libraries !> Serialization interface procedure :: serializable_is_same => compiler_is_same procedure :: dump_to_toml => compiler_dump procedure :: load_from_toml => compiler_load !> Fortran feature support procedure :: check_fortran_source_runs procedure :: check_flags_supported procedure :: with_xdp procedure :: with_qp !> Return compiler name procedure :: name => compiler_name end type compiler_t !> Definition of archiver object type , extends ( serializable_t ) :: archiver_t !> Path to archiver character ( len = :), allocatable :: ar !> Use response files to pass arguments logical :: use_response_file = . false . !> Print all command logical :: echo = . true . !> Verbose output of command logical :: verbose = . true . contains !> Create static archive procedure :: make_archive !> Serialization interface procedure :: serializable_is_same => ar_is_same procedure :: dump_to_toml procedure :: load_from_toml end type archiver_t !> Create debug printout interface debug module procedure :: debug_compiler module procedure :: debug_archiver end interface debug character ( * ), parameter :: & flag_gnu_coarray = \" -fcoarray=single\" , & flag_gnu_backtrace = \" -fbacktrace\" , & flag_gnu_opt = \" -O3 -funroll-loops\" , & flag_gnu_debug = \" -g\" , & flag_gnu_pic = \" -fPIC\" , & flag_gnu_warn = \" -Wall -Wextra\" , & flag_gnu_check = \" -fcheck=bounds -fcheck=array-temps\" , & flag_gnu_limit = \" -fmax-errors=1\" , & flag_gnu_external = \" -Wimplicit-interface\" , & flag_gnu_openmp = \" -fopenmp\" , & flag_gnu_no_implicit_typing = \" -fimplicit-none\" , & flag_gnu_no_implicit_external = \" -Werror=implicit-interface\" , & flag_gnu_free_form = \" -ffree-form\" , & flag_gnu_fixed_form = \" -ffixed-form\" character ( * ), parameter :: & flag_pgi_backslash = \" -Mbackslash\" , & flag_pgi_traceback = \" -traceback\" , & flag_pgi_debug = \" -g\" , & flag_pgi_check = \" -Mbounds -Mchkptr -Mchkstk\" , & flag_pgi_warn = \" -Minform=inform\" , & flag_pgi_openmp = \" -mp\" , & flag_pgi_free_form = \" -Mfree\" , & flag_pgi_fixed_form = \" -Mfixed\" character ( * ), parameter :: & flag_ibmxl_backslash = \" -qnoescape\" character ( * ), parameter :: & flag_intel_backtrace = \" -traceback\" , & flag_intel_warn = \" -warn all\" , & flag_intel_check = \" -check all\" , & flag_intel_debug = \" -O0 -g\" , & flag_intel_opt = \" -O3\" , & flag_intel_fp = \" -fp-model precise -pc64\" , & flag_intel_align = \" -align all\" , & flag_intel_limit = \" -error-limit 1\" , & flag_intel_pthread = \" -reentrancy threaded\" , & flag_intel_nogen = \" -nogen-interfaces\" , & flag_intel_byterecl = \" -assume byterecl\" , & flag_intel_openmp = \" -qopenmp\" , & flag_intel_free_form = \" -free\" , & flag_intel_fixed_form = \" -fixed\" , & flag_intel_standard_compliance = \" -standard-semantics\" , & flag_intel_unknown_cmd_err = \" -diag-error 10006\" character ( * ), parameter :: & flag_intel_llvm_check = \" -check all,nouninit\" character ( * ), parameter :: & flag_intel_backtrace_win = \" /traceback\" , & flag_intel_warn_win = \" /warn:all\" , & flag_intel_check_win = \" /check:all\" , & flag_intel_debug_win = \" /Od /Z7\" , & flag_intel_opt_win = \" /O3\" , & flag_intel_fp_win = \" /fp:precise\" , & flag_intel_align_win = \" /align:all\" , & flag_intel_limit_win = \" /error-limit:1\" , & flag_intel_pthread_win = \" /reentrancy:threaded\" , & flag_intel_nogen_win = \" /nogen-interfaces\" , & flag_intel_byterecl_win = \" /assume:byterecl\" , & flag_intel_openmp_win = \" /Qopenmp\" , & flag_intel_free_form_win = \" /free\" , & flag_intel_fixed_form_win = \" /fixed\" , & flag_intel_standard_compliance_win = \" /standard-semantics\" , & flag_intel_unknown_cmd_err_win = \" /Qdiag-error:10006\" character ( * ), parameter :: & flag_nag_coarray = \" -coarray=single\" , & flag_nag_pic = \" -PIC\" , & flag_nag_check = \" -C\" , & flag_nag_debug = \" -g -O0\" , & flag_nag_opt = \" -O4\" , & flag_nag_backtrace = \" -gline\" , & flag_nag_openmp = \" -openmp\" , & flag_nag_free_form = \" -free\" , & flag_nag_fixed_form = \" -fixed\" , & flag_nag_no_implicit_typing = \" -u\" character ( * ), parameter :: & flag_lfortran_opt = \" --fast\" , & flag_lfortran_openmp = \" --openmp\" , & flag_lfortran_implicit_typing = \" --implicit-typing\" , & flag_lfortran_implicit_external = \" --implicit-interface\" , & flag_lfortran_fixed_form = \" --fixed-form\" character ( * ), parameter :: & flag_cray_no_implicit_typing = \" -dl\" , & flag_cray_implicit_typing = \" -el\" , & flag_cray_fixed_form = \" -ffixed\" , & flag_cray_free_form = \" -ffree\" character ( * ), parameter :: & flag_flang_new_openmp = \" -fopenmp\" contains function get_default_flags ( self , release ) result ( flags ) class ( compiler_t ), intent ( in ) :: self logical , intent ( in ) :: release character ( len = :), allocatable :: flags character ( len = :), allocatable :: pic_flag if ( release ) then call get_release_compile_flags ( self % id , flags ) else call get_debug_compile_flags ( self % id , flags ) end if ! Append position-independent code (PIC) flag, that is necessary ! building shared libraries select case ( self % id ) case ( id_gcc , id_f95 , id_caf , id_flang , id_flang_new , id_f18 , id_lfortran , & id_intel_classic_nix , id_intel_classic_mac , id_intel_llvm_nix , & id_pgi , id_nvhpc , id_nag , id_cray , id_ibmxl ) pic_flag = \" -fPIC\" case ( id_intel_classic_windows , id_intel_llvm_windows ) pic_flag = \"\" ! Windows does not use -fPIC case default pic_flag = \" -fPIC\" ! Conservative fallback end select flags = flags // pic_flag end function get_default_flags subroutine get_release_compile_flags ( id , flags ) integer ( compiler_enum ), intent ( in ) :: id character ( len = :), allocatable , intent ( out ) :: flags select case ( id ) case default flags = \"\" case ( id_caf ) flags = & flag_gnu_opt // & flag_gnu_external // & flag_gnu_pic // & flag_gnu_limit case ( id_gcc ) flags = & flag_gnu_opt // & flag_gnu_external // & flag_gnu_pic // & flag_gnu_limit // & flag_gnu_coarray case ( id_f95 ) flags = & flag_gnu_opt // & flag_gnu_external // & flag_gnu_pic // & flag_gnu_limit case ( id_nvhpc ) flags = & flag_pgi_backslash case ( id_ibmxl ) flags = & flag_ibmxl_backslash case ( id_intel_classic_nix ) flags = & flag_intel_opt // & flag_intel_fp // & flag_intel_align // & flag_intel_limit // & flag_intel_pthread // & flag_intel_nogen // & flag_intel_byterecl case ( id_intel_classic_mac ) flags = & flag_intel_opt // & flag_intel_fp // & flag_intel_align // & flag_intel_limit // & flag_intel_pthread // & flag_intel_nogen // & flag_intel_byterecl case ( id_intel_classic_windows ) flags = & flag_intel_opt_win // & flag_intel_fp_win // & flag_intel_align_win // & flag_intel_limit_win // & flag_intel_pthread_win // & flag_intel_nogen_win // & flag_intel_byterecl_win case ( id_intel_llvm_nix ) flags = & flag_intel_opt // & flag_intel_fp // & flag_intel_align // & flag_intel_limit // & flag_intel_pthread // & flag_intel_nogen // & flag_intel_byterecl case ( id_intel_llvm_windows ) flags = & flag_intel_opt_win // & flag_intel_fp_win // & flag_intel_align_win // & flag_intel_limit_win // & flag_intel_pthread_win // & flag_intel_nogen_win // & flag_intel_byterecl_win case ( id_nag ) flags = & flag_nag_opt // & flag_nag_coarray // & flag_nag_pic case ( id_lfortran ) flags = & flag_lfortran_opt end select end subroutine get_release_compile_flags subroutine get_debug_compile_flags ( id , flags ) integer ( compiler_enum ), intent ( in ) :: id character ( len = :), allocatable , intent ( out ) :: flags select case ( id ) case default flags = \"\" case ( id_caf ) flags = & flag_gnu_warn // & flag_gnu_pic // & flag_gnu_limit // & flag_gnu_debug // & flag_gnu_check // & flag_gnu_backtrace case ( id_gcc ) flags = & flag_gnu_warn // & flag_gnu_pic // & flag_gnu_limit // & flag_gnu_debug // & flag_gnu_check // & flag_gnu_backtrace // & flag_gnu_coarray case ( id_f95 ) flags = & flag_gnu_warn // & flag_gnu_pic // & flag_gnu_limit // & flag_gnu_debug // & flag_gnu_check // & ' -Wno-maybe-uninitialized -Wno-uninitialized' // & flag_gnu_backtrace case ( id_nvhpc ) flags = & flag_pgi_warn // & flag_pgi_backslash // & flag_pgi_check // & flag_pgi_traceback case ( id_ibmxl ) flags = & flag_ibmxl_backslash case ( id_intel_classic_nix ) flags = & flag_intel_warn // & flag_intel_check // & flag_intel_limit // & flag_intel_debug // & flag_intel_byterecl // & flag_intel_backtrace case ( id_intel_classic_mac ) flags = & flag_intel_warn // & flag_intel_check // & flag_intel_limit // & flag_intel_debug // & flag_intel_byterecl // & flag_intel_backtrace case ( id_intel_classic_windows ) flags = & flag_intel_warn_win // & flag_intel_check_win // & flag_intel_limit_win // & flag_intel_debug_win // & flag_intel_byterecl_win // & flag_intel_backtrace_win case ( id_intel_llvm_nix ) flags = & flag_intel_unknown_cmd_err // & flag_intel_llvm_check // & flag_intel_limit // & flag_intel_debug // & flag_intel_byterecl // & flag_intel_backtrace case ( id_intel_llvm_windows ) flags = & flag_intel_unknown_cmd_err_win // & flag_intel_check_win // & flag_intel_limit_win // & flag_intel_debug_win // & flag_intel_byterecl_win case ( id_nag ) flags = & flag_nag_debug // & flag_nag_check // & flag_nag_backtrace // & flag_nag_coarray // & flag_nag_pic case ( id_lfortran ) flags = \"\" end select end subroutine get_debug_compile_flags pure subroutine set_cpp_preprocessor_flags ( id , flags ) integer ( compiler_enum ), intent ( in ) :: id character ( len = :), allocatable , intent ( inout ) :: flags character ( len = :), allocatable :: flag_cpp_preprocessor !> Modify the flag_cpp_preprocessor on the basis of the compiler. select case ( id ) case default flag_cpp_preprocessor = \"\" case ( id_caf , id_gcc , id_f95 , id_nvhpc ) flag_cpp_preprocessor = \"-cpp\" case ( id_intel_classic_windows , id_intel_llvm_windows ) flag_cpp_preprocessor = \"/fpp\" case ( id_intel_classic_nix , id_intel_classic_mac , id_intel_llvm_nix , id_nag ) flag_cpp_preprocessor = \"-fpp\" case ( id_lfortran ) flag_cpp_preprocessor = \"--cpp\" end select flags = flag_cpp_preprocessor // flags end subroutine set_cpp_preprocessor_flags !> This function will parse and read the macros list and !> return them as defined flags. function get_macros ( id , macros_list , version ) result ( macros ) integer ( compiler_enum ), intent ( in ) :: id character ( len = :), allocatable , intent ( in ) :: version type ( string_t ), allocatable , intent ( in ) :: macros_list (:) character ( len = :), allocatable :: macros character ( len = :), allocatable :: macro_definition_symbol character (:), allocatable :: valued_macros (:) integer :: i if (. not . allocated ( macros_list )) then macros = \"\" return end if !> Set macro defintion symbol on the basis of compiler used select case ( id ) case default macro_definition_symbol = \" -D\" case ( id_intel_classic_windows , id_intel_llvm_windows ) macro_definition_symbol = \" /D\" end select !> Check if macros are not allocated. if (. not . allocated ( macros )) then macros = \"\" end if do i = 1 , size ( macros_list ) !> Split the macro name and value. call split ( macros_list ( i )% s , valued_macros , delimiters = \"=\" ) if ( size ( valued_macros ) > 1 ) then !> Check if the value of macro starts with '{' character. if ( str_begins_with_str ( trim ( valued_macros ( size ( valued_macros ))), \"{\" )) then !> Check if the value of macro ends with '}' character. if ( str_ends_with ( trim ( valued_macros ( size ( valued_macros ))), \"}\" )) then !> Check if the string contains \"version\" as substring. if ( index ( valued_macros ( size ( valued_macros )), \"version\" ) /= 0 ) then !> These conditions are placed in order to ensure proper spacing between the macros. macros = macros // macro_definition_symbol // trim ( valued_macros ( 1 )) // '=' // version cycle end if end if end if end if macros = macros // macro_definition_symbol // macros_list ( i )% s end do end function get_macros function get_include_flag ( self , path ) result ( flags ) class ( compiler_t ), intent ( in ) :: self character ( len =* ), intent ( in ) :: path character ( len = :), allocatable :: flags select case ( self % id ) case default flags = \"-I \" // path case ( id_caf , id_gcc , id_f95 , id_cray , id_nvhpc , id_pgi , & & id_flang , id_flang_new , id_f18 , & & id_intel_classic_nix , id_intel_classic_mac , & & id_intel_llvm_nix , id_lahey , id_nag , id_ibmxl , & & id_lfortran ) flags = \"-I \" // path case ( id_intel_classic_windows , id_intel_llvm_windows ) flags = \"/I\" // path end select end function get_include_flag function get_module_flag ( self , path ) result ( flags ) class ( compiler_t ), intent ( in ) :: self character ( len =* ), intent ( in ) :: path character ( len = :), allocatable :: flags select case ( self % id ) case default flags = \"-module \" // path case ( id_caf , id_gcc , id_f95 , id_cray , id_lfortran ) flags = \"-J \" // path case ( id_nvhpc , id_pgi , id_flang ) flags = \"-module \" // path case ( id_flang_new , id_f18 ) flags = \"-module-dir \" // path case ( id_intel_classic_nix , id_intel_classic_mac , & & id_intel_llvm_nix ) flags = \"-module \" // path case ( id_intel_classic_windows , id_intel_llvm_windows ) flags = \"/module:\" // path case ( id_lahey ) flags = \"-M \" // path case ( id_nag ) flags = \"-mdir \" // path case ( id_ibmxl ) flags = \"-qmoddir \" // path end select end function get_module_flag function get_shared_flag ( self ) result ( shared_flag ) class ( compiler_t ), intent ( in ) :: self character ( len = :), allocatable :: shared_flag select case ( self % id ) case default shared_flag = \"-shared\" case ( id_gcc , id_f95 , id_flang , id_flang_new , id_lfortran ) shared_flag = \"-shared\" case ( id_intel_classic_nix , id_intel_llvm_nix , id_pgi , id_nvhpc ) shared_flag = \"-shared\" case ( id_intel_classic_windows , id_intel_llvm_windows ) shared_flag = \"/DLL\" case ( id_nag ) shared_flag = \"-Wl,-shared\" case ( id_ibmxl ) shared_flag = \"-qmkshrobj\" case ( id_cray , id_lahey ) shared_flag = \"\" ! Needs special handling end select end function get_shared_flag function get_feature_flag ( self , feature ) result ( flags ) class ( compiler_t ), intent ( in ) :: self character ( len =* ), intent ( in ) :: feature character ( len = :), allocatable :: flags flags = \"\" select case ( feature ) case ( \"no-implicit-typing\" ) select case ( self % id ) case ( id_caf , id_gcc , id_f95 ) flags = flag_gnu_no_implicit_typing case ( id_nag ) flags = flag_nag_no_implicit_typing case ( id_cray ) flags = flag_cray_no_implicit_typing end select case ( \"implicit-typing\" ) select case ( self % id ) case ( id_cray ) flags = flag_cray_implicit_typing case ( id_lfortran ) flags = flag_lfortran_implicit_typing end select case ( \"no-implicit-external\" ) select case ( self % id ) case ( id_caf , id_gcc , id_f95 ) flags = flag_gnu_no_implicit_external end select case ( \"implicit-external\" ) select case ( self % id ) case ( id_lfortran ) flags = flag_lfortran_implicit_external end select case ( \"free-form\" ) select case ( self % id ) case ( id_caf , id_gcc , id_f95 ) flags = flag_gnu_free_form case ( id_pgi , id_nvhpc , id_flang ) flags = flag_pgi_free_form case ( id_nag ) flags = flag_nag_free_form case ( id_intel_classic_nix , id_intel_classic_mac , id_intel_llvm_nix , & & id_intel_llvm_unknown ) flags = flag_intel_free_form case ( id_intel_classic_windows , id_intel_llvm_windows ) flags = flag_intel_free_form_win case ( id_cray ) flags = flag_cray_free_form end select case ( \"fixed-form\" ) select case ( self % id ) case ( id_caf , id_gcc , id_f95 ) flags = flag_gnu_fixed_form case ( id_pgi , id_nvhpc , id_flang ) flags = flag_pgi_fixed_form case ( id_nag ) flags = flag_nag_fixed_form case ( id_intel_classic_nix , id_intel_classic_mac , id_intel_llvm_nix , & & id_intel_llvm_unknown ) flags = flag_intel_fixed_form case ( id_intel_classic_windows , id_intel_llvm_windows ) flags = flag_intel_fixed_form_win case ( id_cray ) flags = flag_cray_fixed_form case ( id_lfortran ) flags = flag_lfortran_fixed_form end select case ( \"default-form\" ) continue case default error stop \"Unknown feature '\" // feature // \"'\" end select end function get_feature_flag !> Get special flags for the main linker subroutine get_main_flags ( self , language , flags ) class ( compiler_t ), intent ( in ) :: self character ( len =* ), intent ( in ) :: language character ( len = :), allocatable , intent ( out ) :: flags flags = \"\" select case ( language ) case ( \"fortran\" ) flags = \"\" case ( \"c\" ) ! If the main program is on a C/C++ source, the Intel Fortran compiler requires option ! -nofor-main to avoid \"duplicate main\" errors. ! https://stackoverflow.com/questions/36221612/p3dfft-compilation-ifort-compiler-error-multiple-definiton-of-main select case ( self % id ) case ( id_intel_classic_nix , id_intel_classic_mac , id_intel_llvm_nix ) flags = '-nofor-main' case ( id_intel_classic_windows , id_intel_llvm_windows ) flags = '/nofor-main' case ( id_pgi , id_nvhpc ) flags = '-Mnomain' end select case ( \"c++\" , \"cpp\" , \"cxx\" ) select case ( self % id ) case ( id_intel_classic_nix , id_intel_classic_mac , id_intel_llvm_nix ) flags = '-nofor-main' case ( id_intel_classic_windows , id_intel_llvm_windows ) flags = '/nofor-main' case ( id_pgi , id_nvhpc ) flags = '-Mnomain' end select case default error stop \"Unknown language '\" // language // '\", try \"fortran\", \"c\", \"c++\"' end select end subroutine get_main_flags subroutine get_default_c_compiler ( f_compiler , c_compiler ) character ( len =* ), intent ( in ) :: f_compiler character ( len = :), allocatable , intent ( out ) :: c_compiler integer ( compiler_enum ) :: id id = get_compiler_id ( f_compiler ) select case ( id ) case ( id_intel_classic_nix , id_intel_classic_mac , id_intel_classic_windows ) c_compiler = 'icc' case ( id_intel_llvm_nix , id_intel_llvm_windows ) c_compiler = 'icx' case ( id_flang , id_flang_new , id_f18 ) c_compiler = 'clang' case ( id_ibmxl ) c_compiler = 'xlc' case ( id_lfortran ) c_compiler = 'cc' case ( id_gcc ) c_compiler = 'gcc' case default ! Fall-back to using Fortran compiler c_compiler = f_compiler end select end subroutine get_default_c_compiler !> Get C++ Compiler. subroutine get_default_cxx_compiler ( f_compiler , cxx_compiler ) character ( len =* ), intent ( in ) :: f_compiler character ( len = :), allocatable , intent ( out ) :: cxx_compiler integer ( compiler_enum ) :: id id = get_compiler_id ( f_compiler ) select case ( id ) case ( id_intel_classic_nix , id_intel_classic_mac , id_intel_classic_windows ) cxx_compiler = 'icpc' case ( id_intel_llvm_nix , id_intel_llvm_windows ) cxx_compiler = 'icpx' case ( id_flang , id_flang_new , id_f18 ) cxx_compiler = 'clang++' case ( id_ibmxl ) cxx_compiler = 'xlc++' case ( id_lfortran ) cxx_compiler = 'cc' case ( id_gcc ) cxx_compiler = 'g++' case default ! Fall-back to using Fortran compiler cxx_compiler = f_compiler end select end subroutine get_default_cxx_compiler function get_compiler_id ( compiler ) result ( id ) character ( len =* ), intent ( in ) :: compiler integer ( kind = compiler_enum ) :: id character ( len = :), allocatable :: full_command , full_command_parts (:), command , output integer :: stat , io ! Check whether we are dealing with an MPI compiler wrapper first if ( check_compiler ( compiler , \"mpifort\" ) & & . or . check_compiler ( compiler , \"mpif90\" ) & & . or . check_compiler ( compiler , \"mpif77\" )) then output = get_temp_filename () call run ( compiler // \" -show > \" // output // \" 2>&1\" , & & echo = . false ., exitstat = stat ) if ( stat == 0 ) then open ( file = output , newunit = io , iostat = stat ) if ( stat == 0 ) call getline ( io , full_command , stat ) close ( io , iostat = stat ) ! If we get a command from the wrapper, we will try to identify it call split ( full_command , full_command_parts , delimiters = ' ' ) if ( size ( full_command_parts ) > 0 ) then command = trim ( full_command_parts ( 1 )) endif if ( allocated ( command )) then id = get_id ( command ) if ( id /= id_unknown ) return end if end if end if id = get_id ( compiler ) end function get_compiler_id function get_id ( compiler ) result ( id ) character ( len =* ), intent ( in ) :: compiler integer ( kind = compiler_enum ) :: id if ( check_compiler ( compiler , \"gfortran\" )) then id = id_gcc return end if if ( check_compiler ( compiler , \"f95\" )) then id = id_f95 return end if if ( check_compiler ( compiler , \"caf\" )) then id = id_caf return end if if ( check_compiler ( compiler , \"ifort\" )) then select case ( get_os_type ()) case default id = id_intel_classic_nix case ( OS_MACOS ) id = id_intel_classic_mac case ( OS_WINDOWS , OS_CYGWIN ) id = id_intel_classic_windows end select return end if if ( check_compiler ( compiler , \"ifx\" )) then select case ( get_os_type ()) case default id = id_intel_llvm_nix case ( OS_WINDOWS , OS_CYGWIN ) id = id_intel_llvm_windows end select return end if if ( check_compiler ( compiler , \"nvfortran\" )) then id = id_nvhpc return end if if ( check_compiler ( compiler , \"pgfortran\" ) & & . or . check_compiler ( compiler , \"pgf90\" ) & & . or . check_compiler ( compiler , \"pgf95\" )) then id = id_pgi return end if if ( check_compiler ( compiler , \"nagfor\" )) then id = id_nag return end if if ( check_compiler ( compiler , \"flang-new\" )) then id = id_flang_new return end if if ( check_compiler ( compiler , \"f18\" )) then id = id_f18 return end if if ( check_compiler ( compiler , \"flang\" )) then id = id_flang return end if if ( check_compiler ( compiler , \"xlf90\" )) then id = id_ibmxl return end if if ( check_compiler ( compiler , \"crayftn\" )) then id = id_cray return end if if ( check_compiler ( compiler , \"lfc\" )) then id = id_lahey return end if if ( check_compiler ( compiler , \"lfortran\" )) then id = id_lfortran return end if id = id_unknown end function get_id function check_compiler ( compiler , expected ) result ( match ) character ( len =* ), intent ( in ) :: compiler character ( len =* ), intent ( in ) :: expected logical :: match match = compiler == expected if (. not . match ) then match = index ( basename ( compiler ), expected ) > 0 end if end function check_compiler pure function is_unknown ( self ) class ( compiler_t ), intent ( in ) :: self logical :: is_unknown is_unknown = self % id == id_unknown end function is_unknown pure logical function is_intel ( self ) class ( compiler_t ), intent ( in ) :: self is_intel = any ( self % id == [ id_intel_classic_nix , id_intel_classic_mac , id_intel_classic_windows , & id_intel_llvm_nix , id_intel_llvm_windows , id_intel_llvm_unknown ]) end function is_intel pure logical function is_gnu ( self ) class ( compiler_t ), intent ( in ) :: self is_gnu = any ( self % id == [ id_f95 , id_gcc , id_caf ]) end function is_gnu !> !> Enumerate libraries, based on compiler and platform !> function enumerate_libraries ( self , prefix , libs ) result ( r ) class ( compiler_t ), intent ( in ) :: self character ( len =* ), intent ( in ) :: prefix type ( string_t ), intent ( in ) :: libs (:) character ( len = :), allocatable :: r character ( len = :), allocatable :: joined if ( size ( libs ) == 0 ) then r = prefix return end if select case ( self % id ) case ( id_intel_classic_windows , id_intel_llvm_windows ) ! Windows Intel uses `.lib` files directly joined = string_cat ( libs , \".lib \" ) // \".lib\" r = trim ( prefix ) // \" \" // trim ( joined ) case ( id_nag , id_ibmxl ) ! NAG and IBMXL need -Wl, wrapper around linker flags joined = string_cat ( libs , \" -Wl,\" ) r = trim ( prefix ) // \" -Wl,\" // trim ( joined ) case default ! Generic Unix-style linker flags: use `-lfoo` joined = string_cat ( libs , \" -l\" ) r = trim ( prefix ) // \" -l\" // trim ( joined ) end select end function enumerate_libraries !> !> Generate library export flags for a shared library build !> function get_export_flags ( self , target_dir , target_name ) result ( export_flags ) !> Instance of the compiler class ( compiler_t ), intent ( in ) :: self !> Path and package name character ( len =* ), intent ( in ) :: target_dir , target_name character ( len = :), allocatable :: export_flags character ( len = :), allocatable :: implib_path , def_path ! Only apply on Windows if ( get_os_type () /= OS_WINDOWS ) then export_flags = \"\" return end if select case ( self % id ) case ( id_gcc , id_caf , id_f95 ) ! GNU-based: emit both import library and def file implib_path = quote ( join_path ( target_dir , target_name // \".dll.a\" ) , for_cmd = . true .) def_path = quote ( join_path ( target_dir , target_name // \".def\" ) , for_cmd = . true .) export_flags = \" -Wl,--out-implib,\" // implib_path // & \" -Wl,--output-def,\" // def_path case ( id_intel_classic_windows , id_intel_llvm_windows ) ! Intel/MSVC-style implib_path = quote ( join_path ( target_dir , target_name // \".lib\" ) , for_cmd = . true .) def_path = quote ( join_path ( target_dir , target_name // \".def\" ) , for_cmd = . true .) export_flags = \" /IMPLIB:\" // implib_path // & \" /DEF:\" // def_path case default export_flags = \"\" ! Do nothing elsewhere end select end function get_export_flags !> !> Generate `install_name` flag for a shared library build on macOS !> function get_install_name_flags ( self , target_dir , target_name ) result ( flags ) class ( compiler_t ), intent ( in ) :: self character ( len =* ), intent ( in ) :: target_dir , target_name character ( len = :), allocatable :: flags character ( len = :), allocatable :: library_file if ( get_os_type () /= OS_MACOS ) then flags = \"\" return end if ! Shared library basename (e.g., libfoo.dylib) if ( str_ends_with ( target_name , \".dylib\" )) then library_file = target_name else library_file = library_filename ( target_name ,. true .,. false ., OS_MACOS ) end if flags = \" -Wl,-install_name,@rpath/\" // library_file end function get_install_name_flags !> !> Generate header padding flags for install_name_tool compatibility on macOS !> function get_headerpad_flags ( self ) result ( flags ) class ( compiler_t ), intent ( in ) :: self character ( len = :), allocatable :: flags if ( get_os_type () /= OS_MACOS ) then flags = \"\" return end if ! Reserve enough space in the Mach-O header to safely add two install_name or rpath later flags = \" -Wl,-headerpad,0x200\" end function get_headerpad_flags !> Create new compiler instance subroutine new_compiler ( self , fc , cc , cxx , echo , verbose ) !> New instance of the compiler type ( compiler_t ), intent ( out ) :: self !> Fortran compiler name or path character ( len =* ), intent ( in ) :: fc !> C compiler name or path character ( len =* ), intent ( in ) :: cc !> C++ Compiler name or path character ( len =* ), intent ( in ) :: cxx !> Echo compiler command logical , intent ( in ) :: echo !> Verbose mode: dump compiler output logical , intent ( in ) :: verbose self % id = get_compiler_id ( fc ) self % echo = echo self % verbose = verbose self % fc = fc if ( len_trim ( cc ) > 0 ) then self % cc = cc else call get_default_c_compiler ( self % fc , self % cc ) end if if ( len_trim ( cxx ) > 0 ) then self % cxx = cxx else call get_default_cxx_compiler ( self % fc , self % cxx ) end if end subroutine new_compiler !> Create new archiver instance subroutine new_archiver ( self , ar , echo , verbose ) !> New instance of the archiver type ( archiver_t ), intent ( out ) :: self !> User provided archiver command character ( len =* ), intent ( in ) :: ar !> Echo compiler command logical , intent ( in ) :: echo !> Verbose mode: dump compiler output logical , intent ( in ) :: verbose integer :: estat , os_type character ( len =* ), parameter :: arflags = \" -rs \" , libflags = \" /OUT:\" if ( len_trim ( ar ) > 0 ) then ! Check first for ar-like commands if ( check_compiler ( ar , \"ar\" )) then self % ar = ar // arflags end if ! Check for lib-like commands if ( check_compiler ( ar , \"lib\" )) then self % ar = ar // libflags end if ! Fallback and assume ar-like behaviour self % ar = ar // arflags else os_type = get_os_type () if ( os_type /= OS_WINDOWS . and . os_type /= OS_UNKNOWN ) then self % ar = \"ar\" // arflags else ! Attempt \"ar\" call execute_command_line ( \"ar --version > \" // get_temp_filename () // \" 2>&1\" , & & exitstat = estat ) if ( estat == 0 ) then self % ar = \"ar\" // arflags else ! Then \"gcc-ar\" call execute_command_line ( \"gcc-ar --version > \" // get_temp_filename () // \" 2>&1\" , & & exitstat = estat ) if ( estat /= 0 ) then self % ar = \"lib\" // libflags else self % ar = \"gcc-ar\" // arflags end if endif end if end if self % use_response_file = os_type == OS_WINDOWS self % echo = echo self % verbose = verbose end subroutine new_archiver !> Compile a Fortran object subroutine compile_fortran ( self , input , output , args , log_file , stat , table , dry_run ) !> Instance of the compiler object class ( compiler_t ), intent ( in ) :: self !> Source file input character ( len =* ), intent ( in ) :: input !> Output file of object character ( len =* ), intent ( in ) :: output !> Arguments for compiler character ( len =* ), intent ( in ) :: args !> Compiler output log file character ( len =* ), intent ( in ) :: log_file !> Status flag integer , intent ( out ) :: stat !> Optional compile_commands table type ( compile_command_table_t ), optional , intent ( inout ) :: table !> Optional mocking logical , optional , intent ( in ) :: dry_run character ( len = :), allocatable :: command type ( error_t ), allocatable :: error logical :: mock ! Check if we're actually building this file mock = . false . if ( present ( dry_run )) mock = dry_run ! Set command command = self % fc // \" -c \" // input // \" \" // args // \" -o \" // output ! Execute command if (. not . mock ) then call run ( command , echo = self % echo , verbose = self % verbose , redirect = log_file , exitstat = stat ) if ( stat /= 0 ) return endif ! Optionally register compile command if ( present ( table )) then call table % register ( command , get_os_type (), error ) stat = merge ( - 1 , 0 , allocated ( error )) endif end subroutine compile_fortran !> Compile a C object subroutine compile_c ( self , input , output , args , log_file , stat , table , dry_run ) !> Instance of the compiler object class ( compiler_t ), intent ( in ) :: self !> Source file input character ( len =* ), intent ( in ) :: input !> Output file of object character ( len =* ), intent ( in ) :: output !> Arguments for compiler character ( len =* ), intent ( in ) :: args !> Compiler output log file character ( len =* ), intent ( in ) :: log_file !> Status flag integer , intent ( out ) :: stat !> Optional compile_commands table type ( compile_command_table_t ), optional , intent ( inout ) :: table !> Optional mocking logical , optional , intent ( in ) :: dry_run character ( len = :), allocatable :: command type ( error_t ), allocatable :: error logical :: mock ! Check if we're actually building this file mock = . false . if ( present ( dry_run )) mock = dry_run ! Set command command = self % cc // \" -c \" // input // \" \" // args // \" -o \" // output ! Execute command if (. not . mock ) then call run ( command , echo = self % echo , verbose = self % verbose , redirect = log_file , exitstat = stat ) if ( stat /= 0 ) return endif ! Optionally register compile command if ( present ( table )) then call table % register ( command , get_os_type (), error ) stat = merge ( - 1 , 0 , allocated ( error )) endif end subroutine compile_c !> Compile a CPP object subroutine compile_cpp ( self , input , output , args , log_file , stat , table , dry_run ) !> Instance of the compiler object class ( compiler_t ), intent ( in ) :: self !> Source file input character ( len =* ), intent ( in ) :: input !> Output file of object character ( len =* ), intent ( in ) :: output !> Arguments for compiler character ( len =* ), intent ( in ) :: args !> Compiler output log file character ( len =* ), intent ( in ) :: log_file !> Status flag integer , intent ( out ) :: stat !> Optional compile_commands table type ( compile_command_table_t ), optional , intent ( inout ) :: table !> Optional mocking logical , optional , intent ( in ) :: dry_run character ( len = :), allocatable :: command type ( error_t ), allocatable :: error logical :: mock ! Check if we're actually building this file mock = . false . if ( present ( dry_run )) mock = dry_run ! Set command command = self % cxx // \" -c \" // input // \" \" // args // \" -o \" // output ! Execute command if (. not . mock ) then call run ( command , echo = self % echo , verbose = self % verbose , redirect = log_file , exitstat = stat ) if ( stat /= 0 ) return endif ! Optionally register compile command if ( present ( table )) then call table % register ( command , get_os_type (), error ) stat = merge ( - 1 , 0 , allocated ( error )) endif end subroutine compile_cpp !> Link an executable subroutine link_executable ( self , output , args , log_file , stat , dry_run ) !> Instance of the compiler object class ( compiler_t ), intent ( in ) :: self !> Output file of object character ( len =* ), intent ( in ) :: output !> Arguments for compiler character ( len =* ), intent ( in ) :: args !> Compiler output log file character ( len =* ), intent ( in ) :: log_file !> Status flag integer , intent ( out ) :: stat !> Optional mocking logical , optional , intent ( in ) :: dry_run character ( len = :), allocatable :: command logical :: mock ! Check if we're actually linking mock = . false . if ( present ( dry_run )) mock = dry_run ! Set command command = self % fc // \" \" // args // \" -o \" // output ! Execute command if (. not . mock ) & call run ( command , echo = self % echo , verbose = self % verbose , redirect = log_file , exitstat = stat ) end subroutine link_executable !> Link a shared library subroutine link_shared ( self , output , args , log_file , stat , dry_run ) !> Instance of the compiler object class ( compiler_t ), intent ( in ) :: self !> Output file of shared library object character ( len =* ), intent ( in ) :: output !> Arguments for the compiler character ( len =* ), intent ( in ) :: args !> Compiler output log file character ( len =* ), intent ( in ) :: log_file !> Status flag integer , intent ( out ) :: stat !> Optional mocking logical , optional , intent ( in ) :: dry_run character ( len = :), allocatable :: command logical :: mock character ( len = :), allocatable :: shared_flag mock = . false . if ( present ( dry_run )) mock = dry_run shared_flag = get_shared_flag ( self ) command = self % fc // \" \" // shared_flag // \" \" // args // \" -o \" // output if (. not . mock ) & call run ( command , echo = self % echo , verbose = self % verbose , redirect = log_file , exitstat = stat ) end subroutine link_shared !> Create an archive !> @todo For Windows OS, use the local `delete_file_win32` in stead of `delete_file`. !> This may be related to a bug in Mingw64-openmp and is expected to be resolved in the future, !> see issue #707, #708 and #808. subroutine make_archive ( self , output , args , log_file , stat , dry_run ) !> Instance of the archiver object class ( archiver_t ), intent ( in ) :: self !> Name of the archive to generate character ( len =* ), intent ( in ) :: output !> Object files to include into the archive type ( string_t ), intent ( in ) :: args (:) !> Compiler output log file character ( len =* ), intent ( in ) :: log_file !> Status flag integer , intent ( out ) :: stat !> Optional mocking logical , optional , intent ( in ) :: dry_run logical :: mock ! Check if we're actually linking mock = . false . if ( present ( dry_run )) mock = dry_run if ( mock ) return if ( self % use_response_file ) then call write_response_file ( output // \".resp\" , args ) call run ( self % ar // output // \" @\" // output // \".resp\" , echo = self % echo , & & verbose = self % verbose , redirect = log_file , exitstat = stat ) call delete_file_win32 ( output // \".resp\" ) else call run ( self % ar // output // \" \" // string_cat ( args , \" \" ), & & echo = self % echo , verbose = self % verbose , redirect = log_file , exitstat = stat ) end if contains subroutine delete_file_win32 ( file ) character ( len =* ), intent ( in ) :: file logical :: exist integer :: unit , iostat inquire ( file = file , exist = exist ) if ( exist ) then open ( file = file , newunit = unit ) close ( unit , status = 'delete' , iostat = iostat ) end if end subroutine delete_file_win32 end subroutine make_archive !> Response files allow to read command line options from files. !> Whitespace is used to separate the arguments, we will use newlines !> as separator to create readable response files which can be inspected !> in case of errors. subroutine write_response_file ( name , argv ) character ( len =* ), intent ( in ) :: name type ( string_t ), intent ( in ) :: argv (:) integer :: iarg , io open ( file = name , newunit = io , status = 'replace' ) do iarg = 1 , size ( argv ) write ( io , '(a)' ) unix_path ( argv ( iarg )% s ) end do close ( io ) end subroutine write_response_file !> String representation of a compiler object pure function debug_compiler ( self ) result ( repr ) !> Instance of the compiler object type ( compiler_t ), intent ( in ) :: self !> Representation as string character ( len = :), allocatable :: repr repr = 'fc=\"' // self % fc // '\", cc=\"' // self % cc // '\"' end function debug_compiler !> String representation of an archiver object pure function debug_archiver ( self ) result ( repr ) !> Instance of the archiver object type ( archiver_t ), intent ( in ) :: self !> Representation as string character ( len = :), allocatable :: repr repr = 'ar=\"' // self % ar // '\"' end function debug_archiver !> Check that two archiver_t objects are equal logical function ar_is_same ( this , that ) class ( archiver_t ), intent ( in ) :: this class ( serializable_t ), intent ( in ) :: that ar_is_same = . false . select type ( other => that ) type is ( archiver_t ) if ( allocated ( this % ar ). neqv . allocated ( other % ar )) return if ( allocated ( this % ar )) then if (. not .( this % ar == other % ar )) return end if if (. not .( this % use_response_file . eqv . other % use_response_file )) return if (. not .( this % echo . eqv . other % echo )) return if (. not .( this % verbose . eqv . other % verbose )) return class default ! Not the same type return end select !> All checks passed! ar_is_same = . true . end function ar_is_same !> Dump dependency to toml table subroutine dump_to_toml ( self , table , error ) !> Instance of the serializable object class ( archiver_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Path to archiver call set_string ( table , \"ar\" , self % ar , error , 'archiver_t' ) if ( allocated ( error )) return call set_value ( table , \"use-response-file\" , self % use_response_file , error , 'archiver_t' ) if ( allocated ( error )) return call set_value ( table , \"echo\" , self % echo , error , 'archiver_t' ) if ( allocated ( error )) return call set_value ( table , \"verbose\" , self % verbose , error , 'archiver_t' ) if ( allocated ( error )) return end subroutine dump_to_toml !> Read dependency from toml table (no checks made at this stage) subroutine load_from_toml ( self , table , error ) !> Instance of the serializable object class ( archiver_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error call get_value ( table , \"ar\" , self % ar ) call get_value ( table , \"use-response-file\" , self % use_response_file , error , 'archiver_t' ) if ( allocated ( error )) return call get_value ( table , \"echo\" , self % echo , error , 'archiver_t' ) if ( allocated ( error )) return call get_value ( table , \"verbose\" , self % verbose , error , 'archiver_t' ) if ( allocated ( error )) return end subroutine load_from_toml !> Check that two compiler_t objects are equal logical function compiler_is_same ( this , that ) class ( compiler_t ), intent ( in ) :: this class ( serializable_t ), intent ( in ) :: that compiler_is_same = . false . select type ( other => that ) type is ( compiler_t ) if (. not .( this % id == other % id )) return if ( allocated ( this % fc ). neqv . allocated ( other % fc )) return if ( allocated ( this % fc )) then if (. not .( this % fc == other % fc )) return end if if ( allocated ( this % cc ). neqv . allocated ( other % cc )) return if ( allocated ( this % cc )) then if (. not .( this % cc == other % cc )) return end if if ( allocated ( this % cxx ). neqv . allocated ( other % cxx )) return if ( allocated ( this % cxx )) then if (. not .( this % cxx == other % cxx )) return end if if (. not .( this % echo . eqv . other % echo )) return if (. not .( this % verbose . eqv . other % verbose )) return class default ! Not the same type return end select !> All checks passed! compiler_is_same = . true . end function compiler_is_same !> Dump dependency to toml table subroutine compiler_dump ( self , table , error ) !> Instance of the serializable object class ( compiler_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: ierr call set_value ( table , \"id\" , self % id , error , 'compiler_t' ) if ( allocated ( error )) return call set_string ( table , \"fc\" , self % fc , error , 'compiler_t' ) if ( allocated ( error )) return call set_string ( table , \"cc\" , self % cc , error , 'compiler_t' ) if ( allocated ( error )) return call set_string ( table , \"cxx\" , self % cxx , error , 'compiler_t' ) if ( allocated ( error )) return call set_value ( table , \"echo\" , self % echo , error , 'compiler_t' ) if ( allocated ( error )) return call set_value ( table , \"verbose\" , self % verbose , error , 'compiler_t' ) if ( allocated ( error )) return end subroutine compiler_dump !> Read dependency from toml table (no checks made at this stage) subroutine compiler_load ( self , table , error ) !> Instance of the serializable object class ( compiler_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error call get_value ( table , \"id\" , self % id , error , 'compiler_t' ) if ( allocated ( error )) return call get_value ( table , \"fc\" , self % fc ) call get_value ( table , \"cc\" , self % cc ) call get_value ( table , \"cxx\" , self % cxx ) call get_value ( table , \"echo\" , self % echo , error , 'compiler_t' ) if ( allocated ( error )) return call get_value ( table , \"verbose\" , self % verbose , error , 'compiler_t' ) if ( allocated ( error )) return end subroutine compiler_load !> Return a compiler name string pure function compiler_name ( self ) result ( name ) !> Instance of the compiler object class ( compiler_t ), intent ( in ) :: self !> Representation as string character ( len = :), allocatable :: name select case ( self % id ) case ( id_gcc ); name = \"gfortran\" case ( id_f95 ); name = \"f95\" case ( id_caf ); name = \"caf\" case ( id_intel_classic_nix ); name = \"ifort\" case ( id_intel_classic_mac ); name = \"ifort\" case ( id_intel_classic_windows ); name = \"ifort\" case ( id_intel_llvm_nix ); name = \"ifx\" case ( id_intel_llvm_windows ); name = \"ifx\" case ( id_intel_llvm_unknown ); name = \"ifx\" case ( id_pgi ); name = \"pgfortran\" case ( id_nvhpc ); name = \"nvfortran\" case ( id_nag ); name = \"nagfor\" case ( id_flang ); name = \"flang\" case ( id_flang_new ); name = \"flang-new\" case ( id_f18 ); name = \"f18\" case ( id_ibmxl ); name = \"xlf90\" case ( id_cray ); name = \"crayftn\" case ( id_lahey ); name = \"lfc\" case ( id_lfortran ); name = \"lFortran\" case default ; name = \"invalid/unknown\" end select end function compiler_name !> Run a single-source Fortran program using the current compiler !> Compile a Fortran object logical function check_fortran_source_runs ( self , input , compile_flags , link_flags ) result ( success ) !> Instance of the compiler object class ( compiler_t ), intent ( in ) :: self !> Program Source character ( len =* ), intent ( in ) :: input !> Optional build and link flags character ( len =* ), optional , intent ( in ) :: compile_flags , link_flags integer :: stat , unit character (:), allocatable :: source , object , logf , exe , flags , ldflags success = . false . !> Create temporary source file exe = get_temp_filename () source = exe // '.f90' object = exe // '.o' logf = exe // '.log' open ( newunit = unit , file = source , action = 'readwrite' , iostat = stat ) if ( stat /= 0 ) return !> Write contents write ( unit , * ) input close ( unit ) !> Get flags flags = self % get_default_flags ( release = . false .) ldflags = self % get_default_flags ( release = . false .) if ( present ( compile_flags )) flags = flags // \" \" // compile_flags if ( present ( link_flags )) ldflags = ldflags // \" \" // link_flags !> Intel: Needs -warn last for error on unknown command line arguments to work if ( self % id == id_intel_llvm_nix ) then flags = flags // \" \" // flag_intel_warn ldflags = ldflags // \" \" // flag_intel_warn elseif ( self % id == id_intel_llvm_windows ) then flags = flags // \" \" // flag_intel_warn_win ldflags = ldflags // \" \" // flag_intel_warn_win end if !> Compile and link program call self % compile_fortran ( source , object , flags , logf , stat ) if ( stat == 0 ) & call self % link ( exe , ldflags // \" \" // object , logf , stat ) !> Run and retrieve exit code if ( stat == 0 ) & call run ( exe , echo = . false ., exitstat = stat , verbose = . false ., redirect = logf ) !> Successful exit on 0 exit code success = stat == 0 !> Delete files open ( newunit = unit , file = source , action = 'readwrite' , iostat = stat ) close ( unit , status = 'delete' ) open ( newunit = unit , file = object , action = 'readwrite' , iostat = stat ) close ( unit , status = 'delete' ) open ( newunit = unit , file = logf , action = 'readwrite' , iostat = stat ) close ( unit , status = 'delete' ) open ( newunit = unit , file = exe , action = 'readwrite' , iostat = stat ) close ( unit , status = 'delete' ) end function check_fortran_source_runs !> Check if the given compile and/or link flags are accepted by the compiler logical function check_flags_supported ( self , compile_flags , link_flags ) class ( compiler_t ), intent ( in ) :: self character ( len =* ), optional , intent ( in ) :: compile_flags , link_flags ! Minimal program that always compiles character ( len =* ), parameter :: hello_world = \"print *, 'Hello, World!'; end\" check_flags_supported = self % check_fortran_source_runs ( hello_world , compile_flags , link_flags ) end function check_flags_supported !> Check if the current compiler supports 128-bit real precision logical function with_qp ( self ) !> Instance of the compiler object class ( compiler_t ), intent ( in ) :: self with_qp = self % check_fortran_source_runs & ( 'if (selected_real_kind(33) == -1) stop 1; end' ) end function with_qp !> Check if the current compiler supports 80-bit \"extended\" real precision logical function with_xdp ( self ) !> Instance of the compiler object class ( compiler_t ), intent ( in ) :: self with_xdp = self % check_fortran_source_runs & ( 'if (any(selected_real_kind(18) == [-1, selected_real_kind(33)])) stop 1; end' ) end function with_xdp !> Append new flags to existing flags, removing duplicates and empty flags (string version) subroutine append_clean_flags ( flags , new_flags ) character (:), intent ( inout ), allocatable :: flags character ( * ), intent ( in ) :: new_flags type ( string_t ), allocatable :: flags_array (:), new_flags_array (:) integer :: i call tokenize_flags ( flags , flags_array ) call tokenize_flags ( new_flags , new_flags_array ) call append_clean_flags_array ( flags_array , new_flags_array ) do i = 1 , size ( flags_array ) flags = flags // \" \" // flags_array ( i )% s end do end subroutine append_clean_flags !> Append new flags to existing flags, removing duplicates and empty flags (array version) subroutine append_clean_flags_array ( flags_array , new_flags_array ) type ( string_t ), allocatable , intent ( inout ) :: flags_array (:) type ( string_t ), intent ( in ) :: new_flags_array (:) integer :: i do i = 1 , size ( new_flags_array ) if ( string_array_contains ( new_flags_array ( i )% s , flags_array )) cycle ! Filter out empty flags and arguments if ( new_flags_array ( i )% s == \"\" ) cycle if ( trim ( new_flags_array ( i )% s ) == \"-l\" ) cycle if ( trim ( new_flags_array ( i )% s ) == \"-L\" ) cycle if ( trim ( new_flags_array ( i )% s ) == \"-I\" ) cycle if ( trim ( new_flags_array ( i )% s ) == \"-J\" ) cycle if ( trim ( new_flags_array ( i )% s ) == \"-M\" ) cycle flags_array = [ flags_array , new_flags_array ( i )] end do end subroutine append_clean_flags_array !> Tokenize a string into an array of compiler flags subroutine tokenize_flags ( flags , flags_array ) character ( * ), intent ( in ) :: flags type ( string_t ), allocatable , intent ( out ) :: flags_array (:) character ( len = :), allocatable :: flags_char_array (:) integer :: i logical :: success flags_char_array = sh_split ( flags , join_spaced = . true ., keep_quotes = . true ., success = success ) if (. not . success ) then allocate ( flags_array ( 0 )) return end if allocate ( flags_array ( size ( flags_char_array ))) do i = 1 , size ( flags_char_array ) flags_array ( i )% s = trim ( adjustl ( flags_char_array ( i ))) end do end subroutine tokenize_flags end module fpm_compiler","tags":"","url":"sourcefile/fpm_compiler.f90.html"},{"title":"fpm_sources.f90 – Fortran-lang/fpm","text":"Source Code !># Discovery of sources !> !> This module implements subroutines for building a list of !> `[[srcfile_t]]` objects by looking for source files in the filesystem. !> module fpm_sources use fpm_error , only : error_t use fpm_model , only : srcfile_t , FPM_UNIT_PROGRAM use fpm_filesystem , only : basename , canon_path , dirname , join_path , list_files , is_hidden_file use fpm_environment , only : get_os_type , OS_WINDOWS use fpm_strings , only : lower , str_ends_with , string_t , operator (. in .) use fpm_source_parsing , only : parse_f_source , parse_c_source use fpm_manifest_executable , only : executable_config_t implicit none private public :: add_sources_from_dir , add_executable_sources public :: get_exe_name_with_suffix character ( 4 ), parameter :: fortran_suffixes ( 2 ) = [ \".f90\" , & \".f \" ] character ( 4 ), parameter :: c_suffixes ( 4 ) = [ \".c \" , \".h \" , \".cpp\" , \".hpp\" ] contains !> Wrapper to source parsing routines. !> Selects parsing routine based on source file name extension function parse_source ( source_file_path , custom_f_ext , error ) result ( source ) character ( * ), intent ( in ) :: source_file_path type ( string_t ), optional , intent ( in ) :: custom_f_ext (:) type ( error_t ), allocatable , intent ( out ) :: error type ( srcfile_t ) :: source type ( string_t ), allocatable :: f_ext (:) call list_fortran_suffixes ( f_ext , custom_f_ext ) if ( str_ends_with ( lower ( source_file_path ), f_ext )) then source = parse_f_source ( source_file_path , error ) if ( source % unit_type == FPM_UNIT_PROGRAM ) then source % exe_name = basename ( source_file_path , suffix = . false .) end if else if ( str_ends_with ( lower ( source_file_path ), c_suffixes )) then source = parse_c_source ( source_file_path , error ) endif if ( allocated ( error )) then return end if end function parse_source !> List fortran suffixes, including optional ones subroutine list_fortran_suffixes ( suffixes , with_f_ext ) type ( string_t ), allocatable , intent ( out ) :: suffixes (:) !> Additional user-defined (preprocessor) extensions that should be treated as Fortran sources type ( string_t ), intent ( in ), optional :: with_f_ext (:) integer :: ndefault , nuser , i ndefault = size ( fortran_suffixes ) nuser = 0 ; if ( present ( with_f_ext )) nuser = size ( with_f_ext ) allocate ( suffixes ( ndefault + nuser )) do i = 1 , ndefault suffixes ( i ) = string_t ( fortran_suffixes ( i )) end do if ( present ( with_f_ext )) then do i = 1 , nuser suffixes ( ndefault + i ) = string_t ( with_f_ext ( i )% s ) end do endif end subroutine list_fortran_suffixes !> Add to `sources` by looking for source files in `directory` subroutine add_sources_from_dir ( sources , directory , scope , with_executables , with_f_ext , recurse , error ) !> List of `[[srcfile_t]]` objects to append to. Allocated if not allocated type ( srcfile_t ), allocatable , intent ( inout ), target :: sources (:) !> Directory in which to search for source files character ( * ), intent ( in ) :: directory !> Scope to apply to the discovered sources, see [[fpm_model]] for enumeration integer , intent ( in ) :: scope !> Executable sources (fortran `program`s) are ignored unless `with_executables=.true.` logical , intent ( in ), optional :: with_executables !> Additional user-defined (preprocessor) extensions that should be treated as Fortran sources type ( string_t ), intent ( in ), optional :: with_f_ext (:) !> Whether to recursively search subdirectories, default is `.true.` logical , intent ( in ), optional :: recurse !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: i logical , allocatable :: is_source (:), exclude_source (:) logical :: recurse_ type ( string_t ), allocatable :: file_names (:) type ( string_t ), allocatable :: src_file_names (:), f_ext (:) type ( string_t ), allocatable :: existing_src_files (:) type ( srcfile_t ), allocatable :: dir_sources (:) recurse_ = . true . if ( present ( recurse )) recurse_ = recurse ! Scan directory for sources call list_files ( directory , file_names , recurse = recurse_ ) if ( allocated ( sources )) then allocate ( existing_src_files ( size ( sources ))) do i = 1 , size ( sources ) existing_src_files ( i )% s = canon_path ( sources ( i )% file_name ) end do else allocate ( existing_src_files ( 0 )) end if ! Get legal fortran suffixes call list_fortran_suffixes ( f_ext , with_f_ext ) is_source = [(. not .( is_hidden_file ( basename ( file_names ( i )% s ))) . and . & . not .( canon_path ( file_names ( i )% s ) . in . existing_src_files ) . and . & ( str_ends_with ( lower ( file_names ( i )% s ), f_ext ) . or . & str_ends_with ( lower ( file_names ( i )% s ), c_suffixes ) ), i = 1 , size ( file_names ))] src_file_names = pack ( file_names , is_source ) allocate ( dir_sources ( size ( src_file_names ))) allocate ( exclude_source ( size ( src_file_names ))) do i = 1 , size ( src_file_names ) dir_sources ( i ) = parse_source ( src_file_names ( i )% s , with_f_ext , error ) if ( allocated ( error )) return dir_sources ( i )% unit_scope = scope allocate ( dir_sources ( i )% link_libraries ( 0 )) ! Exclude executables unless specified otherwise exclude_source ( i ) = ( dir_sources ( i )% unit_type == FPM_UNIT_PROGRAM ) if ( dir_sources ( i )% unit_type == FPM_UNIT_PROGRAM . and . & & present ( with_executables )) then if ( with_executables ) then exclude_source ( i ) = . false . end if end if end do if (. not . allocated ( sources )) then sources = pack ( dir_sources ,. not . exclude_source ) else sources = [ sources , pack ( dir_sources ,. not . exclude_source )] end if end subroutine add_sources_from_dir !> Add to `sources` using the executable and test entries in the manifest and !> applies any executable-specific overrides such as `executable%name`. !> Adds all sources (including modules) from each `executable%source_dir` subroutine add_executable_sources ( sources , executables , scope , auto_discover , with_f_ext , error ) !> List of `[[srcfile_t]]` objects to append to. Allocated if not allocated type ( srcfile_t ), allocatable , intent ( inout ), target :: sources (:) !> List of `[[executable_config_t]]` entries from manifest class ( executable_config_t ), intent ( in ) :: executables (:) !> Scope to apply to the discovered sources: either `FPM_SCOPE_APP` or `FPM_SCOPE_TEST`, see [[fpm_model]] integer , intent ( in ) :: scope !> If `.false.` only executables and tests specified in the manifest are added to `sources` logical , intent ( in ) :: auto_discover !> Additional user-defined (preprocessor) extensions that should be treated as Fortran sources type ( string_t ), intent ( in ), optional :: with_f_ext (:) !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: i , j type ( string_t ), allocatable :: exe_dirs (:) type ( srcfile_t ) :: exe_source call get_executable_source_dirs ( exe_dirs , executables ) do i = 1 , size ( exe_dirs ) call add_sources_from_dir ( sources , exe_dirs ( i )% s , scope , & with_executables = auto_discover , with_f_ext = with_f_ext , recurse = . false ., error = error ) if ( allocated ( error )) then return end if end do exe_loop : do i = 1 , size ( executables ) ! Check if executable already discovered automatically ! and apply any overrides do j = 1 , size ( sources ) !> Compare lowercase strings to allow auto-discovery of pre-processed extensions if ( lower ( basename ( sources ( j )% file_name , suffix = . true .)) == lower ( executables ( i )% main ) . and .& canon_path ( dirname ( sources ( j )% file_name )) == & canon_path ( executables ( i )% source_dir ) ) then sources ( j )% exe_name = executables ( i )% name if ( allocated ( executables ( i )% link )) then sources ( j )% link_libraries = executables ( i )% link end if sources ( j )% unit_type = FPM_UNIT_PROGRAM cycle exe_loop end if end do ! Add if not already discovered (auto_discovery off) associate ( exe => executables ( i )) exe_source = parse_source ( join_path ( exe % source_dir , exe % main ), with_f_ext , error ) exe_source % exe_name = exe % name if ( allocated ( exe % link )) then exe_source % link_libraries = exe % link end if exe_source % unit_type = FPM_UNIT_PROGRAM exe_source % unit_scope = scope end associate if ( allocated ( error )) return if (. not . allocated ( sources )) then sources = [ exe_source ] else sources = [ sources , exe_source ] end if end do exe_loop end subroutine add_executable_sources !> Build a list of unique source directories !> from executables specified in manifest subroutine get_executable_source_dirs ( exe_dirs , executables ) type ( string_t ), allocatable , intent ( inout ) :: exe_dirs (:) class ( executable_config_t ), intent ( in ) :: executables (:) type ( string_t ) :: dirs_temp ( size ( executables )) integer :: i , n n = 0 do i = 1 , size ( executables ) dirs_temp ( i )% s = ' ' enddo do i = 1 , size ( executables ) if (. not .( executables ( i )% source_dir . in . dirs_temp )) then n = n + 1 dirs_temp ( n )% s = executables ( i )% source_dir end if end do if (. not . allocated ( exe_dirs )) then exe_dirs = dirs_temp ( 1 : n ) else exe_dirs = [ exe_dirs , dirs_temp ( 1 : n )] end if end subroutine get_executable_source_dirs !> Build an executable name with suffix. Safe routine that always returns an allocated string function get_exe_name_with_suffix ( source ) result ( suffixed ) type ( srcfile_t ), intent ( in ) :: source character ( len = :), allocatable :: suffixed if ( allocated ( source % exe_name )) then if ( get_os_type () == OS_WINDOWS ) then suffixed = source % exe_name // '.exe' else suffixed = source % exe_name end if else suffixed = \"\" endif end function get_exe_name_with_suffix end module fpm_sources","tags":"","url":"sourcefile/fpm_sources.f90.html"},{"title":"fpm_meta_base.f90 – Fortran-lang/fpm","text":"Source Code module fpm_meta_base use fpm_error , only : error_t , fatal_error use fpm_versioning , only : version_t use fpm_model , only : fpm_model_t , fortran_features_t use fpm_command_line , only : fpm_cmd_settings , fpm_run_settings use fpm_manifest_dependency , only : dependency_config_t use fpm_manifest_preprocess , only : preprocess_config_t use fpm_manifest , only : package_config_t use fpm_strings , only : string_t , len_trim , split , join use fpm_compiler , only : append_clean_flags , append_clean_flags_array implicit none private public :: destroy !> Type for describing a source file type , public :: metapackage_t !> Package name character (:), allocatable :: name !> Package version (if supported) type ( version_t ), allocatable :: version logical :: has_link_libraries = . false . logical :: has_link_flags = . false . logical :: has_build_flags = . false . logical :: has_fortran_flags = . false . logical :: has_c_flags = . false . logical :: has_cxx_flags = . false . logical :: has_include_dirs = . false . logical :: has_dependencies = . false . logical :: has_run_command = . false . logical :: has_external_modules = . false . !> List of compiler flags and options to be added type ( string_t ) :: flags type ( string_t ) :: fflags type ( string_t ) :: cflags type ( string_t ) :: cxxflags type ( string_t ) :: link_flags type ( string_t ) :: run_command type ( string_t ), allocatable :: incl_dirs (:) type ( string_t ), allocatable :: link_libs (:) type ( string_t ), allocatable :: external_modules (:) !> Special fortran features type ( fortran_features_t ), allocatable :: fortran !> Preprocessor configuration type ( preprocess_config_t ), allocatable :: preprocess !> List of Development dependency meta data. !> Metapackage dependencies are never exported from the model type ( dependency_config_t ), allocatable :: dependency (:) contains !> Clean metapackage structure procedure :: destroy !> Add metapackage dependencies to the model procedure , private :: resolve_cmd procedure , private :: resolve_model procedure , private :: resolve_package_config generic :: resolve => resolve_cmd , resolve_model , resolve_package_config end type metapackage_t contains elemental subroutine destroy ( this ) class ( metapackage_t ), intent ( inout ) :: this this % has_link_libraries = . false . this % has_link_flags = . false . this % has_build_flags = . false . this % has_fortran_flags = . false . this % has_c_flags = . false . this % has_cxx_flags = . false . this % has_include_dirs = . false . this % has_dependencies = . false . this % has_run_command = . false . this % has_external_modules = . false . if ( allocated ( this % fortran )) deallocate ( this % fortran ) if ( allocated ( this % preprocess )) deallocate ( this % preprocess ) if ( allocated ( this % name )) deallocate ( this % name ) if ( allocated ( this % version )) deallocate ( this % version ) if ( allocated ( this % flags % s )) deallocate ( this % flags % s ) if ( allocated ( this % link_libs )) deallocate ( this % link_libs ) if ( allocated ( this % incl_dirs )) deallocate ( this % incl_dirs ) if ( allocated ( this % external_modules )) deallocate ( this % external_modules ) end subroutine destroy !> Resolve metapackage dependencies into the command line settings subroutine resolve_cmd ( self , settings , error ) class ( metapackage_t ), intent ( in ) :: self class ( fpm_cmd_settings ), intent ( inout ) :: settings type ( error_t ), allocatable , intent ( out ) :: error ! Add customize run commands if ( self % has_run_command ) then select type ( cmd => settings ) class is ( fpm_run_settings ) ! includes fpm_test_settings ! Only override runner if user has not provided a custom one if (. not . len_trim ( cmd % runner ) > 0 ) cmd % runner = self % run_command % s end select endif end subroutine resolve_cmd !> Resolve metapackage dependencies into the model subroutine resolve_model ( self , model , error ) class ( metapackage_t ), intent ( in ) :: self type ( fpm_model_t ), intent ( inout ) :: model type ( error_t ), allocatable , intent ( out ) :: error ! Add global build flags, to apply to all sources if ( self % has_build_flags ) then call append_clean_flags ( model % fortran_compile_flags , self % flags % s ) call append_clean_flags ( model % c_compile_flags , self % flags % s ) call append_clean_flags ( model % cxx_compile_flags , self % flags % s ) endif ! Add language-specific flags if ( self % has_fortran_flags ) call append_clean_flags ( model % fortran_compile_flags , self % fflags % s ) if ( self % has_c_flags ) call append_clean_flags ( model % c_compile_flags , self % cflags % s ) if ( self % has_cxx_flags ) call append_clean_flags ( model % cxx_compile_flags , self % cxxflags % s ) if ( self % has_link_flags ) then call append_clean_flags ( model % link_flags , self % link_flags % s ) end if if ( self % has_link_libraries ) then call append_clean_flags_array ( model % link_libraries , self % link_libs ) end if if ( self % has_include_dirs ) then call append_clean_flags_array ( model % include_dirs , self % incl_dirs ) end if if ( self % has_external_modules ) then call append_clean_flags_array ( model % external_modules , self % external_modules ) end if end subroutine resolve_model subroutine resolve_package_config ( self , package , error ) class ( metapackage_t ), intent ( in ) :: self type ( package_config_t ), intent ( inout ) :: package type ( error_t ), allocatable , intent ( out ) :: error integer :: i ! All metapackage dependencies are added as dev-dependencies, ! as they may change if built upstream if ( self % has_dependencies ) then if ( allocated ( package % dev_dependency )) then package % dev_dependency = [ package % dev_dependency , self % dependency ] else package % dev_dependency = self % dependency end if end if ! Check if there are any special fortran requests which the package does not comply to if ( allocated ( self % fortran )) then if ( self % fortran % implicit_external . neqv . package % fortran % implicit_external ) then call fatal_error ( error , 'metapackage fortran error: metapackage ' // & dn ( self % fortran % implicit_external ) // ' require implicit-external, main package ' // & dn ( package % fortran % implicit_external )) return end if if ( self % fortran % implicit_typing . neqv . package % fortran % implicit_typing ) then call fatal_error ( error , 'metapackage fortran error: metapackage ' // & dn ( self % fortran % implicit_external ) // ' require implicit-typing, main package ' // & dn ( package % fortran % implicit_external )) return end if end if ! Check if there are preprocessor configurations if ( allocated ( self % preprocess )) then if ( self % preprocess % is_cpp ()) then if ( allocated ( package % preprocess )) then if ( size ( package % preprocess ) < 1 ) then deallocate ( package % preprocess ) allocate ( package % preprocess ( 1 ), source = self % preprocess ) else do i = 1 , size ( package % preprocess ) if ( package % preprocess ( i )% is_cpp ()) then call package % preprocess ( i )% add_config ( self % preprocess ) exit end if end do end if else ! Copy configuration allocate ( package % preprocess ( 1 ), source = self % preprocess ) end if else call fatal_error ( error , 'non-cpp preprocessor configuration ' // & self % preprocess % name // ' is not supported' ) return end if end if contains pure function dn ( bool ) logical , intent ( in ) :: bool character ( len = :), allocatable :: dn if ( bool ) then dn = \"does\" else dn = \"does not\" end if end function dn end subroutine resolve_package_config end module fpm_meta_base","tags":"","url":"sourcefile/fpm_meta_base.f90.html"},{"title":"downloader.f90 – Fortran-lang/fpm","text":"Source Code module fpm_downloader use fpm_error , only : error_t , fatal_error use fpm_filesystem , only : which , run use fpm_versioning , only : version_t use jonquil , only : json_object , json_value , json_error , json_load , cast_to_object use fpm_strings , only : string_t implicit none private public :: downloader_t !> This type could be entirely avoided but it is quite practical because it can be mocked for testing. type downloader_t contains procedure , nopass :: get_pkg_data , get_file , upload_form , unpack end type contains !> Perform an http get request, save output to file, and parse json. subroutine get_pkg_data ( url , version , tmp_pkg_file , json , error ) character ( * ), intent ( in ) :: url type ( version_t ), allocatable , intent ( in ) :: version character ( * ), intent ( in ) :: tmp_pkg_file type ( json_object ), intent ( out ) :: json type ( error_t ), allocatable , intent ( out ) :: error class ( json_value ), allocatable :: j_value type ( json_object ), pointer :: ptr type ( json_error ), allocatable :: j_error if ( allocated ( version )) then ! Request specific version. call get_file ( url // '/' // version % s (), tmp_pkg_file , error ) else ! Request latest version. call get_file ( url , tmp_pkg_file , error ) end if if ( allocated ( error )) return call json_load ( j_value , tmp_pkg_file , error = j_error ) if ( allocated ( j_error )) then allocate ( error ); call move_alloc ( j_error % message , error % message ); call json % destroy (); return end if ptr => cast_to_object ( j_value ) if (. not . associated ( ptr )) then call fatal_error ( error , \"Error parsing JSON from '\" // url // \"'.\" ); return end if json = ptr end !> Download a file from a url using either curl or wget. subroutine get_file ( url , tmp_pkg_file , error ) character ( * ), intent ( in ) :: url character ( * ), intent ( in ) :: tmp_pkg_file type ( error_t ), allocatable , intent ( out ) :: error integer :: stat if ( which ( 'curl' ) /= '' ) then print * , \"Downloading '\" // url // \"' -> '\" // tmp_pkg_file // \"'\" call execute_command_line ( 'curl ' // url // ' -s -o ' // tmp_pkg_file , exitstat = stat ) else if ( which ( 'wget' ) /= '' ) then print * , \"Downloading '\" // url // \"' -> '\" // tmp_pkg_file // \"'\" call execute_command_line ( 'wget ' // url // ' -q -O ' // tmp_pkg_file , exitstat = stat ) else call fatal_error ( error , \"Neither 'curl' nor 'wget' installed.\" ); return end if if ( stat /= 0 ) then call fatal_error ( error , \"Error downloading package from '\" // url // \"'.\" ); return end if end !> Perform an http post request with form data. subroutine upload_form ( endpoint , form_data , verbose , error ) !> Endpoint to upload to. character ( len =* ), intent ( in ) :: endpoint !> Form data to upload. type ( string_t ), intent ( in ) :: form_data (:) !> Print additional information if true. logical , intent ( in ) :: verbose !> Error handling. type ( error_t ), allocatable , intent ( out ) :: error integer :: stat , i character ( len = :), allocatable :: form_data_str form_data_str = '' do i = 1 , size ( form_data ) form_data_str = form_data_str // \"-F '\" // form_data ( i )% s // \"' \" end do if ( which ( 'curl' ) /= '' ) then print * , 'Uploading package ...' call run ( 'curl -X POST -H \"Content-Type: multipart/form-data\" ' // & & form_data_str // endpoint , exitstat = stat , echo = verbose ) else call fatal_error ( error , \"'curl' not installed.\" ); return end if if ( stat /= 0 ) then call fatal_error ( error , \"Error uploading package to registry.\" ); return end if end !> Unpack a tarball to a destination. subroutine unpack ( tmp_pkg_file , destination , error ) !> Path to tarball. character ( * ), intent ( in ) :: tmp_pkg_file !> Destination to unpack to. character ( * ), intent ( in ) :: destination !> Error handling. type ( error_t ), allocatable , intent ( out ) :: error integer :: stat if ( which ( 'tar' ) == '' ) then call fatal_error ( error , \"'tar' not installed.\" ); return end if print * , \"Unpacking '\" // tmp_pkg_file // \"' to '\" // destination // \"' ...\" call execute_command_line ( 'tar -zxf ' // tmp_pkg_file // ' -C ' // destination , exitstat = stat ) if ( stat /= 0 ) then call fatal_error ( error , \"Error unpacking '\" // tmp_pkg_file // \"'.\" ); return end if end end","tags":"","url":"sourcefile/downloader.f90.html"},{"title":"fpm_source_parsing.f90 – Fortran-lang/fpm","text":"Source Code !># Parsing of package source files !> !> This module exposes two functions, `[[parse_f_source]]` and `[[parse_c_source]]`, !> which perform a rudimentary parsing of fortran and c source files !> in order to extract information required for module dependency tracking. !> !> Both functions additionally calculate and store a file digest (hash) which !> is used by the backend ([[fpm_backend]]) to skip compilation of unmodified sources. !> !> Both functions return an instance of the [[srcfile_t]] type. !> !> For more information, please read the documentation for each function: !> !> - `[[parse_f_source]]` !> - `[[parse_c_source]]` !> module fpm_source_parsing use fpm_error , only : error_t , file_parse_error , fatal_error , file_not_found_error use fpm_strings , only : string_t , string_cat , len_trim , split , lower , str_ends_with , fnv_1a , is_fortran_name use fpm_model , only : srcfile_t , & FPM_UNIT_UNKNOWN , FPM_UNIT_PROGRAM , FPM_UNIT_MODULE , & FPM_UNIT_SUBMODULE , FPM_UNIT_SUBPROGRAM , & FPM_UNIT_CSOURCE , FPM_UNIT_CHEADER , FPM_SCOPE_UNKNOWN , & FPM_SCOPE_DEP , FPM_SCOPE_APP , FPM_SCOPE_TEST , FPM_UNIT_CPPSOURCE use fpm_filesystem , only : read_lines , read_lines_expanded , exists implicit none private public :: parse_f_source , parse_c_source , parse_use_statement contains !> Parsing of free-form fortran source files !> !> The following statements are recognised and parsed: !> !> - `Module`/`submodule`/`program` declaration !> - Module `use` statement !> - `include` statement !> !> @note Intrinsic modules used by sources are not listed in !> the `modules_used` field of source objects. !> !> @note Submodules are treated as normal modules which `use` their !> corresponding parent modules. !> !>### Parsing limitations !> !> __Statements must not continued onto another line !> except for an `only:` list in the `use` statement.__ !> !> This is supported: !> !>```fortran !> use my_module, only: & !> my_var, my_function, my_subroutine !>``` !> !> This is __NOT supported:__ !> !>```fortran !> use & !> my_module !>``` !> function parse_f_source ( f_filename , error ) result ( f_source ) character ( * ), intent ( in ) :: f_filename type ( srcfile_t ) :: f_source type ( error_t ), allocatable , intent ( out ) :: error logical :: inside_module , inside_interface , using , intrinsic_module integer :: stat integer :: fh , n_use , n_include , n_mod , n_parent , i , j , ic , pass type ( string_t ), allocatable :: file_lines (:), file_lines_lower (:) character (:), allocatable :: temp_string , mod_name , string_parts (:) if (. not . exists ( f_filename )) then call file_not_found_error ( error , f_filename ) return end if f_source % file_name = f_filename file_lines = read_lines_expanded ( f_filename ) ! for efficiency in parsing make a lowercase left-adjusted copy of the file ! Need a copy because INCLUDE (and #include) file arguments are case-sensitive file_lines_lower = file_lines do i = 1 , size ( file_lines_lower ) file_lines_lower ( i )% s = adjustl ( lower ( file_lines_lower ( i )% s )) enddo ! fnv_1a can only be applied to non-zero-length arrays if ( len_trim ( file_lines_lower ) > 0 ) f_source % digest = fnv_1a ( file_lines ) do pass = 1 , 2 n_use = 0 n_include = 0 n_mod = 0 n_parent = 0 inside_module = . false . inside_interface = . false . file_loop : do i = 1 , size ( file_lines_lower ) ! Skip comment lines and preprocessor directives if ( index ( file_lines_lower ( i )% s , '!' ) == 1 . or . & index ( file_lines_lower ( i )% s , '#' ) == 1 . or . & len_trim ( file_lines_lower ( i )% s ) < 1 ) then cycle end if ! Detect exported C-API via bind(C) if (. not . inside_interface . and . & parse_subsequence ( file_lines_lower ( i )% s , 'bind' , '(' , 'c' )) then do j = i , 1 , - 1 if ( index ( file_lines_lower ( j )% s , 'function' ) > 0 . or . & index ( file_lines_lower ( j )% s , 'subroutine' ) > 0 ) then f_source % unit_type = FPM_UNIT_SUBPROGRAM exit end if if ( j > 1 ) then ic = index ( file_lines_lower ( j - 1 )% s , '!' ) if ( ic < 1 ) then ic = len ( file_lines_lower ( j - 1 )% s ) end if temp_string = trim ( file_lines_lower ( j - 1 )% s ( 1 : ic )) if ( index ( temp_string , '&' ) /= len ( temp_string )) then exit end if end if end do end if ! Skip lines that are continued: not statements if ( i > 1 ) then ic = index ( file_lines_lower ( i - 1 )% s , '!' ) if ( ic < 1 ) then ic = len ( file_lines_lower ( i - 1 )% s ) end if temp_string = trim ( file_lines_lower ( i - 1 )% s ( 1 : ic )) if ( len ( temp_string ) > 0 . and . index ( temp_string , '&' ) == len ( temp_string )) then cycle end if end if ! Detect beginning of interface block if ( index ( file_lines_lower ( i )% s , 'interface' ) == 1 & . or . parse_sequence ( file_lines_lower ( i )% s , 'abstract' , 'interface' )) then inside_interface = . true . cycle end if ! Detect end of interface block if ( parse_sequence ( file_lines_lower ( i )% s , 'end' , 'interface' )) then inside_interface = . false . cycle end if ! Process 'USE' statements call parse_use_statement ( f_filename , i , file_lines_lower ( i )% s , using , intrinsic_module , mod_name , error ) if ( allocated ( error )) return if ( using ) then ! Not a valid module name? if (. not . is_fortran_name ( mod_name )) cycle ! Valid intrinsic module: not a dependency if ( intrinsic_module ) cycle n_use = n_use + 1 if ( pass == 2 ) f_source % modules_used ( n_use )% s = mod_name cycle endif ! Process 'INCLUDE' statements ic = index ( file_lines_lower ( i )% s , 'include' ) if ( ic == 1 ) then ic = index ( lower ( file_lines ( i )% s ), 'include' ) if ( index ( adjustl ( file_lines ( i )% s ( ic + 7 :)), '\"' ) == 1 . or . & index ( adjustl ( file_lines ( i )% s ( ic + 7 :)), \"'\" ) == 1 ) then n_include = n_include + 1 if ( pass == 2 ) then f_source % include_dependencies ( n_include )% s = & & split_n ( file_lines ( i )% s , n = 2 , delims = \"'\" // '\"' , stat = stat ) if ( stat /= 0 ) then call file_parse_error ( error , f_filename , & 'unable to find include file name' , i , & file_lines ( i )% s ) return end if end if cycle end if end if ! Extract name of module if is module if ( index ( file_lines_lower ( i )% s , 'module ' ) == 1 ) then ! Remove any trailing comments ic = index ( file_lines_lower ( i )% s , '!' ) - 1 if ( ic < 1 ) then ic = len ( file_lines_lower ( i )% s ) end if temp_string = trim ( file_lines_lower ( i )% s ( 1 : ic )) ! R1405 module-stmt := \"MODULE\" module-name ! module-stmt has two space-delimited parts only ! (no line continuations) call split ( temp_string , string_parts , ' ' ) if ( size ( string_parts ) /= 2 ) then cycle end if mod_name = trim ( adjustl ( string_parts ( 2 ))) if ( scan ( mod_name , '=(&' ) > 0 ) then ! Ignore these cases: ! module & ! module =* ! module (i) cycle end if if (. not . is_fortran_name ( mod_name )) then call file_parse_error ( error , f_filename , & 'empty or invalid name for module' , i , & file_lines_lower ( i )% s , index ( file_lines_lower ( i )% s , mod_name )) return end if n_mod = n_mod + 1 if ( pass == 2 ) then f_source % modules_provided ( n_mod ) = string_t ( mod_name ) end if if ( f_source % unit_type == FPM_UNIT_UNKNOWN ) then f_source % unit_type = FPM_UNIT_MODULE end if if (. not . inside_module ) then inside_module = . true . else ! Must have missed an end module statement (can't assume a pure module) if ( f_source % unit_type /= FPM_UNIT_PROGRAM ) then f_source % unit_type = FPM_UNIT_SUBPROGRAM end if end if cycle end if ! Extract name of submodule if is submodule if ( index ( file_lines_lower ( i )% s , 'submodule' ) == 1 ) then mod_name = split_n ( file_lines_lower ( i )% s , n = 3 , delims = '()' , stat = stat ) if ( stat /= 0 ) then call file_parse_error ( error , f_filename , & 'unable to get submodule name' , i , & file_lines_lower ( i )% s ) return end if if (. not . is_fortran_name ( mod_name )) then call file_parse_error ( error , f_filename , & 'empty or invalid name for submodule' , i , & file_lines_lower ( i )% s , index ( file_lines_lower ( i )% s , mod_name )) return end if n_mod = n_mod + 1 temp_string = split_n ( file_lines_lower ( i )% s , n = 2 , delims = '()' , stat = stat ) if ( stat /= 0 ) then call file_parse_error ( error , f_filename , & 'unable to get submodule ancestry' , i , & file_lines_lower ( i )% s ) return end if if ( f_source % unit_type /= FPM_UNIT_PROGRAM ) then f_source % unit_type = FPM_UNIT_SUBMODULE end if n_use = n_use + 1 inside_module = . true . n_parent = n_parent + 1 if ( pass == 2 ) then if ( index ( temp_string , ':' ) > 0 ) then temp_string = temp_string ( index ( temp_string , ':' ) + 1 :) end if if (. not . is_fortran_name ( temp_string )) then call file_parse_error ( error , f_filename , & 'empty or invalid name for submodule parent' , i , & file_lines_lower ( i )% s , index ( file_lines_lower ( i )% s , temp_string )) return end if f_source % modules_used ( n_use )% s = temp_string f_source % parent_modules ( n_parent )% s = temp_string f_source % modules_provided ( n_mod )% s = mod_name end if cycle end if ! Detect if contains a program ! - no modules allowed after program def ! - program header may be missing (only \"end program\" statement present) if ( index ( file_lines_lower ( i )% s , 'program ' ) == 1 . or . & parse_sequence ( file_lines_lower ( i )% s , 'end' , 'program' )) then temp_string = split_n ( file_lines_lower ( i )% s , n = 2 , delims = ' ' , stat = stat ) if ( stat == 0 ) then if ( scan ( temp_string , '=(' ) > 0 ) then ! Ignore: ! program =* ! program (i) =* cycle end if end if f_source % unit_type = FPM_UNIT_PROGRAM cycle end if ! Parse end module statement ! (to check for code outside of modules) if ( parse_sequence ( file_lines_lower ( i )% s , 'end' , 'module' ) . or . & parse_sequence ( file_lines_lower ( i )% s , 'end' , 'submodule' )) then inside_module = . false . cycle end if ! Any statements not yet parsed are assumed to be other code statements if (. not . inside_module . and . f_source % unit_type /= FPM_UNIT_PROGRAM ) then f_source % unit_type = FPM_UNIT_SUBPROGRAM end if end do file_loop ! If unable to parse end of module statement, then can't assume pure module ! (there could be non-module subprograms present) if ( inside_module . and . f_source % unit_type == FPM_UNIT_MODULE ) then f_source % unit_type = FPM_UNIT_SUBPROGRAM end if if ( pass == 1 ) then allocate ( f_source % modules_used ( n_use )) allocate ( f_source % include_dependencies ( n_include )) allocate ( f_source % modules_provided ( n_mod )) allocate ( f_source % parent_modules ( n_parent )) end if end do end function parse_f_source !> Parsing of c, cpp source files !> !> The following statements are recognised and parsed: !> !> - `#include` preprocessor statement !> function parse_c_source ( c_filename , error ) result ( c_source ) character ( * ), intent ( in ) :: c_filename type ( srcfile_t ) :: c_source type ( error_t ), allocatable , intent ( out ) :: error integer :: fh , n_include , i , pass , stat type ( string_t ), allocatable :: file_lines (:) c_source % file_name = c_filename if ( str_ends_with ( lower ( c_filename ), \".c\" )) then c_source % unit_type = FPM_UNIT_CSOURCE else if ( str_ends_with ( lower ( c_filename ), \".h\" )) then c_source % unit_type = FPM_UNIT_CHEADER else if ( str_ends_with ( lower ( c_filename ), \".cpp\" )) then c_source % unit_type = FPM_UNIT_CPPSOURCE end if allocate ( c_source % modules_used ( 0 )) allocate ( c_source % modules_provided ( 0 )) allocate ( c_source % parent_modules ( 0 )) file_lines = read_lines ( c_filename ) ! Ignore empty files, returned as FPM_UNIT_UNKNOWN if ( len_trim ( file_lines ) < 1 ) then c_source % unit_type = FPM_UNIT_UNKNOWN return end if c_source % digest = fnv_1a ( file_lines ) do pass = 1 , 2 n_include = 0 file_loop : do i = 1 , size ( file_lines ) ! Process 'INCLUDE' statements if ( index ( adjustl ( lower ( file_lines ( i )% s )), '#include' ) == 1 . and . & index ( file_lines ( i )% s , '\"' ) > 0 ) then n_include = n_include + 1 if ( pass == 2 ) then c_source % include_dependencies ( n_include )% s = & & split_n ( file_lines ( i )% s , n = 2 , delims = '\"' , stat = stat ) if ( stat /= 0 ) then call file_parse_error ( error , c_filename , & 'unable to get c include file' , i , & file_lines ( i )% s , index ( file_lines ( i )% s , '\"' )) return end if end if end if end do file_loop if ( pass == 1 ) then allocate ( c_source % include_dependencies ( n_include )) end if end do end function parse_c_source !> Split a string on one or more delimeters !> and return the nth substring if it exists !> !> n=0 will return the last item !> n=-1 will return the penultimate item etc. !> !> stat = 1 on return if the index !> is not found !> function split_n ( string , delims , n , stat ) result ( substring ) character ( * ), intent ( in ) :: string character ( * ), intent ( in ) :: delims integer , intent ( in ) :: n integer , intent ( out ) :: stat character (:), allocatable :: substring integer :: i character (:), allocatable :: string_parts (:) call split ( string , string_parts , delims ) if ( n < 1 ) then i = size ( string_parts ) + n if ( i < 1 ) then allocate ( character ( len = 0 ) :: substring ) ! ifort bus error otherwise stat = 1 return end if else i = n end if if ( i > size ( string_parts )) then allocate ( character ( len = 0 ) :: substring ) ! ifort bus error otherwise stat = 1 return end if substring = trim ( adjustl ( string_parts ( i ))) stat = 0 end function split_n !> Parse a subsequence of blank-separated tokens within a string !> (see parse_sequence) function parse_subsequence ( string , t1 , t2 , t3 , t4 ) result ( found ) character ( * ), intent ( in ) :: string character ( * ), intent ( in ) :: t1 character ( * ), intent ( in ), optional :: t2 , t3 , t4 logical :: found integer :: offset , i found = . false . offset = 1 do i = index ( string ( offset :), t1 ) if ( i == 0 ) return offset = offset + i - 1 found = parse_sequence ( string ( offset :), t1 , t2 , t3 , t4 ) if ( found ) return offset = offset + len ( t1 ) if ( offset > len ( string )) return end do end function parse_subsequence !> Helper utility to parse sequences of tokens !> that may be optionally separated by zero or more spaces function parse_sequence ( string , t1 , t2 , t3 , t4 ) result ( found ) character ( * ), intent ( in ) :: string character ( * ), intent ( in ) :: t1 character ( * ), intent ( in ), optional :: t2 , t3 , t4 logical :: found integer :: post , n , incr , pos , token_n logical :: match n = len ( string ) found = . false . pos = 1 do token_n = 1 , 4 do while ( pos <= n ) if ( string ( pos : pos ) /= ' ' ) then exit end if pos = pos + 1 end do select case ( token_n ) case ( 1 ) incr = len ( t1 ) if ( pos + incr - 1 > n ) return match = string ( pos : pos + incr - 1 ) == t1 case ( 2 ) if (. not . present ( t2 )) exit incr = len ( t2 ) if ( pos + incr - 1 > n ) return match = string ( pos : pos + incr - 1 ) == t2 case ( 3 ) if (. not . present ( t3 )) exit incr = len ( t3 ) if ( pos + incr - 1 > n ) return match = string ( pos : pos + incr - 1 ) == t3 case ( 4 ) if (. not . present ( t4 )) exit incr = len ( t4 ) if ( pos + incr - 1 > n ) return match = string ( pos : pos + incr - 1 ) == t4 case default exit end select if (. not . match ) then return end if pos = pos + incr end do found = . true . end function parse_sequence ! USE [, intrinsic] :: module_name [, only: only_list] ! USE [, non_intrinsic] :: module_name [, only: only_list] subroutine parse_use_statement ( f_filename , i , line , use_stmt , is_intrinsic , module_name , error ) !> Current file name and line number (for error messaging) character ( * ), intent ( in ) :: f_filename integer , intent ( in ) :: i !> The line being parsed. MUST BE preprocessed with trim(adjustl() character ( * ), intent ( in ) :: line !> Does this line contain a `use` statement? logical , intent ( out ) :: use_stmt !> Is the module in this statement intrinsic? logical , intent ( out ) :: is_intrinsic !> used module name character (:), allocatable , intent ( out ) :: module_name !> Error handling type ( error_t ), allocatable , intent ( out ) :: error character ( 15 ), parameter :: INTRINSIC_NAMES ( * ) = & [ 'iso_c_binding ' , & 'iso_fortran_env' , & 'ieee_arithmetic' , & 'ieee_exceptions' , & 'ieee_features ' , & 'omp_lib ' ] character ( len = :), allocatable :: temp_string integer :: colons , intr , nonintr , j , stat logical :: has_intrinsic_name use_stmt = . false . is_intrinsic = . false . if ( len_trim ( line ) <= 0 ) return ! Quick check that the line is preprocessed if ( line ( 1 : 1 ) == ' ' ) then call fatal_error ( error , 'internal_error: source file line is not trim(adjustl()) on input to parse_use_statement' ) return end if ! 'use' should be the first string in the adjustl line use_stmt = index ( line , 'use ' ) == 1 . or . index ( line , 'use::' ) == 1 . or . index ( line , 'use,' ) == 1 if (. not . use_stmt ) return colons = index ( line , '::' ) nonintr = 0 intr = 0 have_colons : if ( colons > 3 ) then ! there may be an intrinsic/non-intrinsic spec nonintr = index ( line ( 1 : colons - 1 ), 'non_intrinsic' ) if ( nonintr == 0 ) intr = index ( line ( 1 : colons - 1 ), 'intrinsic' ) temp_string = split_n ( line , delims = ':' , n = 2 , stat = stat ) if ( stat /= 0 ) then call file_parse_error ( error , f_filename , & 'unable to find used module name' , i , & line , colons ) return end if module_name = split_n ( temp_string , delims = ' ,' , n = 1 , stat = stat ) if ( stat /= 0 ) then call file_parse_error ( error , f_filename , & 'unable to find used module name' , i , & line ) return end if else module_name = split_n ( line , n = 2 , delims = ' ,' , stat = stat ) if ( stat /= 0 ) then call file_parse_error ( error , f_filename , & 'unable to find used module name' , i , & line ) return end if end if have_colons ! If declared intrinsic, check that it is true has_intrinsic_name = any ([( index ( module_name , trim ( INTRINSIC_NAMES ( j ))) > 0 , & j = 1 , size ( INTRINSIC_NAMES ))]) if ( intr > 0 . and . . not . has_intrinsic_name ) then ! An intrinsic module was not found. Its name could be in the next line, ! in which case, we just skip this check. The compiler will do the job if the name is invalid. ! Module name was not read: it's in the next line if ( index ( module_name , '&' ) <= 0 ) then call file_parse_error ( error , f_filename , & 'module ' // module_name // ' is declared intrinsic but it is not ' , i , & line ) return endif endif ! Should we treat this as an intrinsic module is_intrinsic = nonintr == 0 . and . & ! not declared non-intrinsic ( intr > 0 . or . has_intrinsic_name ) end subroutine parse_use_statement end module fpm_source_parsing","tags":"","url":"sourcefile/fpm_source_parsing.f90.html"},{"title":"executable.f90 – Fortran-lang/fpm","text":"Source Code !> Implementation of the meta data for an executables. !> !> An executable table can currently have the following fields !> !>```toml !>[[ executable ]] !>name = \"string\" !>source-dir = \"path\" !>main = \"file\" !>link = [\"lib\"] !>[executable.dependencies] !>``` module fpm_manifest_executable use fpm_manifest_dependency , only : dependency_config_t , new_dependencies , resize use fpm_error , only : error_t , syntax_error , bad_name_error , fatal_error use fpm_strings , only : string_t , operator ( == ) use tomlf , only : toml_table , toml_key , toml_stat use fpm_toml , only : get_value , get_list , serializable_t , add_table , & set_string , set_list implicit none private public :: executable_config_t , new_executable !> Configuation meta data for an executable type , extends ( serializable_t ) :: executable_config_t !> Name of the resulting executable character ( len = :), allocatable :: name !> Source directory for collecting the executable character ( len = :), allocatable :: source_dir !> Name of the source file declaring the main program character ( len = :), allocatable :: main !> Dependency meta data for this executable type ( dependency_config_t ), allocatable :: dependency (:) !> Libraries to link against type ( string_t ), allocatable :: link (:) contains !> Print information on this instance procedure :: info !> Serialization interface procedure :: serializable_is_same => exe_is_same procedure :: dump_to_toml procedure :: load_from_toml end type executable_config_t character ( * ), parameter , private :: class_name = 'executable_config_t' contains !> Construct a new executable configuration from a TOML data structure subroutine new_executable ( self , table , error ) !> Instance of the executable configuration type ( executable_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_table ), pointer :: child call check ( table , error ) if ( allocated ( error )) return call get_value ( table , \"name\" , self % name ) if (. not . allocated ( self % name )) then call syntax_error ( error , \"Could not retrieve executable name\" ) return end if if ( bad_name_error ( error , 'executable' , self % name )) then return endif call get_value ( table , \"source-dir\" , self % source_dir , \"app\" ) call get_value ( table , \"main\" , self % main , \"main.f90\" ) call get_value ( table , \"dependencies\" , child , requested = . false .) if ( associated ( child )) then call new_dependencies ( self % dependency , child , error = error ) if ( allocated ( error )) return end if call get_list ( table , \"link\" , self % link , error ) if ( allocated ( error )) return end subroutine new_executable !> Check local schema for allowed entries subroutine check ( table , error ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_key ), allocatable :: list (:) logical :: name_present integer :: ikey name_present = . false . call table % get_keys ( list ) if ( size ( list ) < 1 ) then call syntax_error ( error , \"Executable section does not provide sufficient entries\" ) return end if do ikey = 1 , size ( list ) select case ( list ( ikey )% key ) case default call syntax_error ( error , \"Key \" // list ( ikey )% key // \" is not allowed as executable entry\" ) exit case ( \"name\" ) name_present = . true . case ( \"source-dir\" , \"main\" , \"dependencies\" , \"link\" ) continue end select end do if ( allocated ( error )) return if (. not . name_present ) then call syntax_error ( error , \"Executable name is not provided, please add a name entry\" ) end if end subroutine check !> Write information on instance subroutine info ( self , unit , verbosity ) !> Instance of the executable configuration class ( executable_config_t ), intent ( in ) :: self !> Unit for IO integer , intent ( in ) :: unit !> Verbosity of the printout integer , intent ( in ), optional :: verbosity integer :: pr , ii character ( len =* ), parameter :: fmt = '(\"#\", 1x, a, t30, a)' , & & fmti = '(\"#\", 1x, a, t30, i0)' if ( present ( verbosity )) then pr = verbosity else pr = 1 end if if ( pr < 1 ) return write ( unit , fmt ) \"Executable target\" if ( allocated ( self % name )) then write ( unit , fmt ) \"- name\" , self % name end if if ( allocated ( self % source_dir )) then if ( self % source_dir /= \"app\" . or . pr > 2 ) then write ( unit , fmt ) \"- source directory\" , self % source_dir end if end if if ( allocated ( self % main )) then if ( self % main /= \"main.f90\" . or . pr > 2 ) then write ( unit , fmt ) \"- program source\" , self % main end if end if if ( allocated ( self % dependency )) then if ( size ( self % dependency ) > 1 . or . pr > 2 ) then write ( unit , fmti ) \"- dependencies\" , size ( self % dependency ) end if do ii = 1 , size ( self % dependency ) call self % dependency ( ii )% info ( unit , pr - 1 ) end do end if end subroutine info logical function exe_is_same ( this , that ) class ( executable_config_t ), intent ( in ) :: this class ( serializable_t ), intent ( in ) :: that integer :: ii exe_is_same = . false . select type ( other => that ) type is ( executable_config_t ) if (. not . this % link == other % link ) return if ( allocated ( this % name ). neqv . allocated ( other % name )) return if ( allocated ( this % name )) then if (. not . this % name == other % name ) return end if if ( allocated ( this % source_dir ). neqv . allocated ( other % source_dir )) return if ( allocated ( this % source_dir )) then if (. not . this % source_dir == other % source_dir ) return end if if ( allocated ( this % main ). neqv . allocated ( other % main )) return if ( allocated ( this % main )) then if (. not . this % main == other % main ) return end if if ( allocated ( this % dependency ). neqv . allocated ( other % dependency )) return if ( allocated ( this % dependency )) then if (. not .( size ( this % dependency ) == size ( other % dependency ))) return do ii = 1 , size ( this % dependency ) if (. not .( this % dependency ( ii ) == other % dependency ( ii ))) return end do end if class default ! Not the same type return end select !> All checks passed! exe_is_same = . true . end function exe_is_same !> Dump install config to toml table subroutine dump_to_toml ( self , table , error ) !> Instance of the serializable object class ( executable_config_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Local variables integer :: ierr , ii type ( toml_table ), pointer :: ptr_deps , ptr character ( 27 ) :: unnamed call set_string ( table , \"name\" , self % name , error ) if ( allocated ( error )) return call set_string ( table , \"source-dir\" , self % source_dir , error ) if ( allocated ( error )) return call set_string ( table , \"main\" , self % main , error ) if ( allocated ( error )) return if ( allocated ( self % dependency )) then ! Create dependency table call add_table ( table , \"dependencies\" , ptr_deps ) if (. not . associated ( ptr_deps )) then call fatal_error ( error , class_name // \" cannot create dependency table \" ) return end if do ii = 1 , size ( self % dependency ) associate ( dep => self % dependency ( ii )) !> Because dependencies are named, fallback if this has no name !> So, serialization will work regardless of size(self%dep) == self%ndep if ( len_trim ( dep % name ) == 0 ) then write ( unnamed , 1 ) ii call add_table ( ptr_deps , trim ( unnamed ), ptr ) else call add_table ( ptr_deps , dep % name , ptr ) end if if (. not . associated ( ptr )) then call fatal_error ( error , class_name // \" cannot create entry for dependency \" // dep % name ) return end if call dep % dump_to_toml ( ptr , error ) if ( allocated ( error )) return end associate end do endif call set_list ( table , \"link\" , self % link , error ) if ( allocated ( error )) return 1 format ( 'UNNAMED_DEPENDENCY_' , i0 ) end subroutine dump_to_toml !> Read install config from toml table (no checks made at this stage) subroutine load_from_toml ( self , table , error ) !> Instance of the serializable object class ( executable_config_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error !> Local variables type ( toml_key ), allocatable :: keys (:), dep_keys (:) type ( toml_table ), pointer :: ptr_deps , ptr integer :: ii , jj , ierr call table % get_keys ( keys ) call get_value ( table , \"name\" , self % name ) if ( allocated ( error )) return call get_value ( table , \"source-dir\" , self % source_dir ) if ( allocated ( error )) return call get_value ( table , \"main\" , self % main ) if ( allocated ( error )) return call get_list ( table , \"link\" , self % link , error ) find_deps_table : do ii = 1 , size ( keys ) if ( keys ( ii )% key == \"dependencies\" ) then call get_value ( table , keys ( ii ), ptr_deps ) if (. not . associated ( ptr_deps )) then call fatal_error ( error , class_name // ': error retrieving dependency table from TOML table' ) return end if !> Read all dependencies call ptr_deps % get_keys ( dep_keys ) call resize ( self % dependency , size ( dep_keys )) do jj = 1 , size ( dep_keys ) call get_value ( ptr_deps , dep_keys ( jj ), ptr ) call self % dependency ( jj )% load_from_toml ( ptr , error ) if ( allocated ( error )) return end do exit find_deps_table endif end do find_deps_table end subroutine load_from_toml end module fpm_manifest_executable","tags":"","url":"sourcefile/executable.f90.html"},{"title":"fpm_meta_hdf5.f90 – Fortran-lang/fpm","text":"Source Code module fpm_meta_hdf5 use fpm_compiler , only : compiler_t , get_include_flag use fpm_strings , only : str_begins_with_str , str_ends_with , string_t use fpm_filesystem , only : join_path use fpm_pkg_config , only : assert_pkg_config , pkgcfg_has_package , pkgcfg_list_all use fpm_meta_base , only : metapackage_t , destroy use fpm_meta_util , only : add_pkg_config_compile_options , lib_get_trailing use fpm_manifest_metapackages , only : metapackage_request_t use fpm_error , only : error_t , fatal_error implicit none private public :: init_hdf5 contains !> Initialize HDF5 metapackage for the current system subroutine init_hdf5 ( this , compiler , all_meta , error ) class ( metapackage_t ), intent ( inout ) :: this type ( compiler_t ), intent ( in ) :: compiler type ( metapackage_request_t ), intent ( in ) :: all_meta (:) type ( error_t ), allocatable , intent ( out ) :: error character ( * ), parameter :: find_hl ( * ) = & [ character ( 11 ) :: '_hl_fortran' , 'hl_fortran' , '_fortran' , '_hl' ] character ( * ), parameter :: candidates ( * ) = & [ character ( 15 ) :: 'hdf5_hl_fortran' , 'hdf5-hl-fortran' , 'hdf5_fortran' , 'hdf5-fortran' ,& 'hdf5_hl' , 'hdf5' , 'hdf5-serial' ] integer :: i , j , k , l logical :: s , found_hl ( size ( find_hl )), found type ( string_t ) :: log , this_lib type ( string_t ), allocatable :: libs (:), flags (:), modules (:), non_fortran (:) character ( len = :), allocatable :: name , include_flag , libdir , ext , pref include_flag = get_include_flag ( compiler , \"\" ) !> Cleanup call destroy ( this ) allocate ( this % link_libs ( 0 ), this % incl_dirs ( 0 ), this % external_modules ( 0 ), non_fortran ( 0 )) this % link_flags = string_t ( \"\" ) this % flags = string_t ( \"\" ) !> Set name this % name = \"hdf5\" !> Assert pkg-config is installed if (. not . assert_pkg_config ()) then call fatal_error ( error , 'hdf5 metapackage requires pkg-config' ) return end if !> Find pkg-config package file by priority name = 'NOT_FOUND' find_package : do i = 1 , size ( candidates ) if ( pkgcfg_has_package ( trim ( candidates ( i )))) then name = trim ( candidates ( i )) exit find_package end if end do find_package !> some distros put hdf5-1.2.3.pc with version number in .pc filename. if ( name == 'NOT_FOUND' ) then modules = pkgcfg_list_all ( error ) find_global_package : do i = 1 , size ( modules ) if ( str_begins_with_str ( modules ( i )% s , 'hdf5' )) then name = modules ( i )% s exit find_global_package end if end do find_global_package end if if ( name == 'NOT_FOUND' ) then call fatal_error ( error , 'pkg-config could not find a suitable hdf5 package.' ) return end if call add_pkg_config_compile_options ( this , name , include_flag , libdir , error ) if ( allocated ( error )) return ! Some pkg-config hdf5.pc (e.g. Ubuntu) don't include the commonly-used HL HDF5 libraries, ! so let's add them if they exist if ( len_trim ( libdir ) > 0 ) then do i = 1 , size ( this % link_libs ) found_hl = . false . if (. not . str_ends_with ( this % link_libs ( i )% s , find_hl )) then ! Extract name with no extension call lib_get_trailing ( this % link_libs ( i )% s , libdir , pref , ext , found ) ! Search how many versions with the Fortran endings there are finals : do k = 1 , size ( find_hl ) do j = 1 , size ( this % link_libs ) if ( str_begins_with_str ( this % link_libs ( j )% s , this % link_libs ( i )% s ) . and . & str_ends_with ( this % link_libs ( j )% s , trim ( find_hl ( k )))) then found_hl ( k ) = . true . cycle finals end if end do end do finals ! For each of the missing ones, if there is a file, add it add_missing : do k = 1 , size ( find_hl ) if ( found_hl ( k )) cycle add_missing ! Build file name this_lib % s = join_path ( libdir , pref // this % link_libs ( i )% s // trim ( find_hl ( k )) // ext ) inquire ( file = this_lib % s , exist = found ) ! File exists, but it is not linked against if ( found ) this % link_libs = [ this % link_libs , & string_t ( this % link_libs ( i )% s // trim ( find_hl ( k )))] end do add_missing end if end do endif !> Add HDF5 modules as external this % has_external_modules = . true . this % external_modules = [ string_t ( 'h5a' ), & string_t ( 'h5d' ), & string_t ( 'h5es' ), & string_t ( 'h5e' ), & string_t ( 'h5f' ), & string_t ( 'h5g' ), & string_t ( 'h5i' ), & string_t ( 'h5l' ), & string_t ( 'h5o' ), & string_t ( 'h5p' ), & string_t ( 'h5r' ), & string_t ( 'h5s' ), & string_t ( 'h5t' ), & string_t ( 'h5vl' ), & string_t ( 'h5z' ), & string_t ( 'h5lt' ), & string_t ( 'h5lib' ), & string_t ( 'h5global' ), & string_t ( 'h5_gen' ), & string_t ( 'h5fortkit' ), & string_t ( 'hdf5' )] end subroutine init_hdf5 end module fpm_meta_hdf5","tags":"","url":"sourcefile/fpm_meta_hdf5.f90.html"},{"title":"new.f90 – Fortran-lang/fpm","text":"Source Code module fpm_cmd_new !># Definition of the \"new\" subcommand !> !> A type of the general command base class [[fpm_cmd_settings]] !> was created for the \"new\" subcommand ==> type [[fpm_new_settings]]. !> This procedure read the values that were set on the command line !> from this type to decide what actions to take. !> !> It is virtually self-contained and so independant of the rest of the !> application that it could function as a separate program. !> !> The \"new\" subcommand options currently consist of a SINGLE top !> directory name to create that must have a name that is an !> allowable Fortran variable name. That should have been ensured !> by the command line processing before this procedure is called. !> So basically this routine has already had the options vetted and !> just needs to conditionally create a few files. !> !> As described in the documentation it will selectively !> create the subdirectories app/, test/, src/, and example/ !> and populate them with sample files. !> !> It also needs to create an initial manifest file \"fpm.toml\". !> !> It then calls the system command \"git init\". !> !> It should test for file existence and not overwrite existing !> files and inform the user if there were conflicts. !> !> Any changes should be reflected in the documentation in !> [[fpm_command_line.f90]] !> !> FUTURE !> A filename like \".\" would need system commands or a standard routine !> like realpath(3c) to process properly. !> !> Perhaps allow more than one name on a single command. It is an arbitrary !> restriction based on a concensus preference, not a required limitation. !> !> Initially the name of the directory is used as the module name in the !> src file so it must be an allowable Fortran variable name. If there are !> complaints about it it might be changed. Handling unicode at this point !> might be problematic as not all current compilers handle it. Other !> utilities like content trackers (ie. git) or repositories like github !> might also have issues with alternative names or names with spaces, etc. !> So for the time being it seems prudent to encourage simple ASCII top directory !> names (similiar to the primary programming language Fortran itself). !> !> Should be able to create or pull more complicated initial examples !> based on various templates. It should place or mention other relevant !> documents such as a description of the manifest file format in user hands; !> or how to access registered packages and local packages, !> although some other command might provide that (and the help command should !> be the first go-to for a CLI utility). use fpm_command_line , only : fpm_new_settings use fpm_environment , only : OS_LINUX , OS_MACOS , OS_WINDOWS use fpm_filesystem , only : join_path , exists , basename , mkdir , is_dir use fpm_filesystem , only : fileopen , fileclose , warnwrite , which , run use fpm_strings , only : join , to_fortran_name use fpm_error , only : fpm_stop use , intrinsic :: iso_fortran_env , only : stderr => error_unit implicit none private public :: cmd_new contains subroutine cmd_new ( settings ) type ( fpm_new_settings ), intent ( in ) :: settings integer , parameter :: tfc = selected_char_kind ( 'DEFAULT' ) character ( len = :, kind = tfc ), allocatable :: bname ! baeename of NAME character ( len = :, kind = tfc ), allocatable :: tomlfile (:) character ( len = :, kind = tfc ), allocatable :: littlefile (:) !> TOP DIRECTORY NAME PROCESSING !> see if requested new directory already exists and process appropriately if ( exists ( settings % name ) . and . . not . settings % backfill ) then write ( stderr , '(*(g0,1x))' )& & '' , settings % name , 'already exists.' write ( stderr , '(*(g0,1x))' )& & ' perhaps you wanted to add --backfill ?' return elseif ( is_dir ( settings % name ) . and . settings % backfill ) then write ( * , '(*(g0))' ) 'backfilling ' , settings % name elseif ( exists ( settings % name ) ) then write ( stderr , '(*(g0,1x))' )& & '' , settings % name , 'already exists and is not a directory.' return else ! make new directory call mkdir ( settings % name ) endif !> temporarily change to new directory as a test. NB: System dependent call run ( 'cd ' // settings % name ) ! NOTE: need some system routines to handle filenames like \".\" ! like realpath() or getcwd(). bname = basename ( settings % name ) littlefile = [ character ( len = 80 ) :: '# ' // bname , 'My cool new project!' ] ! create NAME/README.md call warnwrite ( join_path ( settings % name , 'README.md' ), littlefile ) ! start building NAME/fpm.toml if ( settings % with_full ) then tomlfile = [ character ( len = 80 ) :: & & ' # This is your fpm(Fortran Package Manager) manifest file ' ,& & ' # (\"fpm.toml\"). It is heavily annotated to help guide you though ' ,& & ' # customizing a package build, although the defaults are sufficient ' ,& & ' # for many basic packages. ' ,& & ' # ' ,& & ' # The manifest file is not only used to provide metadata identifying ' ,& & ' # your project (so it can be used by others as a dependency). It can ' ,& & ' # specify where your library and program sources live, what the name ' ,& & ' # of the executable(s) will be, what files to build, dependencies on ' ,& & ' # other fpm packages, and what external libraries are required. ' ,& & ' # ' ,& & ' # The manifest format must conform to the TOML configuration file ' ,& & ' # standard. ' ,& & ' # ' ,& & ' # TOML files support flexible use of white-space and commenting of the ' ,& & ' # configuration data, but for clarity in this sample active directives ' ,& & ' # begin in column one. Inactive example directives are commented ' ,& & ' # out with a pound character (\"#\") but begin in column one as well. ' ,& & ' # Commentary begins with a pound character in column three. ' ,& & ' # ' ,& & ' # This file draws heavily upon the following references: ' ,& & ' # ' ,& & ' # The fpm home page at ' ,& & ' # https://github.com/fortran-lang/fpm ' ,& & ' # A complete list of keys and their attributes at ' ,& & ' # https://github.com/fortran-lang/fpm/blob/main/manifest-reference.md ' ,& & ' # examples of fpm project packaging at ' ,& & ' # https://github.com/fortran-lang/fpm/blob/main/PACKAGING.md ' ,& & ' # The Fortran TOML file interface and it''s references at ' ,& & ' # https://github.com/toml-f/toml-f ' ,& & ' # ' ,& & ' #----------------------- ' ,& & ' # project Identification ' ,& & ' #----------------------- ' ,& & ' # We begin with project metadata at the manifest root. This data is designed ' ,& & ' # to aid others when searching for the project in a repository and to ' ,& & ' # identify how and when to contact the package supporters. ' ,& & ' ' ,& & 'name = \"' // bname // '\"' ,& & ' # The project name (required) is how the project will be referred to. ' ,& & ' # The name is used by other packages using it as a dependency. It also ' ,& & ' # is used as the default name of any library built and the optional ' ,& & ' # default executable built from app/main.f90. It must conform to the rules ' ,& & ' # for a Fortran variable name. ' ,& & ' ' ,& & 'version = \"0.1.0\" ' ,& & ' # The project version number is a string. A recommended scheme for ' ,& & ' # specifying versions is the Semantic Versioning scheme. ' ,& & ' ' ,& & 'license = \"license\" ' ,& & ' # Licensing information specified using SPDX identifiers is preferred ' ,& & ' # (eg. \"Apache-2.0 OR MIT\" or \"LGPL-3.0-or-later\"). ' ,& & ' ' ,& & 'maintainer = \"jane.doe@example.com\" ' ,& & ' # Information on the project maintainer and means to reach out to them. ' ,& & ' ' ,& & 'author = \"Jane Doe\" ' ,& & ' # Information on the project author. ' ,& & ' ' ,& & 'copyright = \"Copyright 2020 Jane Doe\" ' ,& & ' # A statement clarifying the Copyright status of the project. ' ,& & ' ' ,& & '#description = \"A short project summary in plain text\" ' ,& & ' # The description provides a short summary on the project. It should be ' ,& & ' # plain text and not use any markup formatting. ' ,& & ' ' ,& & '#categories = [\"fortran\", \"graphics\"] ' ,& & ' # Categories associated with the project. Listing only one is preferred. ' ,& & ' ' ,& & '#keywords = [\"hdf5\", \"mpi\"] ' ,& & ' # The keywords field is an array of strings describing the project. ' ,& & ' ' ,& & '#homepage = \"https://stdlib.fortran-lang.org\" ' ,& & ' # URL to the webpage of the project. ' ,& & ' ' ,& & ' # ----------------------------------------- ' ,& & ' # We are done with identifying the project. ' ,& & ' # ----------------------------------------- ' ,& & ' # ' ,& & ' # Now lets start describing how the project should be built. ' ,& & ' # ' ,& & ' # Note tables would go here but we will not be talking about them (much)!!' ,& & ' # ' ,& & ' # Tables are a way to explicitly specify large numbers of programs in ' ,& & ' # a compact format instead of individual per-program entries in the ' ,& & ' # [[executable]], [[test]], and [[example]] sections to follow but ' ,& & ' # will not be discussed further except for the following notes: ' ,& & ' # ' ,& & ' # + Tables must appear (here) before any sections are declared. Once a ' ,& & ' # section is specified in a TOML file everything afterwards must be ' ,& & ' # values for that section or the beginning of a new section. A simple ' ,& & ' # example looks like: ' ,& & ' ' ,& & '#executable = [ ' ,& & '# { name = \"a-prog\" }, ' ,& & '# { name = \"app-tool\", source-dir = \"tool\" }, ' ,& & '# { name = \"fpm-man\", source-dir = \"tool\", main=\"fman.f90\" } ' ,& & '#] ' ,& & ' ' ,& & ' # This would be in lieue of the [[executable]] section found later in this ' ,& & ' # configuration file. ' ,& & ' # + See the reference documents (at the beginning of this document) ' ,& & ' # for more information on tables if you have long lists of programs ' ,& & ' # to build and are not simply depending on auto-detection. ' ,& & ' # ' ,& & ' # Now lets begin the TOML sections (lines beginning with \"[\") ... ' ,& & ' # ' ,& & ' ' ,& & '[install] # Options for the \"install\" subcommand ' ,& & ' ' ,& & ' # When you run the \"install\" subcommand only executables are installed by ' ,& & ' # default on the local system. Library projects that will be used outside of ' ,& & ' # \"fpm\" can set the \"library\" boolean to also allow installing the module ' ,& & ' # files and library archive. Without this being set to \"true\" an \"install\" ' ,& & ' # subcommand ignores parameters that specify library installation. ' ,& & ' ' ,& & ' # If your project sets `[library] type = \"shared\"`, enabling this option ' ,& & ' # will install the compiled `.so`, `.dylib`, or `.dll` files into the ' ,& & ' # appropriate `lib/` folder. This applies equally to static archives. ' ,& & ' # ' ,& & ' # For shared libraries, installing is typically required for runtime usage. ' ,& & ' ' ,& & 'library = false ' ,& & ' ' ,& & '[build] # General Build Options ' ,& & ' ' ,& & ' ### Automatic target discovery ' ,& & ' # ' ,& & ' # Normally fpm recursively searches the app/, example/, and test/ directories ' ,& & ' # for program sources and builds them. To disable this automatic discovery of ' ,& & ' # program targets set the following to \"false\": ' ,& & ' ' ,& & '#auto-executables = true ' ,& & '#auto-examples = true ' ,& & '#auto-tests = true ' ,& & ' ' ,& & ' ### Package-level External Library Links ' ,& & ' # ' ,& & ' # To declare link-time dependencies on external libraries a list of ' ,& & ' # native libraries can be specified with the \"link\" entry. You may ' ,& & ' # have one library name or a list of strings in case several ' ,& & ' # libraries should be linked. This list of library dependencies is ' ,& & ' # exported to dependent packages. You may have to alter your library ' ,& & ' # search-path to ensure the libraries can be accessed. Typically, ' ,& & ' # this is done with the LD_LIBRARY_PATH environment variable on ULS ' ,& & ' # (Unix-Like Systems). You only specify the core name of the library ' ,& & ' # (as is typical with most programming environments, where you ' ,& & ' # would specify \"-lz\" on your load command to link against the zlib ' ,& & ' # compression library even though the library file would typically be ' ,& & ' # a file called \"libz.a\" \"or libz.so\"). So to link against that library ' ,& & ' # you would specify: ' ,& & ' ' ,& & '#link = \"z\" ' ,& & ' ' ,& & ' # Note that in some cases the order of the libraries matters: ' ,& & ' ' ,& & '#link = [\"blas\", \"lapack\"] ' ,& & '' ] endif if ( settings % with_bare ) then elseif ( settings % with_lib ) then call mkdir ( join_path ( settings % name , 'src' ) ) ! create next section of fpm.toml if ( settings % with_full ) then tomlfile = [ character ( len = 80 ) :: tomlfile , & & '[library] ' ,& & ' ' ,& & ' # You can change the name of the directory to search for your library ' ,& & ' # source from the default of \"src/\". Library targets are exported ' ,& & ' # and usable by other projects. ' ,& & ' ' ,& & 'source-dir=\"src\" ' ,& & ' ' ,& & ' # this can be a list: ' ,& & ' ' ,& & '#source-dir=[\"src\", \"src2\"] ' ,& & ' ' ,& & ' # More complex libraries may organize their modules in subdirectories. ' ,& & ' # For modules in a top-level directory fpm requires (but does not ' ,& & ' # enforce) that: ' ,& & ' # ' ,& & ' # + The module has the same name as the source file. This is important. ' ,& & ' # + There should be only one module per file. ' ,& & ' # ' ,& & ' # These two requirements simplify the build process for fpm. As Fortran ' ,& & ' # compilers emit module files (.mod) with the same name as the module ' ,& & ' # itself (but not the source file, .f90), naming the module the same ' ,& & ' # as the source file allows fpm to: ' ,& & ' # ' ,& & ' # + Uniquely and exactly map a source file (.f90) to its object (.o) ' ,& & ' # and module (.mod) files. ' ,& & ' # + Avoid conflicts with modules of the same name that could appear ' ,& & ' # in dependency packages. ' ,& & ' # ' ,& & ' ### Multi-level library source ' ,& & ' # You can place your module source files in any number of levels of ' ,& & ' # subdirectories inside your source directory, but there are certain naming ' ,& & ' # conventions to be followed -- module names must contain the path components ' ,& & ' # of the directory that its source file is in. ' ,& & ' # ' ,& & ' # This rule applies generally to any number of nested directories and ' ,& & ' # modules. For example, src/a/b/c/d.f90 must define a module called a_b_c_d. ' ,& & ' # Again, this is not enforced but may be required in future releases. ' ,& & ' ' ,& & ' ### Library type ' ,& & ' # Set `type = \"shared\"` to build dynamic libraries (.so/.dylib/.dll) ' ,& & ' # instead of a static archive. You can also set `type = \"static\"` to ' ,& & ' # generate per-package archives, or use `type = \"monolithic\"` (default) ' ,& & ' # to bundle all sources and dependencies into a single archive. ' ,& & ' # ' ,& & ' # Supported types: ' ,& & ' # ' ,& & ' # + \"monolithic\": Single archive with used sources and dependencies. ' ,& & ' # + \"static\": One full archive per package (for external integration). ' ,& & ' # + \"shared\": One shared library per package, for dynamic linking. ' ,& & ' # ' ,& & ' # Shared libraries are useful for plugin systems, dynamic linking, or ' ,& & ' # language bindings. Static per-package archives may aid external reuse. ' ,& & ' # ' ,& & ' # When running with `fpm run`, shared library paths are automatically ' ,& & ' # added to the environment (e.g. `LD_LIBRARY_PATH`, `PATH`) at runtime. ' ,& & ' # ' ,& & ' # Note: library files are not installed unless `[install] library=true` ' ,& & ' # is also enabled. ' ,& & ' # ' ,& & ' # Example: ' ,& & ' ' ,& & 'type = \"shared\" ' ,& & ' ' ,& & '' ] endif ! create placeholder module src/bname.f90 littlefile = [ character ( len = 80 ) :: & & 'module ' // to_fortran_name ( bname ), & & ' implicit none' , & & ' private' , & & '' , & & ' public :: say_hello' , & & 'contains' , & & ' subroutine say_hello' , & & ' print *, \"Hello, ' // bname // '!\"' , & & ' end subroutine say_hello' , & & 'end module ' // to_fortran_name ( bname )] ! create NAME/src/NAME.f90 call warnwrite ( join_path ( settings % name , 'src' , bname // '.f90' ),& & littlefile ) endif if ( settings % with_full ) then tomlfile = [ character ( len = 80 ) :: tomlfile ,& & '[dependencies] ' ,& & ' ' ,& & ' # Inevitably, you will want to be able to include other packages in ' ,& & ' # a project. Fpm makes this incredibly simple, by taking care of ' ,& & ' # fetching and compiling your dependencies for you. You just tell it ' ,& & ' # what your dependencies names are, and where to find them. ' ,& & ' # ' ,& & ' # If you are going to distribute your package only place dependencies ' ,& & ' # here someone using your package as a remote dependency needs built. ' ,& & ' # You can define dependencies just for developer executables in the ' ,& & ' # next section, or even for specific executables as we will see below ' ,& & ' # (Then fpm will still fetch and compile it when building your ' ,& & ' # developer executables, but users of your library will not have to). ' ,& & ' # ' ,& & ' ## GLOBAL DEPENDENCIES (exported with your project) ' ,& & ' # ' ,& & ' # Typically, dependencies are defined by specifying the project''s ' ,& & ' # git repository. ' ,& & ' # ' ,& & ' # You can be specific about which version of a dependency you would ' ,& & ' # like. By default the latest default branch is used. You can ' ,& & ' # optionally specify a branch, a tag or a commit value. ' ,& & ' # ' ,& & ' # So here are several alternates for specifying a remote dependency (you ' ,& & ' # can have at most one of \"branch\", \"rev\" or \"tag\" present): ' ,& & ' ' ,& & '#stdlib = { git = \"https://github.com/LKedward/stdlib-fpm.git\" } ' ,& & '#stdlib = {git=\"https://github.com/LKedward/stdlib-fpm.git\",branch = \"master\" },' ,& & '#stdlib = {git=\"https://github.com/LKedward/stdlib-fpm.git\", tag = \"v0.1.0\" }, ' ,& & '#stdlib = {git=\"https://github.com/LKedward/stdlib-fpm.git\", rev = \"5a9b7a8\" }. ' ,& & ' ' ,& & ' # There may be multiple packages listed: ' ,& & ' ' ,& & '#M_strings = { git = \"https://github.com/urbanjost/M_strings.git\" } ' ,& & '#M_time = { git = \"https://github.com/urbanjost/M_time.git\" } ' ,& & ' ' ,& & ' # ' ,& & ' # You can even specify the local path to another project if it is in ' ,& & ' # a sub-folder (If for example you have got another fpm package **in ' ,& & ' # the same repository**) like this: ' ,& & ' ' ,& & '#M_strings = { path = \"M_strings\" } ' ,& & ' ' ,& & ' # This tells fpm that we depend on a crate called M_strings which is found ' ,& & ' # in the M_strings folder (relative to the fpm.toml it’s written in). ' ,& & ' # ' ,& & ' # For a more verbose layout use normal tables rather than inline tables ' ,& & ' # to specify dependencies: ' ,& & ' ' ,& & '#[dependencies.toml-f] ' ,& & '#git = \"https://github.com/toml-f/toml-f\" ' ,& & '#rev = \"2f5eaba864ff630ba0c3791126a3f811b6e437f3\" ' ,& & ' ' ,& & ' # Now you can use any modules from these libraries anywhere in your ' ,& & ' # code -- whether is in your library source or a program source. ' ,& & ' ' ,& & '[dev-dependencies] ' ,& & ' ' ,& & ' ## Dependencies Only for Development ' ,& & ' # ' ,& & ' # You can specify dependencies your library or application does not ' ,& & ' # depend on in a similar way. The difference is that these will not ' ,& & ' # be exported as part of your project to those using it as a remote ' ,& & ' # dependency. ' ,& & ' # ' ,& & ' # Currently, like a global dependency it will still be available for ' ,& & ' # all codes. It is up to the developer to ensure that nothing except ' ,& & ' # developer test programs rely upon it. ' ,& & ' ' ,& & '#M_msg = { git = \"https://github.com/urbanjost/M_msg.git\" } ' ,& & '#M_verify = { git = \"https://github.com/urbanjost/M_verify.git\" } ' ,& & '' ] endif if ( settings % with_bare ) then elseif ( settings % with_executable ) then ! create next section of fpm.toml call mkdir ( join_path ( settings % name , 'app' )) ! create NAME/app or stop if ( settings % with_full ) then tomlfile = [ character ( len = 80 ) :: tomlfile , & & ' #----------------------------------- ' ,& & ' ## Application-specific declarations ' ,& & ' #----------------------------------- ' ,& & ' # Now lets begin entries for the TOML tables (lines beginning with \"[[\") ' ,& & ' # that describe the program sources -- applications, tests, and examples. ' ,& & ' # ' ,& & ' # First we will configuration individual applications run with \"fpm run\". ' ,& & ' # ' ,& & ' # + the \"name\" entry for the executable to be built must always ' ,& & ' # be specified. The name must satisfy the rules for a Fortran ' ,& & ' # variable name. This will be the name of the binary installed by ' ,& & ' # the \"install\" subcommand and used on the \"run\" subcommand. ' ,& & ' # + The source directory for each executable can be adjusted by the ' ,& & ' # \"source-dir\" entry. ' ,& & ' # + The basename of the source file containing the program body can ' ,& & ' # be specified with the \"main\" entry. ' ,& & ' # + Executables can also specify their own external package and ' ,& & ' # library link dependencies. ' ,& & ' # ' ,& & ' # Currently, like a global dependency any external package dependency ' ,& & ' # will be available for all codes. It is up to the developer to ensure ' ,& & ' # that nothing except the application programs specified rely upon it. ' ,& & ' # ' ,& & ' # Note if your application needs to use a module internally, but you do not ' ,& & ' # intend to build it as a library to be used in other projects, you can ' ,& & ' # include the module in your program source file or directory as well. ' ,& & ' ' ,& & '[[executable]] ' ,& & 'name=\"' // bname // '\"' ,& & 'source-dir=\"app\" ' ,& & 'main=\"main.f90\" ' ,& & ' ' ,& & ' # You may repeat this pattern to define additional applications. For instance,' ,& & ' # the following sample illustrates all accepted options, where \"link\" and ' ,& & ' # \"executable.dependencies\" keys are the same as the global external library ' ,& & ' # links and package dependencies described previously except they apply ' ,& & ' # only to this executable: ' ,& & ' ' ,& & '#[[ executable ]] ' ,& & '#name = \"app-name\" ' ,& & '#source-dir = \"prog\" ' ,& & '#main = \"program.f90\" ' ,& & '#link = \"z\" ' ,& & '#[executable.dependencies] ' ,& & '#M_CLI = { git = \"https://github.com/urbanjost/M_CLI.git\" } ' ,& & '#helloff = { git = \"https://gitlab.com/everythingfunctional/helloff.git\" } ' ,& & '#M_path = { git = \"https://github.com/urbanjost/M_path.git\" } ' ,& & '' ] endif if ( exists ( bname // '/src/' )) then littlefile = [ character ( len = 80 ) :: & & 'program main' , & & ' use ' // to_fortran_name ( bname ) // ', only: say_hello' , & & ' implicit none' , & & '' , & & ' call say_hello()' , & & 'end program main' ] else littlefile = [ character ( len = 80 ) :: & & 'program main' , & & ' implicit none' , & & '' , & & ' print *, \"hello from project ' // bname // '\"' , & & 'end program main' ] endif call warnwrite ( join_path ( settings % name , 'app/main.f90' ), littlefile ) endif if ( settings % with_bare ) then elseif ( settings % with_test ) then ! create NAME/test or stop call mkdir ( join_path ( settings % name , 'test' )) ! create next section of fpm.toml if ( settings % with_full ) then tomlfile = [ character ( len = 80 ) :: tomlfile ,& & '[[test]] ' ,& & ' ' ,& & ' # The same declarations can be made for test programs, which are ' ,& & ' # executed with the \"fpm test\" command and are not build when your ' ,& & ' # package is used as a dependency by other packages. These are ' ,& & ' # typically unit tests of the package only used during package ' ,& & ' # development. ' ,& & ' ' ,& & 'name=\"runTests\" ' ,& & 'source-dir=\"test\" ' ,& & 'main=\"check.f90\" ' ,& & ' ' ,& & ' # you may repeat this pattern to add additional explicit test program ' ,& & ' # parameters. The following example contains a sample of all accepted ' ,& & ' # options. ' ,& & ' ' ,& & '#[[ test ]] ' ,& & '#name = \"tester\" ' ,& & '#source-dir=\"test\" ' ,& & '#main=\"tester.f90\" ' ,& & '#link = [\"blas\", \"lapack\"] ' ,& & '#[test.dependencies] ' ,& & '#M_CLI2 = { git = \"https://github.com/urbanjost/M_CLI2.git\" } ' ,& & '#M_io = { git = \"https://github.com/urbanjost/M_io.git\" } ' ,& & '#M_system= { git = \"https://github.com/urbanjost/M_system.git\" } ' ,& & '' ] endif littlefile = [ character ( len = 80 ) :: & & 'program check' , & & 'implicit none' , & & '' , & & 'print *, \"Put some tests in here!\"' , & & 'end program check' ] ! create NAME/test/check.f90 call warnwrite ( join_path ( settings % name , 'test/check.f90' ), littlefile ) endif if ( settings % with_bare ) then elseif ( settings % with_example ) then ! create NAME/example or stop call mkdir ( join_path ( settings % name , 'example' )) ! create next section of fpm.toml if ( settings % with_full ) then tomlfile = [ character ( len = 80 ) :: tomlfile , & & '[[example]] ' ,& & ' ' ,& & ' # Example applications for a project are defined here. ' ,& & ' # These are run via \"fpm run --example NAME\" and like the ' ,& & ' # test applications, are not built when this package is used as a ' ,& & ' # dependency by other packages. ' ,& & ' ' ,& & 'name=\"demo\" ' ,& & 'source-dir=\"example\" ' ,& & 'main=\"demo.f90\" ' ,& & ' ' ,& & ' # ' ,& & ' # you may add additional programs to the example table. The following ' ,& & ' # example contains a sample of all accepted options ' ,& & ' ' ,& & '#[[ example ]] ' ,& & '#name = \"example-tool\" ' ,& & '#source-dir=\"example\" ' ,& & '#main=\"tool.f90\" ' ,& & '#link = \"z\" ' ,& & '#[example.dependencies] ' ,& & '#M_kracken95 = { git = \"https://github.com/urbanjost/M_kracken95.git\" } ' ,& & '#datetime = {git = \"https://github.com/wavebitscientific/datetime-fortran.git\" }' ,& & '' ] endif littlefile = [ character ( len = 80 ) :: & & 'program demo' , & & 'implicit none' , & & '' , & & 'print *, \"Put some examples in here!\"' , & & 'end program demo' ] ! create NAME/example/demo.f90 call warnwrite ( join_path ( settings % name , 'example/demo.f90' ), littlefile ) endif ! now that built it write NAME/fpm.toml if ( allocated ( tomlfile ) ) then call validate_toml_data ( tomlfile ) call warnwrite ( join_path ( settings % name , 'fpm.toml' ), tomlfile ) else call create_verified_basic_manifest ( join_path ( settings % name , 'fpm.toml' )) endif ! assumes git(1) is installed and in path if ( which ( 'git' ) /= '' ) then call run ( 'git init ' // settings % name ) endif contains function git_metadata ( what ) result ( returned ) !> get metadata values such as email address and git name from git(1) or return appropriate default use fpm_filesystem , only : get_temp_filename , getline character ( len =* ), intent ( in ) :: what ! keyword designating what git metatdata to query character ( len = :), allocatable :: returned ! value to return for requested keyword character ( len = :), allocatable :: command character ( len = :), allocatable :: temp_filename character ( len = :), allocatable :: iomsg character ( len = :), allocatable :: temp_value integer :: stat , unit temp_filename = get_temp_filename () ! for known keywords set default value for RETURNED and associated git(1) command for query select case ( what ) case ( 'uname' ) returned = \"Jane Doe\" command = \"git config --get user.name > \" // temp_filename case ( 'email' ) returned = \"jane.doe@example.com\" command = \"git config --get user.email > \" // temp_filename case default write ( stderr , '(*(g0,1x))' )& & ' *git_metadata* unknown metadata name ' , trim ( what ) returned = '' return end select ! Execute command if git(1) is in command path if ( which ( 'git' ) /= '' ) then call run ( command , exitstat = stat ) if ( stat /= 0 ) then ! If command failed just return default return else ! Command did not return an error so try to read expected output file open ( file = temp_filename , newunit = unit , iostat = stat ) if ( stat == 0 ) then ! Read file into a scratch variable until status of doing so is checked call getline ( unit , temp_value , stat , iomsg ) if ( stat == 0 . and . temp_value /= '' ) then ! Return output from successful command returned = temp_value endif endif ! Always do the CLOSE because a failed open has unpredictable results. ! Add IOSTAT so a failed close does not cause program to stop close ( unit , status = \"delete\" , iostat = stat ) endif endif end function git_metadata subroutine create_verified_basic_manifest ( filename ) !> create a basic but verified default manifest file use tomlf , only : toml_table , toml_serialize use fpm_toml , only : set_value use fpm_manifest_package , only : package_config_t , new_package use fpm_error , only : error_t implicit none character ( len =* ), intent ( in ) :: filename type ( toml_table ) :: table type ( package_config_t ) :: package type ( error_t ), allocatable :: error integer :: lun character ( len = 8 ) :: date character (:), allocatable :: output if ( exists ( filename )) then write ( stderr , '(*(g0,1x))' ) ' ' , filename ,& & 'already exists. Not overwriting' return endif !> get date to put into metadata in manifest file \"fpm.toml\" call date_and_time ( DATE = date ) table = toml_table () call fileopen ( filename , lun ) ! fileopen stops on error call set_value ( table , \"name\" , BNAME ) call set_value ( table , \"version\" , \"0.1.0\" ) call set_value ( table , \"license\" , \"license\" ) call set_value ( table , \"author\" , git_metadata ( 'uname' )) call set_value ( table , \"maintainer\" , git_metadata ( 'email' )) call set_value ( table , \"copyright\" , 'Copyright ' // date ( 1 : 4 ) // ', ' // git_metadata ( 'uname' )) ! continue building of manifest ! ... call new_package ( package , table , error = error ) if ( allocated ( error )) call fpm_stop ( 3 , '' ) output = toml_serialize ( table ) if ( settings % verbose ) then print '(a)' , output endif write ( lun , '(a)' ) output call fileclose ( lun ) ! fileopen stops on error end subroutine create_verified_basic_manifest subroutine validate_toml_data ( input ) !> verify a string array is a valid fpm.toml file ! use tomlf , only : toml_table , toml_load , toml_serialize implicit none character ( kind = tfc , len = :), intent ( in ), allocatable :: input (:) character ( len = 1 ), parameter :: nl = new_line ( 'a' ) type ( toml_table ), allocatable :: table character ( kind = tfc , len = :), allocatable :: joined_string ! you have to add a newline character by using the intrinsic ! function `new_line(\"a\")` to get the lines processed correctly. joined_string = join ( input , right = nl ) if ( allocated ( table )) deallocate ( table ) call toml_load ( table , joined_string ) if ( allocated ( table )) then if ( settings % verbose ) then ! If the TOML file is successfully parsed the table will be allocated and ! can be written by `toml_serialize` to the standard output print '(a)' , toml_serialize ( table ) endif call table % destroy endif end subroutine validate_toml_data end subroutine cmd_new end module fpm_cmd_new","tags":"","url":"sourcefile/new.f90.html"},{"title":"library.f90 – Fortran-lang/fpm","text":"Source Code !> Implementation of the meta data for libraries. !> !> A library table can currently have the following fields !> !>```toml !>[library] !>source-dir = \"path\" !>include-dir = [\"path1\",\"path2\"] !>build-script = \"file\" !>``` module fpm_manifest_library use fpm_error , only : error_t , syntax_error , fatal_error use fpm_strings , only : string_t , string_cat , operator ( == ) use tomlf , only : toml_table , toml_key , toml_stat use fpm_toml , only : get_value , get_list , serializable_t , set_value , & set_list , set_string , get_value , has_list implicit none private public :: library_config_t , new_library !> Configuration meta data for a library type , extends ( serializable_t ) :: library_config_t !> Source path prefix character ( len = :), allocatable :: source_dir !> Include path prefix type ( string_t ), allocatable :: include_dir (:) !> Alternative build script to be invoked character ( len = :), allocatable :: build_script !> Shared / Static / Monolithic library character (:), allocatable :: lib_type contains !> Print information on this instance procedure :: info !> Serialization interface procedure :: serializable_is_same => library_is_same procedure :: dump_to_toml procedure :: load_from_toml !> Check library types procedure , non_overridable :: monolithic procedure , non_overridable :: shared procedure , non_overridable :: static end type library_config_t character ( * ), parameter , private :: class_name = 'library_config_t' contains !> Check if this is a shared library config !> (full packages built as shared libs) elemental logical function shared ( self ) !> Instance of the library configuration class ( library_config_t ), intent ( in ) :: self if ( allocated ( self % lib_type )) then shared = self % lib_type == \"shared\" else shared = . false . endif end function shared !> Check if this is a static library config !> (full packages built as static libs) elemental logical function static ( self ) !> Instance of the library configuration class ( library_config_t ), intent ( in ) :: self if ( allocated ( self % lib_type )) then static = self % lib_type == \"static\" else static = . false . endif end function static !> Check if this is a monolithic library config !> (single monolithic archive with all objects used by this project) elemental logical function monolithic ( self ) !> Instance of the library configuration class ( library_config_t ), intent ( in ) :: self monolithic = . not .( static ( self ) . or . shared ( self )) end function monolithic !> Construct a new library configuration from a TOML data structure subroutine new_library ( self , table , error ) !> Instance of the library configuration type ( library_config_t ), intent ( out ) :: self !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error integer :: stat call check ( table , error ) if ( allocated ( error )) return if ( has_list ( table , \"source-dir\" )) then call syntax_error ( error , \"Manifest key [library.source-dir] does not allow list input\" ) return end if if ( has_list ( table , \"type\" )) then call syntax_error ( error , \"Manifest key [library.type] does not allow list input\" ) return end if call get_value ( table , \"source-dir\" , self % source_dir , \"src\" ) call get_value ( table , \"build-script\" , self % build_script ) call get_list ( table , \"include-dir\" , self % include_dir , error ) if ( allocated ( error )) return call get_value ( table , \"type\" , self % lib_type , \"monolithic\" ) select case ( self % lib_type ) case ( \"shared\" , \"static\" , \"monolithic\" ) ! OK case default call fatal_error ( error , \"Value of library.type cannot be '\" // self % lib_type & // \"', choose shared/static/monolithic (default)\" ) return end select ! Set default value of include-dir if not found in manifest if (. not . allocated ( self % include_dir )) then self % include_dir = [ string_t ( \"include\" )] end if if (. not . allocated ( self % lib_type )) then self % lib_type = \"monolithic\" end if end subroutine new_library !> Check local schema for allowed entries subroutine check ( table , error ) !> Instance of the TOML data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error type ( toml_key ), allocatable :: list (:) integer :: ikey call table % get_keys ( list ) ! table can be empty if ( size ( list ) < 1 ) return do ikey = 1 , size ( list ) select case ( list ( ikey )% key ) case default call syntax_error ( error , \"Key \" // list ( ikey )% key // \" is not allowed in library\" ) exit case ( \"source-dir\" , \"include-dir\" , \"build-script\" , \"type\" ) continue end select end do end subroutine check !> Write information on instance subroutine info ( self , unit , verbosity ) !> Instance of the library configuration class ( library_config_t ), intent ( in ) :: self !> Unit for IO integer , intent ( in ) :: unit !> Verbosity of the printout integer , intent ( in ), optional :: verbosity integer :: pr character ( len =* ), parameter :: fmt = '(\"#\", 1x, a, t30, a)' if ( present ( verbosity )) then pr = verbosity else pr = 1 end if if ( pr < 1 ) return write ( unit , fmt ) \"Library target\" if ( allocated ( self % source_dir )) then write ( unit , fmt ) \"- source directory\" , self % source_dir end if if ( allocated ( self % include_dir )) then write ( unit , fmt ) \"- include directory\" , string_cat ( self % include_dir , \",\" ) end if write ( unit , fmt ) \"- library type\" , self % lib_type if ( allocated ( self % build_script )) then write ( unit , fmt ) \"- custom build\" , self % build_script end if end subroutine info logical function library_is_same ( this , that ) class ( library_config_t ), intent ( in ) :: this class ( serializable_t ), intent ( in ) :: that library_is_same = . false . select type ( other => that ) type is ( library_config_t ) if (. not . this % include_dir == other % include_dir ) return if ( allocated ( this % source_dir ). neqv . allocated ( other % source_dir )) return if ( allocated ( this % source_dir )) then if (. not . this % source_dir == other % source_dir ) return end if if ( allocated ( this % build_script ). neqv . allocated ( other % build_script )) return if ( allocated ( this % build_script )) then if (. not . this % build_script == other % build_script ) return end if if ( allocated ( this % lib_type ). neqv . allocated ( other % lib_type )) return if ( allocated ( this % lib_type )) then if (. not . this % lib_type == other % lib_type ) return end if class default ! Not the same type return end select !> All checks passed! library_is_same = . true . end function library_is_same !> Dump install config to toml table subroutine dump_to_toml ( self , table , error ) !> Instance of the serializable object class ( library_config_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error call set_string ( table , \"source-dir\" , self % source_dir , error , class_name ) if ( allocated ( error )) return call set_string ( table , \"build-script\" , self % build_script , error , class_name ) if ( allocated ( error )) return call set_list ( table , \"include-dir\" , self % include_dir , error ) if ( allocated ( error )) return call set_string ( table , \"type\" , self % lib_type , error , class_name ) if ( allocated ( error )) return end subroutine dump_to_toml !> Read install config from toml table (no checks made at this stage) subroutine load_from_toml ( self , table , error ) !> Instance of the serializable object class ( library_config_t ), intent ( inout ) :: self !> Data structure type ( toml_table ), intent ( inout ) :: table !> Error handling type ( error_t ), allocatable , intent ( out ) :: error call get_value ( table , \"source-dir\" , self % source_dir ) if ( allocated ( error )) return call get_value ( table , \"build-script\" , self % build_script ) if ( allocated ( error )) return call get_list ( table , \"include-dir\" , self % include_dir , error ) if ( allocated ( error )) return call get_value ( table , \"type\" , self % lib_type ) if ( allocated ( error )) return end subroutine load_from_toml end module fpm_manifest_library","tags":"","url":"sourcefile/library.f90.html"},{"title":"Packaging and contributing – Fortran-lang/fpm","text":"","tags":"","url":"page/index.html"},{"title":"Contributing Guidelines – Fortran-lang/fpm","text":"Contributing to the Fortran Package Manager Thank you for considering contributing to the Fortran Package Manager ( fpm ).\nPlease review and follow these guidelines to make the contribution process\nsimple and effective for all involved. It will help communicate that you\nrespect the time of the community developers. In return, the community will\nhelp address your problem, evaluate changes, and guide you through your pull\nrequests. By contributing to fpm , you certify that you own or are allowed to share the\ncontent of your contribution under the fpm license . Style Reporting a bug Suggesting a feature Workflow General guidelines For new contributors Style Please follow the Fortran stdlib style guide for any Fortran code that you contribute.\nThis allows us to focus on substance rather than style. Reporting a bug A bug is a demonstrable problem caused by the code in this repository.\nGood bug reports are extremely valuable to us—thank you! Before opening a bug report: Check if the issue has already been reported\n ( issues ). Check if it is still an issue or it has been fixed?\n Try to reproduce it with the latest version from the default branch. Isolate the problem and create a minimal test case. A good bug report should include all information needed to reproduce the bug.\nPlease be as detailed as possible: Which version of fpm are you using? Please be specific. What are the steps to reproduce the issue? What is the expected outcome? What happens instead? This information will help the community diagnose the issue quickly and with\nminimal back-and-forth. Suggesting a feature Before suggesting a new feature, take a moment to find out if it fits the scope\nof the project, or if it has already been discussed. It is up to you to provide\na strong argument to convince the community of the benefits of this feature.\nPlease provide as much detail and context as possible. If applicable, include a\nmocked-up snippet of what the output or behavior would look like with this\nfeature implemented. “Crazy”, out-of-the-box ideas are especially welcome.\nIt’s quite possible that we are not considering an unusually creative solution. Workflow fpm is a community project. There is no one single person making final\ndecisions. This is the workflow that we follow: Open a new issue to\n describe a bug or propose a new feature.\n Refer to the earlier sections on how to write a good bug report or feature\n request. Discuss with the community and reach majority consensus about what should be\n done about the bug or feature request.\n We define “majority” loosely as 80%.\n This means that at least 4 of 5 people engaged in the discussion should be\n able to agree on the next step.\n This allows us to have the community mostly agree while not getting stuck if\n one person disagrees.\n At this stage, the scope of the fix/feature, its behavior, and API if\n applicable should be defined.\n Only when you have community consensus on these items you should proceed to\n writing code and opening a PR. When actively working on code towards a PR, please assign yourself to the\n issue on GitHub. This is good collaborative practice to avoid duplicated effort and also\n inform others what you are currently working on. Open a new Pull Request (PR) with your contribution.\n The body of the PR should at least include a bullet-point summary of the\n changes, and a detailed description is encouraged.\n If the PR completely addresses the issue you opened in step 1, include in\n the PR description the following line: Fixes # . Request reviewers to your PR.\n For small bug fixes or documentation improvements, 1 to 2 reviewers is\n sufficient.\n For implementation of bigger features, request 3 to 4 or more reviewers.\n Ideally, request reviewers that participated in step 2. If your PR implements a feature that adds or changes the behavior of fpm ,\n your PR must also include appropriate changes to the documentation. This workflow can evolve and change over time as we learn how best to work\ntogether. If you have an idea on how to improve the workflow itself, please\nopen an issue and we’ll discuss it. General guidelines A PR should implement only one feature or bug fix. Do not commit changes to files that are irrelevant to your feature or bug fix. Smaller PRs are better than large PRs, and will lead to a shorter review and\n merge cycle Add tests for your feature or bug fix to be sure that it stays functional and useful Be open to constructive criticism and requests for improving your code. Again, please follow the Fortran stdlib style guide . For new contributors If you have never created a pull request before, welcome :tada:.\nYou can learn how from this great tutorial . Don’t know where to start?\nYou can start by looking through the list of open issues .","tags":"","url":"page/Contributing.html"},{"title":"License – Fortran-lang/fpm","text":"MIT License Copyright (c) 2020 fpm contributors Permission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the “Software”), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software. THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.","tags":"","url":"page/License.html"},{"title":"Manifest reference – Fortran-lang/fpm","text":"301 - Moved This document now lives at https://fpm.fortran-lang.org/spec/manifest.html","tags":"","url":"page/Manifest.html"},{"title":"Packaging with fpm – Fortran-lang/fpm","text":"Preparing your package for FPM This document describes how you need to organize your application or library for\nit to successfully build with the Fortran Package Manager ( fpm ). What kind of package can fpm build? Example package layouts Single program Single-module library Multi-module library Application and library Multi-level library Be more explicit Add some tests Adding dependencies Custom build scripts What kind of package can fpm build? You can use fpm to build: Applications (program only) Libraries (modules only) Combination of the two (programs and modules combined) Let’s look at some examples of different kinds of package layouts that you can\nuse with fpm . Example package layouts This section describes some example package layouts that you can build with fpm . You can use them to model the layout of your own package. Single program Let’s start with the simplest package imaginable—a single program without\ndependencies or modules. Here’s what the layout of the top-level directory\nlooks like: .\n├── app\n│   └── main.f90\n└── fpm.toml We have one source file ( main.f90 ) in one directory ( app ). Its contents\nare: program main print * , 'Hello, World!' end program main This program prints the usual greeting to the standard output, and nothing more. There’s another important file in the top-level directory, fpm.toml . This is fpm ’s configuration file specific to your package. It includes all the data\nthat fpm needs to build your app. In our simple case, it looks like this: name = \"hello\" version = \"0.1.0\" license = \"MIT\" author = \"Jane Programmer\" maintainer = \"jane@example.com\" copyright = \"2020 Jane Programmer\" The preamble includes some metadata, such as license , author , and similar,\nthat you may have seen in other package manager configuration files. The one\noption that matters here right now is: name = \"hello\" This line specifies the name of your package, which determines the name of the\nexecutable file of your program. In this example, our program executable, once\nbuilt, will be called hello . Let’s now build this program using fpm : $ fpm build # gfortran (for build/debug/app/main.o) # gfortran (for build/debug/app/hello) On the first line, we ran fpm build to compile and link the application.\nThe latter two lines are emitted by fpm , and indicate which command was\nexecuted at each build step ( gfortran ), and which files have been output\nby it: object file main.o , and executable hello . We can now run the app with fpm run : $ fpm run Hello, World! If your application needs to use a module internally, but you don’t intend\nto build it as a library to be used in other projects, you can include the\nmodule in your program source file as well.\nFor example: $ cat app / main . f90 module math_constants real , parameter :: pi = 4 * atan ( 1. ) end module math_constants program main use math_constants , only : pi print * , 'Hello, World!' print * , 'pi = ' , pi end program main Now, run this using fpm run : $ fpm run # gfortran (for build/debug/app/main.o) # gfortran (for build/debug/app/hello) Hello, World! pi = 3 .14159274 Although we have named our program hello , which is the same name as the\npackage name in fpm.toml , you can name it anything you want as long as it’s\npermitted by the language. Notice that you can run fpm run , and if the package hasn’t been built yet, fpm build will run automatically for you. This is true if the source files\nhave been updated since the last build. Thus, if you want to run your\napplication, you can skip the fpm build step, and go straight to fpm run . When running your application using fpm run , the program’s exit code is\npassed by fpm back to the operating system. So, it is possible to use Fortran\nnumbered stop and error stop codes to pass termination reasons back to the terminal. Try running the following app with fpm run : program main use math_constants , only : pi real :: angle read ( * , * , iostat = ierr ) angle if ( ierr /= 0 ) then stop 2 ! Not real elseif ( angle > pi ) then stop 1 else stop 0 endif end program main and then checking that the error code matches. Note that error codes are passed to variable $? on Unix/Mac systems, and to environment variable %errorlevel% on Windows. In this last example, our source file defined a math_constants module inside\nthe same source file as the main program. Let’s see how we can define an fpm package that makes this module available as a library. Single-module library The package layout for this example looks like this: . ├── fpm . toml └── src └── math_constants . f90 In this example we’ll build a simple math constants library that exports\nthe number pi as a parameter: $ cat src / math_constants . f90 module math_constants real , parameter :: pi = 4 * atan ( 1. ) end module math_constants and our fpm.toml is the same as before. Now use fpm build to build the package: $ fpm build # gfortran (for build/debug/library/math_constants.o build/debug/library/math_constants.mod) # ar (for build/debug/library/math_constants.a) ar: creating build/debug/library/math_constants.a Based on the output of fpm build , fpm first ran gfortran to emit the\nbinary object ( math_constants.o ) and module ( math_constants.mod ) files.\nThen it ran ar to create a static library archive math_constants.a . build/debug/library is thus both your include and library path, should you\nwant to compile and link an external program with this library. For modules in the top-level ( src ) directory, fpm requires that: The module has the same name as the source file. There is only one module per file. These two requirements simplify the build process for fpm . As Fortran\ncompilers emit module files ( .mod ) with the same name as the module itself\n(but not the source file, .f90 ), naming the module the same as the source file\nallows fpm to: Uniquely and exactly map a source file ( .f90 ) to its object ( .o ) and\nmodule ( .mod ) files. Avoid conflicts with modules of the same name that could appear in dependency\npackages (more on this in a bit). Since this is a library without executable programs, fpm run here does\nnothing. In this example, our library is made of only one module. However, most\nreal-world libraries are likely to use multiple modules. Let’s see how you can\npackage your multi-module library. Multi-module library In this example, we’ll use another module to define a 64-bit real kind\nparameter and make it available in math_constants to define pi with\nhigher precision. To make this exercise worthwhile, we’ll define another math\nconstant, Euler’s number. Our package layout looks like this: . ├── fpm . toml └── src ├── math_constants . f90 └── type_kinds . f90 And our source file contents are: $ cat src / math_constants . f90 module math_constants use type_kinds , only : rk real ( rk ), parameter :: pi = 4 * atan ( 1._rk ) real ( rk ), parameter :: e = exp ( 1._rk ) end module math_constants $ cat src / type_kinds . f90 module type_kinds use iso_fortran_env , only : real64 integer , parameter :: rk = real64 end module type_kinds and there are no changes to our fpm.toml relative to previous examples. Like before, notice that the module type_kinds is name exactly as the\nsource file that contains it.\nThis is important. By now you know how to build the package: $ fpm build # gfortran (for build/debug/library/type_kinds.o build/debug/library/type_kinds.mod) # gfortran (for build/debug/library/math_constants.o build/debug/library/math_constants.mod) # ar (for build/debug/library/math_constants.a) ar: creating build/debug/library/math_constants.a Our build path now contains: $ ls build/debug/library/\nmath_constants.a math_constants.mod math_constants.o type_kinds.mod type_kinds.o And the static library includes all the object files: $ nm build/debug/library/math_constants.a\n\nmath_constants.o:\n\ntype_kinds.o: The takeaways from this example are that: fpm automatically scanned the src directory for any source files. It also resolved the dependency order between different modules. Application and library Let’s now combine the two previous examples into one: We’ll build the math\nconstants library and an executable program that uses it. We’ll use this\nprogram as a demo, and to verify that defining higher-precision constants from\nthe previous example actually worked. Here’s the package layout for your application + library package: . ├── app │ └── main . f90 ├── fpm . toml └── src ├── math_constants . f90 └── type_kinds . f90 Our fpm.toml remains unchanged and our executable program source file is: $ cat app / main . f90 program main use math_constants , only : e , pi print * , 'math_constants library demo' print * , 'pi = ' , pi print * , 'e = ' , e end program main Let’s go straight to running the demo program: $ fpm run # gfortran (for build/debug/library/type_kinds.o build/debug/library/type_kinds.mod) # gfortran (for build/debug/library/math_constants.o build/debug/library/math_constants.mod) # ar (for build/debug/library/math_constants.a) ar: creating build/debug/library/math_constants.a # gfortran (for build/debug/app/main.o) # gfortran (for build/debug/app/math_constants) math_constants library demo pi = 3 .1415926535897931 e = 2 .7182818284590451 The fpm build + run process works as expected, and our program correctly\noutputs higher-precision constants. So far we covered how fpm builds: A single program A single-module library A multi-module library A program and a library However, all our modules so far have been organized in the top level source\ndirectory. More complex libraries may organize their modules in subdirectories.\nLet’s see how we can build this with fpm . Multi-level library In this example, we’ll define our library as a collection of modules, two of\nwhich are defined in a subdirectory: . ├── app │ └── main . f90 ├── fpm . toml └── src ├── math_constants │ ├── derived . f90 │ └── fundamental . f90 ├── math_constants . f90 └── type_kinds . f90 First, fpm.toml and src/type_kinds.f90 remain unchanged relative to the\nprevious example. The rest of the source files are: $ cat src / math_constants . f90 module math_constants use math_constants_fundamental , only : e , pi use math_constants_derived , only : half_pi , two_pi end module math_constants $ cat src / math_constants / fundamental . f90 module math_constants_fundamental use type_kinds , only : rk real ( rk ), parameter :: pi = 4 * atan ( 1._rk ) real ( rk ), parameter :: e = exp ( 1._rk ) end module math_constants_fundamental $ cat src / math_constants / derived . f90 module math_constants_derived use math_constants_fundamental , only : pi use type_kinds , only : rk real ( rk ), parameter :: two_pi = 2 * pi real ( rk ), parameter :: half_pi = pi / 2 end module math_constants_derived $ cat app / main . f90 program main use math_constants , only : e , pi , half_pi , two_pi print * , 'math_constants library demo' print * , 'pi = ' , pi print * , '2*pi = ' , two_pi print * , 'pi/2 = ' , half_pi print * , 'e = ' , e end program main Our top-level math_constants module now doesn’t define the constants, but\nimports them from the two modules in the subdirectory. Constants e and pi we define in the math_constants_fundamental module, and two_pi and half_pi in the math_constants_derived module. From the main program, we access all\nthe constants from the top-level module math_constants . Let’s build and run this package: $ fpm run # gfortran (for build/debug/library/type_kinds.o build/debug/library/type_kinds.mod) # gfortran (for build/debug/library/math_constants_fundamental.o build/debug/library/math_constants_fundamental.mod) # gfortran (for build/debug/library/math_constants_derived.o build/debug/library/math_constants_derived.mod) # gfortran (for build/debug/library/math_constants.o build/debug/library/math_constants.mod) # ar (for build/debug/library/math_constants.a) ar: creating build/debug/library/math_constants.a # gfortran (for build/debug/app/main.o) # gfortran (for build/debug/app/math_constants) math_constants library demo pi = 3 .1415926535897931 2 *pi = 6 .2831853071795862 pi/2 = 1 .5707963267948966 e = 2 .7182818284590451 Again, fpm built and run the package as expected. Recall from an earlier example that fpm required the modules in the top-level src directory to be named the same as their source file. This is why src/math_constants.f90 defines module math_constants . For modules defined in subdirectories, there’s an additional requirement: module\nname must contain the path components of the directory that its source file is\nin. In our case, src/math_constants/fundamental.f90 defines the math_constants_fundamental module. Likewise, src/math_constants/derived.f90 defines the math_constants_derived module. This rule applies generally to any number of nested directories and modules.\nFor example, src/a/b/c/d.f90 must define a module called a_b_c_d . Takeaways from this example are that: You can place your module source files in any levels of subdirectories inside src . The module name must include the path components and the source file name–for example, src/a/b/c/d.f90 must define a module called a_b_c_d . Be more explicit So far we’ve let fpm use its defaults to determine the layout of our package.\nIt determined where our library sources would live, what the name of the\nexecutable will be, and some other things. But we can be more explicit about it,\nand make some changes to those things. Let’s look at what the fpm.toml file from our last example would look like if\nwe specified everything. name = \"math_constants\" version = \"0.1.0\" license = \"MIT\" author = \"Jane Programmer\" maintainer = \"jane@example.com\" copyright = \"2020 Jane Programmer\" [library] source-dir = \"src\" [[ executable ]] name = \"math_constants\" source-dir = \"app\" main = \"main.f90\" You can see that by making these explicit in the fpm.toml we are able to\nchange many of the settings that fpm used by default. We can change the\nfolders where our sources are stored, we can change the name of our executable,\nand we can change the name of the file our program is defined in. Add some tests fpm also provides support for unit testing. By default, fpm looks for a\nprogram in test/main.f90 which it will compile and execute with the command fpm test . The tests are treated pretty much exactly like the executables.\nLet’s define one explicitly in our fpm.toml file. We’ll make sure that our\ndefinition of pi satisfies the property sin(pi) == 0.0 . Here’s the fpm.toml file: name = \"math_constants\" version = \"0.1.0\" license = \"MIT\" author = \"Jane Programmer\" maintainer = \"jane@example.com\" copyright = \"2020 Jane Programmer\" [library] source-dir = \"src\" [[ executable ]] name = \"math_constants\" source-dir = \"app\" main = \"main.f90\" [[ test ]] name = \"runTests\" source-dir = \"test\" main = \"main.f90\" where the contents of the main.f90 file are program main use math_constants , only : pi print * , \"sin(pi) = \" , sin ( pi ) end program main With this setup, we can run our tests. $ fpm test # gfortran (for build/debug/library/type_kinds.o build/debug/library/type_kinds.mod) # gfortran (for build/debug/library/math_constants_fundamental.o build/debug/library/math_constants_fundamental.mod) # gfortran (for build/debug/library/math_constants_derived.o build/debug/library/math_constants_derived.mod) # gfortran (for build/debug/library/math_constants.o build/debug/library/math_constants.mod) # ar (for build/debug/library/math_constants.a) ar: creating build/debug/library/math_constants.a # gfortran (for build/debug/app/main.o) # gfortran (for build/debug/app/math_constants) # gfortran (for build/debug/test/main.o) # gfortran (for build/debug/test/runTests) sin ( pi ) = 1 .2246467991473532E-016 Adding dependencies Inevitably, you’ll want to be able to include other libraries in your project.\nfpm makes this incredibly simple, by taking care of fetching and compiling your\ndependencies for you. You just tell it what your dependencies are, and where to\nfind them. Let’s add a dependency to our library. Now our fpm.toml file looks\nlike this: name = \"math_constants\" version = \"0.1.0\" license = \"MIT\" author = \"Jane Programmer\" maintainer = \"jane@example.com\" copyright = \"2020 Jane Programmer\" [library] source-dir = \"src\" [dependencies] helloff = { git = \"https://gitlab.com/everythingfunctional/helloff.git\" } [[ executable ]] name = \"math_constants\" source-dir = \"app\" main = \"main.f90\" [[ test ]] name = \"runTests\" source-dir = \"test\" main = \"main.f90\" Now you can use any modules from this library anywhere in your code. Just like\nthis: program main use helloff , only : create_greeting use math_constants , only : e , pi , half_pi , two_pi print * , 'math_constants library demo' print * , 'pi = ' , pi print * , '2*pi = ' , two_pi print * , 'pi/2 = ' , half_pi print * , 'e = ' , e print * , create_greeting ( \"fpm\" ) end program main And now, fpm run will output the following: math_constants library demo pi = 3.1415926535897931 2 * pi = 6.2831853071795862 pi / 2 = 1.5707963267948966 e = 2.7182818284590451 Hello , fpm ! Additionally, any users of your library will now automatically depend on your\ndependencies too. So if you don’t need that dependency for the library, like in\nthe above example, then you can specify it for the specific executable like\nbelow. Then fpm will still fetch and compile it when building your executable,\nbut users of your library won’t have to. name = \"math_constants\" version = \"0.1.0\" license = \"MIT\" author = \"Jane Programmer\" maintainer = \"jane@example.com\" copyright = \"2020 Jane Programmer\" [library] source-dir = \"src\" [[ executable ]] name = \"math_constants\" source-dir = \"app\" main = \"main.f90\" [executable.dependencies] helloff = { git = \"https://gitlab.com/everythingfunctional/helloff.git\" } [[ test ]] name = \"runTests\" source-dir = \"test\" main = \"main.f90\" You can also specify dependencies for your tests in a similar way, with [test.dependencies] instead of [executable.dependencies] . There’s also\nanother option for test dependencies. The below example makes the dependencies\navailable for all the tests, but again your users won’t depend on these. name = \"math_constants\" version = \"0.1.0\" license = \"MIT\" author = \"Jane Programmer\" maintainer = \"jane@example.com\" copyright = \"2020 Jane Programmer\" [library] source-dir = \"src\" [dev-dependencies] helloff = { git = \"https://gitlab.com/everythingfunctional/helloff.git\" } [[ executable ]] name = \"math_constants\" source-dir = \"app\" main = \"main.f90\" [[ test ]] name = \"runTests\" source-dir = \"test\" main = \"main.f90\" You can also be specific about which version of a dependency you’d like. You can\nspecify a branch to use like helloff = { git = \"https://gitlab.com/everythingfunctional/helloff.git\", branch = \"master\" } ,\nor a tag like helloff = { git = \"https://gitlab.com/everythingfunctional/helloff.git\", tag = \"v1.2.3\" } ,\nor even a specific commit like helloff = { git = \"https://gitlab.com/everythingfunctional/helloff.git\", rev = \"a1b2c3\" } .\nYou can even specify the path to another folder, if for example you’ve got\nanother fpm package in the same repository. Like this: helloff = { path = \"helloff\" } . Note that you should not specify paths\noutside of your repository, or things won’t work for your users. Custom build scripts If there is something special about your library that makes fpm unable to build\nit, you can provide your own build script. fpm will then simply call your build\nscript to build the library. To specify a build script to be used, put it in the library section of your fpm.toml file, like: [library] source-dir = \"src\" build-script = \"my_build_script\" fpm will set the following environment variables to specify some parameters to\nthe build script: FC – The Fortran compiler to be used. FFLAGS – The flags that should be passed to the Fortran compiler. BUILD_DIR – Where the compiled files should be placed. INCLUDE_DIRS – The folders where any dependencies can be found, space separated.\nIt is then the responsibility of the build script to generate the appropriate\ninclude flags. Additionally, script will be called with the name of the archive ( *.a file)\nthat should be produced as the command line argument. Note: If the name of the build script is Makefile or ends with .mk , then\nthe make program will be used to run it. Not the the archive file is explicitly\nspecified as the target to be built Note: All file and directory names are specified with their full canonical\npath.","tags":"","url":"page/Packaging.html"}]} \ No newline at end of file diff --git a/sourcefile/build.f90.html b/sourcefile/build.f90.html new file mode 100644 index 0000000000..ff28962c06 --- /dev/null +++ b/sourcefile/build.f90.html @@ -0,0 +1,530 @@ + + + + + + + + + + + + + build.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      build.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      !> Implementation of the build configuration data.
      +!>
      +!> A build table can currently have the following fields
      +!>
      +!>```toml
      +!>[build]
      +!>auto-executables = bool
      +!>auto-examples = bool
      +!>auto-tests = bool
      +!>link = ["lib"]
      +!>```
      +module fpm_manifest_build
      +    use fpm_error, only : error_t, syntax_error, fatal_error
      +    use fpm_strings, only : string_t, len_trim, is_valid_module_prefix, operator(==)
      +    use tomlf, only: toml_table, toml_key, toml_stat
      +    use fpm_toml, only : serializable_t, get_value, get_list, set_value, set_string, set_list
      +
      +    implicit none
      +    private
      +
      +    public :: build_config_t, new_build_config
      +
      +    !> Configuration data for build
      +    type, extends(serializable_t) :: build_config_t
      +
      +        !> Automatic discovery of executables
      +        logical :: auto_executables = .true.
      +
      +        !> Automatic discovery of examples
      +        logical :: auto_examples = .true.
      +
      +        !> Automatic discovery of tests
      +        logical :: auto_tests = .true.
      +
      +        !> Enforcing of package module names
      +        logical :: module_naming = .false.
      +        type(string_t) :: module_prefix
      +
      +        !> Libraries to link against
      +        type(string_t), allocatable :: link(:)
      +
      +        !> External modules to use
      +        type(string_t), allocatable :: external_modules(:)
      +
      +    contains
      +
      +        !> Print information on this instance
      +        procedure :: info
      +
      +        !> Serialization interface
      +        procedure :: serializable_is_same => build_conf_is_same
      +        procedure :: dump_to_toml
      +        procedure :: load_from_toml
      +
      +    end type build_config_t
      +
      +    character(*), parameter, private :: class_name = 'build_config_t'
      +
      +
      +contains
      +
      +
      +    !> Construct a new build configuration from a TOML data structure
      +    subroutine new_build_config(self, table, package_name, error)
      +
      +        !> Instance of the build configuration
      +        type(build_config_t), intent(out) :: self
      +
      +        !> Instance of the TOML data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> Package name
      +        character(len=*), intent(in) :: package_name
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        integer :: stat
      +
      +        call check(table, package_name, error)
      +        if (allocated(error)) return
      +
      +        call get_value(table, "auto-executables", self%auto_executables, .true., stat=stat)
      +
      +        if (stat /= toml_stat%success) then
      +            call fatal_error(error,"Error while reading value for 'auto-executables' in fpm.toml, expecting logical")
      +            return
      +        end if
      +
      +        call get_value(table, "auto-tests", self%auto_tests, .true., stat=stat)
      +
      +        if (stat /= toml_stat%success) then
      +            call fatal_error(error,"Error while reading value for 'auto-tests' in fpm.toml, expecting logical")
      +            return
      +        end if
      +
      +        call get_value(table, "auto-examples", self%auto_examples, .true., stat=stat)
      +
      +        if (stat /= toml_stat%success) then
      +            call fatal_error(error,"Error while reading value for 'auto-examples' in fpm.toml, expecting logical")
      +            return
      +        end if
      +
      +        !> Module naming: fist, attempt boolean value first
      +        call get_value(table, "module-naming", self%module_naming, .false., stat=stat)
      +
      +        if (stat == toml_stat%success) then
      +
      +            ! Boolean value found. Set no custom prefix. This also falls back to key not provided
      +            if (allocated(self%module_prefix%s)) deallocate(self%module_prefix%s)
      +
      +        else
      +
      +            !> Value found, but not a boolean. Attempt to read a prefix string
      +            call get_value(table, "module-naming", self%module_prefix%s)
      +
      +            if (.not.allocated(self%module_prefix%s)) then
      +               call syntax_error(error,"Could not read value for 'module-naming' in fpm.toml, expecting logical or a string")
      +               return
      +            end if
      +
      +            if (.not.is_valid_module_prefix(self%module_prefix)) then
      +               call syntax_error(error,"Invalid custom module name prefix for in fpm.toml: <"//self%module_prefix%s// &
      +                            ">, expecting a valid alphanumeric string")
      +               return
      +            end if
      +
      +            ! Set module naming to ON
      +            self%module_naming = .true.
      +
      +        end if
      +
      +        call get_list(table, "link", self%link, error)
      +        if (allocated(error)) return
      +
      +        call get_list(table, "external-modules", self%external_modules, error)
      +        if (allocated(error)) return
      +
      +    end subroutine new_build_config
      +
      +    !> Check local schema for allowed entries
      +    subroutine check(table, package_name, error)
      +
      +        !> Instance of the TOML data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> Package name
      +        character(len=*), intent(in) :: package_name
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        type(toml_key), allocatable :: list(:)
      +        integer :: ikey
      +
      +        call table%get_keys(list)
      +
      +        ! table can be empty
      +        if (size(list) < 1) return
      +
      +        do ikey = 1, size(list)
      +            select case(list(ikey)%key)
      +
      +            case("auto-executables", "auto-examples", "auto-tests", "link", "external-modules", "module-naming")
      +                continue
      +
      +            case default
      +
      +                call syntax_error(error, 'Manifest file syntax error: key "'//list(ikey)%key//'" found in the [build] '//&
      +                                         'section of package/dependency "'//package_name//'" fpm.toml is not allowed')
      +                exit
      +
      +            end select
      +        end do
      +
      +    end subroutine check
      +
      +
      +    !> Write information on build configuration instance
      +    subroutine info(self, unit, verbosity)
      +
      +        !> Instance of the build configuration
      +        class(build_config_t), intent(in) :: self
      +
      +        !> Unit for IO
      +        integer, intent(in) :: unit
      +
      +        !> Verbosity of the printout
      +        integer, intent(in), optional :: verbosity
      +
      +        integer :: pr, ilink, imod
      +        character(len=*), parameter :: fmt = '("#", 1x, a, t30, a)'
      +
      +        if (present(verbosity)) then
      +            pr = verbosity
      +        else
      +            pr = 1
      +        end if
      +
      +        if (pr < 1) return
      +
      +        write(unit, fmt) "Build configuration"
      +        write(unit, fmt) " - auto-discovery (apps) ", merge("enabled ", "disabled", self%auto_executables)
      +        write(unit, fmt) " - auto-discovery (examples) ", merge("enabled ", "disabled", self%auto_examples)
      +        write(unit, fmt) " - auto-discovery (tests) ", merge("enabled ", "disabled", self%auto_tests)
      +        write(unit, fmt) " - enforce module naming ", merge("enabled ", "disabled", self%module_naming)
      +        if (allocated(self%link)) then
      +            write(unit, fmt) " - link against"
      +            do ilink = 1, size(self%link)
      +                write(unit, fmt) "   - " // self%link(ilink)%s
      +            end do
      +        end if
      +        if (allocated(self%external_modules)) then
      +            write(unit, fmt) " - external modules"
      +            do imod = 1, size(self%external_modules)
      +                write(unit, fmt) "   - " // self%external_modules(imod)%s
      +            end do
      +        end if
      +
      +    end subroutine info
      +
      +    !> Check that two dependency trees are equal
      +    logical function build_conf_is_same(this,that)
      +      class(build_config_t), intent(in) :: this
      +      class(serializable_t), intent(in) :: that
      +
      +      build_conf_is_same = .false.
      +
      +      select type (other=>that)
      +         type is (build_config_t)
      +
      +             if (this%auto_executables.neqv.other%auto_executables) return
      +             if (this%auto_examples.neqv.other%auto_examples) return
      +             if (this%auto_tests.neqv.other%auto_tests) return
      +             if (this%module_naming.neqv.other%module_naming) return
      +             if (.not.this%module_prefix==other%module_prefix) return
      +             if (.not.this%link==other%link) return
      +             if (.not.this%external_modules==other%external_modules) return
      +
      +         class default
      +            ! Not the same type
      +            return
      +      end select
      +
      +      !> All checks passed!
      +      build_conf_is_same = .true.
      +
      +    end function build_conf_is_same
      +
      +    !> Dump build config to toml table
      +    subroutine dump_to_toml(self, table, error)
      +
      +        !> Instance of the serializable object
      +        class(build_config_t), intent(inout) :: self
      +
      +        !> Data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        call set_value(table, "auto-executables", self%auto_executables, error, class_name)
      +        if (allocated(error)) return
      +        call set_value(table, "auto-tests", self%auto_tests, error, class_name)
      +        if (allocated(error)) return
      +        call set_value(table, "auto-examples", self%auto_examples, error, class_name)
      +        if (allocated(error)) return
      +
      +        ! Module naming can either contain a boolean value, or the prefix
      +        has_prefix: if (self%module_naming .and. len_trim(self%module_prefix)>0) then
      +            call set_string(table, "module-naming", self%module_prefix, error, class_name)
      +        else
      +            call set_value (table, "module-naming", self%module_naming, error, class_name)
      +        end if has_prefix
      +        if (allocated(error)) return
      +
      +        call set_list(table, "link", self%link, error)
      +        if (allocated(error)) return
      +        call set_list(table, "external-modules", self%external_modules, error)
      +        if (allocated(error)) return
      +
      +    end subroutine dump_to_toml
      +
      +    !> Read build config from toml table (no checks made at this stage)
      +    subroutine load_from_toml(self, table, error)
      +
      +        !> Instance of the serializable object
      +        class(build_config_t), intent(inout) :: self
      +
      +        !> Data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        integer :: stat
      +
      +        call get_value(table, "auto-executables", self%auto_executables, error, class_name)
      +        if (allocated(error)) return
      +        call get_value(table, "auto-tests", self%auto_tests, error, class_name)
      +        if (allocated(error)) return
      +        call get_value(table, "auto-examples", self%auto_examples, error, class_name)
      +        if (allocated(error)) return
      +
      +        !> Module naming: fist, attempt boolean value first
      +        call get_value(table, "module-naming", self%module_naming, .false., stat=stat)
      +        if (stat == toml_stat%success) then
      +            ! Boolean value found. Set no custom prefix. This also falls back to key not provided
      +            if (allocated(self%module_prefix%s)) deallocate(self%module_prefix%s)
      +        else
      +            !> Value found, but not a boolean. Attempt to read a prefix string
      +            call get_value(table, "module-naming", self%module_prefix%s)
      +            if (.not.allocated(self%module_prefix%s)) then
      +               call syntax_error(error,"Could not read value for 'module-naming' in fpm.toml, expecting logical or a string")
      +               return
      +            end if
      +            self%module_naming = .true.
      +        end if
      +
      +        call get_list(table, "link", self%link, error)
      +        if (allocated(error)) return
      +        call get_list(table, "external-modules", self%external_modules, error)
      +        if (allocated(error)) return
      +
      +    end subroutine load_from_toml
      +
      +
      +end module fpm_manifest_build
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/dependency.f90.html b/sourcefile/dependency.f90.html new file mode 100644 index 0000000000..5f4c578223 --- /dev/null +++ b/sourcefile/dependency.f90.html @@ -0,0 +1,2046 @@ + + + + + + + + + + + + + dependency.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      dependency.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      !> # Dependency management
      +!>
      +!> ## Fetching dependencies and creating a dependency tree
      +!>
      +!> Dependencies on the top-level can be specified from:
      +!>
      +!> - `package%dependencies`
      +!> - `package%dev_dependencies`
      +!> - `package%executable(:)%dependencies`
      +!> - `package%test(:)%dependencies`
      +!>
      +!> Each dependency is fetched in some way and provides a path to its package
      +!> manifest.
      +!> The `package%dependencies` of the dependencies are resolved recursively.
      +!>
      +!> To initialize the dependency tree all dependencies are recursively fetched
      +!> and stored in a flat data structure to avoid retrieving a package twice.
      +!> The data structure used to store this information should describe the current
      +!> status of the dependency tree. Important information are:
      +!>
      +!> - name of the package
      +!> - version of the package
      +!> - path to the package root
      +!>
      +!> Additionally, for version controlled dependencies the following should be
      +!> stored along with the package:
      +!>
      +!> - the upstream url
      +!> - the current checked out revision
      +!>
      +!> Fetching a remote (version controlled) dependency turns it for our purpose
      +!> into a local path dependency which is handled by the same means.
      +!>
      +!> ## Updating dependencies
      +!>
      +!> For a given dependency tree all top-level dependencies can be updated.
      +!> We have two cases to consider, a remote dependency and a local dependency,
      +!> again, remote dependencies turn into local dependencies by fetching.
      +!> Therefore we will update remote dependencies by simply refetching them.
      +!>
      +!> For remote dependencies we have to refetch if the revision in the manifest
      +!> changes or the upstream HEAD has changed (for branches _and_ tags).
      +!>
      +!> @Note For our purpose a tag is just a fancy branch name. Tags can be delete and
      +!>       modified afterwards, therefore they do not differ too much from branches
      +!>       from our perspective.
      +!>
      +!> For the latter case we only know if we actually fetch from the upstream URL.
      +!>
      +!> In case of local (and fetched remote) dependencies we have to read the package
      +!> manifest and compare its dependencies against our dependency tree, any change
      +!> requires updating the respective dependencies as well.
      +!>
      +!> ## Handling dependency compatibilties
      +!>
      +!> Currenly ignored. First come, first serve.
      +module fpm_dependency
      +  use, intrinsic :: iso_fortran_env, only: output_unit
      +  use fpm_environment, only: get_os_type, OS_WINDOWS, os_is_unix
      +  use fpm_error, only: error_t, fatal_error
      +  use fpm_filesystem, only: exists, join_path, mkdir, canon_path, windows_path, list_files, is_dir, basename, &
      +                            os_delete_dir, get_temp_filename, parent_dir
      +  use fpm_git, only: git_target_revision, git_target_default, git_revision, serializable_t
      +  use fpm_manifest, only: package_config_t, dependency_config_t, get_package_data, get_package_dependencies
      +  use fpm_manifest_dependency, only: manifest_has_changed, dependency_destroy
      +  use fpm_manifest_preprocess, only: operator(==)
      +  use fpm_strings, only: string_t, operator(.in.), operator(==), str
      +  use tomlf, only: toml_table, toml_key, toml_error, toml_load, toml_stat, toml_array, len, add_array
      +  use fpm_toml, only: toml_serialize, get_value, set_value, add_table, set_string, get_list, set_list
      +  use fpm_versioning, only: version_t, new_version
      +  use fpm_settings, only: fpm_global_settings, get_global_settings, official_registry_base_url
      +  use fpm_downloader, only: downloader_t
      +  use jonquil, only: json_object
      +  implicit none
      +  private
      +
      +  public :: dependency_tree_t, new_dependency_tree, dependency_node_t, new_dependency_node, resize, &
      +            & check_and_read_pkg_data, destroy_dependency_node
      +
      +  !> Overloaded reallocation interface
      +  interface resize
      +    module procedure :: resize_dependency_node
      +  end interface resize
      +
      +  !> Dependency node in the projects dependency tree
      +  type, extends(dependency_config_t) :: dependency_node_t
      +    !> Actual version of this dependency
      +    type(version_t), allocatable  :: version
      +    !> Installation prefix of this dependencies
      +    character(len=:), allocatable :: proj_dir
      +    !> Checked out revision of the version control system
      +    character(len=:), allocatable :: revision
      +    !> Dependency is handled
      +    logical :: done = .false.
      +    !> Dependency should be updated
      +    logical :: update = .false.
      +    !> Dependency was loaded from a cache
      +    logical :: cached = .false.
      +    !> Package dependencies of this node 
      +    type(string_t), allocatable :: package_dep(:)    
      +  contains
      +
      +    !> Update dependency from project manifest.
      +    procedure :: register    
      +
      +    !> Get dependency from the registry.
      +    procedure :: get_from_registry
      +    procedure, private :: get_from_local_registry
      +    !> Print information on this instance
      +    procedure :: info
      +
      +    !> Serialization interface
      +    procedure :: serializable_is_same => dependency_node_is_same
      +    procedure :: dump_to_toml         => node_dump_to_toml
      +    procedure :: load_from_toml       => node_load_from_toml
      +
      +  end type dependency_node_t
      +
      +  !> Respresentation of a projects dependencies
      +  !>
      +  !> The dependencies are stored in a simple array for now, this can be replaced
      +  !> with a binary-search tree or a hash table in the future.
      +  type, extends(serializable_t) :: dependency_tree_t
      +    !> Unit for IO
      +    integer :: unit = output_unit
      +    !> Verbosity of printout
      +    integer :: verbosity = 1
      +    !> Installation prefix for dependencies
      +    character(len=:), allocatable :: dep_dir
      +    !> Number of currently registered dependencies
      +    integer :: ndep = 0
      +    !> Flattend list of all dependencies
      +    type(dependency_node_t), allocatable :: dep(:)
      +    !> Cache file
      +    character(len=:), allocatable :: cache
      +    !> Custom path to the global config file
      +    character(len=:), allocatable :: path_to_config
      +
      +  contains
      +
      +    !> Overload procedure to add new dependencies to the tree
      +    generic :: add => add_project, add_project_dependencies, add_dependencies, &
      +      add_dependency, add_dependency_node
      +    !> Main entry point to add a project
      +    procedure, private :: add_project
      +    !> Add a project and its dependencies to the dependency tree
      +    procedure, private :: add_project_dependencies
      +    !> Add a list of dependencies to the dependency tree
      +    procedure, private :: add_dependencies
      +    !> Add a single dependency to the dependency tree
      +    procedure, private :: add_dependency
      +    !> Add a single dependency node to the dependency tree
      +    procedure, private :: add_dependency_node
      +    !> Resolve dependencies
      +    generic :: resolve => resolve_dependencies, resolve_dependency
      +    !> Resolve dependencies
      +    procedure, private :: resolve_dependencies
      +    !> Resolve dependency
      +    procedure, private :: resolve_dependency
      +    !> True if entity can be found
      +    generic :: has => has_dependency
      +    !> True if dependency is part of the tree
      +    procedure, private :: has_dependency
      +    !> Find a dependency in the tree
      +    generic :: find => find_name
      +    !> Find a dependency by its name
      +    procedure, private :: find_name
      +    !> Establish local link order for a node's package dependencies
      +    procedure :: local_link_order
      +    !> Depedendncy resolution finished
      +    procedure :: finished
      +    !> Reading of dependency tree
      +    generic :: load_cache => load_cache_from_file, load_cache_from_unit, load_cache_from_toml
      +    !> Read dependency tree from file
      +    procedure, private :: load_cache_from_file
      +    !> Read dependency tree from formatted unit
      +    procedure, private :: load_cache_from_unit
      +    !> Read dependency tree from TOML data structure
      +    procedure, private :: load_cache_from_toml
      +    !> Writing of dependency tree
      +    generic :: dump_cache => dump_cache_to_file, dump_cache_to_unit, dump_cache_to_toml
      +    !> Write dependency tree to file
      +    procedure, private :: dump_cache_to_file
      +    !> Write dependency tree to formatted unit
      +    procedure, private :: dump_cache_to_unit
      +    !> Write dependency tree to TOML data structure
      +    procedure, private :: dump_cache_to_toml
      +    !> Update dependency tree
      +    generic :: update => update_dependency, update_tree
      +    !> Update a list of dependencies
      +    procedure, private :: update_dependency
      +    !> Update all dependencies in the tree
      +    procedure, private :: update_tree
      +
      +    !> Serialization interface
      +    procedure :: serializable_is_same => dependency_tree_is_same
      +    procedure :: dump_to_toml         => tree_dump_to_toml
      +    procedure :: load_from_toml       => tree_load_from_toml
      +
      +  end type dependency_tree_t
      +
      +  !> Common output format for writing to the command line
      +  character(len=*), parameter :: out_fmt = '("#", *(1x, g0))'
      +
      +contains
      +
      +  !> Create a new dependency tree
      +  subroutine new_dependency_tree(self, verbosity, cache, path_to_config)
      +    !> Instance of the dependency tree
      +    type(dependency_tree_t), intent(out) :: self
      +    !> Verbosity of printout
      +    integer, intent(in), optional :: verbosity
      +    !> Name of the cache file
      +    character(len=*), intent(in), optional :: cache
      +    !> Path to the global config file.
      +    character(len=*), intent(in), optional :: path_to_config
      +
      +    call resize(self%dep)
      +    self%dep_dir = join_path("build", "dependencies")
      +
      +    if (present(verbosity)) self%verbosity = verbosity
      +
      +    if (present(cache)) self%cache = cache
      +
      +    if (present(path_to_config)) self%path_to_config = path_to_config
      +
      +  end subroutine new_dependency_tree
      +
      +  !> Create a new dependency node from a configuration
      +  subroutine new_dependency_node(self, dependency, version, proj_dir, update)
      +    !> Instance of the dependency node
      +    type(dependency_node_t), intent(out) :: self
      +    !> Dependency configuration data
      +    type(dependency_config_t), intent(in) :: dependency
      +    !> Version of the dependency
      +    type(version_t), intent(in), optional :: version
      +    !> Installation prefix of the dependency
      +    character(len=*), intent(in), optional :: proj_dir
      +    !> Dependency should be updated
      +    logical, intent(in), optional :: update
      +
      +    self%dependency_config_t = dependency
      +
      +    if (present(version)) then
      +      self%version = version
      +    end if
      +
      +    if (present(proj_dir)) then
      +      self%proj_dir = proj_dir
      +    end if
      +
      +    if (present(update)) then
      +      self%update = update
      +    end if
      +
      +  end subroutine new_dependency_node
      +
      +  !> Write information on instance
      +  subroutine info(self, unit, verbosity)
      +
      +    !> Instance of the dependency configuration
      +    class(dependency_node_t), intent(in) :: self
      +
      +    !> Unit for IO
      +    integer, intent(in) :: unit
      +
      +    !> Verbosity of the printout
      +    integer, intent(in), optional :: verbosity
      +
      +    integer :: pr, i
      +    character(len=*), parameter :: fmt = '("#", 1x, a, t30, a)'
      +
      +    if (present(verbosity)) then
      +      pr = verbosity
      +    else
      +      pr = 1
      +    end if
      +
      +    !> Call base object info
      +    call self%dependency_config_t%info(unit, pr)
      +
      +    if (allocated(self%version)) then
      +      write (unit, fmt) "- version", self%version%s()
      +    end if
      +
      +    if (allocated(self%proj_dir)) then
      +      write (unit, fmt) "- dir", self%proj_dir
      +    end if
      +
      +    if (allocated(self%revision)) then
      +      write (unit, fmt) "- revision", self%revision
      +    end if
      +
      +    write (unit, fmt) "- done", merge('YES', 'NO ', self%done)
      +    write (unit, fmt) "- update", merge('YES', 'NO ', self%update)
      +    
      +    if (allocated(self%package_dep)) then
      +        write(unit, fmt) " - package_dep "
      +        do i = 1, size(self%package_dep)
      +           write(unit, fmt) "   - " // self%package_dep(i)%s
      +        end do            
      +    end if
      +    
      +  end subroutine info
      +
      +  !> Add project dependencies, each depth level after each other.
      +  !>
      +  !> We implement this algorithm in an interative rather than a recursive fashion
      +  !> as a choice of design.
      +  subroutine add_project(self, package, error)
      +    !> Instance of the dependency tree
      +    class(dependency_tree_t), intent(inout) :: self
      +    !> Project configuration to add
      +    type(package_config_t), intent(in) :: package
      +    !> Error handling
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    type(dependency_config_t) :: dependency
      +    type(dependency_tree_t) :: cached
      +    character(len=*), parameter :: root = '.'
      +    integer :: id
      +
      +    if (.not. exists(self%dep_dir)) then
      +      call mkdir(self%dep_dir)
      +    end if
      +
      +    ! Create this project as the first dependency node (depth 0)
      +    dependency%name = package%name
      +    dependency%path = root
      +    call self%add(dependency, error)
      +    if (allocated(error)) return
      +
      +    ! Resolve the root project
      +    call self%resolve(root, error)
      +    if (allocated(error)) return
      +    
      +    ! Add the root project dependencies (depth 1)
      +    call self%add(package, root, .true., error)
      +    if (allocated(error)) return
      +
      +    ! After resolving all dependencies, check if we have cached ones to avoid updates
      +    if (allocated(self%cache)) then
      +      call new_dependency_tree(cached, verbosity=self%verbosity,cache=self%cache)
      +      call cached%load_cache(self%cache, error)
      +      if (allocated(error)) return
      +
      +      ! Skip root node
      +      do id = 2, cached%ndep
      +        cached%dep(id)%cached = .true.
      +        call self%add(cached%dep(id), error)
      +        if (allocated(error)) return
      +      end do
      +    end if
      +
      +    ! Now decent into the dependency tree, level for level
      +    do while (.not. self%finished())
      +      call self%resolve(root, error)
      +      if (allocated(error)) exit
      +    end do
      +    if (allocated(error)) return
      +        
      +    ! Resolve internal dependency graph and remove temporary package storage
      +    call resolve_dependency_graph(self, package, error)
      +    if (allocated(error)) return
      +
      +    if (allocated(self%cache)) then
      +      call self%dump_cache(self%cache, error)
      +      if (allocated(error)) return
      +    end if
      +
      +  end subroutine add_project
      +
      +  subroutine resolve_dependency_graph(self, main, error)
      +      !> Instance of the dependency tree
      +      class(dependency_tree_t), intent(inout) :: self
      +      !> Main project configuration 
      +      type(package_config_t), intent(in) :: main      
      +      !> Error handling
      +      type(error_t), allocatable, intent(out) :: error
      +
      +      integer :: i,nit
      +      integer, parameter   :: MAXIT = 50
      +      logical, allocatable :: finished(:)
      +      type(string_t), allocatable :: old_package_dep(:)
      +      
      +      if (self%ndep<1) then 
      +          call fatal_error(error, "Trying to compute the dependency graph of an empty tree")
      +          return
      +      end if
      +      
      +      nit = 0
      +      allocate(finished(self%ndep),source=.false.)
      +      do while (.not.all(finished) .and. nit<MAXIT)
      +        
      +          nit = nit+1
      +      
      +          do i = 1, self%ndep
      +            
      +              ! Save old deps
      +              call move_alloc(from=self%dep(i)%package_dep,to=old_package_dep)
      +              
      +              call get_required_packages(self, i, error=error)
      +              if (allocated(error)) return
      +              
      +              finished(i) = all_alloc(self%dep(i)%package_dep, old_package_dep)
      +              
      +          end do  
      +      
      +      end do
      +      
      +      if (nit>=MAXIT) call fatal_error(error, "Infinite loop detected computing the dependency graph")
      +      
      +      contains
      +      
      +      pure logical function all_alloc(this,that)
      +          type(string_t), intent(in), allocatable :: this(:),that(:)
      +          all_alloc = .false.
      +          if (allocated(this).neqv.allocated(that)) return
      +          if (.not.allocated(this)) then 
      +              all_alloc = .true.
      +          else  
      +              if (size(this)/=size(that)) return
      +              if (.not.(this==that)) return
      +              all_alloc = .true.
      +          end if
      +      end function all_alloc
      +
      +  end subroutine resolve_dependency_graph
      +
      +  !> Add a project and its dependencies to the dependency tree
      +  recursive subroutine add_project_dependencies(self, package, root, main, error)
      +    !> Instance of the dependency tree
      +    class(dependency_tree_t), intent(inout) :: self
      +    !> Project configuration to add
      +    type(package_config_t), intent(in) :: package
      +    !> Current project root directory
      +    character(len=*), intent(in) :: root
      +    !> Is the main project
      +    logical, intent(in) :: main
      +    !> Error handling
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    integer :: ii
      +
      +    if (allocated(package%dependency)) then
      +      call self%add(package%dependency, error)
      +      if (allocated(error)) return
      +    end if
      +
      +    if (main) then
      +      if (allocated(package%dev_dependency)) then
      +        call self%add(package%dev_dependency, error)
      +        if (allocated(error)) return
      +      end if
      +
      +      if (allocated(package%executable)) then
      +        do ii = 1, size(package%executable)
      +          if (allocated(package%executable(ii)%dependency)) then
      +            call self%add(package%executable(ii)%dependency, error)
      +            if (allocated(error)) exit
      +          end if
      +        end do
      +        if (allocated(error)) return
      +      end if
      +
      +      if (allocated(package%example)) then
      +        do ii = 1, size(package%example)
      +          if (allocated(package%example(ii)%dependency)) then
      +            call self%add(package%example(ii)%dependency, error)
      +            if (allocated(error)) exit
      +          end if
      +        end do
      +        if (allocated(error)) return
      +      end if
      +
      +      if (allocated(package%test)) then
      +        do ii = 1, size(package%test)
      +          if (allocated(package%test(ii)%dependency)) then
      +            call self%add(package%test(ii)%dependency, error)
      +            if (allocated(error)) exit
      +          end if
      +        end do
      +        if (allocated(error)) return
      +      end if
      +    end if
      +
      +    !> Ensure allocation fits
      +    call resize(self%dep,self%ndep)
      +
      +  end subroutine add_project_dependencies
      +
      +  !> Add a list of dependencies to the dependency tree
      +  subroutine add_dependencies(self, dependency, error)
      +    !> Instance of the dependency tree
      +    class(dependency_tree_t), intent(inout) :: self
      +    !> Dependency configuration to add
      +    type(dependency_config_t), intent(in) :: dependency(:)
      +    !> Error handling
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    integer :: ii, ndep
      +
      +    ndep = size(self%dep)
      +    if (ndep < size(dependency) + self%ndep) then
      +      call resize(self%dep, ndep + ndep/2 + size(dependency))
      +    end if
      +
      +    do ii = 1, size(dependency)
      +      call self%add(dependency(ii), error)
      +      if (allocated(error)) exit
      +    end do
      +    if (allocated(error)) return
      +
      +    !> Ensure allocation fits ndep
      +    call resize(self%dep,self%ndep)
      +
      +  end subroutine add_dependencies
      +
      +  !> Add a single dependency node to the dependency tree
      +  !> Dependency nodes contain additional information (version, git, revision)
      +  subroutine add_dependency_node(self, dependency, error)
      +    !> Instance of the dependency tree
      +    class(dependency_tree_t), intent(inout) :: self
      +    !> Dependency configuration to add
      +    type(dependency_node_t), intent(in) :: dependency
      +    !> Error handling
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    integer :: id
      +
      +    if (self%has_dependency(dependency)) then
      +      ! A dependency with this same name is already in the dependency tree.
      +      ! Check if it needs to be updated
      +      id = self%find(dependency%name)
      +
      +      ! If this dependency was in the cache, and we're now requesting a different version
      +      ! in the manifest, ensure it is marked for update. Otherwise, if we're just querying
      +      ! the same dependency from a lower branch of the dependency tree, the existing one from
      +      ! the manifest has priority
      +      if (dependency%cached) then
      +        if (dependency_has_changed(dependency, self%dep(id), self%verbosity, self%unit)) then
      +          if (self%verbosity > 0) write (self%unit, out_fmt) "Dependency change detected:", dependency%name
      +          self%dep(id)%update = .true.
      +        else
      +          ! Store the cached one
      +          self%dep(id) = dependency
      +          self%dep(id)%update = .false.
      +        end if
      +      end if
      +    else
      +
      +      !> Safety: reallocate if necessary
      +      if (size(self%dep)==self%ndep) call resize(self%dep,self%ndep+1)
      +
      +      ! New dependency: add from scratch
      +      self%ndep = self%ndep + 1
      +      self%dep(self%ndep) = dependency
      +      self%dep(self%ndep)%update = .false.
      +    end if
      +
      +  end subroutine add_dependency_node
      +
      +  !> Add a single dependency to the dependency tree
      +  subroutine add_dependency(self, dependency, error)
      +    !> Instance of the dependency tree
      +    class(dependency_tree_t), intent(inout) :: self
      +    !> Dependency configuration to add
      +    type(dependency_config_t), intent(in) :: dependency
      +    !> Error handling
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    type(dependency_node_t) :: node
      +
      +    call new_dependency_node(node, dependency)
      +    call add_dependency_node(self, node, error)
      +
      +  end subroutine add_dependency
      +
      +  !> Update dependency tree
      +  subroutine update_dependency(self, name, error)
      +    !> Instance of the dependency tree
      +    class(dependency_tree_t), intent(inout) :: self
      +    !> Name of the dependency to update
      +    character(len=*), intent(in) :: name
      +    !> Error handling
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    integer :: id
      +    character(len=:), allocatable :: proj_dir, root
      +
      +    id = self%find(name)
      +    root = "."
      +
      +    if (id <= 0) then
      +      call fatal_error(error, "Cannot update dependency '"//name//"'")
      +      return
      +    end if
      +
      +    associate (dep => self%dep(id))
      +      if (allocated(dep%git) .and. dep%update) then
      +        if (self%verbosity > 0) write (self%unit, out_fmt) "Update:", dep%name
      +        proj_dir = join_path(self%dep_dir, dep%name)
      +        call dep%git%checkout(proj_dir, error)
      +        if (allocated(error)) return
      +
      +        ! Unset dependency and remove updatable attribute
      +        dep%done = .false.
      +        dep%update = .false.
      +
      +        ! Now decent into the dependency tree, level for level
      +        do while (.not. self%finished())
      +          call self%resolve(root, error)
      +          if (allocated(error)) exit
      +        end do
      +        if (allocated(error)) return
      +      end if
      +    end associate
      +
      +  end subroutine update_dependency
      +
      +  !> Update whole dependency tree
      +  subroutine update_tree(self, error)
      +    !> Instance of the dependency tree
      +    class(dependency_tree_t), intent(inout) :: self
      +    !> Error handling
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    integer :: i
      +
      +    ! Update dependencies where needed
      +    do i = 1, self%ndep
      +      call self%update(self%dep(i)%name, error)
      +      if (allocated(error)) return
      +    end do
      +
      +  end subroutine update_tree
      +
      +  !> Resolve all dependencies in the tree
      +  subroutine resolve_dependencies(self, root, error)
      +    !> Instance of the dependency tree
      +    class(dependency_tree_t), intent(inout) :: self
      +    !> Current installation prefix
      +    character(len=*), intent(in) :: root
      +    !> Error handling
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    type(fpm_global_settings) :: global_settings
      +    character(:), allocatable :: parent_directory
      +    integer :: ii
      +
      +    ! Register path to global config file if it was entered via the command line.
      +    if (allocated(self%path_to_config)) then
      +      if (len_trim(self%path_to_config) > 0) then
      +        parent_directory = parent_dir(self%path_to_config)
      +
      +        if (len_trim(parent_directory) == 0) then
      +          global_settings%path_to_config_folder = "."
      +        else
      +          global_settings%path_to_config_folder = parent_directory
      +        end if
      +
      +        global_settings%config_file_name = basename(self%path_to_config)
      +      end if
      +    end if
      +
      +    call get_global_settings(global_settings, error)
      +    if (allocated(error)) return
      +
      +    do ii = 1, self%ndep
      +      call self%resolve(self%dep(ii), global_settings, root, error)
      +      if (allocated(error)) exit
      +    end do
      +
      +    if (allocated(error)) return
      +
      +  end subroutine resolve_dependencies
      +
      +  !> Resolve a single dependency node
      +  subroutine resolve_dependency(self, dependency, global_settings, root, error)
      +    !> Instance of the dependency tree
      +    class(dependency_tree_t), intent(inout) :: self
      +    !> Dependency configuration to add
      +    type(dependency_node_t), intent(inout) :: dependency
      +    !> Global configuration settings.
      +    type(fpm_global_settings), intent(in) :: global_settings
      +    !> Current installation prefix
      +    character(len=*), intent(in) :: root
      +    !> Error handling
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    type(package_config_t) :: package
      +    character(len=:), allocatable :: manifest, proj_dir, revision
      +    logical :: fetch
      +
      +    if (dependency%done) return
      +
      +    fetch = .false.
      +    if (allocated(dependency%proj_dir)) then
      +      proj_dir = dependency%proj_dir
      +    else if (allocated(dependency%path)) then
      +      proj_dir = join_path(root, dependency%path)
      +    else if (allocated(dependency%git)) then
      +      proj_dir = join_path(self%dep_dir, dependency%name)
      +      fetch = .not. exists(proj_dir)
      +      if (fetch) then
      +        call dependency%git%checkout(proj_dir, error)
      +        if (allocated(error)) return
      +      end if
      +    else
      +      call dependency%get_from_registry(proj_dir, global_settings, error)
      +      if (allocated(error)) return
      +    end if
      +
      +    if (allocated(dependency%git)) then
      +      call git_revision(proj_dir, revision, error)
      +      if (allocated(error)) return
      +    end if
      +
      +    manifest = join_path(proj_dir, "fpm.toml")
      +    call get_package_data(package, manifest, error)
      +    if (allocated(error)) return
      +
      +    call dependency%register(package, proj_dir, fetch, revision, error)
      +    if (allocated(error)) return
      +    
      +
      +    if (self%verbosity > 1) then
      +      write (self%unit, out_fmt) &
      +        "Dep:", dependency%name, "version", dependency%version%s(), &
      +        "at", dependency%proj_dir
      +    end if
      +
      +    call self%add(package, proj_dir, .false., error)
      +    if (allocated(error)) return
      +    
      +  end subroutine resolve_dependency
      +
      +  !> Get a dependency from the registry. Whether the dependency is fetched
      +  !> from a local, a custom remote or the official registry is determined
      +  !> by the global configuration settings.
      +  subroutine get_from_registry(self, target_dir, global_settings, error, downloader_)
      +
      +    !> Instance of the dependency configuration.
      +    class(dependency_node_t), intent(in) :: self
      +
      +    !> The target directory of the dependency.
      +    character(:), allocatable, intent(out) :: target_dir
      +
      +    !> Global configuration settings.
      +    type(fpm_global_settings), intent(in) :: global_settings
      +
      +    !> Error handling.
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    !> Downloader instance.
      +    class(downloader_t), optional, intent(in) :: downloader_
      +
      +    character(:), allocatable :: cache_path, target_url, tmp_file
      +    type(version_t) :: version
      +    integer :: stat, unit
      +    type(json_object) :: json
      +    class(downloader_t), allocatable :: downloader
      +
      +    if (present(downloader_)) then
      +      downloader = downloader_
      +    else
      +      allocate (downloader)
      +    end if
      +
      +    ! Use local registry if it was specified in the global config file.
      +    if (allocated(global_settings%registry_settings%path)) then
      +      call self%get_from_local_registry(target_dir, global_settings%registry_settings%path, error); return
      +    end if
      +
      +    ! Include namespace and package name in the cache path.
      +    cache_path = join_path(global_settings%registry_settings%cache_path, self%namespace, self%name)
      +
      +    ! Check cache before downloading from the remote registry if a specific version was requested. When no specific
      +    ! version was requested, do network request first to check which is the newest version.
      +    if (allocated(self%requested_version)) then
      +      if (exists(join_path(cache_path, self%requested_version%s(), 'fpm.toml'))) then
      +        print *, "Using cached version of '", join_path(self%namespace, self%name, self%requested_version%s()), "'."
      +        target_dir = join_path(cache_path, self%requested_version%s()); return
      +      end if
      +    end if
      +
      +    tmp_file = get_temp_filename()
      +    open (newunit=unit, file=tmp_file, action='readwrite', iostat=stat)
      +    if (stat /= 0) then
      +      call fatal_error(error, "Error creating temporary file for downloading package '"//self%name//"'."); return
      +    end if
      +
      +    ! Include namespace and package name in the target url and download package data.
      +    target_url = global_settings%registry_settings%url//'/packages/'//self%namespace//'/'//self%name
      +    call downloader%get_pkg_data(target_url, self%requested_version, tmp_file, json, error)
      +    close (unit, status='delete')
      +    if (allocated(error)) return
      +
      +    ! Verify package data and read relevant information.
      +    call check_and_read_pkg_data(json, self, target_url, version, error)
      +    if (allocated(error)) return
      +
      +    ! Open new tmp file for downloading the actual package.
      +    open (newunit=unit, file=tmp_file, action='readwrite', iostat=stat)
      +    if (stat /= 0) then
      +      call fatal_error(error, "Error creating temporary file for downloading package '"//self%name//"'."); return
      +    end if
      +
      +    ! Include version number in the cache path. If no cached version exists, download it.
      +    cache_path = join_path(cache_path, version%s())
      +    if (.not. exists(join_path(cache_path, 'fpm.toml'))) then
      +      if (is_dir(cache_path)) call os_delete_dir(os_is_unix(), cache_path)
      +      call mkdir(cache_path)
      +
      +      call downloader%get_file(target_url, tmp_file, error)
      +      if (allocated(error)) then
      +        close (unit, status='delete'); return
      +      end if
      +
      +      ! Unpack the downloaded package to the final location.
      +      call downloader%unpack(tmp_file, cache_path, error)
      +      close (unit, status='delete')
      +      if (allocated(error)) return
      +    end if
      +
      +    target_dir = cache_path
      +
      +  end subroutine get_from_registry
      +
      +  subroutine check_and_read_pkg_data(json, node, download_url, version, error)
      +    type(json_object), intent(inout) :: json
      +    class(dependency_node_t), intent(in) :: node
      +    character(:), allocatable, intent(out) :: download_url
      +    type(version_t), intent(out) :: version
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    integer :: code, stat
      +    type(json_object), pointer :: p, q
      +    character(:), allocatable :: version_key, version_str, error_message, namespace, name
      +
      +    namespace = ""
      +    name = "UNNAMED_NODE"
      +    if (allocated(node%namespace)) namespace = node%namespace
      +    if (allocated(node%name)) name = node%name
      +
      +    if (.not. json%has_key('code')) then
      +      call fatal_error(error, "Failed to download '"//join_path(namespace, name)//"': No status code."); return
      +    end if
      +
      +    call get_value(json, 'code', code, stat=stat)
      +    if (stat /= 0) then
      +      call fatal_error(error, "Failed to download '"//join_path(namespace, name)//"': "// &
      +      & "Failed to read status code."); return
      +    end if
      +
      +    if (code /= 200) then
      +      if (.not. json%has_key('message')) then
      +        call fatal_error(error, "Failed to download '"//join_path(namespace, name)//"': No error message."); return
      +      end if
      +
      +      call get_value(json, 'message', error_message, stat=stat)
      +      if (stat /= 0) then
      +        call fatal_error(error, "Failed to download '"//join_path(namespace, name)//"': "// &
      +        & "Failed to read error message."); return
      +      end if
      +
      +      call fatal_error(error, "Failed to download '"//join_path(namespace, name)//"'. Status code: '"// &
      +      & str(code)//"'. Error message: '"//error_message//"'."); return
      +    end if
      +
      +    if (.not. json%has_key('data')) then
      +      call fatal_error(error, "Failed to download '"//join_path(namespace, name)//"': No data."); return
      +    end if
      +
      +    call get_value(json, 'data', p, stat=stat)
      +    if (stat /= 0) then
      +      call fatal_error(error, "Failed to read package data for '"//join_path(namespace, name)//"'."); return
      +    end if
      +
      +    if (allocated(node%requested_version)) then
      +      version_key = 'version_data'
      +    else
      +      version_key = 'latest_version_data'
      +    end if
      +
      +    if (.not. p%has_key(version_key)) then
      +      call fatal_error(error, "Failed to download '"//join_path(namespace, name)//"': No version data."); return
      +    end if
      +
      +    call get_value(p, version_key, q, stat=stat)
      +    if (stat /= 0) then
      +      call fatal_error(error, "Failed to retrieve version data for '"//join_path(namespace, name)//"'."); return
      +    end if
      +
      +    if (.not. q%has_key('download_url')) then
      +      call fatal_error(error, "Failed to download '"//join_path(namespace, name)//"': No download url."); return
      +    end if
      +
      +    call get_value(q, 'download_url', download_url, stat=stat)
      +    if (stat /= 0) then
      +      call fatal_error(error, "Failed to read download url for '"//join_path(namespace, name)//"'."); return
      +    end if
      +
      +    download_url = official_registry_base_url//download_url
      +
      +    if (.not. q%has_key('version')) then
      +      call fatal_error(error, "Failed to download '"//join_path(namespace, name)//"': No version found."); return
      +    end if
      +
      +    call get_value(q, 'version', version_str, stat=stat)
      +    if (stat /= 0) then
      +      call fatal_error(error, "Failed to read version data for '"//join_path(namespace, name)//"'."); return
      +    end if
      +
      +    call new_version(version, version_str, error)
      +    if (allocated(error)) then
      +      call fatal_error(error, "'"//version_str//"' is not a valid version for '"// &
      +      & join_path(namespace, name)//"'."); return
      +    end if
      +  end subroutine
      +
      +  !> Get the dependency from a local registry.
      +  subroutine get_from_local_registry(self, target_dir, registry_path, error)
      +
      +    !> Instance of the dependency configuration.
      +    class(dependency_node_t), intent(in) :: self
      +
      +    !> The target directory to download the dependency to.
      +    character(:), allocatable, intent(out) :: target_dir
      +
      +    !> The path to the local registry.
      +    character(*), intent(in) :: registry_path
      +
      +    !> Error handling.
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    character(:), allocatable :: path_to_name
      +    type(string_t), allocatable :: files(:)
      +    type(version_t), allocatable :: versions(:)
      +    type(version_t) :: version
      +    integer :: i
      +
      +    path_to_name = join_path(registry_path, self%namespace, self%name)
      +
      +    if (.not. exists(path_to_name)) then
      +      call fatal_error(error, "Dependency resolution of '"//self%name// &
      +      & "': Directory '"//path_to_name//"' doesn't exist."); return
      +    end if
      +
      +    call list_files(path_to_name, files)
      +    if (size(files) == 0) then
      +      call fatal_error(error, "No versions of '"//self%name//"' found in '"//path_to_name//"'."); return
      +    end if
      +
      +    ! Version requested, find it in the cache.
      +    if (allocated(self%requested_version)) then
      +      do i = 1, size(files)
      +        ! Identify directory that matches the version number.
      +        if (files(i)%s == join_path(path_to_name, self%requested_version%s()) .and. is_dir(files(i)%s)) then
      +          if (.not. exists(join_path(files(i)%s, 'fpm.toml'))) then
      +            call fatal_error(error, "'"//files(i)%s//"' is missing an 'fpm.toml' file."); return
      +          end if
      +          target_dir = files(i)%s; return
      +        end if
      +      end do
      +      call fatal_error(error, "Version '"//self%requested_version%s()//"' not found in '"//path_to_name//"'")
      +      return
      +    end if
      +
      +    ! No specific version requested, therefore collect available versions.
      +    allocate (versions(0))
      +    do i = 1, size(files)
      +      if (is_dir(files(i)%s)) then
      +        call new_version(version, basename(files(i)%s), error)
      +        if (allocated(error)) return
      +        versions = [versions, version]
      +      end if
      +    end do
      +
      +    if (size(versions) == 0) then
      +      call fatal_error(error, "No versions found in '"//path_to_name//"'"); return
      +    end if
      +
      +    ! Find the latest version.
      +    version = versions(1)
      +    do i = 1, size(versions)
      +      if (versions(i) > version) version = versions(i)
      +    end do
      +
      +    path_to_name = join_path(path_to_name, version%s())
      +
      +    if (.not. exists(join_path(path_to_name, 'fpm.toml'))) then
      +      call fatal_error(error, "'"//path_to_name//"' is missing an 'fpm.toml' file."); return
      +    end if
      +
      +    target_dir = path_to_name
      +  end subroutine get_from_local_registry
      +
      +  !> True if dependency is part of the tree
      +  pure logical function has_dependency(self, dependency)
      +    !> Instance of the dependency tree
      +    class(dependency_tree_t), intent(in) :: self
      +    !> Dependency configuration to check
      +    class(dependency_node_t), intent(in) :: dependency
      +
      +    has_dependency = self%find(dependency%name) /= 0
      +
      +  end function has_dependency
      +
      +  !> Find a dependency in the dependency tree
      +  pure function find_name(self, name) result(pos)
      +    !> Instance of the dependency tree
      +    class(dependency_tree_t), intent(in) :: self
      +    !> Dependency configuration to add
      +    character(len=*), intent(in) :: name
      +    !> Index of the dependency
      +    integer :: pos
      +
      +    integer :: ii
      +
      +    pos = 0
      +    do ii = 1, self%ndep
      +      if (name == self%dep(ii)%name) then
      +        pos = ii
      +        exit
      +      end if
      +    end do
      +
      +  end function find_name
      +
      +  !> Check if we are done with the dependency resolution
      +  pure function finished(self)
      +    !> Instance of the dependency tree
      +    class(dependency_tree_t), intent(in) :: self
      +    !> All dependencies are updated
      +    logical :: finished
      +
      +    finished = all(self%dep(:self%ndep)%done)
      +
      +  end function finished
      +
      +  !> Update dependency from project manifest
      +  subroutine register(node, package, root, fetch, revision, error)
      +    !> Instance of the dependency node
      +    class(dependency_node_t), intent(inout) :: node
      +    !> Package configuration data
      +    type(package_config_t), intent(in) :: package
      +   
      +    !> Project has been fetched
      +    logical, intent(in) :: fetch
      +    !> Root directory of the project
      +    character(len=*), intent(in) :: root
      +    !> Git revision of the project
      +    character(len=*), intent(in), optional :: revision
      +    !> Error handling
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    logical :: update
      +
      +    update = .false.
      +    if (node%name /= package%name) then
      +      call fatal_error(error, "Dependency name '"//package%name// &
      +        & "' found, but expected '"//node%name//"' instead")
      +        return
      +    end if
      +
      +    node%version  = package%version
      +    node%proj_dir = root
      +
      +    if (allocated(node%git) .and. present(revision)) then
      +      node%revision = revision
      +      if (.not. fetch) then
      +        ! Change in revision ID was checked already. Only update if ALL git information is missing
      +        update = .not. allocated(node%git%url)
      +      end if
      +    end if
      +  
      +    if (update) node%update = update
      +    node%done = .true.  
      +    
      +  end subroutine register
      +
      +  !> Capture the list of "required" packages while the manifest is loaded. 
      +  !> This subroutine should be called during the "resolve" phase, i.e. when the whole 
      +  !> dependency tree has been built already
      +  subroutine get_required_packages(tree, node_ID, error)
      +      !> Instance of the dependency tree
      +      class(dependency_tree_t), intent(inout) :: tree     
      +      !> Instance of the dependency node
      +      integer, intent(in) :: node_ID
      +      !> Error handling
      +      type(error_t), allocatable, intent(out) :: error
      +      
      +      integer :: nreq,k,id
      +      type(dependency_config_t), allocatable :: dependency(:)
      +      type(package_config_t) :: manifest
      +      logical :: required(tree%ndep),main
      +      
      +      associate(node => tree%dep(node_ID))
      +        
      +      ! Is the main project
      +      main = node_ID==1  
      +      
      +      ! Get manifest
      +      call get_package_data(manifest, join_path(node%proj_dir,"fpm.toml"), error)
      +      if (allocated(error)) return
      +      
      +      call get_package_dependencies(manifest, main, dependency) 
      +      nreq = size(dependency)
      +    
      +      ! Translate names -> indices
      +      required = .false.
      +
      +      do k = 1, nreq
      +        
      +          id = tree%find(dependency(k)%name)
      +          if (id<=0) then
      +             ! Shouldn't happen because tree already contains every dep
      +             call fatal_error(error, "Internal error: "//trim(node%name)// &
      +                  & " cannot find resolved dependency "//trim(dependency(k)%name)//" in tree")                  
      +             return             
      +          end if
      +          
      +          ! Recurse dependencies
      +          call recurse_deps(tree, id, required)
      +                    
      +      end do    
      +      
      +      ! Recursed list
      +      nreq = count(required)
      +      if (allocated(node%package_dep)) deallocate(node%package_dep)
      +      allocate(node%package_dep(nreq))  
      +      k = 0
      +      do id=1,tree%ndep
      +         if (.not.required(id)) cycle
      +         k = k+1
      +         node%package_dep(k) = string_t(tree%dep(id)%name)
      +      end do
      +      
      +      endassociate
      +      
      +      contains
      +                
      +          recursive subroutine recurse_deps(tree, id, required)
      +              class(dependency_tree_t), intent(in) :: tree
      +              integer, intent(in) :: id
      +              logical, intent(inout) :: required(:)
      +
      +              integer :: j,dep_id
      +              
      +              if (required(id)) return
      +              
      +              required(id) = .true.
      +              if (allocated(tree%dep(id)%package_dep)) then
      +                  do j = 1, size(tree%dep(id)%package_dep)
      +                      dep_id = tree%find(tree%dep(id)%package_dep(j)%s)
      +                      call recurse_deps(tree, dep_id, required)
      +                  end do
      +              end if
      +          end subroutine recurse_deps         
      +      
      +  end subroutine get_required_packages  
      +
      +  !> Build a correct topological link order for a given dependency node.
      +  !>
      +  !> This routine returns the list of dependencies required to build `root_id`,
      +  !> sorted such that each dependency appears *before* any node that depends on it.
      +  !> This is suitable for correct linker ordering: `-lA -lB` means B can use symbols from A.
      +  !>
      +  !> The returned list includes both the transitive dependencies and the node itself.
      +  !> Example: if node 3 requires [5, 7, 9, 2] and 9 also requires 2,
      +  !> then the result will ensure that 2 appears before 9, etc.
      +  subroutine local_link_order(tree, root_id, order, error)
      +    !> The full dependency graph
      +    class(dependency_tree_t), intent(in) :: tree
      +    !> Index of the node for which to compute link order (e.g., the target being linked)
      +    integer, intent(in) :: root_id
      +    !> Ordered list of dependency indices (subset of tree%dep(:)) in link-safe order
      +    integer, allocatable, intent(out) :: order(:)
      +    !> Optional fatal error if a cycle is detected (not expected)
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    !> Track which nodes have been visited
      +    logical, allocatable :: visited(:)
      +    !> Work stack holding post-order DFS traversal
      +    integer, allocatable :: stack(:)
      +    !> Total number of nodes and current stack position
      +    integer :: n, top
      +
      +    n = tree%ndep
      +    allocate(visited(n), source=.false.)
      +    allocate(stack(n), source=0)
      +    top = 0
      +
      +    !> Depth-First Search from root node
      +    call dfs(root_id,visited,stack,top,error)
      +    if (allocated(error)) return
      +
      +    !> The final link order is the reverse of the DFS post-order
      +    allocate(order(top))
      +    if (top>0) order(:) = stack(:top)
      +    
      +  contains
      +
      +    !> Recursive depth-first search, post-order
      +    recursive subroutine dfs(i,visited,stack,top,error)
      +        integer, intent(in) :: i
      +        logical, intent(inout) :: visited(:)
      +        integer, intent(inout) :: stack(:),top
      +        type(error_t), allocatable, intent(out) :: error
      +        integer :: k, id
      +
      +        if (.not.(i>0 .and. i<=tree%ndep)) then 
      +            call fatal_error(error,'package graph failed: invalid dependency ID')
      +            return
      +        end if
      +        if (visited(i)) return
      +        
      +        visited(i) = .true.
      +
      +        ! Visit all required dependencies before this node
      +        if (allocated(tree%dep(i)%package_dep)) then
      +            do k = 1, size(tree%dep(i)%package_dep)
      +                id = tree%find(tree%dep(i)%package_dep(k)%s)
      +                
      +                if (.not.(id>0 .and. id<=tree%ndep)) then 
      +                    call fatal_error(error,'package graph failed: cannot find '//tree%dep(i)%package_dep(k)%s)
      +                    return
      +                end if
      +
      +                call dfs(id, visited, stack, top, error)
      +                if (allocated(error)) return
      +            end do
      +        end if
      +
      +        ! Now that all dependencies are handled, record this node
      +        top = top + 1
      +        stack(top) = i
      +    end subroutine dfs
      +
      +  end subroutine local_link_order
      +
      +  !> Read dependency tree from file
      +  subroutine load_cache_from_file(self, file, error)
      +    !> Instance of the dependency tree
      +    class(dependency_tree_t), intent(inout) :: self
      +    !> File name
      +    character(len=*), intent(in) :: file
      +    !> Error handling
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    integer :: unit
      +    logical :: exist
      +
      +    inquire (file=file, exist=exist)
      +    if (.not. exist) return
      +
      +    open (file=file, newunit=unit)
      +    call self%load_cache(unit, error)
      +    close (unit)
      +  end subroutine load_cache_from_file
      +
      +  !> Read dependency tree from file
      +  subroutine load_cache_from_unit(self, unit, error)
      +    !> Instance of the dependency tree
      +    class(dependency_tree_t), intent(inout) :: self
      +    !> File name
      +    integer, intent(in) :: unit
      +    !> Error handling
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    type(toml_error), allocatable :: parse_error
      +    type(toml_table), allocatable :: table
      +
      +    call toml_load(table, unit, error=parse_error)
      +
      +    if (allocated(parse_error)) then
      +      allocate (error)
      +      call move_alloc(parse_error%message, error%message)
      +      return
      +    end if
      +
      +    call self%load_cache(table, error)
      +    if (allocated(error)) return
      +
      +  end subroutine load_cache_from_unit
      +
      +  !> Read dependency tree from TOML data structure
      +  subroutine load_cache_from_toml(self, table, error)
      +    !> Instance of the dependency tree
      +    class(dependency_tree_t), intent(inout) :: self
      +    !> Data structure
      +    type(toml_table), intent(inout) :: table
      +    !> Error handling
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    integer :: ndep, ii
      +    logical :: is_unix
      +    character(len=:), allocatable :: version, url, obj, rev, proj_dir
      +    type(toml_key), allocatable :: list(:)
      +    type(toml_table), pointer :: ptr
      +
      +    call table%get_keys(list)
      +
      +    ndep = size(self%dep)
      +    if (ndep < size(list) + self%ndep) then
      +      call resize(self%dep, ndep + ndep/2 + size(list))
      +    end if
      +
      +    is_unix = get_os_type() /= OS_WINDOWS
      +
      +    do ii = 1, size(list)
      +      call get_value(table, list(ii)%key, ptr)
      +      call get_value(ptr, "version", version)
      +      call get_value(ptr, "proj-dir", proj_dir)
      +      call get_value(ptr, "git", url)
      +      call get_value(ptr, "obj", obj)
      +      call get_value(ptr, "rev", rev)
      +      if (.not. allocated(proj_dir)) cycle
      +      self%ndep = self%ndep + 1
      +      associate (dep => self%dep(self%ndep))
      +        dep%name = list(ii)%key
      +        if (is_unix) then
      +          dep%proj_dir = proj_dir
      +        else
      +          dep%proj_dir = windows_path(proj_dir)
      +        end if
      +        dep%done = .false.
      +        if (allocated(version)) then
      +          if (.not. allocated(dep%version)) allocate (dep%version)
      +          call new_version(dep%version, version, error)
      +          if (allocated(error)) exit
      +        end if
      +        if (allocated(url)) then
      +          if (allocated(obj)) then
      +            dep%git = git_target_revision(url, obj)
      +          else
      +            dep%git = git_target_default(url)
      +          end if
      +          if (allocated(rev)) then
      +            dep%revision = rev
      +          end if
      +        else
      +          dep%path = proj_dir
      +        end if
      +      end associate
      +    end do
      +    if (allocated(error)) return
      +
      +    self%ndep = size(list)
      +  end subroutine load_cache_from_toml
      +
      +  !> Write dependency tree to file
      +  subroutine dump_cache_to_file(self, file, error)
      +    !> Instance of the dependency tree
      +    class(dependency_tree_t), intent(inout) :: self
      +    !> File name
      +    character(len=*), intent(in) :: file
      +    !> Error handling
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    integer :: unit
      +
      +    open (file=file, newunit=unit)
      +    call self%dump_cache(unit, error)
      +    close (unit)
      +    if (allocated(error)) return
      +
      +  end subroutine dump_cache_to_file
      +
      +  !> Write dependency tree to file
      +  subroutine dump_cache_to_unit(self, unit, error)
      +    !> Instance of the dependency tree
      +    class(dependency_tree_t), intent(inout) :: self
      +    !> Formatted unit
      +    integer, intent(in) :: unit
      +    !> Error handling
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    type(toml_table) :: table
      +
      +    table = toml_table()
      +    call self%dump_cache(table, error)
      +
      +    write (unit, '(a)') toml_serialize(table)
      +
      +  end subroutine dump_cache_to_unit
      +
      +  !> Write dependency tree to TOML datastructure
      +  subroutine dump_cache_to_toml(self, table, error)
      +    !> Instance of the dependency tree
      +    class(dependency_tree_t), intent(inout) :: self
      +    !> Data structure
      +    type(toml_table), intent(inout) :: table
      +    !> Error handling
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    integer :: ii
      +    type(toml_table), pointer :: ptr
      +    character(len=:), allocatable :: proj_dir
      +
      +    do ii = 1, self%ndep
      +      associate (dep => self%dep(ii))
      +        call add_table(table, dep%name, ptr)
      +        if (.not. associated(ptr)) then
      +          call fatal_error(error, "Cannot create entry for "//dep%name)
      +          exit
      +        end if
      +        if (allocated(dep%version)) then
      +          call set_value(ptr, "version", dep%version%s())
      +        end if
      +        proj_dir = canon_path(dep%proj_dir)
      +        call set_value(ptr, "proj-dir", proj_dir)
      +        if (allocated(dep%git)) then
      +          call set_value(ptr, "git", dep%git%url)
      +          if (allocated(dep%git%object)) then
      +            call set_value(ptr, "obj", dep%git%object)
      +          end if
      +          if (allocated(dep%revision)) then
      +            call set_value(ptr, "rev", dep%revision)
      +          end if
      +        end if
      +      end associate
      +    end do
      +    if (allocated(error)) return
      +
      +  end subroutine dump_cache_to_toml
      +
      +  !> Reallocate a list of dependencies
      +  pure subroutine resize_dependency_node(var, n)
      +    !> Instance of the array to be resized
      +    type(dependency_node_t), allocatable, intent(inout) :: var(:)
      +    !> Dimension of the final array size
      +    integer, intent(in), optional :: n
      +
      +    type(dependency_node_t), allocatable :: tmp(:)
      +    integer :: this_size, new_size
      +    integer, parameter :: initial_size = 16
      +
      +    if (allocated(var)) then
      +      this_size = size(var, 1)
      +      call move_alloc(var, tmp)
      +    else
      +      this_size = initial_size
      +    end if
      +
      +    if (present(n)) then
      +      new_size = n
      +    else
      +      new_size = this_size + this_size/2 + 1
      +    end if
      +
      +    allocate (var(new_size))
      +
      +    if (allocated(tmp)) then
      +      this_size = min(size(tmp, 1), size(var, 1))
      +      var(:this_size) = tmp(:this_size)
      +      deallocate (tmp)
      +    end if
      +
      +  end subroutine resize_dependency_node
      +
      +  !> Check if a dependency node has changed
      +  logical function dependency_has_changed(cached, manifest, verbosity, iunit) result(has_changed)
      +    !> Two instances of the same dependency to be compared
      +    type(dependency_node_t), intent(in) :: cached, manifest
      +
      +    !> Log verbosity
      +    integer, intent(in) :: verbosity, iunit
      +
      +    integer :: ip
      +
      +    has_changed = .true.
      +
      +    !> All the following entities must be equal for the dependency to not have changed
      +    if (manifest_has_changed(cached=cached, manifest=manifest, verbosity=verbosity, iunit=iunit)) return
      +
      +    !> For now, only perform the following checks if both are available. A dependency in cache.toml
      +    !> will always have this metadata; a dependency from fpm.toml which has not been fetched yet
      +    !> may not have it
      +    if (allocated(cached%version) .and. allocated(manifest%version)) then
      +      if (cached%version /= manifest%version) then
      +        if (verbosity > 1) write (iunit, out_fmt) "VERSION has changed: "//cached%version%s()//" vs. "//manifest%version%s()
      +        return
      +      end if
      +    else
      +      if (verbosity > 1) write (iunit, out_fmt) "VERSION has changed presence "
      +    end if
      +    if (allocated(cached%revision) .and. allocated(manifest%revision)) then
      +      if (cached%revision /= manifest%revision) then
      +        if (verbosity > 1) write (iunit, out_fmt) "REVISION has changed: "//cached%revision//" vs. "//manifest%revision
      +        return
      +      end if
      +    else
      +      if (verbosity > 1) write (iunit, out_fmt) "REVISION has changed presence "
      +    end if
      +    if (allocated(cached%proj_dir) .and. allocated(manifest%proj_dir)) then
      +      if (cached%proj_dir /= manifest%proj_dir) then
      +        if (verbosity > 1) write (iunit, out_fmt) "PROJECT DIR has changed: "//cached%proj_dir//" vs. "//manifest%proj_dir
      +        return
      +      end if
      +    else
      +      if (verbosity > 1) write (iunit, out_fmt) "PROJECT DIR has changed presence "
      +    end if
      +    if (allocated(cached%preprocess) .eqv. allocated(manifest%preprocess)) then
      +      if (allocated(cached%preprocess)) then
      +          if (size(cached%preprocess) /= size(manifest%preprocess)) then
      +            if (verbosity > 1) write (iunit, out_fmt) "PREPROCESS has changed size"
      +            return
      +          end if
      +          do ip=1,size(cached%preprocess)
      +             if (.not.(cached%preprocess(ip) == manifest%preprocess(ip))) then
      +                if (verbosity > 1) write (iunit, out_fmt) "PREPROCESS config has changed"
      +                return
      +             end if
      +          end do
      +      endif
      +    else
      +      if (verbosity > 1) write (iunit, out_fmt) "PREPROCESS has changed presence "
      +      return
      +    end if
      +
      +    !> All checks passed: the two dependencies have no differences
      +    has_changed = .false.
      +
      +  end function dependency_has_changed
      +
      +  !> Check that two dependency nodes are equal
      +  logical function dependency_node_is_same(this,that)
      +      class(dependency_node_t), intent(in) :: this
      +      class(serializable_t), intent(in) :: that
      +
      +      dependency_node_is_same = .false.
      +
      +      select type (other=>that)
      +         type is (dependency_node_t)
      +
      +            ! Base class must match
      +            if (.not.(this%dependency_config_t==other%dependency_config_t)) return
      +
      +            ! Extension must match
      +            if (.not.(this%done  .eqv.other%done)) return
      +            if (.not.(this%update.eqv.other%update)) return
      +            if (.not.(this%cached.eqv.other%cached)) return
      +
      +            if (allocated(this%proj_dir) .neqv. allocated(other%proj_dir)) return
      +            if (allocated(this%proj_dir)) then
      +              if (.not.(this%proj_dir==other%proj_dir)) return
      +            endif
      +            if (allocated(this%revision) .neqv. allocated(other%revision)) return
      +            if (allocated(this%revision)) then
      +              if (.not.(this%revision==other%revision)) return
      +            endif
      +
      +            if (allocated(this%version).neqv.allocated(other%version)) return
      +            if (allocated(this%version)) then
      +              if (.not.(this%version==other%version)) return
      +            endif
      +
      +            if (allocated(this%package_dep).neqv.allocated(other%package_dep)) return
      +            if (allocated(this%package_dep)) then
      +              if (.not.size(this%package_dep)==size(other%package_dep)) return
      +              if (.not.(this%package_dep==other%package_dep)) return
      +            endif
      +            
      +         class default
      +            ! Not the same type
      +            return
      +      end select
      +
      +      !> All checks passed!
      +      dependency_node_is_same = .true.
      +
      +  end function dependency_node_is_same
      +
      +    !> Dump dependency to toml table
      +    subroutine node_dump_to_toml(self, table, error)
      +
      +        !> Instance of the serializable object
      +        class(dependency_node_t), intent(inout) :: self
      +
      +        !> Data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        integer :: i,n,ierr
      +        type(toml_array), pointer :: array
      +
      +        ! Dump parent class
      +        call self%dependency_config_t%dump_to_toml(table, error)
      +        if (allocated(error)) return
      +
      +        if (allocated(self%version)) then
      +            call set_string(table, "version", self%version%s(), error,'dependency_node_t')
      +            if (allocated(error)) return
      +        endif
      +        call set_string(table, "proj-dir", self%proj_dir, error, 'dependency_node_t')
      +        if (allocated(error)) return
      +        call set_string(table, "revision", self%revision, error, 'dependency_node_t')
      +        if (allocated(error)) return
      +        call set_value(table, "done", self%done, error, 'dependency_node_t')
      +        if (allocated(error)) return
      +        call set_value(table, "update", self%update, error, 'dependency_node_t')
      +        if (allocated(error)) return
      +        call set_value(table, "cached", self%cached, error, 'dependency_node_t')
      +        if (allocated(error)) return        
      +        call set_list(table, "package-dep",self%package_dep, error)
      +        if (allocated(error)) return        
      +        
      +    end subroutine node_dump_to_toml
      +
      +    !> Read dependency from toml table (no checks made at this stage)
      +    subroutine node_load_from_toml(self, table, error)
      +
      +        !> Instance of the serializable object
      +        class(dependency_node_t), intent(inout) :: self
      +
      +        !> Data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        !> Local variables
      +        character(len=:), allocatable :: version
      +        integer :: ierr,i,n
      +        type(toml_array), pointer :: array
      +
      +        call destroy_dependency_node(self)
      +
      +        ! Load parent class
      +        call self%dependency_config_t%load_from_toml(table, error)
      +        if (allocated(error)) return
      +
      +        call get_value(table, "done", self%done, error, 'dependency_node_t')
      +        if (allocated(error)) return
      +        call get_value(table, "update", self%update, error, 'dependency_node_t')
      +        if (allocated(error)) return
      +        call get_value(table, "cached", self%cached, error, 'dependency_node_t')
      +        if (allocated(error)) return
      +
      +        call get_value(table, "proj-dir", self%proj_dir)
      +        call get_value(table, "revision", self%revision)
      +
      +        call get_value(table, "version", version)
      +        if (allocated(version)) then
      +            allocate(self%version)
      +            call new_version(self%version, version, error)
      +            if (allocated(error)) then
      +                error%message = 'dependency_node_t: version error from TOML table - '//error%message
      +                return
      +            endif
      +        end if        
      +        
      +        call get_list(table,"package-dep",self%package_dep, error)
      +        if (allocated(error)) return        
      +        
      +    end subroutine node_load_from_toml
      +
      +    !> Destructor
      +    elemental subroutine destroy_dependency_node(self)
      +
      +        class(dependency_node_t), intent(inout) :: self
      +
      +        integer :: ierr
      +
      +        call dependency_destroy(self)
      +
      +        deallocate(self%version,stat=ierr)
      +        deallocate(self%proj_dir,stat=ierr)
      +        deallocate(self%revision,stat=ierr)
      +        deallocate(self%package_dep,stat=ierr)
      +        self%done = .false.
      +        self%update = .false.
      +        self%cached = .false.
      +
      +    end subroutine destroy_dependency_node
      +
      +  !> Check that two dependency trees are equal
      +  logical function dependency_tree_is_same(this,that)
      +    class(dependency_tree_t), intent(in) :: this
      +    class(serializable_t), intent(in) :: that
      +
      +    integer :: ii
      +
      +    dependency_tree_is_same = .false.
      +
      +    select type (other=>that)
      +       type is (dependency_tree_t)
      +
      +          if (.not.(this%unit==other%unit)) return
      +          if (.not.(this%verbosity==other%verbosity)) return
      +          if (allocated(this%dep_dir) .neqv. allocated(other%dep_dir)) return
      +          if (allocated(this%dep_dir)) then
      +            if (.not.(this%dep_dir==other%dep_dir)) return
      +          endif
      +          if (.not.(this%ndep==other%ndep)) return
      +          if (.not.(allocated(this%dep).eqv.allocated(other%dep))) return
      +          if (allocated(this%dep)) then
      +             if (.not.(size(this%dep)==size(other%dep))) return
      +             do ii = 1, size(this%dep)
      +                if (.not.(this%dep(ii)==other%dep(ii))) return
      +             end do
      +          endif
      +          if (allocated(this%cache) .neqv. allocated(other%cache)) return
      +          if (allocated(this%cache)) then
      +            if (.not.(this%cache==other%cache)) return
      +          endif
      +
      +       class default
      +          ! Not the same type
      +          return
      +    end select
      +
      +    !> All checks passed!
      +    dependency_tree_is_same = .true.
      +
      +  end function dependency_tree_is_same
      +
      +    !> Dump dependency to toml table
      +    subroutine tree_dump_to_toml(self, table, error)
      +
      +        !> Instance of the serializable object
      +        class(dependency_tree_t), intent(inout) :: self
      +
      +        !> Data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        integer :: ierr, ii
      +        type(toml_table), pointer :: ptr_deps,ptr
      +        character(27) :: unnamed
      +
      +        call set_value(table, "unit", self%unit, error, 'dependency_tree_t')
      +        if (allocated(error)) return
      +        call set_value(table, "verbosity", self%verbosity, error, 'dependency_tree_t')
      +        if (allocated(error)) return
      +        call set_string(table, "dep-dir", self%dep_dir, error, 'dependency_tree_t')
      +        if (allocated(error)) return
      +        call set_string(table, "cache", self%cache, error, 'dependency_tree_t')
      +        if (allocated(error)) return
      +        call set_value(table, "ndep", self%ndep, error, 'dependency_tree_t')
      +        if (allocated(error)) return
      +
      +        if (allocated(self%dep)) then
      +
      +           ! Create dependency table
      +           call add_table(table, "dependencies", ptr_deps)
      +           if (.not. associated(ptr_deps)) then
      +              call fatal_error(error, "dependency_tree_t cannot create dependency table ")
      +              return
      +           end if
      +
      +           do ii = 1, size(self%dep)
      +              associate (dep => self%dep(ii))
      +
      +                 !> Because dependencies are named, fallback if this has no name
      +                 !> So, serialization will work regardless of size(self%dep) == self%ndep
      +                 if (.not. allocated(dep%name)) then
      +                    write(unnamed,1) ii
      +                    call add_table(ptr_deps, trim(unnamed), ptr)
      +                 else if (len_trim(dep%name)==0) then
      +                    write(unnamed,1) ii
      +                    call add_table(ptr_deps, trim(unnamed), ptr)
      +                 else
      +                    call add_table(ptr_deps, dep%name, ptr)
      +                 end if
      +                 if (.not. associated(ptr)) then
      +                    call fatal_error(error, "dependency_tree_t cannot create entry for dependency "//dep%name)
      +                    return
      +                 end if
      +                 call dep%dump_to_toml(ptr, error)
      +                 if (allocated(error)) return
      +              end associate
      +           end do
      +
      +        endif
      +
      +        1 format('UNNAMED_DEPENDENCY_',i0)
      +
      +    end subroutine tree_dump_to_toml
      +
      +    !> Read dependency from toml table (no checks made at this stage)
      +    subroutine tree_load_from_toml(self, table, error)
      +
      +        !> Instance of the serializable object
      +        class(dependency_tree_t), intent(inout) :: self
      +
      +        !> Data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        !> Local variables
      +        type(toml_key), allocatable :: keys(:),dep_keys(:)
      +        type(toml_table), pointer :: ptr_deps,ptr
      +        integer :: ii, jj, ierr
      +
      +        call table%get_keys(keys)
      +
      +        call get_value(table, "unit", self%unit, error, 'dependency_tree_t')
      +        if (allocated(error)) return
      +        call get_value(table, "verbosity", self%verbosity, error, 'dependency_tree_t')
      +        if (allocated(error)) return
      +        call get_value(table, "ndep", self%ndep, error, 'dependency_tree_t')
      +        if (allocated(error)) return
      +        call get_value(table, "dep-dir", self%dep_dir)
      +        call get_value(table, "cache", self%cache)
      +
      +        find_deps_table: do ii = 1, size(keys)
      +            if (keys(ii)%key=="dependencies") then
      +
      +               call get_value(table, keys(ii), ptr_deps)
      +               if (.not.associated(ptr_deps)) then
      +                  call fatal_error(error,'dependency_tree_t: error retrieving dependency table from TOML table')
      +                  return
      +               end if
      +
      +               !> Read all dependencies
      +               call ptr_deps%get_keys(dep_keys)
      +               call resize(self%dep, size(dep_keys))
      +
      +               do jj = 1, size(dep_keys)
      +
      +                   call get_value(ptr_deps, dep_keys(jj), ptr)
      +                   call self%dep(jj)%load_from_toml(ptr, error)
      +                   if (allocated(error)) return
      +
      +               end do
      +
      +               exit find_deps_table
      +
      +            endif
      +        end do find_deps_table
      +
      +    end subroutine tree_load_from_toml
      +
      +
      +end module fpm_dependency
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/dependency.f90~2.html b/sourcefile/dependency.f90~2.html new file mode 100644 index 0000000000..26c677cf00 --- /dev/null +++ b/sourcefile/dependency.f90~2.html @@ -0,0 +1,812 @@ + + + + + + + + + + + + + dependency.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      dependency.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      !> Implementation of the meta data for dependencies.
      +!>
      +!> A dependency table can currently have the following fields
      +!>
      +!>```toml
      +!>[dependencies]
      +!>"dep1" = { git = "url" }
      +!>"dep2" = { git = "url", branch = "name" }
      +!>"dep3" = { git = "url", tag = "name" }
      +!>"dep4" = { git = "url", rev = "sha1" }
      +!>"dep0" = { path = "path" }
      +!>```
      +!>
      +!> To reduce the amount of boilerplate code this module provides two constructors
      +!> for dependency types, one basic for an actual dependency (inline) table
      +!> and another to collect all dependency objects from a dependencies table,
      +!> which is handling the allocation of the objects and is forwarding the
      +!> individual dependency tables to their respective constructors.
      +!> The usual entry point should be the constructor for the super table.
      +!>
      +!> This objects contains a target to retrieve required `fpm` projects to
      +!> build the target declaring the dependency.
      +!> Resolving a dependency will result in obtaining a new package configuration
      +!> data for the respective project.
      +module fpm_manifest_dependency
      +    use fpm_error, only: error_t, syntax_error, fatal_error
      +    use fpm_git, only: git_target_t, git_target_tag, git_target_branch, &
      +        & git_target_revision, git_target_default, git_matches_manifest
      +    use tomlf, only: toml_table, toml_key, toml_stat
      +    use fpm_toml, only: get_value, check_keys, serializable_t, add_table, &
      +        & set_value, set_string
      +    use fpm_filesystem, only: windows_path, join_path
      +    use fpm_environment, only: get_os_type, OS_WINDOWS
      +    use fpm_manifest_metapackages, only: metapackage_config_t, is_meta_package, new_meta_config, &
      +            metapackage_request_t, new_meta_request
      +    use fpm_versioning, only: version_t, new_version
      +    use fpm_strings, only: string_t
      +    use fpm_manifest_preprocess
      +    implicit none
      +    private
      +
      +    public :: dependency_config_t, new_dependency, new_dependencies, manifest_has_changed, &
      +        & dependency_destroy, resize
      +
      +    !> Configuration meta data for a dependency
      +    type, extends(serializable_t) :: dependency_config_t
      +
      +        !> Name of the dependency
      +        character(len=:), allocatable :: name
      +
      +        !> Local target
      +        character(len=:), allocatable :: path
      +
      +        !> Namespace which the dependency belongs to.
      +        !> Enables multiple dependencies with the same name.
      +        !> Required for dependencies that are obtained via the official registry.
      +        character(len=:), allocatable :: namespace
      +
      +        !> The requested version of the dependency.
      +        !> The latest version is used if not specified.
      +        type(version_t), allocatable :: requested_version
      +
      +        !> Requested macros for the dependency
      +        type(preprocess_config_t), allocatable :: preprocess(:)
      +
      +        !> Git descriptor
      +        type(git_target_t), allocatable :: git
      +
      +    contains
      +
      +        !> Print information on this instance
      +        procedure :: info
      +        
      +        !> Add a preprocessor configuration
      +        procedure :: add_preprocess
      +
      +        !> Serialization interface
      +        procedure :: serializable_is_same => dependency_is_same
      +        procedure :: dump_to_toml
      +        procedure :: load_from_toml
      +
      +    end type dependency_config_t
      +
      +    !> Common output format for writing to the command line
      +    character(len=*), parameter :: out_fmt = '("#", *(1x, g0))'
      +
      +    interface resize
      +        module procedure resize_dependency_config
      +    end interface resize
      +
      +contains
      +
      +    !> Construct a new dependency configuration from a TOML data structure
      +    subroutine new_dependency(self, table, root, error)
      +
      +        !> Instance of the dependency configuration
      +        type(dependency_config_t), intent(out) :: self
      +
      +        !> Instance of the TOML data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> Root directory of the manifest
      +        character(*), intent(in), optional :: root
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        character(len=:), allocatable :: uri, value, requested_version
      +
      +        type(toml_table), pointer :: child
      +
      +        call check(table, error)
      +        if (allocated(error)) return
      +
      +        call table%get_key(self%name)
      +        call get_value(table, "namespace", self%namespace)
      +
      +        call get_value(table, "v", requested_version)
      +        if (allocated(requested_version)) then
      +            if (.not. allocated(self%requested_version)) allocate (self%requested_version)
      +            call new_version(self%requested_version, requested_version, error)
      +            if (allocated(error)) return
      +        end if
      +
      +        !> Get optional preprocessor directives
      +        call get_value(table, "preprocess", child, requested=.false.)
      +        if (associated(child)) then
      +            call new_preprocessors(self%preprocess, child, error)
      +            if (allocated(error)) return
      +        endif
      +
      +        call get_value(table, "path", uri)
      +        if (allocated(uri)) then
      +            if (get_os_type() == OS_WINDOWS) uri = windows_path(uri)
      +            if (present(root)) uri = join_path(root,uri)  ! Relative to the fpm.toml it’s written in
      +            call move_alloc(uri, self%path)
      +            return
      +        end if
      +
      +        call get_value(table, "git", uri)
      +        if (allocated(uri)) then
      +            call get_value(table, "tag", value)
      +            if (allocated(value)) then
      +                self%git = git_target_tag(uri, value)
      +            end if
      +
      +            if (.not. allocated(self%git)) then
      +                call get_value(table, "branch", value)
      +                if (allocated(value)) then
      +                    self%git = git_target_branch(uri, value)
      +                end if
      +            end if
      +
      +            if (.not. allocated(self%git)) then
      +                call get_value(table, "rev", value)
      +                if (allocated(value)) then
      +                    self%git = git_target_revision(uri, value)
      +                end if
      +            end if
      +
      +            if (.not. allocated(self%git)) then
      +                self%git = git_target_default(uri)
      +            end if
      +            return
      +        end if
      +
      +    end subroutine new_dependency
      +
      +    !> Check local schema for allowed entries
      +    subroutine check(table, error)
      +
      +        !> Instance of the TOML data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        character(len=:), allocatable :: name
      +        type(toml_key), allocatable :: list(:)
      +        type(toml_table), pointer :: child
      +
      +        !> List of valid keys for the dependency table.
      +        character(*), dimension(*), parameter :: valid_keys = [character(24) :: &
      +            & "namespace", &
      +              "v", &
      +              "path", &
      +              "git", &
      +              "tag", &
      +              "branch", &
      +              "rev", &
      +              "preprocess" &
      +            & ]
      +
      +        call table%get_key(name)
      +        call table%get_keys(list)
      +
      +        if (size(list) < 1) then
      +            call syntax_error(error, "Dependency '"//name//"' does not provide sufficient entries")
      +            return
      +        end if
      +
      +        call check_keys(table, valid_keys, error)
      +        if (allocated(error)) return
      +
      +        if (table%has_key("path") .and. table%has_key("git")) then
      +            call syntax_error(error, "Dependency '"//name//"' cannot have both git and path entries")
      +            return
      +        end if
      +
      +        if ((table%has_key("branch") .and. table%has_key("rev")) .or. &
      +            (table%has_key("branch") .and. table%has_key("tag")) .or. &
      +            (table%has_key("rev") .and. table%has_key("tag"))) then
      +            call syntax_error(error, "Dependency '"//name//"' can only have one of branch, rev or tag present")
      +            return
      +        end if
      +
      +        if ((table%has_key("branch") .or. table%has_key("tag") .or. table%has_key("rev")) &
      +            .and. .not. table%has_key("git")) then
      +            call syntax_error(error, "Dependency '"//name//"' has git identifier but no git url")
      +            return
      +        end if
      +
      +        if (.not. table%has_key("path") .and. .not. table%has_key("git") &
      +            .and. .not. table%has_key("namespace")) then
      +            call syntax_error(error, "Please provide a 'namespace' for dependency '"//name// &
      +            & "' if it is not a local path or git repository")
      +            return
      +        end if
      +
      +        if (table%has_key('v') .and. (table%has_key('path') .or. table%has_key('git'))) then
      +            call syntax_error(error, "Dependency '"//name//"' cannot have both v and git/path entries")
      +            return
      +        end if
      +
      +        ! Check preprocess key
      +        if (table%has_key('preprocess')) then
      +
      +            call get_value(table, 'preprocess', child)
      +
      +            if (.not.associated(child)) then
      +                call syntax_error(error, "Dependency '"//name//"' has invalid 'preprocess' entry")
      +                return
      +            end if
      +
      +        end if
      +
      +    end subroutine check
      +
      +    !> Construct new dependency array from a TOML data structure
      +    subroutine new_dependencies(deps, table, root, meta, error)
      +
      +        !> Instance of the dependency configuration
      +        type(dependency_config_t), allocatable, intent(out) :: deps(:)
      +
      +        !> (optional) metapackages
      +        type(metapackage_config_t), optional, intent(out) :: meta
      +
      +        !> Instance of the TOML data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> Root directory of the manifest
      +        character(*), intent(in), optional :: root
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        type(toml_table), pointer :: node
      +        type(toml_key), allocatable :: list(:)
      +        type(dependency_config_t), allocatable :: all_deps(:)
      +        type(metapackage_request_t) :: meta_request
      +        logical, allocatable :: is_meta(:)
      +        logical :: metapackages_allowed
      +        integer :: idep, stat, ndep
      +
      +        call table%get_keys(list)
      +        ! An empty table is okay
      +        if (size(list) < 1) return
      +
      +        !> Flag dependencies that should be treated as metapackages
      +        metapackages_allowed = present(meta)
      +        allocate(is_meta(size(list)),source=.false.)
      +        allocate(all_deps(size(list)))
      +
      +        !> Parse all meta- and non-metapackage dependencies
      +        do idep = 1, size(list)
      +
      +            ! Check if this is a standard dependency node
      +            call get_value(table, list(idep)%key, node, stat=stat)
      +            is_standard_dependency: if (stat /= toml_stat%success) then
      +
      +                ! See if it can be a valid metapackage name
      +                call new_meta_request(meta_request, list(idep)%key, table, error=error)
      +
      +                !> Neither a standard dep nor a metapackage
      +                if (allocated(error)) then
      +                   call syntax_error(error, "Dependency "//list(idep)%key//" is not a valid metapackage or a table entry")
      +                   return
      +                endif
      +
      +                !> Valid meta dependency
      +                is_meta(idep) = .true.
      +
      +            else
      +
      +                ! Parse as a standard dependency
      +                is_meta(idep) = .false.
      +
      +                call new_dependency(all_deps(idep), node, root, error)
      +                if (allocated(error)) return
      +
      +            end if is_standard_dependency
      +
      +        end do
      +
      +        ! Non-meta dependencies
      +        ndep = count(.not.is_meta)
      +
      +        ! Finalize standard dependencies
      +        allocate(deps(ndep))
      +        ndep = 0
      +        do idep = 1, size(list)
      +            if (is_meta(idep)) cycle
      +            ndep = ndep+1
      +            deps(ndep) = all_deps(idep)
      +        end do
      +
      +        ! Finalize meta dependencies
      +        if (metapackages_allowed) call new_meta_config(meta,table,is_meta,error)
      +
      +    end subroutine new_dependencies
      +
      +    !> Write information on instance
      +    subroutine info(self, unit, verbosity)
      +
      +        !> Instance of the dependency configuration
      +        class(dependency_config_t), intent(in) :: self
      +
      +        !> Unit for IO
      +        integer, intent(in) :: unit
      +
      +        !> Verbosity of the printout
      +        integer, intent(in), optional :: verbosity
      +
      +        integer :: pr
      +        character(len=*), parameter :: fmt = '("#", 1x, a, t30, a)'
      +
      +        if (present(verbosity)) then
      +            pr = verbosity
      +        else
      +            pr = 1
      +        end if
      +
      +        write (unit, fmt) "Dependency"
      +        if (allocated(self%name)) then
      +            write (unit, fmt) "- name", self%name
      +        end if
      +
      +        if (allocated(self%git)) then
      +            write (unit, fmt) "- kind", "git"
      +            call self%git%info(unit, pr - 1)
      +        end if
      +
      +        if (allocated(self%path)) then
      +            write (unit, fmt) "- kind", "local"
      +            write (unit, fmt) "- path", self%path
      +        end if
      +
      +    end subroutine info
      +
      +    !> Check if two dependency configurations are different
      +    logical function manifest_has_changed(cached, manifest, verbosity, iunit) result(has_changed)
      +
      +        !> Two instances of the dependency configuration
      +        class(dependency_config_t), intent(in) :: cached, manifest
      +
      +        !> Log verbosity
      +        integer, intent(in) :: verbosity, iunit
      +
      +        has_changed = .true.
      +
      +        !> Perform all checks
      +        if (allocated(cached%git).neqv.allocated(manifest%git)) then
      +            if (verbosity>1) write(iunit,out_fmt) "GIT presence has changed. "
      +            return
      +        endif
      +        if (allocated(cached%git)) then
      +            if (.not.git_matches_manifest(cached%git,manifest%git,verbosity,iunit)) return
      +        end if
      +
      +        !> All checks passed! The two instances are equal
      +        has_changed = .false.
      +
      +    end function manifest_has_changed
      +
      +    !> Clean memory
      +    elemental subroutine dependency_destroy(self)
      +        class(dependency_config_t), intent(inout) :: self
      +
      +        if (allocated(self%name)) deallocate(self%name)
      +        if (allocated(self%path)) deallocate(self%path)
      +        if (allocated(self%namespace)) deallocate(self%namespace)
      +        if (allocated(self%requested_version)) deallocate(self%requested_version)
      +        if (allocated(self%git)) deallocate(self%git)
      +
      +    end subroutine dependency_destroy
      +
      +    !> Check that two dependency configs are equal
      +    logical function dependency_is_same(this,that)
      +        class(dependency_config_t), intent(in) :: this
      +        class(serializable_t), intent(in) :: that
      +
      +        dependency_is_same = .false.
      +
      +        select type (other=>that)
      +           type is (dependency_config_t)
      +
      +              if (allocated(this%name).neqv.allocated(other%name)) return
      +              if (allocated(this%name)) then
      +                if (.not.(this%name==other%name)) return
      +              endif
      +              if (allocated(this%path).neqv.allocated(other%path)) return
      +              if (allocated(this%path)) then
      +                if (.not.(this%path==other%path)) return
      +              endif
      +              if (allocated(this%namespace).neqv.allocated(other%namespace)) return
      +              if (allocated(this%namespace)) then
      +                if (.not.(this%namespace==other%namespace)) return
      +              endif
      +              if (allocated(this%requested_version).neqv.allocated(other%requested_version)) return
      +              if (allocated(this%requested_version)) then
      +                if (.not.(this%requested_version==other%requested_version)) return
      +              endif
      +
      +              if ((allocated(this%git).neqv.allocated(other%git))) return
      +              if (allocated(this%git)) then
      +                if (.not.(this%git==other%git)) return
      +              endif
      +
      +           class default
      +              ! Not the same type
      +              return
      +        end select
      +
      +        !> All checks passed!
      +        dependency_is_same = .true.
      +
      +    end function dependency_is_same
      +
      +    !> Dump dependency to toml table
      +    subroutine dump_to_toml(self, table, error)
      +
      +        !> Instance of the serializable object
      +        class(dependency_config_t), intent(inout) :: self
      +
      +        !> Data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> Error handling
      +        type(toml_table), pointer :: ptr
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        integer :: ierr
      +
      +        call set_string(table, "name", self%name, error, 'dependency_config_t')
      +        if (allocated(error)) return
      +        call set_string(table, "path", self%path, error, 'dependency_config_t')
      +        if (allocated(error)) return
      +        call set_string(table, "namespace", self%namespace, error, 'dependency_config_t')
      +        if (allocated(error)) return
      +        if (allocated(self%requested_version)) then
      +             call set_string(table, "requested_version", self%requested_version%s(), error, 'dependency_config_t')
      +             if (allocated(error)) return
      +        endif
      +
      +        if (allocated(self%git)) then
      +            call add_table(table, "git", ptr, error)
      +            if (allocated(error)) return
      +            call self%git%dump_to_toml(ptr, error)
      +            if (allocated(error)) return
      +        endif
      +
      +    end subroutine dump_to_toml
      +
      +    !> Read dependency from toml table (no checks made at this stage)
      +    subroutine load_from_toml(self, table, error)
      +
      +        !> Instance of the serializable object
      +        class(dependency_config_t), intent(inout) :: self
      +
      +        !> Data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        !> Local variables
      +        type(toml_key), allocatable :: list(:)
      +        type(toml_table), pointer :: ptr
      +        character(len=:), allocatable :: requested_version
      +        integer :: ierr,ii
      +
      +        call dependency_destroy(self)
      +
      +        call get_value(table, "name", self%name)
      +        call get_value(table, "path", self%path)
      +        call get_value(table, "namespace", self%namespace)
      +        call get_value(table, "requested_version", requested_version)
      +        if (allocated(requested_version)) then
      +            allocate(self%requested_version)
      +            call new_version(self%requested_version, requested_version, error)
      +            if (allocated(error)) then
      +                error%message = 'dependency_config_t: version error from TOML table - '//error%message
      +                return
      +            endif
      +        end if
      +
      +        call table%get_keys(list)
      +        add_git: do ii = 1, size(list)
      +            if (list(ii)%key=="git") then
      +               call get_value(table, list(ii)%key, ptr, stat=ierr)
      +               if (ierr /= toml_stat%success) then
      +                   call fatal_error(error,'dependency_config_t: cannot retrieve git from TOML table')
      +                   exit
      +               endif
      +               allocate(self%git)
      +               call self%git%load_from_toml(ptr, error)
      +               if (allocated(error)) return
      +               exit add_git
      +            end if
      +        end do add_git
      +
      +    end subroutine load_from_toml
      +
      +    !> Reallocate a list of dependencies
      +    pure subroutine resize_dependency_config(var, n)
      +        !> Instance of the array to be resized
      +        type(dependency_config_t), allocatable, intent(inout) :: var(:)
      +        !> Dimension of the final array size
      +        integer, intent(in), optional :: n
      +
      +        type(dependency_config_t), allocatable :: tmp(:)
      +        integer :: this_size, new_size
      +        integer, parameter :: initial_size = 16
      +
      +        if (allocated(var)) then
      +          this_size = size(var, 1)
      +          call move_alloc(var, tmp)
      +        else
      +          this_size = initial_size
      +        end if
      +
      +        if (present(n)) then
      +          new_size = n
      +        else
      +          new_size = this_size + this_size/2 + 1
      +        end if
      +
      +        allocate (var(new_size))
      +
      +        if (allocated(tmp)) then
      +          this_size = min(size(tmp, 1), size(var, 1))
      +          var(:this_size) = tmp(:this_size)
      +          deallocate (tmp)
      +        end if
      +
      +    end subroutine resize_dependency_config
      +    
      +    subroutine add_preprocess(dep, preprocess)
      +        !> Instance of the dependency config
      +        class(dependency_config_t), intent(inout) :: dep
      +        !> Instance of the preprocessor configuration
      +        type(preprocess_config_t), intent(in) :: preprocess
      +        
      +        integer :: i,n
      +        type(preprocess_config_t), allocatable :: new_preprocess(:)
      +        
      +        if (allocated(dep%preprocess)) then 
      +            
      +            n = size(dep%preprocess)
      +            
      +            if (n<1) then 
      +                deallocate(dep%preprocess)
      +                allocate(dep%preprocess(1),source=preprocess)
      +            else
      +                
      +                find_similar: do i=1,n
      +                    if (dep%preprocess(i)%name==dep%name) then                             
      +                        call dep%preprocess(i)%add_config(preprocess)
      +                        return                            
      +                    end if
      +                end do find_similar                   
      +                
      +                ! Similar preprocessor config not found: add a new one
      +                allocate(new_preprocess(n+1))
      +                new_preprocess(1:n) = dep%preprocess
      +                new_preprocess(n+1) = preprocess
      +                call move_alloc(from=new_preprocess,to=dep%preprocess)
      +                
      +            end if
      +        else
      +            
      +            ! Copy configuration
      +            allocate(dep%preprocess(1),source=preprocess)
      +            
      +        end if                
      +               
      +    end subroutine add_preprocess
      +
      +
      +end module fpm_manifest_dependency
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/downloader.f90.html b/sourcefile/downloader.f90.html new file mode 100644 index 0000000000..d771b5a06e --- /dev/null +++ b/sourcefile/downloader.f90.html @@ -0,0 +1,334 @@ + + + + + + + + + + + + + downloader.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      downloader.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      module fpm_downloader
      +  use fpm_error, only: error_t, fatal_error
      +  use fpm_filesystem, only: which, run
      +  use fpm_versioning, only: version_t
      +  use jonquil, only: json_object, json_value, json_error, json_load, cast_to_object
      +  use fpm_strings, only: string_t
      +
      +  implicit none
      +  private
      +
      +  public :: downloader_t
      +
      +  !> This type could be entirely avoided but it is quite practical because it can be mocked for testing.
      +  type downloader_t
      +  contains
      +    procedure, nopass :: get_pkg_data, get_file, upload_form, unpack
      +  end type
      +
      +contains
      +
      +  !> Perform an http get request, save output to file, and parse json. 
      +  subroutine get_pkg_data(url, version, tmp_pkg_file, json, error)
      +    character(*), intent(in) :: url
      +    type(version_t), allocatable, intent(in) :: version
      +    character(*), intent(in) :: tmp_pkg_file
      +    type(json_object), intent(out) :: json
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    class(json_value), allocatable :: j_value
      +    type(json_object), pointer :: ptr
      +    type(json_error), allocatable :: j_error
      +
      +    if (allocated(version)) then
      +      ! Request specific version.
      +      call get_file(url//'/'//version%s(), tmp_pkg_file, error)
      +    else
      +      ! Request latest version.
      +      call get_file(url, tmp_pkg_file, error)
      +    end if
      +    if (allocated(error)) return
      +
      +    call json_load(j_value, tmp_pkg_file, error=j_error)
      +    if (allocated(j_error)) then
      +      allocate (error); call move_alloc(j_error%message, error%message); call json%destroy(); return
      +    end if
      +
      +    ptr => cast_to_object(j_value)
      +    if (.not. associated(ptr)) then
      +      call fatal_error(error, "Error parsing JSON from '"//url//"'."); return
      +    end if
      +
      +    json = ptr
      +  end
      +
      +  !> Download a file from a url using either curl or wget.
      +  subroutine get_file(url, tmp_pkg_file, error)
      +    character(*), intent(in) :: url
      +    character(*), intent(in) :: tmp_pkg_file
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    integer :: stat
      +
      +    if (which('curl') /= '') then
      +      print *, "Downloading '"//url//"' -> '"//tmp_pkg_file//"'"
      +      call execute_command_line('curl '//url//' -s -o '//tmp_pkg_file, exitstat=stat)
      +    else if (which('wget') /= '') then
      +      print *, "Downloading '"//url//"' -> '"//tmp_pkg_file//"'"
      +      call execute_command_line('wget '//url//' -q -O '//tmp_pkg_file, exitstat=stat)
      +    else
      +      call fatal_error(error, "Neither 'curl' nor 'wget' installed."); return
      +    end if
      +
      +    if (stat /= 0) then
      +      call fatal_error(error, "Error downloading package from '"//url//"'."); return
      +    end if
      +  end
      +
      +  !> Perform an http post request with form data.
      +  subroutine upload_form(endpoint, form_data, verbose, error)
      +    !> Endpoint to upload to.
      +    character(len=*), intent(in) :: endpoint
      +    !> Form data to upload.
      +    type(string_t), intent(in) :: form_data(:)
      +    !> Print additional information if true.
      +    logical, intent(in) :: verbose
      +    !> Error handling.
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    integer :: stat, i
      +    character(len=:), allocatable :: form_data_str
      +
      +    form_data_str = ''
      +    do i = 1, size(form_data)
      +      form_data_str = form_data_str//"-F '"//form_data(i)%s//"' "
      +    end do
      +
      +    if (which('curl') /= '') then
      +      print *, 'Uploading package ...'
      +      call run('curl -X POST -H "Content-Type: multipart/form-data" '// &
      +      & form_data_str//endpoint, exitstat=stat, echo=verbose)
      +    else
      +      call fatal_error(error, "'curl' not installed."); return
      +    end if
      +
      +    if (stat /= 0) then
      +      call fatal_error(error, "Error uploading package to registry."); return
      +    end if
      +  end
      +
      +  !> Unpack a tarball to a destination.
      +  subroutine unpack(tmp_pkg_file, destination, error)
      +    !> Path to tarball.
      +    character(*), intent(in) :: tmp_pkg_file
      +    !> Destination to unpack to.
      +    character(*), intent(in) :: destination
      +    !> Error handling.
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    integer :: stat
      +
      +    if (which('tar') == '') then
      +      call fatal_error(error, "'tar' not installed."); return
      +    end if
      +
      +    print *, "Unpacking '"//tmp_pkg_file//"' to '"//destination//"' ..."
      +    call execute_command_line('tar -zxf '//tmp_pkg_file//' -C '//destination, exitstat=stat)
      +
      +    if (stat /= 0) then
      +      call fatal_error(error, "Error unpacking '"//tmp_pkg_file//"'."); return
      +    end if
      +  end
      +end
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/error.f90.html b/sourcefile/error.f90.html new file mode 100644 index 0000000000..0868139158 --- /dev/null +++ b/sourcefile/error.f90.html @@ -0,0 +1,385 @@ + + + + + + + + + + + + + error.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      error.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      !> Implementation of basic error handling.
      +module fpm_error
      +    use,intrinsic :: iso_fortran_env, only : stdin=>input_unit, stdout=>output_unit, stderr=>error_unit
      +    use fpm_strings, only : is_fortran_name, to_fortran_name
      +    implicit none
      +    private
      +
      +    public :: error_t
      +    public :: fatal_error, syntax_error, file_not_found_error
      +    public :: file_parse_error
      +    public :: bad_name_error
      +    public :: fpm_stop
      +
      +
      +    !> Data type defining an error
      +    type :: error_t
      +
      +        !> Error message
      +        character(len=:), allocatable :: message
      +
      +    end type error_t
      +
      +contains
      +
      +    !> Generic fatal runtime error
      +    subroutine fatal_error(error, message)
      +
      +        !> Instance of the error data
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        !> Error message
      +        character(len=*), intent(in) :: message
      +
      +        allocate(error)
      +        error%message = message
      +
      +    end subroutine fatal_error
      +
      +    subroutine syntax_error(error, message)
      +
      +        !> Instance of the error data
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        !> Error message
      +        character(len=*), intent(in) :: message
      +
      +        allocate(error)
      +        error%message = message
      +
      +    end subroutine syntax_error
      +
      +    function bad_name_error(error, label,name)
      +
      +        !> Instance of the error data
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        !> Error message label to add to message
      +        character(len=*), intent(in) :: label
      +
      +        !> name value to check
      +        character(len=*), intent(in) :: name
      +
      +        logical :: bad_name_error
      +
      +        if(.not.is_fortran_name(to_fortran_name(name)))then
      +           bad_name_error=.true.
      +           allocate(error)
      +           error%message = 'manifest file syntax error: '//label//' name must be composed only of &
      +           &alphanumerics, "-" and "_"  and start with a letter ::'//name
      +        else
      +          bad_name_error=.false.
      +        endif
      +
      +    end function bad_name_error
      +
      +
      +    !> Error created when a file is missing or not found
      +    subroutine file_not_found_error(error, file_name)
      +
      +        !> Instance of the error data
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        !> Name of the missing file
      +        character(len=*), intent(in) :: file_name
      +
      +        allocate(error)
      +        error%message = "'"//file_name//"' could not be found, check if the file exists"
      +
      +    end subroutine file_not_found_error
      +
      +
      +    !> Error created when file parsing fails
      +    subroutine file_parse_error(error, file_name, message, line_num, &
      +                                 line_string, line_col)
      +
      +        !> Instance of the error data
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        !> Name of file
      +        character(len=*), intent(in) :: file_name
      +
      +        !> Parse error message
      +        character(len=*), intent(in) :: message
      +
      +        !> Line number of parse error
      +        integer, intent(in), optional :: line_num
      +
      +        !> Line context string
      +        character(len=*), intent(in), optional :: line_string
      +
      +        !> Line context column
      +        integer, intent(in), optional :: line_col
      +
      +        character(50) :: temp_string
      +
      +        allocate(error)
      +        error%message = 'Parse error: '//message//new_line('a')
      +
      +        error%message = error%message//file_name
      +
      +        if (present(line_num)) then
      +
      +            write(temp_string,'(I0)') line_num
      +
      +            error%message = error%message//':'//trim(temp_string)
      +
      +        end if
      +
      +        if (present(line_col)) then
      +
      +            if (line_col > 0) then
      +
      +                write(temp_string,'(I0)') line_col
      +                error%message = error%message//':'//trim(temp_string)
      +
      +            end if
      +
      +        end if
      +
      +        if (present(line_string)) then
      +
      +            error%message = error%message//new_line('a')
      +            error%message = error%message//'   | '//line_string
      +
      +            if (present(line_col)) then
      +
      +                if (line_col > 0) then
      +
      +                    error%message = error%message//new_line('a')
      +                    error%message = error%message//'   | '//repeat(' ',line_col-1)//'^'
      +
      +                end if
      +
      +            end if
      +
      +        end if
      +
      +    end subroutine file_parse_error
      +
      +    subroutine fpm_stop(value,message)
      +    ! TODO: if verbose mode, call ERROR STOP instead of STOP
      +    ! TODO: if M_escape is used, add color
      +    ! to work with older compilers might need a case statement for values
      +
      +        !> value to use on STOP
      +        integer, intent(in) :: value
      +        !> Error message
      +        character(len=*), intent(in) :: message
      +        integer :: iostat
      +        if(message/='')then
      +           flush(unit=stderr,iostat=iostat)
      +           flush(unit=stdout,iostat=iostat)
      +           if(value>0)then
      +              write(stderr,'("<ERROR> ",a)')trim(message)
      +           else
      +              write(stderr,'("<INFO> ",a)')trim(message)
      +           endif
      +           flush(unit=stderr,iostat=iostat)
      +        endif
      +        stop value
      +    end subroutine fpm_stop
      +
      +end module fpm_error
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/example.f90.html b/sourcefile/example.f90.html new file mode 100644 index 0000000000..2fe787419c --- /dev/null +++ b/sourcefile/example.f90.html @@ -0,0 +1,381 @@ + + + + + + + + + + + + + example.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      example.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      !> Implementation of the meta data for an example.
      +!>
      +!> The example data structure is effectively a decorated version of an executable
      +!> and shares most of its properties, except for the defaults and can be
      +!> handled under most circumstances just like any other executable.
      +!>
      +!> A example table can currently have the following fields
      +!>
      +!>```toml
      +!>[[ example ]]
      +!>name = "string"
      +!>source-dir = "path"
      +!>main = "file"
      +!>link = ["lib"]
      +!>[example.dependencies]
      +!>```
      +module fpm_manifest_example
      +    use fpm_manifest_dependency, only : dependency_config_t, new_dependencies
      +    use fpm_manifest_executable, only : executable_config_t
      +    use fpm_error, only : error_t, syntax_error, bad_name_error
      +    use tomlf, only : toml_table, toml_key, toml_stat
      +    use fpm_toml, only : get_value, get_list
      +    implicit none
      +    private
      +
      +    public :: example_config_t, new_example
      +
      +
      +    !> Configuation meta data for an example
      +    type, extends(executable_config_t) :: example_config_t
      +
      +    contains
      +
      +        !> Print information on this instance
      +        procedure :: info
      +
      +    end type example_config_t
      +
      +
      +contains
      +
      +
      +    !> Construct a new example configuration from a TOML data structure
      +    subroutine new_example(self, table, error)
      +
      +        !> Instance of the example configuration
      +        type(example_config_t), intent(out) :: self
      +
      +        !> Instance of the TOML data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        type(toml_table), pointer :: child
      +
      +        call check(table, error)
      +        if (allocated(error)) return
      +
      +        call get_value(table, "name", self%name)
      +        if (.not.allocated(self%name)) then
      +           call syntax_error(error, "Could not retrieve example name")
      +           return
      +        end if
      +        if (bad_name_error(error,'example',self%name))then
      +           return
      +        endif
      +        call get_value(table, "source-dir", self%source_dir, "example")
      +        call get_value(table, "main", self%main, "main.f90")
      +
      +        call get_value(table, "dependencies", child, requested=.false.)
      +        if (associated(child)) then
      +            call new_dependencies(self%dependency, child, error=error)
      +            if (allocated(error)) return
      +        end if
      +
      +        call get_list(table, "link", self%link, error)
      +        if (allocated(error)) return
      +
      +    end subroutine new_example
      +
      +
      +    !> Check local schema for allowed entries
      +    subroutine check(table, error)
      +
      +        !> Instance of the TOML data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        type(toml_key), allocatable :: list(:)
      +        logical :: name_present
      +        integer :: ikey
      +
      +        name_present = .false.
      +
      +        call table%get_keys(list)
      +
      +        if (size(list) < 1) then
      +            call syntax_error(error, "Example section does not provide sufficient entries")
      +            return
      +        end if
      +
      +        do ikey = 1, size(list)
      +            select case(list(ikey)%key)
      +            case default
      +                call syntax_error(error, "Key "//list(ikey)%key//" is not allowed in example entry")
      +                exit
      +
      +            case("name")
      +                name_present = .true.
      +
      +            case("source-dir", "main", "dependencies", "link")
      +                continue
      +
      +            end select
      +        end do
      +        if (allocated(error)) return
      +
      +        if (.not.name_present) then
      +            call syntax_error(error, "Example name is not provided, please add a name entry")
      +        end if
      +
      +    end subroutine check
      +
      +
      +    !> Write information on instance
      +    subroutine info(self, unit, verbosity)
      +
      +        !> Instance of the example configuration
      +        class(example_config_t), intent(in) :: self
      +
      +        !> Unit for IO
      +        integer, intent(in) :: unit
      +
      +        !> Verbosity of the printout
      +        integer, intent(in), optional :: verbosity
      +
      +        integer :: pr, ii
      +        character(len=*), parameter :: fmt = '("#", 1x, a, t30, a)', &
      +            & fmti = '("#", 1x, a, t30, i0)'
      +
      +        if (present(verbosity)) then
      +            pr = verbosity
      +        else
      +            pr = 1
      +        end if
      +
      +        if (pr < 1) return
      +
      +        write(unit, fmt) "Example target"
      +        if (allocated(self%name)) then
      +            write(unit, fmt) "- name", self%name
      +        end if
      +        if (allocated(self%source_dir)) then
      +            if (self%source_dir /= "example" .or. pr > 2) then
      +                write(unit, fmt) "- source directory", self%source_dir
      +            end if
      +        end if
      +        if (allocated(self%main)) then
      +            if (self%main /= "main.f90" .or. pr > 2) then
      +                write(unit, fmt) "- example source", self%main
      +            end if
      +        end if
      +
      +        if (allocated(self%dependency)) then
      +            if (size(self%dependency) > 1 .or. pr > 2) then
      +                write(unit, fmti) "- dependencies", size(self%dependency)
      +            end if
      +            do ii = 1, size(self%dependency)
      +                call self%dependency(ii)%info(unit, pr - 1)
      +            end do
      +        end if
      +
      +    end subroutine info
      +
      +
      +end module fpm_manifest_example
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/executable.f90.html b/sourcefile/executable.f90.html new file mode 100644 index 0000000000..5336633865 --- /dev/null +++ b/sourcefile/executable.f90.html @@ -0,0 +1,558 @@ + + + + + + + + + + + + + executable.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      executable.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      !> Implementation of the meta data for an executables.
      +!>
      +!> An executable table can currently have the following fields
      +!>
      +!>```toml
      +!>[[ executable ]]
      +!>name = "string"
      +!>source-dir = "path"
      +!>main = "file"
      +!>link = ["lib"]
      +!>[executable.dependencies]
      +!>```
      +module fpm_manifest_executable
      +    use fpm_manifest_dependency, only : dependency_config_t, new_dependencies, resize
      +    use fpm_error, only : error_t, syntax_error, bad_name_error, fatal_error
      +    use fpm_strings, only : string_t, operator(==)
      +    use tomlf, only : toml_table, toml_key, toml_stat
      +    use fpm_toml, only : get_value, get_list, serializable_t, add_table, &
      +                          set_string, set_list
      +    implicit none
      +    private
      +
      +    public :: executable_config_t, new_executable
      +
      +
      +    !> Configuation meta data for an executable
      +    type, extends(serializable_t) :: executable_config_t
      +
      +        !> Name of the resulting executable
      +        character(len=:), allocatable :: name
      +
      +        !> Source directory for collecting the executable
      +        character(len=:), allocatable :: source_dir
      +
      +        !> Name of the source file declaring the main program
      +        character(len=:), allocatable :: main
      +
      +        !> Dependency meta data for this executable
      +        type(dependency_config_t), allocatable :: dependency(:)
      +
      +        !> Libraries to link against
      +        type(string_t), allocatable :: link(:)
      +
      +    contains
      +
      +        !> Print information on this instance
      +        procedure :: info
      +
      +        !> Serialization interface
      +        procedure :: serializable_is_same => exe_is_same
      +        procedure :: dump_to_toml
      +        procedure :: load_from_toml
      +
      +    end type executable_config_t
      +
      +    character(*), parameter, private :: class_name = 'executable_config_t'
      +
      +
      +contains
      +
      +
      +    !> Construct a new executable configuration from a TOML data structure
      +    subroutine new_executable(self, table, error)
      +
      +        !> Instance of the executable configuration
      +        type(executable_config_t), intent(out) :: self
      +
      +        !> Instance of the TOML data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        type(toml_table), pointer :: child
      +
      +        call check(table, error)
      +        if (allocated(error)) return
      +
      +        call get_value(table, "name", self%name)
      +        if (.not.allocated(self%name)) then
      +           call syntax_error(error, "Could not retrieve executable name")
      +           return
      +        end if
      +        if (bad_name_error(error,'executable',self%name))then
      +           return
      +        endif
      +        call get_value(table, "source-dir", self%source_dir, "app")
      +        call get_value(table, "main", self%main, "main.f90")
      +
      +        call get_value(table, "dependencies", child, requested=.false.)
      +        if (associated(child)) then
      +            call new_dependencies(self%dependency, child, error=error)
      +            if (allocated(error)) return
      +        end if
      +
      +        call get_list(table, "link", self%link, error)
      +        if (allocated(error)) return
      +
      +    end subroutine new_executable
      +
      +
      +    !> Check local schema for allowed entries
      +    subroutine check(table, error)
      +
      +        !> Instance of the TOML data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        type(toml_key), allocatable :: list(:)
      +        logical :: name_present
      +        integer :: ikey
      +
      +        name_present = .false.
      +
      +        call table%get_keys(list)
      +
      +        if (size(list) < 1) then
      +            call syntax_error(error, "Executable section does not provide sufficient entries")
      +            return
      +        end if
      +
      +        do ikey = 1, size(list)
      +            select case(list(ikey)%key)
      +            case default
      +                call syntax_error(error, "Key "//list(ikey)%key//" is not allowed as executable entry")
      +                exit
      +
      +            case("name")
      +                name_present = .true.
      +
      +            case("source-dir", "main", "dependencies", "link")
      +                continue
      +
      +            end select
      +        end do
      +        if (allocated(error)) return
      +
      +        if (.not.name_present) then
      +            call syntax_error(error, "Executable name is not provided, please add a name entry")
      +        end if
      +
      +    end subroutine check
      +
      +
      +    !> Write information on instance
      +    subroutine info(self, unit, verbosity)
      +
      +        !> Instance of the executable configuration
      +        class(executable_config_t), intent(in) :: self
      +
      +        !> Unit for IO
      +        integer, intent(in) :: unit
      +
      +        !> Verbosity of the printout
      +        integer, intent(in), optional :: verbosity
      +
      +        integer :: pr, ii
      +        character(len=*), parameter :: fmt = '("#", 1x, a, t30, a)', &
      +            & fmti = '("#", 1x, a, t30, i0)'
      +
      +        if (present(verbosity)) then
      +            pr = verbosity
      +        else
      +            pr = 1
      +        end if
      +
      +        if (pr < 1) return
      +
      +        write(unit, fmt) "Executable target"
      +        if (allocated(self%name)) then
      +            write(unit, fmt) "- name", self%name
      +        end if
      +        if (allocated(self%source_dir)) then
      +            if (self%source_dir /= "app" .or. pr > 2) then
      +                write(unit, fmt) "- source directory", self%source_dir
      +            end if
      +        end if
      +        if (allocated(self%main)) then
      +            if (self%main /= "main.f90" .or. pr > 2) then
      +                write(unit, fmt) "- program source", self%main
      +            end if
      +        end if
      +
      +        if (allocated(self%dependency)) then
      +            if (size(self%dependency) > 1 .or. pr > 2) then
      +                write(unit, fmti) "- dependencies", size(self%dependency)
      +            end if
      +            do ii = 1, size(self%dependency)
      +                call self%dependency(ii)%info(unit, pr - 1)
      +            end do
      +        end if
      +
      +    end subroutine info
      +
      +
      +    logical function exe_is_same(this,that)
      +        class(executable_config_t), intent(in) :: this
      +        class(serializable_t), intent(in) :: that
      +
      +        integer :: ii
      +
      +        exe_is_same = .false.
      +
      +        select type (other=>that)
      +           type is (executable_config_t)
      +              if (.not.this%link==other%link) return
      +              if (allocated(this%name).neqv.allocated(other%name)) return
      +              if (allocated(this%name)) then
      +                if (.not.this%name==other%name) return
      +              end if
      +              if (allocated(this%source_dir).neqv.allocated(other%source_dir)) return
      +              if (allocated(this%source_dir)) then
      +                if (.not.this%source_dir==other%source_dir) return
      +              end if
      +              if (allocated(this%main).neqv.allocated(other%main)) return
      +              if (allocated(this%main)) then
      +                if (.not.this%main==other%main) return
      +              end if
      +              if (allocated(this%dependency).neqv.allocated(other%dependency)) return
      +              if (allocated(this%dependency)) then
      +                 if (.not.(size(this%dependency)==size(other%dependency))) return
      +                 do ii = 1, size(this%dependency)
      +                    if (.not.(this%dependency(ii)==other%dependency(ii))) return
      +                 end do
      +              end if
      +           class default
      +              ! Not the same type
      +              return
      +        end select
      +
      +        !> All checks passed!
      +        exe_is_same = .true.
      +
      +    end function exe_is_same
      +
      +    !> Dump install config to toml table
      +    subroutine dump_to_toml(self, table, error)
      +
      +        !> Instance of the serializable object
      +        class(executable_config_t), intent(inout) :: self
      +
      +        !> Data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        !> Local variables
      +        integer :: ierr, ii
      +        type(toml_table), pointer :: ptr_deps,ptr
      +        character(27) :: unnamed
      +
      +        call set_string(table, "name", self%name, error)
      +        if (allocated(error)) return
      +        call set_string(table, "source-dir", self%source_dir, error)
      +        if (allocated(error)) return
      +        call set_string(table, "main", self%main, error)
      +        if (allocated(error)) return
      +
      +        if (allocated(self%dependency)) then
      +
      +           ! Create dependency table
      +           call add_table(table, "dependencies", ptr_deps)
      +           if (.not. associated(ptr_deps)) then
      +              call fatal_error(error, class_name//" cannot create dependency table ")
      +              return
      +           end if
      +
      +           do ii = 1, size(self%dependency)
      +              associate (dep => self%dependency(ii))
      +
      +                 !> Because dependencies are named, fallback if this has no name
      +                 !> So, serialization will work regardless of size(self%dep) == self%ndep
      +                 if (len_trim(dep%name)==0) then
      +                    write(unnamed,1) ii
      +                    call add_table(ptr_deps, trim(unnamed), ptr)
      +                 else
      +                    call add_table(ptr_deps, dep%name, ptr)
      +                 end if
      +                 if (.not. associated(ptr)) then
      +                    call fatal_error(error, class_name//" cannot create entry for dependency "//dep%name)
      +                    return
      +                 end if
      +                 call dep%dump_to_toml(ptr, error)
      +                 if (allocated(error)) return
      +              end associate
      +           end do
      +
      +        endif
      +
      +        call set_list(table, "link", self%link, error)
      +        if (allocated(error)) return
      +
      +        1 format('UNNAMED_DEPENDENCY_',i0)
      +
      +    end subroutine dump_to_toml
      +
      +    !> Read install config from toml table (no checks made at this stage)
      +    subroutine load_from_toml(self, table, error)
      +
      +        !> Instance of the serializable object
      +        class(executable_config_t), intent(inout) :: self
      +
      +        !> Data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        !> Local variables
      +        type(toml_key), allocatable :: keys(:),dep_keys(:)
      +        type(toml_table), pointer :: ptr_deps,ptr
      +        integer :: ii, jj, ierr
      +
      +        call table%get_keys(keys)
      +
      +        call get_value(table, "name", self%name)
      +        if (allocated(error)) return
      +        call get_value(table, "source-dir", self%source_dir)
      +        if (allocated(error)) return
      +        call get_value(table, "main", self%main)
      +        if (allocated(error)) return
      +        call get_list(table, "link", self%link, error)
      +
      +        find_deps_table: do ii = 1, size(keys)
      +            if (keys(ii)%key=="dependencies") then
      +
      +               call get_value(table, keys(ii), ptr_deps)
      +               if (.not.associated(ptr_deps)) then
      +                  call fatal_error(error,class_name//': error retrieving dependency table from TOML table')
      +                  return
      +               end if
      +
      +               !> Read all dependencies
      +               call ptr_deps%get_keys(dep_keys)
      +               call resize(self%dependency, size(dep_keys))
      +
      +               do jj = 1, size(dep_keys)
      +
      +                   call get_value(ptr_deps, dep_keys(jj), ptr)
      +                   call self%dependency(jj)%load_from_toml(ptr, error)
      +                   if (allocated(error)) return
      +
      +               end do
      +
      +               exit find_deps_table
      +
      +            endif
      +        end do find_deps_table
      +
      +    end subroutine load_from_toml
      +
      +
      +end module fpm_manifest_executable
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/export.f90.html b/sourcefile/export.f90.html new file mode 100644 index 0000000000..0a13d3e9f7 --- /dev/null +++ b/sourcefile/export.f90.html @@ -0,0 +1,284 @@ + + + + + + + + + + + + + export.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      export.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      module fpm_cmd_export
      +  use fpm_command_line, only : fpm_export_settings
      +  use fpm_dependency, only : dependency_tree_t, new_dependency_tree
      +  use fpm_error, only : error_t, fpm_stop
      +  use fpm_filesystem, only : join_path
      +  use fpm_manifest, only : package_config_t, get_package_data
      +  use fpm_toml, only: name_is_json
      +  use fpm_model, only: fpm_model_t
      +  use fpm, only: build_model
      +  implicit none
      +  private
      +  public :: cmd_export
      +
      +contains
      +
      +  !> Entry point for the export subcommand
      +  subroutine cmd_export(settings)
      +    !> Representation of the command line arguments
      +    type(fpm_export_settings), intent(inout) :: settings
      +    type(package_config_t) :: package
      +    type(dependency_tree_t) :: deps
      +    type(fpm_model_t) :: model
      +    type(error_t), allocatable :: error
      +
      +    character(len=:), allocatable :: filename
      +
      +    if (len_trim(settings%dump_manifest)<=0 .and. &
      +        len_trim(settings%dump_model)<=0 .and. &
      +        len_trim(settings%dump_dependencies)<=0) then
      +        call fpm_stop(0,'*cmd_export* exiting: no manifest/model/dependencies keyword provided')
      +    end if
      +
      +    !> Read in manifest
      +    call get_package_data(package, "fpm.toml", error, apply_defaults=.true.)
      +    call handle_error(error)
      +
      +    !> Export manifest
      +    if (len_trim(settings%dump_manifest)>0) then
      +       filename = trim(settings%dump_manifest)
      +       call package%dump(filename, error, json=name_is_json(filename))
      +    end if
      +
      +    !> Export dependency tree
      +    if (len_trim(settings%dump_dependencies)>0) then
      +
      +        !> Generate dependency tree
      +        filename = join_path("build", "cache.toml")
      +        call new_dependency_tree(deps, cache=filename, verbosity=merge(2, 1, settings%verbose))
      +        call deps%add(package, error)
      +        call handle_error(error)
      +
      +        !> Export dependency tree
      +        filename = settings%dump_dependencies
      +        call deps%dump(filename, error, json=name_is_json(filename))
      +        call handle_error(error)
      +    end if
      +
      +    !> Export full model
      +    if (len_trim(settings%dump_model)>0) then
      +
      +        call build_model(model, settings%fpm_build_settings, package, error)
      +        if (allocated(error)) then
      +            call fpm_stop(1,'*cmd_export* Model error: '//error%message)
      +        end if
      +
      +        filename = settings%dump_model
      +        call model%dump(filename, error, json=name_is_json(filename))
      +        call handle_error(error)
      +    end if
      +
      +  end subroutine cmd_export
      +
      +  !> Error handling for this command
      +  subroutine handle_error(error)
      +    !> Potential error
      +    type(error_t), intent(in), optional :: error
      +    if (present(error)) then
      +      call fpm_stop(1, '*cmd_export* error: '//error%message)
      +    end if
      +  end subroutine handle_error
      +
      +end module fpm_cmd_export
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/fortran.f90.html b/sourcefile/fortran.f90.html new file mode 100644 index 0000000000..6ea4ae3aaf --- /dev/null +++ b/sourcefile/fortran.f90.html @@ -0,0 +1,383 @@ + + + + + + + + + + + + + fortran.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      fortran.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      module fpm_manifest_fortran
      +    use fpm_error, only : error_t, syntax_error, fatal_error
      +    use tomlf, only : toml_table, toml_key, toml_stat
      +    use fpm_toml, only : get_value, serializable_t, set_value, set_string
      +    implicit none
      +    private
      +
      +    public :: fortran_config_t, new_fortran_config
      +
      +    !> Configuration data for Fortran
      +    type, extends(serializable_t) :: fortran_config_t
      +
      +        !> Enable default implicit typing
      +        logical :: implicit_typing = .false.
      +
      +        !> Enable implicit external interfaces
      +        logical :: implicit_external = .false.
      +
      +        !> Form to use for all Fortran sources
      +        character(:), allocatable :: source_form
      +
      +        contains
      +
      +            !> Serialization interface
      +            procedure :: serializable_is_same => fortran_is_same
      +            procedure :: dump_to_toml
      +            procedure :: load_from_toml
      +
      +    end type fortran_config_t
      +
      +    character(len=*), parameter, private :: class_name = 'fortran_config_t'
      +
      +contains
      +
      +    !> Construct a new build configuration from a TOML data structure
      +    subroutine new_fortran_config(self, table, error)
      +
      +        !> Instance of the fortran configuration
      +        type(fortran_config_t), intent(out) :: self
      +
      +        !> Instance of the TOML data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        integer :: stat
      +        character(:), allocatable :: source_form
      +
      +        call check(table, error)
      +        if (allocated(error)) return
      +
      +        call get_value(table, "implicit-typing", self%implicit_typing, .false., stat=stat)
      +
      +        if (stat /= toml_stat%success) then
      +            call fatal_error(error,"Error while reading value for 'implicit-typing' in fpm.toml, expecting logical")
      +            return
      +        end if
      +
      +        call get_value(table, "implicit-external", self%implicit_external, .false., stat=stat)
      +
      +        if (stat /= toml_stat%success) then
      +            call fatal_error(error,"Error while reading value for 'implicit-external' in fpm.toml, expecting logical")
      +            return
      +        end if
      +
      +        call get_value(table, "source-form", source_form, "free", stat=stat)
      +
      +        if (stat /= toml_stat%success) then
      +            call fatal_error(error,"Error while reading value for 'source-form' in fpm.toml, expecting logical")
      +            return
      +        end if
      +        select case(source_form)
      +        case default
      +            call fatal_error(error,"Value of source-form cannot be '"//source_form//"'")
      +            return
      +        case("free", "fixed", "default")
      +            self%source_form = source_form
      +        end select
      +
      +    end subroutine new_fortran_config
      +
      +    !> Check local schema for allowed entries
      +    subroutine check(table, error)
      +
      +        !> Instance of the TOML data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        type(toml_key), allocatable :: list(:)
      +        integer :: ikey
      +
      +        call table%get_keys(list)
      +
      +        ! table can be empty
      +        if (size(list) < 1) return
      +
      +        do ikey = 1, size(list)
      +            select case(list(ikey)%key)
      +
      +            case("implicit-typing", "implicit-external", "source-form")
      +                continue
      +
      +            case default
      +                call syntax_error(error, "Key "//list(ikey)%key//" is not allowed in fortran")
      +                exit
      +
      +            end select
      +        end do
      +
      +    end subroutine check
      +
      +  logical function fortran_is_same(this,that)
      +    class(fortran_config_t), intent(in) :: this
      +    class(serializable_t), intent(in) :: that
      +
      +    fortran_is_same = .false.
      +
      +    select type (other=>that)
      +       type is (fortran_config_t)
      +          if (this%implicit_typing.neqv.other%implicit_typing) return
      +          if (this%implicit_external.neqv.other%implicit_external) return
      +          if (allocated(this%source_form).neqv.allocated(other%source_form)) return
      +          if (allocated(this%source_form)) then
      +            if (.not.this%source_form==other%source_form) return
      +          end if
      +       class default
      +          ! Not the same type
      +          return
      +    end select
      +
      +    !> All checks passed!
      +    fortran_is_same = .true.
      +
      +  end function fortran_is_same
      +
      +  !> Dump install config to toml table
      +  subroutine dump_to_toml(self, table, error)
      +
      +    !> Instance of the serializable object
      +    class(fortran_config_t), intent(inout) :: self
      +
      +    !> Data structure
      +    type(toml_table), intent(inout) :: table
      +
      +    !> Error handling
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    call set_value(table, "implicit-typing", self%implicit_typing, error, class_name)
      +    if (allocated(error)) return
      +    call set_value(table, "implicit-external", self%implicit_external, error, class_name)
      +    if (allocated(error)) return
      +    call set_string(table, "source-form", self%source_form, error, class_name)
      +    if (allocated(error)) return
      +
      +  end subroutine dump_to_toml
      +
      +  !> Read install config from toml table (no checks made at this stage)
      +  subroutine load_from_toml(self, table, error)
      +
      +    !> Instance of the serializable object
      +    class(fortran_config_t), intent(inout) :: self
      +
      +    !> Data structure
      +    type(toml_table), intent(inout) :: table
      +
      +    !> Error handling
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    call get_value(table, "implicit-typing", self%implicit_typing, error, class_name)
      +    if (allocated(error)) return
      +    call get_value(table, "implicit-external", self%implicit_external, error, class_name)
      +    if (allocated(error)) return
      +    call get_value(table, "source-form", self%source_form)
      +
      +  end subroutine load_from_toml
      +
      +
      +end module fpm_manifest_fortran
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/fpm.f90.html b/sourcefile/fpm.f90.html new file mode 100644 index 0000000000..ee11104d49 --- /dev/null +++ b/sourcefile/fpm.f90.html @@ -0,0 +1,1095 @@ + + + + + + + + + + + + + fpm.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      fpm.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      module fpm
      +use fpm_strings, only: string_t, operator(.in.), glob, join, string_cat, &
      +                      lower, str_ends_with, is_fortran_name, str_begins_with_str, &
      +                      is_valid_module_name, len_trim
      +use fpm_backend, only: build_package
      +use fpm_command_line, only: fpm_build_settings, fpm_new_settings, &
      +                      fpm_run_settings, fpm_install_settings, fpm_test_settings, &
      +                      fpm_clean_settings
      +use fpm_dependency, only : new_dependency_tree
      +use fpm_filesystem, only: is_dir, join_path, list_files, exists, &
      +                   basename, filewrite, mkdir, run, os_delete_dir
      +use fpm_model, only: fpm_model_t, srcfile_t, show_model, fortran_features_t, &
      +                    FPM_SCOPE_UNKNOWN, FPM_SCOPE_LIB, FPM_SCOPE_DEP, &
      +                    FPM_SCOPE_APP, FPM_SCOPE_EXAMPLE, FPM_SCOPE_TEST
      +use fpm_compiler, only: new_compiler, new_archiver, set_cpp_preprocessor_flags
      +
      +
      +use fpm_sources, only: add_executable_sources, add_sources_from_dir
      +use fpm_targets, only: targets_from_sources, build_target_t, build_target_ptr, &
      +                        FPM_TARGET_EXECUTABLE, get_library_dirs
      +use fpm_manifest, only : get_package_data, package_config_t
      +use fpm_meta, only : resolve_metapackages
      +use fpm_error, only : error_t, fatal_error, fpm_stop
      +use fpm_toml, only: name_is_json
      +use, intrinsic :: iso_fortran_env, only : stdin => input_unit, &
      +                                        & stdout => output_unit, &
      +                                        & stderr => error_unit
      +use iso_c_binding, only: c_char, c_ptr, c_int, c_null_char, c_associated, c_f_pointer
      +use fpm_environment, only: os_is_unix, get_os_type, OS_WINDOWS, OS_MACOS, get_env, set_env, delete_env
      +use fpm_settings, only: fpm_global_settings, get_global_settings
      +
      +implicit none
      +private
      +public :: cmd_build, cmd_run, cmd_clean
      +public :: build_model, check_modules_for_duplicates
      +
      +contains
      +
      +!> Constructs a valid fpm model from command line settings and the toml manifest.
      +subroutine build_model(model, settings, package, error)
      +    type(fpm_model_t), intent(out) :: model
      +    class(fpm_build_settings), intent(inout) :: settings
      +    type(package_config_t), intent(inout), target :: package
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    integer :: i, j
      +    type(package_config_t), target  :: dependency
      +    type(package_config_t), pointer :: manifest
      +    character(len=:), allocatable :: file_name, lib_dir
      +    logical :: has_cpp
      +    logical :: duplicates_found
      +    type(string_t) :: include_dir
      +
      +    model%package_name = package%name
      +
      +    allocate(model%include_dirs(0))
      +    allocate(model%link_libraries(0))
      +    allocate(model%external_modules(0))
      +
      +    call new_compiler(model%compiler, settings%compiler, settings%c_compiler, &
      +        & settings%cxx_compiler, echo=settings%verbose, verbose=settings%verbose)
      +    call new_archiver(model%archiver, settings%archiver, &
      +        & echo=settings%verbose, verbose=settings%verbose)
      +
      +    if (model%compiler%is_unknown()) then
      +        write(*, '(*(a:,1x))') &
      +            "<WARN>", "Unknown compiler", model%compiler%fc, "requested!", &
      +            "Defaults for this compiler might be incorrect"
      +    end if
      +
      +    call new_compiler_flags(model,settings)
      +    model%build_prefix         = join_path("build", basename(model%compiler%fc))
      +    model%include_tests        = settings%build_tests
      +    model%enforce_module_names = package%build%module_naming
      +    model%module_prefix        = package%build%module_prefix
      +
      +    ! Resolve meta-dependencies into the package and the model
      +    call resolve_metapackages(model,package,settings,error)
      +    if (allocated(error)) return
      +    
      +    ! Create dependencies
      +    call new_dependency_tree(model%deps, cache=join_path("build", "cache.toml"), &
      +    & path_to_config=settings%path_to_config)
      +
      +    ! Build and resolve model dependencies
      +    call model%deps%add(package, error)
      +    if (allocated(error)) return
      +
      +    ! Update dependencies where needed
      +    call model%deps%update(error)
      +    if (allocated(error)) return
      +
      +    ! build/ directory should now exist
      +    if (.not.exists("build/.gitignore")) then
      +      call filewrite(join_path("build", ".gitignore"),["*"])
      +    end if
      +
      +    allocate(model%packages(model%deps%ndep))
      +
      +    has_cpp = .false.
      +    do i = 1, model%deps%ndep
      +        associate(dep => model%deps%dep(i))
      +            file_name = join_path(dep%proj_dir, "fpm.toml")
      +
      +            ! The main package manifest should not be reloaded, because it may have been 
      +            ! affected by model dependencies and metapackages
      +            if (i==1) then 
      +                manifest => package
      +            else
      +                
      +                call get_package_data(dependency, file_name, error, apply_defaults=.true.)
      +                if (allocated(error)) exit                
      +                
      +                manifest => dependency
      +            end if            
      +            
      +            model%packages(i)%name = manifest%name
      +            associate(features => model%packages(i)%features)
      +                features%implicit_typing = manifest%fortran%implicit_typing
      +                features%implicit_external = manifest%fortran%implicit_external
      +                features%source_form = manifest%fortran%source_form
      +            end associate
      +            model%packages(i)%version = package%version%s()
      +
      +            !> Add this dependency's manifest macros
      +            if (allocated(manifest%preprocess)) then
      +                do j = 1, size(manifest%preprocess)
      +                    call model%packages(i)%preprocess%add_config(manifest%preprocess(j))
      +                end do
      +            end if
      +
      +            !> Add this dependency's package-level macros
      +            if (allocated(dep%preprocess)) then
      +                do j = 1, size(dep%preprocess)
      +                    call model%packages(i)%preprocess%add_config(dep%preprocess(j))
      +                end do
      +            end if
      +
      +            if (model%packages(i)%preprocess%is_cpp()) has_cpp = .true.
      +
      +            if (.not.allocated(model%packages(i)%sources)) allocate(model%packages(i)%sources(0))
      +
      +            if (allocated(manifest%library)) then
      +
      +                if (allocated(manifest%library%source_dir)) then
      +                    lib_dir = join_path(dep%proj_dir, manifest%library%source_dir)
      +                    if (is_dir(lib_dir)) then
      +                        call add_sources_from_dir(model%packages(i)%sources, lib_dir, FPM_SCOPE_LIB, &
      +                            with_f_ext=model%packages(i)%preprocess%suffixes, error=error)
      +                        if (allocated(error)) exit
      +                    end if
      +                end if
      +
      +                if (allocated(manifest%library%include_dir)) then
      +                    do j=1,size(manifest%library%include_dir)
      +                        include_dir%s = join_path(dep%proj_dir, manifest%library%include_dir(j)%s)
      +                        if (is_dir(include_dir%s)) then
      +                            model%include_dirs = [model%include_dirs, include_dir]
      +                        end if
      +                    end do
      +                end if
      +
      +            end if
      +
      +            if (allocated(manifest%build%link)) then
      +                model%link_libraries = [model%link_libraries, manifest%build%link]
      +            end if
      +
      +            if (allocated(manifest%build%external_modules)) then
      +                model%external_modules = [model%external_modules, manifest%build%external_modules]
      +            end if
      +
      +            ! Copy naming conventions from this dependency's manifest
      +            model%packages(i)%enforce_module_names = manifest%build%module_naming
      +            model%packages(i)%module_prefix        = manifest%build%module_prefix
      +
      +        end associate
      +    end do
      +    if (allocated(error)) return
      +
      +    ! Add optional flags
      +    if (has_cpp) call set_cpp_preprocessor_flags(model%compiler%id, model%fortran_compile_flags)
      +
      +    ! Add sources from executable directories
      +    if (is_dir('app') .and. package%build%auto_executables) then
      +        call add_sources_from_dir(model%packages(1)%sources,'app', FPM_SCOPE_APP, &
      +                                   with_executables=.true., with_f_ext=model%packages(1)%preprocess%suffixes,&
      +                                   error=error)
      +
      +        if (allocated(error)) then
      +            return
      +        end if
      +
      +    end if
      +    if (is_dir('example') .and. package%build%auto_examples) then
      +        call add_sources_from_dir(model%packages(1)%sources,'example', FPM_SCOPE_EXAMPLE, &
      +                                  with_executables=.true., &
      +                                  with_f_ext=model%packages(1)%preprocess%suffixes,error=error)
      +
      +        if (allocated(error)) then
      +            return
      +        end if
      +
      +    end if
      +    if (is_dir('test') .and. package%build%auto_tests) then
      +        call add_sources_from_dir(model%packages(1)%sources,'test', FPM_SCOPE_TEST, &
      +                                  with_executables=.true., &
      +                                  with_f_ext=model%packages(1)%preprocess%suffixes,error=error)
      +
      +        if (allocated(error)) then
      +            return
      +        endif
      +
      +    end if
      +    if (allocated(package%executable)) then
      +        call add_executable_sources(model%packages(1)%sources, package%executable, FPM_SCOPE_APP, &
      +                                     auto_discover=package%build%auto_executables, &
      +                                     with_f_ext=model%packages(1)%preprocess%suffixes, &
      +                                     error=error)
      +
      +        if (allocated(error)) then
      +            return
      +        end if
      +
      +    end if
      +    if (allocated(package%example)) then
      +        call add_executable_sources(model%packages(1)%sources, package%example, FPM_SCOPE_EXAMPLE, &
      +                                     auto_discover=package%build%auto_examples, &
      +                                     with_f_ext=model%packages(1)%preprocess%suffixes, &
      +                                     error=error)
      +
      +        if (allocated(error)) then
      +            return
      +        end if
      +
      +    end if
      +    if (allocated(package%test)) then
      +        call add_executable_sources(model%packages(1)%sources, package%test, FPM_SCOPE_TEST, &
      +                                     auto_discover=package%build%auto_tests, &
      +                                     with_f_ext=model%packages(1)%preprocess%suffixes, &
      +                                     error=error)
      +
      +        if (allocated(error)) then
      +            return
      +        endif
      +
      +    endif
      +
      +    if (settings%verbose) then
      +        write(*,*)'<INFO> BUILD_NAME: ',model%build_prefix
      +        write(*,*)'<INFO> COMPILER:  ',model%compiler%fc
      +        write(*,*)'<INFO> C COMPILER:  ',model%compiler%cc
      +        write(*,*)'<INFO> CXX COMPILER: ',model%compiler%cxx
      +        write(*,*)'<INFO> COMPILER OPTIONS:  ', model%fortran_compile_flags
      +        write(*,*)'<INFO> C COMPILER OPTIONS:  ', model%c_compile_flags
      +        write(*,*)'<INFO> CXX COMPILER OPTIONS: ', model%cxx_compile_flags
      +        write(*,*)'<INFO> LINKER OPTIONS:  ', model%link_flags
      +        write(*,*)'<INFO> INCLUDE DIRECTORIES:  [', string_cat(model%include_dirs,','),']'
      +    end if
      +
      +    ! Check for invalid module names
      +    call check_module_names(model, error)
      +    if (allocated(error)) return
      +
      +    ! Check for duplicate modules
      +    duplicates_found = .false.
      +    call check_modules_for_duplicates(model, duplicates_found)
      +    if (duplicates_found) then
      +        call fpm_stop(1,'*build_model*:Error: One or more duplicate module names found.')
      +    end if
      +end subroutine build_model
      +
      +!> Initialize model compiler flags
      +subroutine new_compiler_flags(model,settings)
      +    type(fpm_model_t), intent(inout) :: model
      +    type(fpm_build_settings), intent(in) :: settings
      +
      +    character(len=:), allocatable :: flags, cflags, cxxflags, ldflags
      +
      +    if (settings%flag == '') then
      +        flags = model%compiler%get_default_flags(settings%profile == "release")
      +    else
      +        flags = settings%flag
      +        select case(settings%profile)
      +        case("release", "debug")
      +            flags = flags // model%compiler%get_default_flags(settings%profile == "release")
      +        end select
      +    end if
      +
      +    cflags   = trim(settings%cflag)
      +    cxxflags = trim(settings%cxxflag)
      +    ldflags  = trim(settings%ldflag)
      +
      +    model%fortran_compile_flags = flags
      +    model%c_compile_flags       = cflags
      +    model%cxx_compile_flags     = cxxflags
      +    model%link_flags            = ldflags
      +
      +end subroutine new_compiler_flags
      +
      +! Check for duplicate modules
      +subroutine check_modules_for_duplicates(model, duplicates_found)
      +    type(fpm_model_t), intent(in) :: model
      +    integer :: maxsize
      +    integer :: i,j,k,l,m,modi
      +    type(string_t), allocatable :: modules(:)
      +    logical :: duplicates_found
      +    ! Initialise the size of array
      +    maxsize = 0
      +    ! Get number of modules provided by each source file of every package
      +    do i=1,size(model%packages)
      +      do j=1,size(model%packages(i)%sources)
      +        if (allocated(model%packages(i)%sources(j)%modules_provided)) then
      +          maxsize = maxsize + size(model%packages(i)%sources(j)%modules_provided)
      +        end if
      +      end do
      +    end do
      +    ! Allocate array to contain distinct names of modules
      +    allocate(modules(maxsize))
      +
      +    ! Initialise index to point at start of the newly allocated array
      +    modi = 1
      +
      +    ! Loop through modules provided by each source file of every package
      +    ! Add it to the array if it is not already there
      +    ! Otherwise print out warning about duplicates
      +    do k=1,size(model%packages)
      +      do l=1,size(model%packages(k)%sources)
      +        if (allocated(model%packages(k)%sources(l)%modules_provided)) then
      +          do m=1,size(model%packages(k)%sources(l)%modules_provided)
      +            if (model%packages(k)%sources(l)%modules_provided(m)%s.in.modules(:modi-1)) then
      +              write(stderr, *) "Warning: Module ",model%packages(k)%sources(l)%modules_provided(m)%s, &
      +                " in ",model%packages(k)%sources(l)%file_name," is a duplicate"
      +              duplicates_found = .true.
      +            else
      +              modules(modi) = model%packages(k)%sources(l)%modules_provided(m)
      +              modi = modi + 1
      +            end if
      +          end do
      +        end if
      +      end do
      +    end do
      +end subroutine check_modules_for_duplicates
      +
      +! Check names of all modules in this package and its dependencies
      +subroutine check_module_names(model, error)
      +    type(fpm_model_t), intent(in) :: model
      +    type(error_t), allocatable, intent(out) :: error
      +    integer :: k,l,m
      +    logical :: valid,errors_found,enforce_this_file
      +    type(string_t) :: package_name,module_name,package_prefix
      +
      +    errors_found = .false.
      +
      +    ! Loop through modules provided by each source file of every package
      +    ! Add it to the array if it is not already there
      +    ! Otherwise print out warning about duplicates
      +    do k=1,size(model%packages)
      +
      +        package_name = string_t(model%packages(k)%name)
      +
      +        ! Custom prefix is taken from each dependency's manifest
      +        if (model%packages(k)%enforce_module_names) then
      +            package_prefix = model%packages(k)%module_prefix
      +        else
      +            package_prefix = string_t("")
      +        end if
      +
      +        ! Warn the user if some of the dependencies have loose naming
      +        if (model%enforce_module_names .and. .not.model%packages(k)%enforce_module_names) then
      +           write(stderr, *) "Warning: Dependency ",package_name%s // &
      +                            " does not enforce module naming, but project does. "
      +        end if
      +
      +        do l=1,size(model%packages(k)%sources)
      +
      +            ! Module naming is not enforced in test modules
      +            enforce_this_file =  model%enforce_module_names .and. &
      +                                 model%packages(k)%sources(l)%unit_scope/=FPM_SCOPE_TEST
      +
      +            if (allocated(model%packages(k)%sources(l)%modules_provided)) then
      +
      +                do m=1,size(model%packages(k)%sources(l)%modules_provided)
      +
      +                    module_name = model%packages(k)%sources(l)%modules_provided(m)
      +
      +                    valid = is_valid_module_name(module_name, &
      +                                                 package_name, &
      +                                                 package_prefix, &
      +                                                 enforce_this_file)
      +
      +                    if (.not.valid) then
      +
      +                        if (enforce_this_file) then
      +
      +                            if (len_trim(package_prefix)>0) then
      +
      +                            write(stderr, *) "ERROR: Module ",module_name%s, &
      +                                             " in ",model%packages(k)%sources(l)%file_name, &
      +                                             " does not match its package name ("//package_name%s// &
      +                                             ") or custom prefix ("//package_prefix%s//")."
      +                            else
      +
      +                            write(stderr, *) "ERROR: Module ",module_name%s, &
      +                                             " in ",model%packages(k)%sources(l)%file_name, &
      +                                             " does not match its package name ("//package_name%s//")."
      +
      +                            endif
      +
      +                        else
      +
      +                            write(stderr, *) "ERROR: Module ",module_name%s, &
      +                                             " in ",model%packages(k)%sources(l)%file_name, &
      +                                             " has an invalid Fortran name. "
      +
      +                        end if
      +
      +                        errors_found = .true.
      +
      +                    end if
      +                end do
      +            end if
      +        end do
      +    end do
      +
      +    if (errors_found) then
      +
      +        if (model%enforce_module_names) &
      +            write(stderr, *) "       Hint: Try disabling module naming in the manifest: [build] module-naming=false . "
      +
      +        call fatal_error(error,"The package contains invalid module names. "// &
      +                               "Naming conventions "//merge('are','not',model%enforce_module_names)// &
      +                               " being requested.")
      +    end if
      +
      +end subroutine check_module_names
      +
      +subroutine cmd_build(settings)
      +type(fpm_build_settings), intent(inout) :: settings
      +
      +type(package_config_t) :: package
      +type(fpm_model_t) :: model
      +type(build_target_ptr), allocatable :: targets(:)
      +type(error_t), allocatable :: error
      +
      +integer :: i
      +
      +call get_package_data(package, "fpm.toml", error, apply_defaults=.true.)
      +if (allocated(error)) then
      +    call fpm_stop(1,'*cmd_build* Package error: '//error%message)
      +end if
      +
      +call build_model(model, settings, package, error)
      +if (allocated(error)) then
      +    call fpm_stop(1,'*cmd_build* Model error: '//error%message)
      +end if
      +
      +call targets_from_sources(targets, model, settings%prune, package%library, error)
      +if (allocated(error)) then
      +    call fpm_stop(1,'*cmd_build* Target error: '//error%message)
      +end if
      +
      +!> Dump model to file
      +if (len_trim(settings%dump)>0) then
      +    call model%dump(trim(settings%dump),error,json=name_is_json(trim(settings%dump)))
      +    if (allocated(error)) call fpm_stop(1,'*cmd_build* Model dump error: '//error%message)
      +endif
      +
      +if(settings%list)then
      +    do i=1,size(targets)
      +        write(stderr,*) targets(i)%ptr%output_file
      +    enddo
      +endif
      +if (settings%show_model) then
      +    call show_model(model)
      +else
      +    call build_package(targets,model,verbose=settings%verbose,dry_run=settings%list)
      +endif
      +
      +end subroutine cmd_build
      +
      +subroutine cmd_run(settings,test)
      +    class(fpm_run_settings), intent(inout) :: settings
      +    logical, intent(in) :: test
      +
      +    integer :: i, j, col_width
      +    logical :: found(size(settings%name))
      +    type(error_t), allocatable :: error
      +    type(package_config_t) :: package
      +    type(fpm_model_t) :: model
      +    type(build_target_ptr), allocatable :: targets(:)
      +    type(string_t) :: exe_cmd
      +    type(string_t), allocatable :: executables(:)
      +    type(build_target_t), pointer :: exe_target
      +    type(srcfile_t), pointer :: exe_source
      +    integer :: run_scope,firsterror
      +    integer, allocatable :: stat(:),target_ID(:)
      +    character(len=:),allocatable :: line,run_cmd,library_path
      +
      +    call get_package_data(package, "fpm.toml", error, apply_defaults=.true.)
      +    if (allocated(error)) then
      +        call fpm_stop(1, '*cmd_run* Package error: '//error%message)
      +    end if
      +
      +    call build_model(model, settings, package, error)
      +    if (allocated(error)) then
      +        call fpm_stop(1, '*cmd_run* Model error: '//error%message)
      +    end if
      +
      +    call targets_from_sources(targets, model, settings%prune, package%library, error)
      +    if (allocated(error)) then
      +        call fpm_stop(1, '*cmd_run* Targets error: '//error%message)
      +    end if
      +
      +    if (test) then
      +       run_scope = FPM_SCOPE_TEST
      +    else
      +       run_scope = merge(FPM_SCOPE_EXAMPLE, FPM_SCOPE_APP, settings%example)
      +    end if
      +
      +    ! Enumerate executable targets to run
      +    col_width = -1
      +    found(:) = .false.
      +    allocate(executables(size(targets)),target_ID(size(targets)))
      +    enumerate: do i=1,size(targets)
      +        exe_target => targets(i)%ptr
      +        if (should_be_run(settings,run_scope,exe_target)) then  
      +            
      +            exe_source => exe_target%dependencies(1)%ptr%source
      +                
      +            col_width = max(col_width,len(basename(exe_target%output_file))+2)
      +            
      +            ! Priority by name ID, or 0 if no name present (run first)
      +            j              = settings%name_ID(exe_source%exe_name)
      +            target_ID(i)   = j
      +            if (j>0) found(j) = .true.
      +            
      +            exe_cmd%s      = exe_target%output_file
      +            executables(i) = exe_cmd
      +            
      +        else
      +            target_ID(i)   = huge(target_ID(i))
      +        endif
      +    end do enumerate
      +    
      +    ! sort executables by ascending name ID, resize
      +    call sort_executables(target_ID,executables)
      +    
      +    ! Check if any apps/tests were found
      +    if (col_width < 0) then
      +        if (test) then
      +            call fpm_stop(0,'No tests to run')
      +        else
      +            call fpm_stop(0,'No executables to run')
      +        end if
      +    end if
      +
      +    ! Check all names are valid
      +    ! or no name and found more than one file    
      +    if ( any(.not.found) ) then
      +        line=join(settings%name)
      +        if(line/='.')then ! do not report these special strings
      +           if(any(.not.found))then
      +              write(stderr,'(A)',advance="no")'<ERROR>*cmd_run*:specified names '
      +              do j=1,size(settings%name)
      +                  if (.not.found(j)) write(stderr,'(A)',advance="no") '"'//trim(settings%name(j))//'" '
      +              end do
      +              write(stderr,'(A)') 'not found.'
      +              write(stderr,*)
      +           else if(settings%verbose)then
      +              write(stderr,'(A)',advance="yes")'<INFO>when more than one executable is available'
      +              write(stderr,'(A)',advance="yes")'      program names must be specified.'
      +           endif
      +        endif
      +
      +        call compact_list_all()
      +
      +        if(line=='.' .or. line==' ')then ! do not report these special strings
      +           call fpm_stop(0,'')
      +        else
      +           call fpm_stop(1,'')
      +        endif
      +
      +    end if
      +
      +    call build_package(targets,model,verbose=settings%verbose,dry_run=settings%list)
      +
      +    if (settings%list) then
      +         call compact_list()
      +    else
      +
      +        ! Save current library path and set a new one that includes the local 
      +        ! dynamic library folders
      +        library_path = save_library_path()                
      +        call set_library_path(model, targets, error)
      +        if (allocated(error)) call fpm_stop(1, '*cmd_run* Run error: '//error%message)
      +
      +        allocate(stat(size(executables)))
      +        do i=1,size(executables)
      +            if (exists(executables(i)%s)) then
      +                
      +                ! Prepare command line
      +                                              run_cmd = executables(i)%s
      +                if (settings%runner/=' ')     run_cmd = settings%runner_command()//' '//run_cmd
      +                if (allocated(settings%args)) run_cmd = run_cmd//" "//settings%args
      +                
      +                ! System Integrity Protection will not propagate the .dylib environment variables
      +                ! to the child process: add paths manually
      +                if (get_os_type()==OS_MACOS)  run_cmd = "env DYLD_LIBRARY_PATH=" // &
      +                                                         get_env("DYLD_LIBRARY_PATH","") // &
      +                                                         " " // run_cmd
      +
      +                call run(run_cmd,echo=settings%verbose,exitstat=stat(i))                
      +                
      +            else
      +                call fpm_stop(1,'*cmd_run*:'//executables(i)%s//' not found')
      +            end if
      +        end do
      +
      +        if (any(stat /= 0)) then
      +            do i=1,size(stat)
      +                if (stat(i) /= 0) then
      +                    write(stderr,'(*(g0:,1x))') '<ERROR> Execution for object "',basename(executables(i)%s),&
      +                                                '" returned exit code ',stat(i)
      +                end if
      +            end do
      +            firsterror = findloc(stat/=0,value=.true.,dim=1)
      +            call fpm_stop(stat(firsterror),'*cmd_run*:stopping due to failed executions')
      +        end if
      +        
      +        ! Restore original library path
      +        call restore_library_path(library_path, error)
      +        if (allocated(error)) call fpm_stop(1, '*cmd_run* Environment error: '//error%message)                         
      +
      +    end if
      +
      +    contains
      +
      +    subroutine compact_list_all()
      +    integer, parameter :: LINE_WIDTH = 80
      +    integer :: ii, jj, nCol
      +        jj = 1
      +        nCol = LINE_WIDTH/col_width
      +        write(stderr,*) 'Available names:'
      +        do ii=1,size(targets)
      +
      +            exe_target => targets(ii)%ptr
      +
      +            if (exe_target%target_type == FPM_TARGET_EXECUTABLE .and. &
      +                allocated(exe_target%dependencies)) then
      +
      +                exe_source => exe_target%dependencies(1)%ptr%source
      +
      +                if (exe_source%unit_scope == run_scope) then
      +                    write(stderr,'(A)',advance=(merge("yes","no ",modulo(jj,nCol)==0))) &
      +                        & [character(len=col_width) :: basename(exe_target%output_file, suffix=.false.)]
      +                    jj = jj + 1
      +                end if
      +            end if
      +        end do
      +        write(stderr,*)
      +    end subroutine compact_list_all
      +
      +    subroutine compact_list()
      +    integer, parameter :: LINE_WIDTH = 80
      +    integer :: ii, jj, nCol
      +        jj = 1
      +        nCol = LINE_WIDTH/col_width
      +        write(stderr,*) 'Matched names:'
      +        do ii=1,size(executables)
      +            write(stderr,'(A)',advance=(merge("yes","no ",modulo(jj,nCol)==0))) &
      +                & [character(len=col_width) :: basename(executables(ii)%s, suffix=.false.)]
      +            jj = jj + 1
      +        end do
      +        write(stderr,*)
      +    end subroutine compact_list
      +
      +end subroutine cmd_run
      +
      +subroutine delete_skip(is_unix)
      +    !> delete directories in the build folder, skipping dependencies
      +    logical, intent(in) :: is_unix
      +    character(len=:), allocatable :: dir
      +    type(string_t), allocatable :: files(:)
      +    integer :: i
      +    call list_files('build', files, .false.)
      +    do i = 1, size(files)
      +        if (is_dir(files(i)%s)) then
      +            dir = files(i)%s
      +            if (.not.str_ends_with(dir,'dependencies')) call os_delete_dir(is_unix, dir)
      +        end if
      +    end do
      +end subroutine delete_skip
      +
      +!> Delete the build directory including or excluding dependencies. Can be used
      +!> to clear the registry cache.
      +subroutine cmd_clean(settings)
      +    !> Settings for the clean command.
      +    class(fpm_clean_settings), intent(in) :: settings
      +
      +    character :: user_response
      +    type(fpm_global_settings) :: global_settings
      +    type(error_t), allocatable :: error
      +
      +    ! Clear registry cache
      +    if (settings%registry_cache) then
      +        call get_global_settings(global_settings, error) 
      +        if (allocated(error)) return
      +
      +        call os_delete_dir(os_is_unix(), global_settings%registry_settings%cache_path)
      +    end if
      +
      +    if (is_dir('build')) then
      +        ! Remove the entire build directory
      +        if (settings%clean_all) then
      +            call os_delete_dir(os_is_unix(), 'build'); return
      +        ! Remove the build directory but skip dependencies
      +        else if (settings%clean_skip) then
      +            call delete_skip(os_is_unix()); return
      +        end if
      +
      +        ! Prompt to remove the build directory but skip dependencies
      +        write(stdout, '(A)', advance='no') "Delete build, excluding dependencies (y/n)? "
      +        read(stdin, '(A1)') user_response
      +        if (lower(user_response) == 'y') call delete_skip(os_is_unix())
      +    else
      +        write (stdout, '(A)') "fpm: No build directory found."
      +    end if
      +end subroutine cmd_clean
      +
      +!> Sort executables by namelist ID, and trim unused values
      +pure subroutine sort_executables(target_ID,executables)
      +    integer, allocatable, intent(inout) :: target_ID(:)
      +    type(string_t), allocatable, intent(inout) :: executables(:)
      +    
      +    integer :: i,j,n,used
      +    
      +    n = size(target_ID)
      +    used = 0
      +    
      +    sort: do i=1,n
      +       do j=i+1,n
      +          if (target_ID(j)<target_ID(i)) &
      +          call swap(target_ID(i),target_ID(j),executables(i),executables(j))
      +       end do
      +       if (target_ID(i)<huge(target_ID(i))) used = i
      +    end do sort   
      +    
      +    if (used>0 .and. used<n) then 
      +        target_ID = target_ID(1:used)
      +        executables = executables(1:used)
      +    end if
      +    
      +    contains
      +    
      +    elemental subroutine swap(t1,t2,e1,e2)
      +       integer, intent(inout) :: t1,t2
      +       type(string_t), intent(inout) :: e1,e2
      +       integer :: tmp
      +       type(string_t) :: etmp
      +       
      +       tmp = t1
      +       t1  = t2
      +       t2  = tmp 
      +       etmp = e1
      +       e1  = e2
      +       e2  = etmp        
      +    end subroutine swap
      +    
      +end subroutine sort_executables
      +
      +!> Check if an executable should be run 
      +logical function should_be_run(settings,run_scope,exe_target)
      +    class(fpm_run_settings), intent(in) :: settings
      +    integer, intent(in) :: run_scope
      +    type(build_target_t), intent(in) :: exe_target
      +    
      +    if (exe_target%is_executable_target(run_scope)) then
      +        
      +        associate(exe_source => exe_target%dependencies(1)%ptr%source)
      +            
      +            if (exe_source%unit_scope/=run_scope) then 
      +                
      +                ! Other scope
      +                should_be_run = .false.
      +                
      +            elseif (size(settings%name) == 0 .or. settings%list) then
      +
      +                ! Run all or list all
      +                should_be_run = .true.
      +
      +            else
      +
      +                ! Is found in list
      +                should_be_run = settings%name_ID(exe_source%exe_name)>0
      +                
      +            end if            
      +            
      +        end associate
      +                        
      +    else
      +        
      +        !> Invalid target
      +        should_be_run = .false.
      +        
      +    endif
      +    
      +end function should_be_run
      +
      +!> Save the current runtime library path (e.g., PATH or LD_LIBRARY_PATH)
      +function save_library_path() result(path)
      +    character(len=:), allocatable :: path
      +
      +    select case (get_os_type())
      +    case (OS_WINDOWS)
      +        path = get_env("PATH", default="")
      +    case (OS_MACOS)
      +        path = get_env("DYLD_LIBRARY_PATH", default="")
      +    case default ! UNIX/Linux
      +        path = get_env("LD_LIBRARY_PATH", default="")
      +    end select
      +end function save_library_path
      +
      +!> Set the runtime library path for the current process (used for subprocesses)
      +subroutine set_library_path(model, targets, error)
      +    type(fpm_model_t), intent(in) :: model
      +    type(build_target_ptr), intent(inout), target :: targets(:)
      +    type(error_t), allocatable, intent(out) :: error
      +     
      +    type(string_t), allocatable :: shared_lib_dirs(:)
      +    character(len=:), allocatable :: new_path, sep, current
      +    logical :: success
      +    integer :: i
      +
      +    ! Get library directories
      +    call get_library_dirs(model, targets, shared_lib_dirs)
      +
      +    ! Select platform-specific separator
      +    select case (get_os_type())
      +    case (OS_WINDOWS)
      +        sep = ";"
      +    case default
      +        sep = ":"
      +    end select
      +
      +    ! Join the directories into a path string
      +    new_path = ""
      +    do i = 1, size(shared_lib_dirs)
      +        if (i > 1) new_path = new_path // sep
      +        new_path = new_path // shared_lib_dirs(i)%s
      +    end do    
      +    
      +    ! Get current library path
      +    current = save_library_path()
      +
      +    ! Set the appropriate environment variable
      +    select case (get_os_type())
      +    case (OS_WINDOWS)
      +        success = set_env("PATH", new_path // sep // current)
      +    case (OS_MACOS)
      +        success = set_env("DYLD_LIBRARY_PATH", new_path // sep // current)
      +    case default ! UNIX/Linux
      +        success = set_env("LD_LIBRARY_PATH", new_path // sep // current)
      +    end select
      +    
      +    if (.not.success) call fatal_error(error,"Cannot set library path: "//new_path)
      +
      +end subroutine set_library_path
      +
      +
      +!> Restore a previously saved runtime library path
      +subroutine restore_library_path(saved_path, error)
      +    character(*), intent(in) :: saved_path
      +    type(error_t), allocatable, intent(out) :: error
      +    logical :: success
      +
      +    select case (get_os_type())
      +    case (OS_WINDOWS)
      +        success = set_env("PATH", saved_path)
      +    case (OS_MACOS)
      +        success = set_env("DYLD_LIBRARY_PATH", saved_path)
      +    case default ! UNIX/Linux
      +        success = set_env("LD_LIBRARY_PATH", saved_path)
      +    end select
      +    
      +    if (.not.success) call fatal_error(error, "Cannot restore library path: "//saved_path)
      +
      +end subroutine restore_library_path
      +
      +
      +
      +
      +end module fpm
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/fpm_backend.f90.html b/sourcefile/fpm_backend.f90.html new file mode 100644 index 0000000000..4a3c50ee8c --- /dev/null +++ b/sourcefile/fpm_backend.f90.html @@ -0,0 +1,602 @@ + + + + + + + + + + + + + fpm_backend.F90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      fpm_backend.F90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      !># Build backend
      +!> Uses a list of `[[build_target_ptr]]` and a valid `[[fpm_model]]` instance
      +!> to schedule and execute the compilation and linking of package targets.
      +!>
      +!> The package build process (`[[build_package]]`) comprises three steps:
      +!>
      +!> 1. __Target sorting:__ topological sort of the target dependency graph (`[[sort_target]]`)
      +!> 2. __Target scheduling:__ group targets into schedule regions based on the sorting (`[[schedule_targets]]`)
      +!> 3. __Target building:__ generate targets by compilation or linking
      +!>
      +!> @note If compiled with OpenMP, targets will be build in parallel where possible.
      +!>
      +!>### Incremental compilation
      +!> The backend process supports *incremental* compilation whereby targets are not
      +!> re-compiled if their corresponding dependencies have not been modified.
      +!>
      +!> - Source-based targets (*i.e.* objects) are not re-compiled if the corresponding source
      +!>   file is unmodified AND all of the target dependencies are not marked for re-compilation
      +!>
      +!> - Link targets (*i.e.* executables and libraries) are not re-compiled if the
      +!>   target output file already exists AND all of the target dependencies are not marked for
      +!>   re-compilation
      +!>
      +!> Source file modification is determined by a file digest (hash) which is calculated during
      +!> the source parsing phase ([[fpm_source_parsing]]) and cached to disk after a target is
      +!> successfully generated.
      +!>
      +module fpm_backend
      +
      +use,intrinsic :: iso_fortran_env, only : stdin=>input_unit, stdout=>output_unit, stderr=>error_unit
      +use fpm_error, only : fpm_stop, error_t
      +use fpm_filesystem, only: basename, dirname, join_path, exists, mkdir, run, getline
      +use fpm_model, only: fpm_model_t
      +use fpm_strings, only: string_t, operator(.in.)
      +use fpm_targets, only: build_target_t, build_target_ptr, FPM_TARGET_OBJECT, &
      +                       FPM_TARGET_C_OBJECT, FPM_TARGET_ARCHIVE, FPM_TARGET_EXECUTABLE, &
      +                       FPM_TARGET_CPP_OBJECT, FPM_TARGET_SHARED
      +use fpm_backend_output
      +use fpm_compile_commands, only: compile_command_table_t
      +implicit none
      +
      +private
      +public :: build_package, sort_target, schedule_targets
      +
      +#ifndef FPM_BOOTSTRAP
      +interface
      +    function c_isatty() bind(C, name = 'c_isatty')
      +        use, intrinsic :: iso_c_binding, only: c_int
      +        integer(c_int) :: c_isatty
      +    end function
      +end interface
      +#endif
      +
      +contains
      +
      +!> Top-level routine to build package described by `model`
      +subroutine build_package(targets,model,verbose,dry_run)
      +    type(build_target_ptr), intent(inout) :: targets(:)
      +    type(fpm_model_t), intent(in) :: model
      +    logical, intent(in) :: verbose
      +    
      +    !> If dry_run, the build process is only mocked, but the list of compile_commands 
      +    !> is still created
      +    logical, intent(in) :: dry_run
      + 
      +    integer :: i, j
      +    type(build_target_ptr), allocatable :: queue(:)
      +    integer, allocatable :: schedule_ptr(:), stat(:)
      +    logical :: build_failed, skip_current
      +    type(string_t), allocatable :: build_dirs(:)
      +    type(string_t) :: temp
      +    type(error_t), allocatable :: error
      +
      +    type(build_progress_t) :: progress
      +    logical :: plain_output
      +
      +    ! Need to make output directory for include (mod) files
      +    allocate(build_dirs(0))
      +    do i = 1, size(targets)
      +       associate(target => targets(i)%ptr)
      +          if (target%output_dir .in. build_dirs) cycle
      +          temp%s = target%output_dir
      +          build_dirs = [build_dirs, temp]
      +       end associate
      +    end do
      +
      +    do i = 1, size(build_dirs)
      +       if (.not.dry_run) call mkdir(build_dirs(i)%s,verbose)
      +    end do
      +
      +    ! Perform depth-first topological sort of targets
      +    do i=1,size(targets)
      +
      +        call sort_target(targets(i)%ptr, dry_run)
      +
      +    end do
      +
      +    ! Construct build schedule queue
      +    call schedule_targets(queue, schedule_ptr, targets)
      +
      +    ! Check if queue is empty
      +    if (.not.verbose .and. size(queue) < 1 .and. .not.dry_run) then
      +        write(stderr, '(a)') 'Project is up to date'
      +        return
      +    end if
      +
      +    ! Initialise build status flags
      +    allocate(stat(size(queue)),source=0)
      +    build_failed = .false.
      +
      +    ! Set output mode
      +#ifndef FPM_BOOTSTRAP
      +    plain_output = (.not.(c_isatty()==1)) .or. verbose
      +#else
      +    plain_output = .true.
      +#endif
      +
      +    progress = build_progress_t(queue,plain_output)
      +
      +    ! Loop over parallel schedule regions
      +    do i=1,size(schedule_ptr)-1
      +
      +        ! Build targets in schedule region i
      +        !$omp parallel do default(shared) private(skip_current) schedule(dynamic,1)
      +        do j=schedule_ptr(i),(schedule_ptr(i+1)-1)
      +
      +            ! Check if build already failed
      +            !$omp atomic read
      +            skip_current = build_failed
      +
      +            if (.not.skip_current) then
      +                if (.not.dry_run) call progress%compiling_status(j)
      +                call build_target(model,queue(j)%ptr,verbose,dry_run, &
      +                                  progress%compile_commands,stat(j))
      +                if (.not.dry_run) call progress%completed_status(j,stat(j))
      +            end if
      +
      +            ! Set global flag if this target failed to build
      +            if (stat(j) /= 0) then
      +                !$omp atomic write
      +                build_failed = .true.
      +            end if
      +
      +        end do
      +
      +        ! Check if this schedule region failed: exit with message if failed
      +        if (build_failed) then
      +            write(*,*)
      +            do j=1,size(stat)
      +                if (stat(j) /= 0) Then
      +                    call print_build_log(queue(j)%ptr)
      +                end if
      +            end do
      +            do j=1,size(stat)
      +                if (stat(j) /= 0) then
      +                    write(stderr,'(*(g0:,1x))') '<ERROR> Compilation failed for object "',basename(queue(j)%ptr%output_file),'"'
      +                end if
      +            end do
      +            call fpm_stop(1,'stopping due to failed compilation')
      +        end if
      +
      +    end do
      +
      +    if (.not.dry_run) call progress%success()
      +    call progress%dump_commands(error)
      +    if (allocated(error)) call fpm_stop(1,'error writing compile_commands.json: '//trim(error%message))
      +
      +end subroutine build_package
      +
      +
      +!> Topologically sort a target for scheduling by
      +!>  recursing over its dependencies.
      +!>
      +!> Checks disk-cached source hashes to determine if objects are
      +!>  up-to-date. Up-to-date sources are tagged as skipped.
      +!>
      +!> On completion, `target` should either be marked as
      +!> sorted (`target%sorted=.true.`) or skipped (`target%skip=.true.`)
      +!>
      +!> If `target` is marked as sorted, `target%schedule` should be an
      +!> integer greater than zero indicating the region for scheduling
      +!>
      +recursive subroutine sort_target(target, mock)
      +    type(build_target_t), intent(inout), target :: target
      +    !> Optionally sort ALL targets if this is a dry run
      +    logical, optional, intent(in) :: mock
      +
      +    integer :: i, fh, stat
      +    logical :: dry_run
      +    
      +    dry_run = .false.
      +    if (present(mock)) dry_run = mock
      +
      +    ! Check if target has already been processed (as a dependency)
      +    if (target%sorted .or. target%skip) return
      +
      +    ! Check for a circular dependency
      +    ! (If target has been touched but not processed)
      +    if (target%touched) then
      +        call fpm_stop(1,'(!) Circular dependency found with: '//target%output_file)
      +    else
      +        target%touched = .true.  ! Set touched flag
      +    end if
      +
      +    ! Load cached source file digest if present
      +    if (.not.allocated(target%digest_cached) .and. &
      +         exists(target%output_file) .and. &
      +         exists(target%output_file//'.digest') .and. &
      +         (.not.dry_run)) then 
      +
      +        allocate(target%digest_cached)
      +        open(newunit=fh,file=target%output_file//'.digest',status='old')
      +        read(fh,*,iostat=stat) target%digest_cached
      +        close(fh)
      +
      +        ! Cached digest is not recognized
      +        if (stat /= 0) deallocate(target%digest_cached)
      +
      +    end if
      +    
      +    if (dry_run) then 
      +        
      +        target%skip = .false.
      +        
      +    elseif (allocated(target%source)) then
      +
      +        ! Skip if target is source-based and source file is unmodified
      +        if (allocated(target%digest_cached)) then
      +            if (target%digest_cached == target%source%digest) target%skip = .true.
      +        end if
      +
      +    elseif (exists(target%output_file)) then
      +
      +        ! Skip if target is not source-based and already exists
      +        target%skip = .true.
      +
      +    end if
      +
      +    ! Loop over target dependencies
      +    target%schedule = 1
      +    do i=1,size(target%dependencies)
      +
      +        ! Sort dependency
      +        call sort_target(target%dependencies(i)%ptr, dry_run)
      +
      +        if (.not.target%dependencies(i)%ptr%skip) then
      +
      +            ! Can't skip target if any dependency is not skipped
      +            target%skip = .false.
      +
      +            ! Set target schedule after all of its dependencies
      +            target%schedule = max(target%schedule,target%dependencies(i)%ptr%schedule+1)
      +
      +        end if
      +
      +    end do
      +
      +    ! Mark flag as processed: either sorted or skipped
      +    target%sorted = .not.target%skip
      +
      +end subroutine sort_target
      +
      +
      +!> Construct a build schedule from the sorted targets.
      +!>
      +!> The schedule is broken into regions, described by `schedule_ptr`,
      +!>  where targets in each region can be compiled in parallel.
      +!>
      +subroutine schedule_targets(queue, schedule_ptr, targets)
      +    type(build_target_ptr), allocatable, intent(out) :: queue(:)
      +    integer, allocatable :: schedule_ptr(:)
      +    type(build_target_ptr), intent(in) :: targets(:)
      +
      +    integer :: i, j
      +    integer :: n_schedule, n_sorted
      +
      +    n_schedule = 0   ! Number of schedule regions
      +    n_sorted = 0     ! Total number of targets to build
      +    do i=1,size(targets)
      +
      +        if (targets(i)%ptr%sorted) then
      +            n_sorted = n_sorted + 1
      +        end if
      +        n_schedule = max(n_schedule, targets(i)%ptr%schedule)
      +
      +    end do
      +
      +    allocate(queue(n_sorted))
      +    allocate(schedule_ptr(n_schedule+1))
      +
      +    ! Construct the target queue and schedule region pointer
      +    n_sorted = 1
      +    schedule_ptr(n_sorted) = 1
      +    do i=1,n_schedule
      +
      +        do j=1,size(targets)
      +
      +            if (targets(j)%ptr%sorted) then
      +                if (targets(j)%ptr%schedule == i) then
      +
      +                    queue(n_sorted)%ptr => targets(j)%ptr
      +                    n_sorted = n_sorted + 1
      +                end if
      +            end if
      +
      +        end do
      +
      +        schedule_ptr(i+1) = n_sorted
      +
      +    end do
      +
      +end subroutine schedule_targets
      +
      +
      +!> Call compile/link command for a single target.
      +!>
      +!> If successful, also caches the source file digest to disk.
      +!>
      +subroutine build_target(model,target,verbose,dry_run,table,stat)
      +    type(fpm_model_t), intent(in) :: model
      +    type(build_target_t), intent(in), target :: target
      +    logical, intent(in) :: verbose
      +    !> If dry_run, the build process is only mocked, but compile_commands are still created
      +    logical, intent(in) :: dry_run    
      +    type(compile_command_table_t), intent(inout) :: table
      +    integer, intent(out) :: stat
      +
      +    integer :: fh
      +
      +    !$omp critical
      +    if (.not.exists(dirname(target%output_file)) .and. .not.dry_run) then
      +        call mkdir(dirname(target%output_file),verbose)
      +    end if
      +    !$omp end critical
      +
      +    select case(target%target_type)
      +
      +    case (FPM_TARGET_OBJECT)
      +        call model%compiler%compile_fortran(target%source%file_name, target%output_file, &
      +            & target%compile_flags, target%output_log_file, stat, table, dry_run)
      +
      +    case (FPM_TARGET_C_OBJECT)
      +        call model%compiler%compile_c(target%source%file_name, target%output_file, &
      +            & target%compile_flags, target%output_log_file, stat, table, dry_run)
      +
      +    case (FPM_TARGET_CPP_OBJECT)
      +        call model%compiler%compile_cpp(target%source%file_name, target%output_file, &
      +            & target%compile_flags, target%output_log_file, stat, table, dry_run)
      +
      +    case (FPM_TARGET_EXECUTABLE)
      +        call model%compiler%link(target%output_file, &
      +            & target%compile_flags//" "//target%link_flags, target%output_log_file, stat, dry_run)
      +
      +    case (FPM_TARGET_ARCHIVE)
      +        call model%archiver%make_archive(target%output_file, target%link_objects, &
      +            & target%output_log_file, stat, dry_run)
      +            
      +    case (FPM_TARGET_SHARED)
      +
      +        call model%compiler%link_shared(target%output_file, target%link_flags, &
      +            & target%output_log_file, stat, dry_run)
      +
      +    end select
      +
      +    if (stat == 0 .and. allocated(target%source) .and. .not.dry_run) then
      +        open(newunit=fh,file=target%output_file//'.digest',status='unknown')
      +        write(fh,*) target%source%digest
      +        close(fh)
      +    end if
      +
      +end subroutine build_target
      +
      +
      +!> Read and print the build log for target
      +!>
      +subroutine print_build_log(target)
      +    type(build_target_t), intent(in), target :: target
      +
      +    integer :: fh, ios
      +    character(:), allocatable :: line
      +
      +    if (exists(target%output_log_file)) then
      +
      +        open(newunit=fh,file=target%output_log_file,status='old')
      +        do
      +            call getline(fh, line, ios)
      +            if (ios /= 0) exit
      +            write(*,'(A)') trim(line)
      +        end do
      +        close(fh)
      +
      +    else
      +
      +        write(stderr,'(*(g0:,1x))') '<ERROR> Unable to find build log "',basename(target%output_log_file),'"'
      +
      +    end if
      +
      +end subroutine print_build_log
      +
      +end module fpm_backend
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/fpm_backend_console.f90.html b/sourcefile/fpm_backend_console.f90.html new file mode 100644 index 0000000000..42452e5d3d --- /dev/null +++ b/sourcefile/fpm_backend_console.f90.html @@ -0,0 +1,315 @@ + + + + + + + + + + + + + fpm_backend_console.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      fpm_backend_console.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      !># Build Backend Console
      +!> This module provides a lightweight implementation for printing to the console
      +!> and updating previously-printed console lines. It used by `[[fpm_backend_output]]`
      +!> for pretty-printing build status and progress.
      +!>
      +!> @note The implementation for updating previous lines relies on no other output
      +!> going to `stdout`/`stderr` except through the `console_t` object provided.
      +!>
      +!> @note All write statements to `stdout` are enclosed within OpenMP `critical` regions
      +!>
      +module fpm_backend_console
      +use iso_fortran_env, only: stdout=>output_unit
      +implicit none
      +
      +private
      +public :: console_t
      +public :: LINE_RESET
      +public :: COLOR_RED, COLOR_GREEN, COLOR_YELLOW, COLOR_RESET
      +
      +character(len=*), parameter :: ESC = char(27)
      +!> Escape code for erasing current line
      +character(len=*), parameter :: LINE_RESET = ESC//"[2K"//ESC//"[1G"
      +!> Escape code for moving up one line
      +character(len=*), parameter :: LINE_UP = ESC//"[1A"
      +!> Escape code for moving down one line
      +character(len=*), parameter :: LINE_DOWN = ESC//"[1B"
      +!> Escape code for red foreground color
      +character(len=*), parameter :: COLOR_RED = ESC//"[31m"
      +!> Escape code for green foreground color
      +character(len=*), parameter :: COLOR_GREEN = ESC//"[32m"
      +!> Escape code for yellow foreground color
      +character(len=*), parameter :: COLOR_YELLOW = ESC//"[93m"
      +!> Escape code to reset foreground color
      +character(len=*), parameter :: COLOR_RESET = ESC//"[0m"
      +
      +!> Console object
      +type console_t
      +    !> Number of lines printed
      +    integer :: n_line = 1
      +
      +contains
      +    !> Write a single line to the console
      +    procedure :: write_line => console_write_line
      +    !> Update a previously-written console line
      +    procedure :: update_line => console_update_line
      +end type console_t
      +
      +contains
      +
      +!> Write a single line to the standard output
      +subroutine console_write_line(console,str,line,advance)
      +    !> Console object
      +    class(console_t), intent(inout) :: console
      +    !> String to write
      +    character(*), intent(in) :: str
      +    !> Integer needed to later update console line
      +    integer, intent(out), optional :: line
      +    !> Advancing output (print newline?)
      +    logical, intent(in), optional :: advance
      +
      +    character(3) :: adv
      +
      +    adv = "yes"
      +    if (present(advance)) then
      +        if (.not.advance) then
      +            adv = "no"
      +        end if
      +    end if
      +
      +    !$omp critical
      +
      +    if (present(line)) then
      +        line = console%n_line
      +    end if
      +    
      +    write(stdout,'(A)',advance=trim(adv)) LINE_RESET//str
      +
      +    if (adv=="yes") then
      +        console%n_line = console%n_line + 1
      +    end if
      +
      +    !$omp end critical
      +
      +end subroutine console_write_line
      +
      +!> Overwrite a previously-written line in standard output
      +subroutine console_update_line(console,line_no,str)
      +    !> Console object
      +    class(console_t), intent(in) :: console
      +    !> Integer output from `[[console_write_line]]`
      +    integer, intent(in) :: line_no
      +    !> New string to overwrite line
      +    character(*), intent(in) :: str
      +
      +    integer :: n
      +
      +    !$omp critical
      +
      +    n = console%n_line - line_no
      +
      +    ! Step back to line
      +    write(stdout,'(A)',advance="no") repeat(LINE_UP,n)//LINE_RESET
      +
      +    write(stdout,'(A)',advance="no") str
      +
      +    ! Step forward to end
      +    write(stdout,'(A)',advance="no") repeat(LINE_DOWN,n)//LINE_RESET
      +
      +    !$omp end critical
      +
      +end subroutine console_update_line
      +
      +end module fpm_backend_console
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/fpm_backend_output.f90.html b/sourcefile/fpm_backend_output.f90.html new file mode 100644 index 0000000000..927c3b97f6 --- /dev/null +++ b/sourcefile/fpm_backend_output.f90.html @@ -0,0 +1,402 @@ + + + + + + + + + + + + + fpm_backend_output.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      fpm_backend_output.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      !># Build Backend Progress Output
      +!> This module provides a derived type `build_progress_t` for printing build status
      +!> and progress messages to the console while the backend is building the package.
      +!>
      +!> The `build_progress_t` type supports two modes: `normal` and `plain`
      +!> where the former does 'pretty' output and the latter does not.
      +!> The `normal` mode is intended for typical interactive usage whereas
      +!> 'plain' mode is used with the `--verbose` flag or when `stdout` is not attached
      +!> to a terminal (e.g. when piping or redirecting `stdout`). In these cases,
      +!> the pretty output must be suppressed to avoid control codes being output.
      +
      +module fpm_backend_output
      +use iso_fortran_env, only: stdout=>output_unit
      +use fpm_error, only: error_t
      +use fpm_filesystem, only: basename,join_path
      +use fpm_targets, only: build_target_ptr
      +use fpm_backend_console, only: console_t, LINE_RESET, COLOR_RED, COLOR_GREEN, COLOR_YELLOW, COLOR_RESET
      +use fpm_compile_commands, only: compile_command_t, compile_command_table_t
      +implicit none
      +
      +private
      +public build_progress_t
      +
      +!> Build progress object
      +type build_progress_t
      +    !> Console object for updating console lines
      +    type(console_t) :: console
      +    !> Number of completed targets
      +    integer :: n_complete
      +    !> Total number of targets scheduled
      +    integer :: n_target
      +    !> 'Plain' output (no colors or updating)
      +    logical :: plain_mode = .true.
      +    !> Store needed when updating previous console lines
      +    integer, allocatable :: output_lines(:)
      +    !> Queue of scheduled build targets
      +    type(build_target_ptr), pointer :: target_queue(:)
      +    !> The compile_commands.json table
      +    type(compile_command_table_t) :: compile_commands
      +contains
      +    !> Output 'compiling' status for build target
      +    procedure :: compiling_status => output_status_compiling
      +    !> Output 'complete' status for build target
      +    procedure :: completed_status => output_status_complete
      +    !> Output finished status for whole package
      +    procedure :: success => output_progress_success
      +    !> Output 'compile_commands.json' to build/ folder
      +    procedure :: dump_commands => output_write_compile_commands
      +end type build_progress_t
      +
      +!> Constructor for build_progress_t
      +interface build_progress_t
      +    procedure :: new_build_progress
      +end interface build_progress_t
      +
      +contains
      +    
      +    !> Initialise a new build progress object
      +    function new_build_progress(target_queue,plain_mode) result(progress)
      +        !> The queue of scheduled targets
      +        type(build_target_ptr), intent(in), target :: target_queue(:)
      +        !> Enable 'plain' output for progress object
      +        logical, intent(in), optional :: plain_mode
      +        !> Progress object to initialise
      +        type(build_progress_t) :: progress
      +        
      +        call progress%compile_commands%destroy()
      +
      +        progress%n_target = size(target_queue,1)
      +        progress%target_queue => target_queue
      +        progress%plain_mode = plain_mode
      +        progress%n_complete = 0
      +
      +        allocate(progress%output_lines(progress%n_target))
      +
      +    end function new_build_progress
      +
      +    !> Output 'compiling' status for build target and overall percentage progress
      +    subroutine output_status_compiling(progress, queue_index)
      +        !> Progress object
      +        class(build_progress_t), intent(inout) :: progress
      +        !> Index of build target in the target queue
      +        integer, intent(in) :: queue_index
      +
      +        character(:), allocatable :: target_name
      +        character(100) :: output_string
      +        character(7) :: overall_progress
      +
      +        associate(target=>progress%target_queue(queue_index)%ptr)
      +
      +            if (allocated(target%source)) then
      +                target_name = basename(target%source%file_name)
      +            else
      +                target_name = basename(target%output_file)
      +            end if
      +
      +            write(overall_progress,'(A,I3,A)') '[',100*progress%n_complete/progress%n_target,'%] '
      +
      +            if (progress%plain_mode) then ! Plain output
      +
      +                !$omp critical
      +                write(*,'(A7,A30)') overall_progress,target_name
      +                !$omp end critical
      +
      +            else ! Pretty output
      +
      +                write(output_string,'(A,T40,A,A)') target_name, COLOR_YELLOW//'compiling...'//COLOR_RESET
      +
      +                call progress%console%write_line(trim(output_string),progress%output_lines(queue_index))
      +
      +                call progress%console%write_line(overall_progress//'Compiling...',advance=.false.)
      +
      +            end if
      +
      +        end associate
      +
      +    end subroutine output_status_compiling
      +
      +    !> Output 'complete' status for build target and update overall percentage progress
      +    subroutine output_status_complete(progress, queue_index, build_stat)
      +        !> Progress object
      +        class(build_progress_t), intent(inout) :: progress
      +        !> Index of build target in the target queue
      +        integer, intent(in) :: queue_index
      +        !> Build status flag
      +        integer, intent(in) :: build_stat
      +
      +        character(:), allocatable :: target_name
      +        character(100) :: output_string
      +        character(7) :: overall_progress
      +
      +        !$omp critical 
      +        progress%n_complete = progress%n_complete + 1
      +        !$omp end critical
      +
      +        associate(target=>progress%target_queue(queue_index)%ptr)
      +
      +            if (allocated(target%source)) then
      +                target_name = basename(target%source%file_name)
      +            else
      +                target_name = basename(target%output_file)
      +            end if
      +
      +            if (build_stat == 0) then
      +                write(output_string,'(A,T40,A,A)') target_name,COLOR_GREEN//'done.'//COLOR_RESET
      +            else
      +                write(output_string,'(A,T40,A,A)') target_name,COLOR_RED//'failed.'//COLOR_RESET
      +            end if
      +
      +            write(overall_progress,'(A,I3,A)') '[',100*progress%n_complete/progress%n_target,'%] '
      +
      +            if (progress%plain_mode) then  ! Plain output
      +
      +                !$omp critical
      +                write(*,'(A7,A30,A7)') overall_progress,target_name, 'done.'
      +                !$omp end critical
      +
      +            else ! Pretty output
      +
      +                call progress%console%update_line(progress%output_lines(queue_index),trim(output_string))
      +
      +                call progress%console%write_line(overall_progress//'Compiling...',advance=.false.)
      +
      +            end if
      +
      +        end associate
      +
      +    end subroutine output_status_complete
      +
      +    !> Output finished status for whole package
      +    subroutine output_progress_success(progress)
      +        class(build_progress_t), intent(inout) :: progress
      +        
      +        if (progress%plain_mode) then ! Plain output
      +
      +            write(*,'(A)') '[100%] Project compiled successfully.'
      +
      +        else ! Pretty output
      +
      +            write(*,'(A)') LINE_RESET//COLOR_GREEN//'[100%] Project compiled successfully.'//COLOR_RESET
      +
      +        end if
      +        
      +    end subroutine output_progress_success
      +    
      +    !> Write compile commands table
      +    subroutine output_write_compile_commands(progress,error)
      +        class(build_progress_t), intent(inout) :: progress
      +        
      +        character(:), allocatable :: path
      +        type(error_t), allocatable :: error
      +        
      +        ! Write compile commands 
      +        path = join_path('build','compile_commands.json')
      +        
      +        call progress%compile_commands%write(filename=path, error=error) 
      +        
      +    end subroutine output_write_compile_commands
      +
      +end module fpm_backend_output
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/fpm_command_line.f90.html b/sourcefile/fpm_command_line.f90.html new file mode 100644 index 0000000000..1a376f40df --- /dev/null +++ b/sourcefile/fpm_command_line.f90.html @@ -0,0 +1,1827 @@ + + + + + + + + + + + + + fpm_command_line.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      fpm_command_line.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      !># Definition of the command line interface
      +!>
      +!> This module uses [M_CLI2](https://github.com/urbanjost/M_CLI2) to define
      +!> the command line interface.
      +!> To define a command line interface create a new command settings type
      +!> from the [[fpm_cmd_settings]] base class or the respective parent command
      +!> settings.
      +!>
      +!> The subcommand is selected by the first non-option argument in the command
      +!> line. In the subcase block the actual command line is defined and transferred
      +!> to an instance of the [[fpm_cmd_settings]], the actual type is used by the
      +!> *fpm* main program to determine which command entry point is chosen.
      +!>
      +!> To add a new subcommand add a new case to select construct and specify the
      +!> wanted command line and the expected default values.
      +!> Some of the following points also apply if you add a new option or argument
      +!> to an existing *fpm* subcommand.
      +!> At this point you should create a help page for the new command in a simple
      +!> catman-like format as well in the ``set_help`` procedure.
      +!> Make sure to register new subcommands in the ``fpm-manual`` command by adding
      +!> them to the manual character array and in the help/manual case as well.
      +!> You should add the new command to the synopsis section of the ``fpm-list``,
      +!> ``fpm-help`` and ``fpm --list`` help pages below to make sure the help output
      +!> is complete and consistent as well.
      +module fpm_command_line
      +use fpm_environment,  only : get_os_type, get_env, &
      +                             OS_UNKNOWN, OS_LINUX, OS_MACOS, OS_WINDOWS, &
      +                             OS_CYGWIN, OS_SOLARIS, OS_FREEBSD, OS_OPENBSD, OS_NAME
      +use M_CLI2,           only : set_args, lget, sget, unnamed, remaining, specified
      +use M_CLI2,           only : get_subcommand, CLI_RESPONSE_FILE
      +use fpm_strings,      only : lower, split, to_fortran_name, is_fortran_name, remove_characters_in_set, &
      +                             string_t, glob
      +use fpm_filesystem,   only : basename, canon_path, which, run
      +use fpm_environment,  only : get_command_arguments_quoted
      +use fpm_error,        only : fpm_stop, error_t
      +use fpm_os,           only : get_current_directory
      +use fpm_release,      only : fpm_version, version_t
      +use,intrinsic :: iso_fortran_env, only : stdin=>input_unit, &
      +                                       & stdout=>output_unit, &
      +                                       & stderr=>error_unit
      +
      +implicit none
      +
      +private
      +public :: fpm_cmd_settings, &
      +          fpm_build_settings, &
      +          fpm_install_settings, &
      +          fpm_export_settings, &
      +          fpm_new_settings, &
      +          fpm_run_settings, &
      +          fpm_test_settings, &
      +          fpm_update_settings, &
      +          fpm_clean_settings, &
      +          fpm_publish_settings, &
      +          get_command_line_settings, &
      +          get_fpm_env
      +
      +type, abstract :: fpm_cmd_settings
      +    character(len=:), allocatable :: working_dir
      +    character(len=:), allocatable :: path_to_config
      +    logical                       :: verbose=.true.
      +end type
      +
      +integer,parameter :: ibug=4096
      +
      +type, extends(fpm_cmd_settings)  :: fpm_new_settings
      +    character(len=:),allocatable :: name
      +    logical                      :: with_executable=.false.
      +    logical                      :: with_test=.false.
      +    logical                      :: with_lib=.true.
      +    logical                      :: with_example=.false.
      +    logical                      :: with_full=.false.
      +    logical                      :: with_bare=.false.
      +    logical                      :: backfill=.true.
      +end type
      +
      +type, extends(fpm_cmd_settings)  :: fpm_build_settings
      +    logical                      :: list=.false.
      +    logical                      :: show_model=.false.
      +    logical                      :: build_tests=.false.
      +    logical                      :: prune=.true.
      +    character(len=:),allocatable :: dump
      +    character(len=:),allocatable :: compiler
      +    character(len=:),allocatable :: c_compiler
      +    character(len=:),allocatable :: cxx_compiler
      +    character(len=:),allocatable :: archiver
      +    character(len=:),allocatable :: profile
      +    character(len=:),allocatable :: flag
      +    character(len=:),allocatable :: cflag
      +    character(len=:),allocatable :: cxxflag
      +    character(len=:),allocatable :: ldflag
      +end type
      +
      +type, extends(fpm_build_settings)  :: fpm_run_settings
      +    character(len=ibug),allocatable :: name(:)
      +    character(len=:),allocatable :: args ! passed to the app
      +    character(len=:),allocatable :: runner
      +    character(len=:),allocatable :: runner_args ! passed to the runner
      +    logical :: example
      +    contains
      +       procedure :: runner_command
      +       procedure :: name_ID
      +end type
      +
      +type, extends(fpm_run_settings)  :: fpm_test_settings
      +end type
      +
      +type, extends(fpm_build_settings) :: fpm_install_settings
      +    character(len=:), allocatable :: prefix
      +    character(len=:), allocatable :: bindir
      +    character(len=:), allocatable :: libdir
      +    character(len=:), allocatable :: testdir
      +    character(len=:), allocatable :: includedir
      +    logical :: no_rebuild
      +end type
      +
      +!> Settings for interacting and updating with project dependencies
      +type, extends(fpm_cmd_settings)  :: fpm_update_settings
      +    character(len=ibug),allocatable :: name(:)
      +    character(len=:),allocatable    :: dump
      +    logical                         :: fetch_only
      +    logical                         :: clean
      +end type
      +
      +!> Settings for exporting model data
      +type, extends(fpm_build_settings) :: fpm_export_settings
      +    character(len=:),allocatable  :: dump_manifest
      +    character(len=:),allocatable  :: dump_dependencies
      +    character(len=:),allocatable  :: dump_model
      +end type
      +
      +type, extends(fpm_cmd_settings)   :: fpm_clean_settings
      +    logical                       :: clean_skip = .false.
      +    logical                       :: clean_all = .false.
      +    logical                       :: registry_cache = .false.
      +end type
      +
      +type, extends(fpm_build_settings) :: fpm_publish_settings
      +    logical :: show_package_version = .false.
      +    logical :: show_upload_data = .false.
      +    logical :: is_dry_run = .false.
      +    character(len=:), allocatable :: token
      +end type
      +
      +character(len=:),allocatable :: name
      +character(len=:),allocatable :: os_type
      +character(len=ibug),allocatable :: names(:)
      +character(len=:),allocatable :: tnames(:)
      +
      +character(len=:), allocatable :: version_text(:)
      +character(len=:), allocatable :: help_new(:), help_fpm(:), help_run(:), &
      +                 & help_test(:), help_build(:), help_usage(:), help_runner(:), &
      +                 & help_text(:), help_install(:), help_help(:), help_update(:), &
      +                 & help_list(:), help_list_dash(:), help_list_nodash(:), &
      +                 & help_clean(:), help_publish(:)
      +character(len=20),parameter :: manual(*)=[ character(len=20) ::&
      +&  ' ',     'fpm',    'new',     'build',  'run',    'clean',  &
      +&  'test',  'runner', 'install', 'update', 'list',   'help',   'version', 'publish' ]
      +
      +character(len=:), allocatable :: val_runner, val_compiler, val_flag, val_cflag, val_cxxflag, val_ldflag, &
      +    val_profile, val_runner_args, val_dump
      +
      +
      +!   '12345678901234567890123456789012345678901234567890123456789012345678901234567890',&
      +character(len=80), parameter :: help_text_build_common(*) = [character(len=80) ::      &
      +    ' --profile PROF    Selects the compilation profile for the build.               ',&
      +    '                   Currently available profiles are "release" for               ',&
      +    '                   high optimization and "debug" for full debug options.        ',&
      +    '                   If --flag is not specified the "debug" flags are the         ',&
      +    '                   default.                                                     ',&
      +    ' --no-prune        Disable tree-shaking/pruning of unused module dependencies   '&
      +    ]
      +!   '12345678901234567890123456789012345678901234567890123456789012345678901234567890',&
      +character(len=80), parameter :: help_text_compiler(*) = [character(len=80) :: &
      +    ' --compiler NAME    Specify a compiler name. The default is "gfortran"          ',&
      +    '                    unless set by the environment variable FPM_FC.              ',&
      +    ' --c-compiler NAME  Specify the C compiler name. Automatically determined by    ',&
      +    '                    default unless set by the environment variable FPM_CC.      ',&
      +    ' --cxx-compiler NAME  Specify the C++ compiler name. Automatically determined by',&
      +    '                    default unless set by the environment variable FPM_CXX.     ',&
      +    ' --archiver NAME    Specify the archiver name. Automatically determined by      ',&
      +    '                    default unless set by the environment variable FPM_AR.      '&
      +    ]
      +
      +!   '12345678901234567890123456789012345678901234567890123456789012345678901234567890',&
      +character(len=80), parameter :: help_text_flag(*) = [character(len=80) :: &
      +    ' --flag  FFLAGS    selects compile arguments for the build, the default value is',&
      +    '                   set by the FPM_FFLAGS environment variable. These are added  ',&
      +    '                   to the profile options if --profile is specified, else these ',&
      +    '                   are added to the defaults. To override the defaults, use the ',&
      +    '                   keyword [fortran] in the manifest. Note object and .mod      ',&
      +    '                   directory locations are always built in.                     ',&
      +    ' --c-flag CFLAGS   selects compile arguments specific for C source in the build.',&
      +    '                   The default value is set by the FPM_CFLAGS environment       ',&
      +    '                   variable.                                                    ',&
      +    ' --cxx-flag CFLAGS selects compile arguments specific for C++ source in the     ',&
      +    '                   build. The default value is set by the FPM_CXXFLAGS          ',&
      +    '                   environment variable.                                        ',&
      +    ' --link-flag LDFLAGS  select arguments passed to the linker for the build. The  ',&
      +    '                   default value is set by the FPM_LDFLAGS environment variable.'&
      +    ]
      +
      +
      +character(len=80), parameter :: help_text_environment(*) = [character(len=80) :: &
      +    'ENVIRONMENT VARIABLES',&
      +    ' FPM_FC            sets the path to the Fortran compiler used for the build,', &
      +    '                   will be overwritten by --compiler command line option', &
      +    '', &
      +    ' FPM_FFLAGS        sets the arguments for the Fortran compiler', &
      +    '                   will be overwritten by --flag command line option', &
      +    '', &
      +    ' FPM_CC            sets the path to the C compiler used for the build,', &
      +    '                   will be overwritten by --c-compiler command line option', &
      +    '', &
      +    ' FPM_CFLAGS        sets the arguments for the C compiler', &
      +    '                   will be overwritten by --c-flag command line option', &
      +    '', &
      +    ' FPM_CXX           sets the path to the C++ compiler used for the build,', &
      +    '                   will be overwritten by --cxx-compiler command line option', &
      +    '', &
      +    ' FPM_CXXFLAGS      sets the arguments for the C++ compiler', &
      +    '                   will be overwritten by --cxx-flag command line option', &
      +    '', &
      +    ' FPM_AR            sets the path to the archiver used for the build,', &
      +    '                   will be overwritten by --archiver command line option', &
      +    '', &
      +    ' FPM_LDFLAGS       sets additional link arguments for creating executables', &
      +    '                   will be overwritten by --link-flag command line option' &
      +    ]
      +
      +contains
      +    subroutine get_command_line_settings(cmd_settings)
      +        class(fpm_cmd_settings), allocatable, intent(out) :: cmd_settings
      +
      +        integer, parameter            :: widest = 256
      +        character(len=4096)           :: cmdarg
      +        integer                       :: i
      +        integer                       :: os
      +        type(fpm_install_settings), allocatable :: install_settings
      +        type(fpm_publish_settings), allocatable :: publish_settings
      +        type(fpm_export_settings) , allocatable :: export_settings
      +        type(version_t) :: version
      +        character(len=:), allocatable :: common_args, compiler_args, run_args, working_dir, &
      +            & c_compiler, cxx_compiler, archiver, version_s, token_s, config_file
      +
      +        character(len=*), parameter :: fc_env = "FC", cc_env = "CC", ar_env = "AR", &
      +            & fflags_env = "FFLAGS", cflags_env = "CFLAGS", cxxflags_env = "CXXFLAGS", ldflags_env = "LDFLAGS", &
      +            & fc_default = "gfortran", cc_default = " ", ar_default = " ", flags_default = " ", &
      +            & cxx_env = "CXX", cxx_default = " "
      +        type(error_t), allocatable :: error
      +
      +        call set_help()
      +        os = get_os_type()
      +        ! text for --version switch,
      +        select case (os)
      +            case (OS_LINUX);   os_type =  "OS Type:     Linux"
      +            case (OS_MACOS);   os_type =  "OS Type:     macOS"
      +            case (OS_WINDOWS); os_type =  "OS Type:     Windows"
      +            case (OS_CYGWIN);  os_type =  "OS Type:     Cygwin"
      +            case (OS_SOLARIS); os_type =  "OS Type:     Solaris"
      +            case (OS_FREEBSD); os_type =  "OS Type:     FreeBSD"
      +            case (OS_OPENBSD); os_type =  "OS Type:     OpenBSD"
      +            case (OS_UNKNOWN); os_type =  "OS Type:     Unknown"
      +            case default     ; os_type =  "OS Type:     UNKNOWN"
      +        end select
      +
      +        ! Get current release version
      +        version = fpm_version()
      +        version_s = version%s()
      +
      +        version_text = [character(len=80) :: &
      +         &  'Version:     '//trim(version_s)//', alpha',               &
      +         &  'Program:     fpm(1)',                                     &
      +         &  'Description: A Fortran package manager and build system', &
      +         &  'Home Page:   https://github.com/fortran-lang/fpm',        &
      +         &  'License:     MIT',                                        &
      +         &  os_type]
      +        ! find the subcommand name by looking for first word on command
      +        ! not starting with dash
      +        CLI_RESPONSE_FILE=.true.
      +        cmdarg = get_subcommand()
      +
      +        common_args = &
      +          ' --directory:C " "' // &
      +          ' --verbose F'
      +
      +        run_args = &
      +          ' --target " "' // &
      +          ' --list F' // &
      +          ' --runner " "' // &
      +          ' --runner-args " "'
      +
      +        compiler_args = &
      +          ' --profile " "' // &
      +          ' --no-prune F' // &
      +          ' --compiler "'//get_fpm_env(fc_env, fc_default)//'"' // &
      +          ' --c-compiler "'//get_fpm_env(cc_env, cc_default)//'"' // &
      +          ' --cxx-compiler "'//get_fpm_env(cxx_env, cxx_default)//'"' // &
      +          ' --archiver "'//get_fpm_env(ar_env, ar_default)//'"' // &
      +          ' --flag:: "'//get_fpm_env(fflags_env, flags_default)//'"' // &
      +          ' --c-flag:: "'//get_fpm_env(cflags_env, flags_default)//'"' // &
      +          ' --cxx-flag:: "'//get_fpm_env(cxxflags_env, flags_default)//'"' // &
      +          ' --link-flag:: "'//get_fpm_env(ldflags_env, flags_default)//'"'
      +
      +        ! now set subcommand-specific help text and process commandline
      +        ! arguments. Then call subcommand routine
      +        select case(trim(cmdarg))
      +
      +        case('run')
      +            call set_args(common_args // compiler_args // run_args //'&
      +            & --all F &
      +            & --example F &
      +            & --config-file " " &
      +            & --',help_run,version_text)
      +
      +            call check_build_vals()
      +
      +            if( size(unnamed) > 1 )then
      +                names=unnamed(2:)
      +            else
      +                names=[character(len=len(names)) :: ]
      +            endif
      +
      +            if(specified('target') )then
      +               call split(sget('target'),tnames,delimiters=' ,:')
      +               names=[character(len=max(len(names),len(tnames))) :: names,tnames]
      +            endif
      +
      +            ! convert --all to '*'
      +            if(lget('all'))then
      +               names=[character(len=max(len(names),1)) :: names,'*' ]
      +            endif
      +
      +            ! convert special string '..' to equivalent (shorter) '*'
      +            ! to allow for a string that does not require shift-key and quoting
      +            do i=1,size(names)
      +               if(names(i)=='..')names(i)='*'
      +            enddo
      +
      +            ! If there are additional command-line arguments, remove the additional
      +            ! double quotes which have been added by M_CLI2
      +            val_runner_args=sget('runner-args')
      +            call remove_characters_in_set(val_runner_args,set='"')
      +
      +            c_compiler = sget('c-compiler')
      +            cxx_compiler = sget('cxx-compiler')
      +            archiver = sget('archiver')
      +            config_file = sget('config-file')
      +            allocate(fpm_run_settings :: cmd_settings)
      +            val_runner=sget('runner')
      +            if(specified('runner') .and. val_runner=='')val_runner='echo'
      +
      +            cmd_settings=fpm_run_settings(&
      +            & args=remaining,&
      +            & profile=val_profile,&
      +            & prune=.not.lget('no-prune'), &
      +            & compiler=val_compiler, &
      +            & c_compiler=c_compiler, &
      +            & cxx_compiler=cxx_compiler, &
      +            & archiver=archiver, &
      +            & path_to_config=config_file, &
      +            & flag=val_flag, &
      +            & cflag=val_cflag, &
      +            & cxxflag=val_cxxflag, &
      +            & ldflag=val_ldflag, &
      +            & example=lget('example'), &
      +            & list=lget('list'),&
      +            & build_tests=.false.,&
      +            & name=names,&
      +            & runner=val_runner,&
      +            & runner_args=val_runner_args, &
      +            & verbose=lget('verbose') )
      +
      +        case('build')
      +            call set_args(common_args // compiler_args //'&
      +            & --list F &
      +            & --show-model F &
      +            & --dump " " &
      +            & --tests F &
      +            & --config-file " " &
      +            & --',help_build,version_text)
      +
      +            call check_build_vals()
      +
      +            c_compiler = sget('c-compiler')
      +            cxx_compiler = sget('cxx-compiler')
      +            archiver = sget('archiver')
      +            config_file = sget('config-file')
      +            val_dump = sget('dump')
      +            if (specified('dump') .and. val_dump=='')val_dump='fpm_model.toml'
      +
      +            allocate( fpm_build_settings :: cmd_settings )
      +            cmd_settings=fpm_build_settings(  &
      +            & profile=val_profile,&
      +            & dump=val_dump,&
      +            & prune=.not.lget('no-prune'), &
      +            & compiler=val_compiler, &
      +            & c_compiler=c_compiler, &
      +            & cxx_compiler=cxx_compiler, &
      +            & archiver=archiver, &
      +            & path_to_config=config_file, &
      +            & flag=val_flag, &
      +            & cflag=val_cflag, &
      +            & cxxflag=val_cxxflag, &
      +            & ldflag=val_ldflag, &
      +            & list=lget('list'),&
      +            & show_model=lget('show-model'),&
      +            & build_tests=lget('tests'),&
      +            & verbose=lget('verbose') )
      +
      +        case('new')
      +            call set_args(common_args // '&
      +            & --src F &
      +            & --lib F &
      +            & --app F &
      +            & --test F &
      +            & --example F &
      +            & --backfill F &
      +            & --full F &
      +            & --bare F &
      +            &', help_new, version_text)
      +            select case(size(unnamed))
      +            case(1)
      +                if(lget('backfill'))then
      +                   name='.'
      +                else
      +                   write(stderr,'(*(7x,g0,/))') &
      +                   & '<USAGE> fpm new NAME [[--lib|--src] [--app] [--test] [--example]]|[--full|--bare] [--backfill]'
      +                   call fpm_stop(1,'directory name required')
      +                endif
      +            case(2)
      +                name=trim(unnamed(2))
      +            case default
      +                write(stderr,'(7x,g0)') &
      +                & '<USAGE> fpm new NAME [[--lib|--src] [--app] [--test] [--example]]| [--full|--bare] [--backfill]'
      +                call fpm_stop(2,'only one directory name allowed')
      +            end select
      +            !*! canon_path is not converting ".", etc.
      +            if(name=='.')then
      +               call get_current_directory(name, error)
      +               if (allocated(error)) then
      +                  write(stderr, '("[Error]", 1x, a)') error%message
      +                  stop 1
      +               endif
      +            endif
      +            name=canon_path(name)
      +            if( .not.is_fortran_name(to_fortran_name(basename(name))) )then
      +                write(stderr,'(g0)') [ character(len=72) :: &
      +                & '<ERROR> the fpm project name must be made of up to 63 ASCII letters,', &
      +                & '        numbers, underscores, or hyphens, and start with a letter.']
      +                call fpm_stop(4,' ')
      +            endif
      +
      +            allocate(fpm_new_settings :: cmd_settings)
      +            if (any( specified([character(len=10) :: 'src','lib','app','test','example','bare'])) &
      +            & .and.lget('full') )then
      +                write(stderr,'(*(a))')&
      +                &'<ERROR> --full and any of [--src|--lib,--app,--test,--example,--bare]', &
      +                &'        are mutually exclusive.'
      +                call fpm_stop(5,' ')
      +            elseif (any( specified([character(len=10) :: 'src','lib','app','test','example','full'])) &
      +            & .and.lget('bare') )then
      +                write(stderr,'(*(a))')&
      +                &'<ERROR> --bare and any of [--src|--lib,--app,--test,--example,--full]', &
      +                &'        are mutually exclusive.'
      +                call fpm_stop(3,' ')
      +            elseif (any( specified([character(len=10) :: 'src','lib','app','test','example']) ) )then
      +                cmd_settings=fpm_new_settings(&
      +                 & backfill=lget('backfill'),               &
      +                 & name=name,                               &
      +                 & with_executable=lget('app'),             &
      +                 & with_lib=any([lget('lib'),lget('src')]), &
      +                 & with_test=lget('test'),                  &
      +                 & with_example=lget('example'),            &
      +                 & verbose=lget('verbose') )
      +            else  ! default if no specific directories are requested
      +                cmd_settings=fpm_new_settings(&
      +                 & backfill=lget('backfill') ,           &
      +                 & name=name,                            &
      +                 & with_executable=.true.,               &
      +                 & with_lib=.true.,                      &
      +                 & with_test=.true.,                     &
      +                 & with_example=lget('full'),            &
      +                 & with_full=lget('full'),               &
      +                 & with_bare=lget('bare'),               &
      +                 & verbose=lget('verbose') )
      +            endif
      +
      +        case('help', 'manual')
      +            call set_args(common_args, help_help,version_text)
      +            if(size(unnamed)<2)then
      +                if(unnamed(1)=='help')then
      +                   unnamed=['   ', 'fpm']
      +                else
      +                   unnamed=manual
      +                endif
      +            elseif(unnamed(2)=='manual')then
      +                unnamed=manual
      +            endif
      +            allocate(character(len=widest) :: help_text(0))
      +            do i=2,size(unnamed)
      +                select case(unnamed(i))
      +                case('       ' )
      +                case('fpm    ' )
      +                   help_text=[character(len=widest) :: help_text, help_fpm]
      +                case('new    ' )
      +                   help_text=[character(len=widest) :: help_text, help_new]
      +                case('build  ' )
      +                   help_text=[character(len=widest) :: help_text, help_build]
      +                case('install' )
      +                   help_text=[character(len=widest) :: help_text, help_install]
      +                case('run    ' )
      +                   help_text=[character(len=widest) :: help_text, help_run]
      +                case('test   ' )
      +                   help_text=[character(len=widest) :: help_text, help_test]
      +                case('runner' )
      +                   help_text=[character(len=widest) :: help_text, help_runner]
      +                case('list   ' )
      +                   help_text=[character(len=widest) :: help_text, help_list]
      +                case('update ' )
      +                   help_text=[character(len=widest) :: help_text, help_update]
      +                case('help   ' )
      +                   help_text=[character(len=widest) :: help_text, help_help]
      +                case('version' )
      +                   help_text=[character(len=widest) :: help_text, version_text]
      +                case('clean' )
      +                   help_text=[character(len=widest) :: help_text, help_clean]
      +                case('publish')
      +                   help_text=[character(len=widest) :: help_text, help_publish]
      +                case default
      +                   help_text=[character(len=widest) :: help_text, &
      +                   & '<ERROR> unknown help topic "'//trim(unnamed(i))//'"']
      +                   !!& '<ERROR> unknown help topic "'//trim(unnamed(i)).'not found in:',manual]
      +                end select
      +            enddo
      +            call printhelp(help_text)
      +
      +        case('install')
      +            call set_args(common_args // compiler_args // '&
      +                & --no-rebuild F &
      +                & --prefix " " &
      +                & --list F &
      +                & --test F &
      +                & --libdir "lib" &
      +                & --bindir "bin" &
      +                & --testdir "test" &
      +                & --includedir "include" &
      +                & --config-file " " &
      +                &', help_install, version_text)
      +
      +            call check_build_vals()
      +
      +            c_compiler = sget('c-compiler')
      +            cxx_compiler = sget('cxx-compiler')
      +            archiver = sget('archiver')
      +            config_file = sget('config-file')
      +            allocate(install_settings, source=fpm_install_settings(&
      +                list=lget('list'), &
      +                build_tests=lget('test'), &
      +                profile=val_profile,&
      +                prune=.not.lget('no-prune'), &
      +                compiler=val_compiler, &
      +                c_compiler=c_compiler, &
      +                cxx_compiler=cxx_compiler, &
      +                archiver=archiver, &
      +                path_to_config=config_file, &
      +                flag=val_flag, &
      +                cflag=val_cflag, &
      +                cxxflag=val_cxxflag, &
      +                ldflag=val_ldflag, &
      +                no_rebuild=lget('no-rebuild'), &
      +                verbose=lget('verbose')))
      +            call get_char_arg(install_settings%prefix, 'prefix')
      +            call get_char_arg(install_settings%libdir, 'libdir')
      +            call get_char_arg(install_settings%testdir, 'testdir')
      +            call get_char_arg(install_settings%bindir, 'bindir')
      +            call get_char_arg(install_settings%includedir, 'includedir')
      +            call move_alloc(install_settings, cmd_settings)
      +
      +        case('list')
      +            call set_args(common_args // '&
      +            & --list F &
      +            &', help_list, version_text)
      +            if(lget('list'))then
      +                help_text = [character(widest) :: help_list_nodash, help_list_dash]
      +            else
      +                help_text = help_list_nodash
      +            endif
      +            call printhelp(help_text)
      +
      +        case('test')
      +            call set_args(common_args // compiler_args // run_args // '&
      +            & --config-file " " &
      +            & -- ', help_test,version_text)
      +
      +            call check_build_vals()
      +
      +            if( size(unnamed) > 1 )then
      +                names=unnamed(2:)
      +            else
      +                names=[character(len=len(names)) :: ]
      +            endif
      +
      +            if(specified('target') )then
      +               call split(sget('target'),tnames,delimiters=' ,:')
      +               names=[character(len=max(len(names),len(tnames))) :: names,tnames]
      +            endif
      +
      +            ! convert special string '..' to equivalent (shorter) '*'
      +            ! to allow for a string that does not require shift-key and quoting
      +            do i=1,size(names)
      +               if(names(i)=='..')names(i)='*'
      +            enddo
      +
      +            ! If there are additional command-line arguments, remove the additional
      +            ! double quotes which have been added by M_CLI2
      +            val_runner_args=sget('runner-args')
      +            call remove_characters_in_set(val_runner_args,set='"')
      +
      +            c_compiler = sget('c-compiler')
      +            cxx_compiler = sget('cxx-compiler')
      +            archiver = sget('archiver')
      +            config_file = sget('config-file')
      +
      +            allocate(fpm_test_settings :: cmd_settings)
      +            val_runner=sget('runner')
      +            if(specified('runner') .and. val_runner=='')val_runner='echo'
      +
      +            cmd_settings=fpm_test_settings(&
      +            & args=remaining, &
      +            & profile=val_profile, &
      +            & prune=.not.lget('no-prune'), &
      +            & compiler=val_compiler, &
      +            & c_compiler=c_compiler, &
      +            & cxx_compiler=cxx_compiler, &
      +            & archiver=archiver, &
      +            & path_to_config=config_file, &
      +            & flag=val_flag, &
      +            & cflag=val_cflag, &
      +            & cxxflag=val_cxxflag, &
      +            & ldflag=val_ldflag, &
      +            & example=.false., &
      +            & list=lget('list'), &
      +            & build_tests=.true., &
      +            & name=names, &
      +            & runner=val_runner, &
      +            & runner_args=val_runner_args, &
      +            & verbose=lget('verbose'))
      +
      +        case('update')
      +            call set_args(common_args // '&
      +            & --fetch-only F &
      +            & --clean F &
      +            & --dump " " &
      +            & --config-file " " &
      +            &', help_update, version_text)
      +
      +            if( size(unnamed) > 1 )then
      +                names=unnamed(2:)
      +            else
      +                names=[character(len=len(names)) :: ]
      +            endif
      +
      +
      +            config_file = sget('config-file')
      +            val_dump = sget('dump')
      +            if (specified('dump') .and. val_dump=='')val_dump='fpm_dependencies.toml'
      +
      +
      +            allocate(fpm_update_settings :: cmd_settings)
      +            cmd_settings=fpm_update_settings(name=names, &
      +            & fetch_only=lget('fetch-only'), &
      +            & dump=val_dump, &
      +            & verbose=lget('verbose'), &
      +            & path_to_config=config_file, &
      +            & clean=lget('clean'))
      +
      +        case('export')
      +
      +            call set_args(common_args // compiler_args // '&
      +                & --manifest "filename"  &
      +                & --model "filename" &
      +                & --dependencies "filename" ', &
      +                help_build, version_text)
      +
      +            call check_build_vals()
      +
      +            c_compiler = sget('c-compiler')
      +            cxx_compiler = sget('cxx-compiler')
      +            archiver = sget('archiver')
      +            allocate(export_settings, source=fpm_export_settings(&
      +                profile=val_profile,&
      +                prune=.not.lget('no-prune'), &
      +                compiler=val_compiler, &
      +                c_compiler=c_compiler, &
      +                cxx_compiler=cxx_compiler, &
      +                archiver=archiver, &
      +                flag=val_flag, &
      +                cflag=val_cflag, &
      +                show_model=.true., &
      +                cxxflag=val_cxxflag, &
      +                ldflag=val_ldflag, &
      +                verbose=lget('verbose')))
      +            call get_char_arg(export_settings%dump_model, 'model')
      +            call get_char_arg(export_settings%dump_manifest, 'manifest')
      +            call get_char_arg(export_settings%dump_dependencies, 'dependencies')
      +            call move_alloc(export_settings, cmd_settings)
      +
      +
      +        case('clean')
      +            call set_args(common_args // &
      +            &   ' --registry-cache'   // &
      +            &   ' --skip'             // &
      +            &   ' --all'              // &
      +            &   ' --config-file ""', help_clean, version_text)
      +
      +            block
      +                logical :: skip, clean_all
      +
      +                skip = lget('skip')
      +                clean_all = lget('all')
      +                config_file = sget('config-file')
      +
      +                if (all([skip, clean_all])) then
      +                    call fpm_stop(6, 'Do not specify both --skip and --all options on the clean subcommand.')
      +                end if
      +
      +                allocate(fpm_clean_settings :: cmd_settings)
      +                call get_current_directory(working_dir, error)
      +                cmd_settings = fpm_clean_settings( &
      +                &   working_dir=working_dir, &
      +                &   clean_skip=skip, &
      +                &   registry_cache=lget('registry-cache'), &
      +                &   clean_all=clean_all, &
      +                &   path_to_config=config_file)
      +            end block
      +
      +        case('publish')
      +            call set_args(common_args // compiler_args //'&
      +            & --show-package-version F &
      +            & --show-upload-data F &
      +            & --dry-run F &
      +            & --token " " &
      +            & --list F &
      +            & --show-model F &
      +            & --tests F &
      +            & --config-file " " &
      +            & --', help_publish, version_text)
      +
      +            call check_build_vals()
      +
      +            c_compiler = sget('c-compiler')
      +            cxx_compiler = sget('cxx-compiler')
      +            archiver = sget('archiver')
      +            config_file = sget('config-file')
      +            token_s = sget('token')
      +
      +            allocate(fpm_publish_settings :: cmd_settings)
      +            cmd_settings = fpm_publish_settings( &
      +            & show_package_version = lget('show-package-version'), &
      +            & show_upload_data = lget('show-upload-data'), &
      +            & is_dry_run = lget('dry-run'), &
      +            & profile=val_profile,&
      +            & prune=.not.lget('no-prune'), &
      +            & compiler=val_compiler, &
      +            & c_compiler=c_compiler, &
      +            & cxx_compiler=cxx_compiler, &
      +            & archiver=archiver, &
      +            & flag=val_flag, &
      +            & cflag=val_cflag, &
      +            & cxxflag=val_cxxflag, &
      +            & ldflag=val_ldflag, &
      +            & list=lget('list'),&
      +            & show_model=lget('show-model'),&
      +            & build_tests=lget('tests'),&
      +            & path_to_config=config_file, &
      +            & verbose=lget('verbose'),&
      +            & token=token_s)
      +
      +        case default
      +
      +            if(cmdarg.ne.''.and.which('fpm-'//cmdarg).ne.'')then
      +                call run('fpm-'//trim(cmdarg)//' '// get_command_arguments_quoted(),.false.)
      +                stop
      +            else
      +                call set_args('&
      +                & --list F&
      +                &', help_fpm, version_text)
      +                ! Note: will not get here if --version or --usage or --help
      +                ! is present on commandline
      +                if(lget('list'))then
      +                    help_text = help_list_dash
      +                elseif(len_trim(cmdarg)==0)then
      +                    write(stdout,'(*(a))')'Fortran Package Manager:'
      +                    write(stdout,'(*(a))')' '
      +                    help_text = [character(widest) :: help_list_nodash, help_usage]
      +                else
      +                    write(stderr,'(*(a))')'<ERROR> unknown subcommand [', &
      +                     & trim(cmdarg), ']'
      +                    help_text = [character(widest) :: help_list_dash, help_usage]
      +                endif
      +                call printhelp(help_text)
      +            endif
      +
      +        end select
      +
      +        if (allocated(cmd_settings)) then
      +            working_dir = sget("directory")
      +            call move_alloc(working_dir, cmd_settings%working_dir)
      +        end if
      +
      +    contains
      +
      +    subroutine check_build_vals()
      +        val_compiler=sget('compiler')
      +        if(val_compiler=='') val_compiler='gfortran'
      +
      +        val_flag = " " // sget('flag')
      +        val_cflag = " " // sget('c-flag')
      +        val_cxxflag = " " // sget('cxx-flag')
      +        val_ldflag = " " // sget('link-flag')
      +        val_profile = sget('profile')
      +
      +    end subroutine check_build_vals
      +
      +    !> Print help text and stop
      +    subroutine printhelp(lines)
      +    character(len=:),intent(in),allocatable :: lines(:)
      +    integer :: iii,ii
      +        if(allocated(lines))then
      +           ii=size(lines)
      +           if(ii > 0 .and. len(lines)> 0) then
      +               write(stdout,'(g0)')(trim(lines(iii)), iii=1, ii)
      +           else
      +               write(stdout,'(a)')'<WARNING> *printhelp* output requested is empty'
      +           endif
      +        endif
      +        stop
      +    end subroutine printhelp
      +
      +    end subroutine get_command_line_settings
      +
      +    subroutine set_help()
      +   help_list_nodash=[character(len=80) :: &
      +   'USAGE: fpm [ SUBCOMMAND [SUBCOMMAND_OPTIONS] ]|[--list|--help|--version]', &
      +   '       where SUBCOMMAND is commonly new|build|run|test                  ', &
      +   '                                                                        ', &
      +   ' subcommand may be one of                                               ', &
      +   '                                                                        ', &
      +   '  build     Compile the package placing results in the "build" directory', &
      +   '  help      Display help                                                ', &
      +   '  list      Display this list of subcommand descriptions                ', &
      +   '  new       Create a new Fortran package directory with sample files    ', &
      +   '  run       Run the local package application programs                  ', &
      +   '  test      Run the test programs                                       ', &
      +   '  update    Update and manage project dependencies                      ', &
      +   '  install   Install project                                             ', &
      +   '  clean     Delete the build                                            ', &
      +   '  publish   Publish package to the registry                             ', &
      +   '                                                                        ', &
      +   ' Enter "fpm --list" for a brief list of subcommand options. Enter       ', &
      +   ' "fpm --help" or "fpm SUBCOMMAND --help" for detailed descriptions.     ', &
      +   ' ']
      +   help_list_dash = [character(len=80) :: &
      +   '                                                                                ', &
      +   ' build [--compiler COMPILER_NAME] [--profile PROF] [--flag FFLAGS] [--list]     ', &
      +   '       [--tests] [--no-prune] [--dump [FILENAME]] [--config-file PATH]          ', &
      +   ' help [NAME(s)]                                                                 ', &
      +   ' new NAME [[--lib|--src] [--app] [--test] [--example]]|                         ', &
      +   '          [--full|--bare][--backfill]                                           ', &
      +   ' update [NAME(s)] [--fetch-only] [--clean] [--verbose] [--dump [FILENAME]]      ', &
      +   ' list [--list]                                                                  ', &
      +   ' run  [[--target] NAME(s) [--example] [--profile PROF] [--flag FFLAGS] [--all]  ', &
      +   '      [--runner "CMD"] [--compiler COMPILER_NAME] [--list] [-- ARGS]            ', &
      +   '      [--config-file PATH]                                                      ', &
      +   ' test [[--target] NAME(s)] [--profile PROF] [--flag FFLAGS] [--runner "CMD"]    ', &
      +   '      [--list] [--compiler COMPILER_NAME] [--config-file PATH] [-- ARGS]        ', &
      +   ' install [--profile PROF] [--flag FFLAGS] [--no-rebuild] [--prefix PATH]        ', &
      +   '         [--config-file PATH] [--registry-cache] [options]                      ', &
      +   ' clean [--skip] [--all] [--config-file PATH] [--registry-cache]                 ', &
      +   ' publish [--token TOKEN] [--show-package-version] [--show-upload-data]          ', &
      +   '         [--dry-run] [--verbose] [--config-file PATH]                           ', &
      +   ' ']
      +    help_usage=[character(len=80) :: &
      +    '' ]
      +    help_runner=[character(len=80) :: &
      +   'NAME                                                                            ', &
      +   '   --runner(1) - a shared option for specifying an application to launch        ', &
      +   '                 executables.                                                   ', &
      +   '                                                                                ', &
      +   'SYNOPSIS                                                                        ', &
      +   '   fpm run|test --runner CMD ... --runner-args ARGS -- SUFFIX_OPTIONS           ', &
      +   '                                                                                ', &
      +   'DESCRIPTION                                                                     ', &
      +   '   The --runner option allows specifying a program to launch                    ', &
      +   '   executables selected via the fpm(1) subcommands "run" and "test". This       ', &
      +   '   gives easy recourse to utilities such as debuggers and other tools           ', &
      +   '   that wrap other executables.                                                 ', &
      +   '                                                                                ', &
      +   '   These external commands are not part of fpm(1) itself as they vary           ', &
      +   '   from platform to platform or require independent installation.               ', &
      +   '                                                                                ', &
      +   'OPTION                                                                          ', &
      +   ' --runner ''CMD''  quoted command used to launch the fpm(1) executables.        ', &
      +   '               Available for both the "run" and "test" subcommands.             ', &
      +   '               If the keyword is specified without a value the default command  ', &
      +   '               is "echo".                                                       ', &
      +   ' --runner-args "args"    an additional option to pass command-line arguments    ', &
      +   '               to the runner command, instead of to the fpm app.                ', &
      +   ' -- SUFFIX_OPTIONS  additional options to suffix the command CMD and executable ', &
      +   '                    file names with. These options are passed as command-line   ', &
      +   '                    arguments to the app.                                       ', &
      +   'EXAMPLES                                                                        ', &
      +   '   Use cases for ''fpm run|test --runner "CMD"'' include employing              ', &
      +   '   the following common GNU/Linux and Unix commands:                            ', &
      +   '                                                                                ', &
      +   ' INTERROGATE                                                                    ', &
      +   '    + nm - list symbols from object files                                       ', &
      +   '    + size - list section sizes and total size.                                 ', &
      +   '    + ldd - print shared object dependencies                                    ', &
      +   '    + ls - list directory contents                                              ', &
      +   '    + stat - display file or file system status                                 ', &
      +   '    + file - determine file type                                                ', &
      +   ' PERFORMANCE AND DEBUGGING                                                      ', &
      +   '    + gdb - The GNU Debugger                                                    ', &
      +   '    + valgrind - a suite of tools for debugging and profiling                   ', &
      +   '    + time - time a simple command or give resource usage                       ', &
      +   '    + timeout - run a command with a time limit                                 ', &
      +   ' COPY                                                                           ', &
      +   '    + install - copy files and set attributes                                   ', &
      +   '    + tar - an archiving utility                                                ', &
      +   ' ALTER                                                                          ', &
      +   '    + rm - remove files or directories                                          ', &
      +   '    + chmod - change permissions of a file                                      ', &
      +   '    + strip - remove unnecessary information from strippable files              ', &
      +   '                                                                                ', &
      +   ' For example                                                                    ', &
      +   '                                                                                ', &
      +   '  fpm test --runner gdb                                                         ', &
      +   '  fpm run --runner "tar cvfz $HOME/bundle.tgz"                                  ', &
      +   '  fpm run --runner "mpiexec" --runner-args "-np 12"                             ', &
      +   '  fpm run --runner ldd                                                          ', &
      +   '  fpm run --runner strip                                                        ', &
      +   '  fpm run --runner ''cp -t /usr/local/bin''                                     ', &
      +   '                                                                                ', &
      +   '  # options after executable name can be specified after the -- option          ', &
      +   '  fpm --runner cp run -- /usr/local/bin/                                        ', &
      +   '  # generates commands of the form "cp $FILENAME /usr/local/bin/"               ', &
      +   '                                                                                ', &
      +   '  # bash(1) alias example:                                                      ', &
      +   '  alias fpm-install=\                                                           ', &
      +   '  "fpm run --profile release --runner ''install -vbp -m 0711 -t ~/.local/bin''" ', &
      +   '  fpm-install                                                           ', &
      +    '' ]
      +    help_fpm=[character(len=80) :: &
      +    'NAME                                                                   ', &
      +    '   fpm(1) - A Fortran package manager and build system                 ', &
      +    '                                                                       ', &
      +    'SYNOPSIS                                                               ', &
      +    '   fpm SUBCOMMAND [SUBCOMMAND_OPTIONS]                                 ', &
      +    '                                                                       ', &
      +    '   fpm --help|--version|--list                                         ', &
      +    '                                                                       ', &
      +    'DESCRIPTION                                                            ', &
      +    '   fpm(1) is a package manager that helps you create Fortran projects  ', &
      +    '   from source -- it automatically determines dependencies!            ', &
      +    '                                                                       ', &
      +    '   Most significantly fpm(1) lets you draw upon other fpm(1) packages  ', &
      +    '   in distributed git(1) repositories as if the packages were a basic  ', &
      +    '   part of your default programming environment, as well as letting    ', &
      +    '   you share your projects with others in a similar manner.            ', &
      +    '                                                                       ', &
      +    '   All output goes into the directory "build/" which can generally be  ', &
      +    '   removed and rebuilt if required. Note that if external packages are ', &
      +    '   being used you need network connectivity to rebuild from scratch.   ', &
      +    '                                                                       ', &
      +    'SUBCOMMANDS                                                            ', &
      +    '  Valid fpm(1) subcommands are:                                        ', &
      +    '                                                                       ', &
      +    '  + build    Compile the packages into the "build/" directory.         ', &
      +    '  + new      Create a new Fortran package directory with sample files. ', &
      +    '  + update   Update the project dependencies.                          ', &
      +    '  + run      Run the local package binaries. Defaults to all binaries  ', &
      +    '             for that release.                                         ', &
      +    '  + test     Run the tests.                                            ', &
      +    '  + help     Alternate to the --help switch for displaying help text.  ', &
      +    '  + list     Display brief descriptions of all subcommands.            ', &
      +    '  + install  Install project.                                          ', &
      +    '  + clean    Delete directories in the "build/" directory, except      ', &
      +    '             dependencies. Prompts for confirmation to delete.         ', &
      +    '  + publish  Publish package to the registry.                          ', &
      +    '                                                                       ', &
      +    '  Their syntax is                                                      ', &
      +    '                                                                                ', &
      +    '    build [--profile PROF] [--flag FFLAGS] [--list] [--compiler COMPILER_NAME]  ', &
      +    '          [--tests] [--no-prune] [--config-file PATH]                           ', &
      +    '          [--dump [FILENAME]]                                                   ', &
      +    '    new NAME [[--lib|--src] [--app] [--test] [--example]]|                      ', &
      +    '             [--full|--bare][--backfill]                                        ', &
      +    '    update [NAME(s)] [--fetch-only] [--clean] [--config-file PATH] [--dump [FILENAME]]', &
      +    '    run [[--target] NAME(s)] [--profile PROF] [--flag FFLAGS] [--list] [--all]  ', &
      +    '        [--example] [--runner "CMD"] [--compiler COMPILER_NAME]                 ', &
      +    '        [--no-prune] [-- ARGS] [--config-file PATH]                             ', &
      +    '    test [[--target] NAME(s)] [--profile PROF] [--flag FFLAGS] [--list]         ', &
      +    '         [--runner "CMD"] [--compiler COMPILER_NAME] [--no-prune] [-- ARGS]     ', &
      +    '         [--config-file PATH]                                                   ', &
      +    '    help [NAME(s)]                                                              ', &
      +    '    list [--list]                                                               ', &
      +    '    install [--profile PROF] [--flag FFLAGS] [--no-rebuild] [--prefix PATH]     ', &
      +    '            [options] [--config-file PATH] [--registry-cache]                    ', &
      +    '    clean [--skip] [--all] [--config-file PATH] [--registry-cache]               ', &
      +    '    publish [--token TOKEN] [--show-package-version] [--show-upload-data]       ', &
      +    '            [--dry-run] [--verbose] [--config-file PATH]                        ', &
      +    '                                                                                ', &
      +    'SUBCOMMAND OPTIONS                                                              ', &
      +    ' -C, --directory PATH', &
      +    '             Change working directory to PATH before running any command', &
      +    help_text_build_common, &
      +    help_text_compiler, &
      +    help_text_flag, &
      +    '  --list     List candidates instead of building or running them. On   ', &
      +    '             the fpm(1) command this shows a brief list of subcommands.', &
      +    '  --runner CMD  Provides a command to prefix program execution paths.  ', &
      +    '  -- ARGS    Arguments to pass to executables.                         ', &
      +    '  --skip     Delete directories in the build/ directory without        ', &
      +    '             prompting, but skip dependencies. Cannot be used together ', &
      +    '             with --all.                                               ', &
      +    '  --all      Delete directories in the build/ directory without        ', &
      +    '             prompting, including dependencies. Cannot be used together', &
      +    '             with --skip.                                              ', &
      +    '  --registry-cache  Delete registry cache.                             ', &
      +    '                                                                       ', &
      +    'VALID FOR ALL SUBCOMMANDS                                              ', &
      +    '  --help     Show help text and exit                                   ', &
      +    '  --verbose  Display additional information when available             ', &
      +    '  --version  Show version information and exit.                        ', &
      +    '                                                                       ', &
      +    '@file                                                                  ', &
      +    '   You may replace the default options for the fpm(1) command from a   ', &
      +    '   file if your first options begin with @file. Initial options will   ', &
      +    '   then be read from the "response file" "file.rsp" in the current     ', &
      +    '   directory.                                                          ', &
      +    '                                                                       ', &
      +    '   If "file" does not exist or cannot be read, then an error occurs and', &
      +    '   the program stops. Each line of the file is prefixed with "options" ', &
      +    '   and interpreted as a separate argument. The file itself may not     ', &
      +    '   contain @file arguments. That is, it is not processed recursively.  ', &
      +    '                                                                       ', &
      +    '   For more information on response files see                          ', &
      +    '                                                                       ', &
      +    '      https://urbanjost.github.io/M_CLI2/set_args.3m_cli2.html         ', &
      +    '                                                                       ', &
      +    '   The basic functionality described here will remain the same, but    ', &
      +    '   other features described at the above reference may change.         ', &
      +    '                                                                       ', &
      +    '   An example file:                                                    ', &
      +    '                                                                       ', &
      +    '     # my build options                                                ', &
      +    '     options build                                                     ', &
      +    '     options --compiler gfortran                                       ', &
      +    '     options --flag "-pg -static -pthread -Wunreachable-code -Wunused  ', &
      +    '      -Wuninitialized -g -O -fbacktrace -fdump-core -fno-underscoring  ', &
      +    '      -frecord-marker=4 -L/usr/X11R6/lib -L/usr/X11R6/lib64 -lX11"     ', &
      +    '                                                                       ', &
      +    '   Note --flag would have to be on one line as response files do not   ', &
      +    '   (currently) allow for continued lines or multiple specifications of ', &
      +    '   the same option.                                                    ', &
      +    '                                                                       ', &
      +    help_text_environment, &
      +    '                                                                       ', &
      +    'EXAMPLES                                                               ', &
      +    '   sample commands:                                                    ', &
      +    '                                                                       ', &
      +    '    fpm new mypackage --app --test                                     ', &
      +    '    fpm build                                                          ', &
      +    '    fpm test                                                           ', &
      +    '    fpm run                                                            ', &
      +    '    fpm run --example                                                  ', &
      +    '    fpm new --help                                                     ', &
      +    '    fpm run myprogram --profile release -- -x 10 -y 20 --title "my title"       ', &
      +    '    fpm install --prefix ~/.local                                               ', &
      +    '    fpm clean --all                                                             ', &
      +    '                                                                                ', &
      +    'SEE ALSO                                                                        ', &
      +    '                                                                                ', &
      +    ' + The fpm(1) home page is at https://github.com/fortran-lang/fpm               ', &
      +    ' + Registered fpm(1) packages are at https://fortran-lang.org/packages          ', &
      +    ' + The fpm(1) TOML file format is described at                                  ', &
      +    '   https://fpm.fortran-lang.org/spec/manifest.html                              ', &
      +    '']
      +    help_list=[character(len=80) :: &
      +    'NAME                                                                   ', &
      +    ' list(1) - list summary of fpm(1) subcommands                          ', &
      +    '                                                                       ', &
      +    'SYNOPSIS                                                               ', &
      +    ' fpm list                                                              ', &
      +    '                                                                       ', &
      +    ' fpm list --help|--version                                             ', &
      +    '                                                                       ', &
      +    'DESCRIPTION                                                            ', &
      +    ' Display a short description for each fpm(1) subcommand.               ', &
      +    '                                                                       ', &
      +    'OPTIONS                                                                ', &
      +    ' --list     display a list of command options as well. This is the     ', &
      +    '            same output as generated by "fpm --list".                  ', &
      +    '                                                                       ', &
      +    'EXAMPLES                                                               ', &
      +    ' display a short list of fpm(1) subcommands                            ', &
      +    '                                                                       ', &
      +    '  fpm list                                                             ', &
      +    '  fpm --list                                                           ', &
      +    '' ]
      +    help_run=[character(len=80) :: &
      +    'NAME                                                                   ', &
      +    ' run(1) - the fpm(1) subcommand to run project applications            ', &
      +    '                                                                       ', &
      +    'SYNOPSIS                                                               ', &
      +    ' fpm run [[--target] NAME(s)] [--profile PROF] [--flag FFLAGS]', &
      +    '         [--compiler COMPILER_NAME] [--runner "CMD"] [--example]', &
      +    '         [--list] [--all] [--config-file PATH] [-- ARGS]', &
      +    '                                                                       ', &
      +    ' fpm run --help|--version                                              ', &
      +    '                                                                       ', &
      +    'DESCRIPTION                                                            ', &
      +    ' Run the applications in your fpm(1) package. By default applications  ', &
      +    ' in /app or specified as "executable" in your "fpm.toml" manifest are  ', &
      +    ' used. Alternatively demonstration programs in example/ or specified in', &
      +    ' the "example" section in "fpm.toml" can be executed. The applications ', &
      +    ' are automatically rebuilt before being run if they are out of date.   ', &
      +    '                                                                       ', &
      +    'OPTIONS                                                                ', &
      +    ' --target NAME(s)  list of application names to execute. No name is    ', &
      +    '                   required if only one target exists. If no name is   ', &
      +    '                   supplied and more than one candidate exists or a    ', &
      +    '                   name has no match a list is produced and fpm(1)     ', &
      +    '                   exits.                                              ', &
      +    '                                                                       ', &
      +    '                   Basic "globbing" is supported where "?" represents  ', &
      +    '                   any single character and "*" represents any string. ', &
      +    '                   Note The glob string normally needs quoted to       ', &
      +    '                   the special characters from shell expansion.        ', &
      +    ' --all  Run all examples or applications. An alias for --target ''*''. ', &
      +    ' --example  Run example programs instead of applications.              ', &
      +    ' --config-file PATH  Custom location of the global config file.        ', &
      +    help_text_build_common, &
      +    help_text_compiler, &
      +    help_text_flag, &
      +    ' --runner CMD  A command to prefix the program execution paths with.   ', &
      +    '               see "fpm help runner" for further details.              ', &
      +    ' --list     list basenames of candidates instead of running them. Note ', &
      +    '            out-of-date candidates will still be rebuilt before being  ', &
      +    '            listed.                                                    ', &
      +    ' -- ARGS    optional arguments to pass to the program(s). The same     ', &
      +    '            arguments are passed to all program names specified.       ', &
      +    '                                                                       ', &
      +    help_text_environment, &
      +    '                                                                       ', &
      +    'EXAMPLES                                                               ', &
      +    ' fpm(1) - run or display project applications:                         ', &
      +    '                                                                       ', &
      +    '  fpm run        # run a target when only one exists or list targets   ', &
      +    '  fpm run --list # list basename of all targets, running nothing.      ', &
      +    '  fpm run "demo*" --list # list target basenames starting with "demo*".', &
      +    '  fpm run "psi*" --runner # list target pathnames starting with "psi*".', &
      +    '  fpm run --all  # run all targets, no matter how many there are.      ', &
      +    '                                                                       ', &
      +    '  # run default program built or to be built with the compiler command ', &
      +    '  # "f90". If more than one app exists a list displays and target names', &
      +    '  # are required.                                                      ', &
      +    '  fpm run --compiler f90                                               ', &
      +    '                                                                       ', &
      +    '  # run example programs instead of the application programs.          ', &
      +    '  fpm run --example "*"                                                ', &
      +    '                                                                       ', &
      +    '  # run a specific program and pass arguments to the command           ', &
      +    '  fpm run myprog -- -x 10 -y 20 --title "my title line"                ', &
      +    '                                                                       ', &
      +    '  # run production version of two applications                         ', &
      +    '  fpm run --target prg1,prg2 --profile release                         ', &
      +    '                                                                       ', &
      +    '  # install executables in directory (assuming install(1) exists)      ', &
      +    '  fpm run --runner ''install -b -m 0711 -p -t /usr/local/bin''         ', &
      +    '' ]
      +    help_build=[character(len=80) :: &
      +    'NAME                                                                   ', &
      +    ' build(1) - the fpm(1) subcommand to build a project                   ', &
      +    '                                                                       ', &
      +    'SYNOPSIS                                                               ', &
      +    ' fpm build [--profile PROF] [--flag FFLAGS] [--compiler COMPILER_NAME] ', &
      +    '           [--list] [--tests] [--config-file PATH] [--dump [FILENAME]] ', &
      +    '                                                                       ', &
      +    ' fpm build --help|--version                                            ', &
      +    '                                                                       ', &
      +    'DESCRIPTION                                                            ', &
      +    ' The "fpm build" command                                               ', &
      +    '    o Fetches any dependencies                                         ', &
      +    '    o Scans your sources                                               ', &
      +    '    o Builds them in the proper order                                  ', &
      +    '                                                                       ', &
      +    ' The Fortran source files are assumed by default to be in              ', &
      +    '    o src/     for modules and procedure source                        ', &
      +    '    o app/     main program(s) for applications                        ', &
      +    '    o test/    main program(s) and support files for project tests     ', &
      +    '    o example/ main program(s) for example programs                    ', &
      +    ' Changed or new files found are rebuilt. The results are placed in     ', &
      +    ' the build/ directory.                                                 ', &
      +    '                                                                       ', &
      +    ' Non-default pathnames and remote dependencies are used if             ', &
      +    ' specified in the "fpm.toml" file.                                     ', &
      +    '                                                                       ', &
      +    'OPTIONS                                                                ', &
      +    help_text_build_common,&
      +    help_text_compiler, &
      +    help_text_flag, &
      +    ' --list        list candidates instead of building or running them.    ', &
      +    '               all dependencies are downloaded, and the build sequence ', &
      +    '               is saved to `build/compile_commands.json`.              ', &
      +    ' --tests       build all tests (otherwise only if needed)              ', &
      +    ' --show-model  show the model and exit (do not build)                  ', &
      +    ' --dump [FILENAME] save model representation to file. use JSON format  ', &
      +    '                   if file name is *.json; use TOML format otherwise   ', &
      +    '                   (default file name: model.toml)                     ', &
      +    ' --help        print this help and exit                                ', &
      +    ' --version     print program version information and exit              ', &
      +    ' --config-file PATH  custom location of the global config file         ', &    
      +    '                                                                       ', &
      +    help_text_environment, &
      +    '                                                                       ', &
      +    'EXAMPLES                                                               ', &
      +    ' Sample commands:                                                      ', &
      +    '                                                                       ', &
      +    '  fpm build                   # build with debug options               ', &
      +    '  fpm build --profile release # build with high optimization           ', &
      +    '' ]
      +
      +    help_help=[character(len=80) :: &
      +    'NAME                                                                   ', &
      +    '   help(1) - the fpm(1) subcommand to display help                     ', &
      +    '                                                                       ', &
      +    'SYNOPSIS                                                               ', &
      +    '   fpm help [fpm] [new] [build] [run] [test] [help] [version] [manual] ', &
      +    '   [runner]                                                            ', &
      +    '                                                                       ', &
      +    'DESCRIPTION                                                            ', &
      +    '   The "fpm help" command is an alternative to the --help parameter    ', &
      +    '   on the fpm(1) command and its subcommands.                          ', &
      +    '                                                                       ', &
      +    'OPTIONS                                                                ', &
      +    '   NAME(s)    A list of topic names to display. All the subcommands    ', &
      +    '              have their own page (new, build, run, test, ...).        ', &
      +    '                                                                       ', &
      +    '              The special name "manual" displays all the fpm(1)        ', &
      +    '              built-in documentation.                                  ', &
      +    '                                                                       ', &
      +    '              The default is to display help for the fpm(1) command    ', &
      +    '              itself.                                                  ', &
      +    '                                                                       ', &
      +    'EXAMPLES                                                               ', &
      +    '   Sample usage:                                                       ', &
      +    '                                                                       ', &
      +    '     fpm help           # general fpm(1) command help                  ', &
      +    '     fpm help version   # show program version                         ', &
      +    '     fpm help new       # display help for "new" subcommand            ', &
      +    '     fpm help manual    # All fpm(1) built-in documentation            ', &
      +    '                                                                       ', &
      +    '' ]
      +    help_new=[character(len=80) ::                                             &
      +    'NAME                                                                   ', &
      +    ' new(1) - the fpm(1) subcommand to initialize a new project            ', &
      +    '                                                                       ', &
      +    'SYNOPSIS                                                               ', &
      +    ' fpm new NAME [[--lib|--src] [--app] [--test] [--example]]|            ', &
      +    '              [--full|--bare][--backfill]                              ', &
      +    ' fpm new --help|--version                                              ', &
      +    '                                                                       ', &
      +    'DESCRIPTION                                                            ', &
      +    ' "fpm new" creates and populates a new programming project directory.  ', &
      +    '                                                                       ', &
      +    ' It                                                                    ', &
      +    '   o creates a directory with the specified name                       ', &
      +    '   o runs the command "git init" in that directory                     ', &
      +    '   o populates the directory with the default project directories      ', &
      +    '   o adds sample Fortran source files                                  ', &
      +    '                                                                       ', &
      +    ' The default file structure (that will be automatically scanned) is    ', &
      +    '                                                                       ', &
      +    '     NAME/                                                             ', &
      +    '       fpm.toml                                                        ', &
      +    '       src/                                                            ', &
      +    '           NAME.f90                                                    ', &
      +    '       app/                                                            ', &
      +    '           main.f90                                                    ', &
      +    '       test/                                                           ', &
      +    '           check.f90                                                   ', &
      +    '       example/                                                        ', &
      +    '           demo.f90                                                    ', &
      +    '                                                                       ', &
      +    ' Using this file structure is highly encouraged, particularly for      ', &
      +    ' small packages primarily intended to be used as dependencies.         ', &
      +    '                                                                       ', &
      +    ' If you find this restrictive and need to customize the package        ', &
      +    ' structure you will find using the --full switch creates a             ', &
      +    ' heavily annotated manifest file with references to documentation      ', &
      +    ' to aid in constructing complex package structures.                    ', &
      +    '                                                                       ', &
      +    ' Remember to update the information in the sample "fpm.toml"           ', &
      +    ' file with your name and e-mail address.                               ', &
      +    '                                                                       ', &
      +    'OPTIONS                                                                ', &
      +    ' NAME   the name of the project directory to create. The name          ', &
      +    '        must be made of up to 63 ASCII letters, digits, underscores,   ', &
      +    '        or hyphens, and start with a letter.                           ', &
      +    '                                                                       ', &
      +    ' The default is to create the src/, app/, and test/ directories.       ', &
      +    ' If any of the following options are specified then only the           ', &
      +    ' selected subdirectories are generated:                                ', &
      +    '                                                                       ', &
      +    ' --lib,--src  create directory src/ and a placeholder module           ', &
      +    '              named "NAME.f90" for use with subcommand "build".        ', &
      +    ' --app        create directory app/ and a placeholder main             ', &
      +    '              program for use with subcommand "run".                   ', &
      +    ' --test       create directory test/ and a placeholder program         ', &
      +    '              for use with the subcommand "test". Note that sans       ', &
      +    '              "--lib" it really does not have anything to test.        ', &
      +    ' --example    create directory example/ and a placeholder program      ', &
      +    '              for use with the subcommand "run --example".             ', &
      +    '              It is only created by default if "--full is" specified.  ', &
      +    '                                                                       ', &
      +    ' So the default is equivalent to                                        ',&
      +    '                                                                       ', &
      +    '    fpm NAME --lib --app --test                                        ', &
      +    '                                                                       ', &
      +    ' --backfill   By default the directory must not exist. If this         ', &
      +    '              option is present the directory may pre-exist and        ', &
      +    '              only subdirectories and files that do not                ', &
      +    '              already exist will be created. For example, if you       ', &
      +    '              previously entered "fpm new myname --lib" entering       ', &
      +    '              "fpm new myname -full --backfill" will create any missing', &
      +    '              app/, example/, and test/ directories and programs.      ', &
      +    '                                                                       ', &
      +    ' --full       By default a minimal manifest file ("fpm.toml") is       ', &
      +    '              created that depends on auto-discovery. With this        ', &
      +    '              option a much more extensive manifest sample is written  ', &
      +    '              and the example/ directory is created and populated.     ', &
      +    '              It is designed to facilitate creating projects that      ', &
      +    '              depend extensively on non-default build options.         ', &
      +    '                                                                       ', &
      +    ' --bare       A minimal manifest file ("fpm.toml") is created and      ', &
      +    '              "README.md" file is created but no directories or        ', &
      +    '              sample Fortran are generated.                            ', &
      +    '                                                                       ', &
      +    ' --help       print this help and exit                                 ', &
      +    ' --version    print program version information and exit               ', &
      +    '                                                                       ', &
      +    'EXAMPLES                                                               ', &
      +    ' Sample use                                                            ', &
      +    '                                                                       ', &
      +    '   fpm new myproject  # create new project directory and seed it       ', &
      +    '   cd myproject       # Enter the new directory                        ', &
      +    '   # and run commands such as                                          ', &
      +    '   fpm build                                                           ', &
      +    '   fpm run            # run lone example application program           ', &
      +    '   fpm test           # run example test program(s)                    ', &
      +    '   fpm run --example  # run lone example program                       ', &
      +    '                                                                       ', &
      +    '   fpm new A --full # create example/ and an annotated fpm.toml as well', &
      +    '   fpm new A --bare # create no directories                            ', &
      +    '   create any missing files in current directory                       ', &
      +    '   fpm new --full --backfill                                           ', &
      +    '' ]
      +    help_test=[character(len=80) :: &
      +    'NAME                                                                   ', &
      +    ' test(1) - the fpm(1) subcommand to run project tests                  ', &
      +    '                                                                       ', &
      +    'SYNOPSIS                                                               ', &
      +    ' fpm test [[--target] NAME(s)] [--profile PROF] [--flag FFLAGS]        ', &
      +    '          [--compiler COMPILER_NAME ] [--runner "CMD"] [--list]        ', &
      +    '          [-- ARGS] [--config-file PATH]                               ', &
      +    '                                                                       ', &
      +    ' fpm test --help|--version                                             ', &
      +    '                                                                       ', &
      +    'DESCRIPTION                                                            ', &
      +    ' Run applications you have built to test your project.                 ', &
      +    '                                                                       ', &
      +    'OPTIONS                                                                ', &
      +    ' --target NAME(s)  optional list of specific test names to execute.    ', &
      +    '                   The default is to run all the tests in test/        ', &
      +    '                   or the tests listed in the "fpm.toml" file.         ', &
      +    '                                                                       ', &
      +    '                   Basic "globbing" is supported where "?" represents  ', &
      +    '                   any single character and "*" represents any string. ', &
      +    '                   Note The glob string normally needs quoted to       ', &
      +    '                   protect the special characters from shell expansion.', &
      +    help_text_build_common,&
      +    help_text_compiler, &
      +    help_text_flag, &
      +    ' --runner CMD  A command to prefix the program execution paths with.   ', &
      +    '               see "fpm help runner" for further details.              ', &
      +    ' --list     list candidate basenames instead of running them. Note they', &
      +    ' --list     will still be built if not currently up to date.           ', &
      +    ' --config-file PATH  Custom location of the global config file.        ', &
      +    ' -- ARGS    optional arguments to pass to the test program(s).         ', &
      +    '            The same arguments are passed to all test names            ', &
      +    '            specified.                                                 ', &
      +    '                                                                       ', &
      +    help_text_environment, &
      +    '                                                                       ', &
      +    'EXAMPLES                                                               ', &
      +    'run tests                                                              ', &
      +    '                                                                       ', &
      +    ' # run default tests in /test or as specified in "fpm.toml"            ', &
      +    ' fpm test                                                              ', &
      +    '                                                                       ', &
      +    ' # run using compiler command "f90"                                    ', &
      +    ' fpm test --compiler f90                                               ', &
      +    '                                                                       ', &
      +    ' # run a specific test and pass arguments to the command               ', &
      +    ' fpm test mytest -- -x 10 -y 20 --title "my title line"                ', &
      +    '                                                                       ', &
      +    ' fpm test tst1 tst2 --profile PROF  # run production version of two tests', &
      +    '' ]
      +    help_update=[character(len=80) :: &
      +    'NAME', &
      +    ' update(1) - manage project dependencies', &
      +    '', &
      +    'SYNOPSIS', &
      +    ' fpm update [--fetch-only] [--clean] [--verbose] [--dump [FILENAME]] [NAME(s)]', &
      +    '            [--config-file PATH] ', &
      +    '', &
      +    'DESCRIPTION', &
      +    ' Manage and update project dependencies. If no dependency names are', &
      +    ' provided all the dependencies are updated automatically.', &
      +    '', &
      +    'OPTIONS', &
      +    ' --fetch-only        Only fetch dependencies, do not update existing projects', &
      +    ' --clean             Do not use previous dependency cache', &
      +    ' --config-file PATH  Custom location of the global config file', &
      +    ' --verbose           Show additional printout', &
      +    ' --dump [FILENAME]   Dump updated dependency tree to file. use JSON format  ', &
      +    '                     if file name is *.json; use TOML format otherwise      ', &
      +    '                     (default file name: fpm_dependencies.toml)             ', &
      +    '', &
      +    'SEE ALSO', &
      +    ' The fpm(1) home page at https://github.com/fortran-lang/fpm', &
      +    '' ]
      +    help_install=[character(len=80) :: &
      +    'NAME', &
      +    ' install(1) - install fpm projects', &
      +    '', &
      +    'SYNOPSIS', &
      +    ' fpm install [--profile PROF] [--flag FFLAGS] [--list] [--no-rebuild]', &
      +    '             [--prefix DIR] [--bindir DIR] [--libdir DIR] [--includedir DIR]', &
      +    '             [--verbose] [--config-file PATH]', &
      +    '', &
      +    'DESCRIPTION', &
      +    ' Subcommand to install fpm projects. Running install will export the', &
      +    ' current project to the selected prefix, this will by default install all', &
      +    ' executables (tests and examples are excluded) which are part of the projects.', &
      +    ' Libraries and module files are only installed for projects requiring the', &
      +    ' installation of those components in the package manifest.', &
      +    '', &
      +    'OPTIONS', &
      +    ' --list            list all installable targets for this project,', &
      +    '                   but do not install any of them', &
      +    help_text_build_common,&
      +    help_text_flag, &
      +    ' --no-rebuild        do not rebuild project before installation', &
      +    ' --test              also install test programs', &    
      +    ' --prefix DIR        path to installation directory (requires write access),', &
      +    '                     the default prefix on Unix systems is $HOME/.local', &
      +    '                     and %APPDATA%\local on Windows', &
      +    ' --bindir DIR        subdirectory to place executables in (default: bin)', &
      +    ' --libdir DIR        subdirectory to place libraries and archives in', &
      +    '                     (default: lib)', &
      +    ' --includedir DIR    subdirectory to place headers and module files in', &
      +    '                     (default: include)', &
      +    ' --testdir DIR       subdirectory to place test programs in (default: test)', &     
      +    ' --config-file PATH  custom location of the global config file', &
      +    ' --verbose           print more information', &
      +    '', &
      +    help_text_environment, &
      +    '', &
      +    'EXAMPLES', &
      +    ' 1. Install release version of project:', &
      +    '', &
      +    '    fpm install --profile release', &
      +    '', &
      +    ' 2. Install the project without rebuilding the executables:', &
      +    '', &
      +    '    fpm install --no-rebuild', &
      +    '', &
      +    ' 3. Install executables to a custom prefix into the exe directory:', &
      +    '', &
      +    '    fpm install --prefix $PWD --bindir exe', &
      +    ' 4. Install executables and test programs into the same "exe" directory:', &
      +    '', &
      +    '    fpm install --prefix $PWD --test --bindir exe --testdir exe', &
      +    '' ]
      +    help_clean=[character(len=80) :: &
      +    'NAME', &
      +    ' clean(1) - delete the build', &
      +    '', &
      +    'SYNOPSIS', &
      +    ' fpm clean', &
      +    '', &
      +    'DESCRIPTION', &
      +    ' Prompts the user to confirm deletion of the build. If affirmative,', &
      +    ' directories in the build/ directory are deleted, except dependencies.', &
      +    ' Use the --registry-cache option to delete the registry cache.', &
      +    '', &
      +    'OPTIONS', &
      +    ' --skip              Delete the build without prompting but skip dependencies.', &
      +    ' --all               Delete the build without prompting including dependencies.', &
      +    ' --config-file PATH  Custom location of the global config file.', &
      +    ' --registry-cache    Delete registry cache.', &
      +    '' ]
      +    help_publish=[character(len=80) :: &
      +    'NAME', &
      +    ' publish(1) - publish package to the registry', &
      +    '', &
      +    'SYNOPSIS', &
      +    ' fpm publish [--token TOKEN] [--show-package-version] [--show-upload-data]', &
      +    '             [--dry-run] [--verbose] [--config-file PATH]', &
      +    '', &
      +    ' fpm publish --help|--version', &
      +    '', &
      +    'DESCRIPTION', &
      +    ' Follow the steps to create a tarball and upload a package to the registry:', &
      +    '', &
      +    '  1. Register on the website (https://registry-phi.vercel.app/).', &
      +    '  2. Create a namespace. Uploaded packages must be assigned to a unique', &
      +    '     namespace to avoid conflicts among packages with similar names. A', &
      +    '     namespace can accommodate multiple packages.', &
      +    '  3. Create a token for that namespace. A token is linked to your username', &
      +    '     and is used to authenticate you during the upload process. Do not share', &
      +    '     the token with others.', &
      +    '  4. Run fpm publish --token TOKEN to upload the package to the registry.', &
      +    '     But be aware that the upload is permanent. An uploaded package cannot be', &
      +    '     deleted.', &
      +    '', &
      +    ' See documentation for more information regarding package upload and usage:', &
      +    '', &
      +    ' Package upload:', &
      +    ' https://fpm.fortran-lang.org/spec/publish.html', &
      +    '', &
      +    ' Package usage:', &
      +    ' https://fpm.fortran-lang.org/spec/manifest.html#dependencies-from-a-registry', &
      +    '', &
      +    'OPTIONS', &
      +    ' --show-package-version   show package version without publishing', &
      +    ' --show-upload-data       show upload data without publishing', &
      +    ' --dry-run                perform dry run without publishing', &
      +    ' --help                   print this help and exit', &
      +    ' --version                print program version information and exit', &
      +    ' --config-file PATH       custom location of the global config file', &
      +    ' --verbose                print more information', &
      +    '', &
      +    'EXAMPLES', &
      +    '', &
      +    ' fpm publish --show-package-version    # show package version without publishing', &
      +    ' fpm publish --show-upload-data        # show upload data without publishing', &
      +    ' fpm publish --token TOKEN --dry-run   # perform dry run without publishing', &
      +    ' fpm publish --token TOKEN             # upload package to the registry', &
      +    '' ]
      +     end subroutine set_help
      +
      +    subroutine get_char_arg(var, arg)
      +      character(len=:), allocatable, intent(out) :: var
      +      character(len=*), intent(in) :: arg
      +      var = sget(arg)
      +      if (len_trim(var) == 0) deallocate(var)
      +    end subroutine get_char_arg
      +
      +
      +    !> Get an environment variable for fpm, this routine ensures that every variable
      +    !> used by fpm is prefixed with FPM_.
      +    function get_fpm_env(env, default) result(val)
      +      character(len=*), intent(in) :: env
      +      character(len=*), intent(in) :: default
      +      character(len=:), allocatable :: val
      +
      +      character(len=*), parameter :: fpm_prefix = "FPM_"
      +
      +      val = get_env(fpm_prefix//env, default)
      +    end function get_fpm_env
      +
      +
      +    !> Build a full runner command (executable + command-line arguments)
      +    function runner_command(cmd) result(run_cmd)
      +        class(fpm_run_settings), intent(in) :: cmd
      +        character(len=:), allocatable :: run_cmd
      +        !> Get executable
      +        if (len_trim(cmd%runner)>0) then
      +            run_cmd = trim(cmd%runner)
      +        else
      +            run_cmd = ''
      +        end if
      +        !> Append command-line arguments
      +        if (len_trim(cmd%runner_args)>0) run_cmd = run_cmd//' '//trim(cmd%runner_args)
      +    end function runner_command
      +
      +    !> Check name in list ID. return 0 if not found
      +    integer function name_ID(cmd,name)
      +       class(fpm_run_settings), intent(in) :: cmd
      +       character(*), intent(in) :: name
      +       
      +       integer :: j
      +       
      +       !> Default: not found
      +       name_ID = 0
      +       if (.not.allocated(cmd%name)) return
      +       
      +       do j=1,size(cmd%name)
      +          
      +          if (glob(trim(name),trim(cmd%name(j)))) then 
      +              name_ID = j
      +              return
      +          end if
      +          
      +       end do
      +    
      +    end function name_ID
      +
      +
      +end module fpm_command_line
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/fpm_compile_commands.f90.html b/sourcefile/fpm_compile_commands.f90.html new file mode 100644 index 0000000000..d66f0a63ed --- /dev/null +++ b/sourcefile/fpm_compile_commands.f90.html @@ -0,0 +1,649 @@ + + + + + + + + + + + + + fpm_compile_commands.F90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      fpm_compile_commands.F90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      !># Store compiler commands in a `compile_commands.json` table
      +module fpm_compile_commands
      +    use fpm_toml, only: serializable_t, set_string, set_list, get_value, get_list, add_table, &
      +        toml_array, add_array, toml_stat, len
      +    use tomlf, only: toml_table
      +    use jonquil, only: json_serialize, json_ser_config
      +    use fpm_strings, only: string_t, operator(==)
      +    use fpm_error, only: error_t, syntax_error, fatal_error
      +    use fpm_os, only: get_current_directory
      +    use fpm_environment, only: get_os_type, OS_WINDOWS
      +    use shlex_module, only: sh_split => split, ms_split
      +    implicit none
      +    
      +    !> Definition of a build command
      +    type, extends(serializable_t) :: compile_command_t
      +        
      +        type(string_t) :: directory
      +        
      +        type(string_t), allocatable :: arguments(:)
      +        
      +        type(string_t) :: file
      +        
      +        contains
      +        
      +        !> Operation
      +        procedure :: destroy              => compile_command_destroy
      +        
      +        !> Serialization interface
      +        procedure :: serializable_is_same => compile_command_is_same
      +        procedure :: dump_to_toml         => compile_command_dump_toml
      +        procedure :: load_from_toml       => compile_command_load_toml
      +        
      +    end type compile_command_t    
      +    
      +    type, extends(serializable_t) :: compile_command_table_t
      +        
      +        type(compile_command_t), allocatable :: command(:)
      +        
      +        contains
      +        
      +        !> Operation
      +        procedure :: destroy              => cct_destroy        
      +        procedure :: write                => cct_write
      +        
      +        procedure, private :: cct_register
      +        procedure, private :: cct_register_object
      +        generic   :: register             => cct_register, &
      +                                             cct_register_object
      +        
      +        !> Serialization interface
      +        procedure :: serializable_is_same => cct_is_same
      +        procedure :: dump_to_toml         => cct_dump_toml
      +        procedure :: load_from_toml       => cct_load_toml
      +        
      +        
      +    end type compile_command_table_t    
      +    
      +    interface compile_command_t
      +        module procedure cct_new
      +    end interface compile_command_t
      +    
      +    contains
      +    
      +    !> Override default initializer (GCC 15 bug)
      +    type(compile_command_t) function cct_new(directory,arguments,file) result(cct)
      +        character(len=*), intent(in) :: directory,file
      +        character(len=*), optional, intent(in) :: arguments(:)
      +        
      +        integer :: i,n
      +        
      +        cct%directory = string_t(trim(directory))
      +        cct%file = string_t(trim(file))
      +        
      +        if (present(arguments)) then 
      +           n = size(arguments)
      +        else
      +           n = 0
      +        endif
      +        allocate(cct%arguments(n))
      +        do i=1,n
      +            cct%arguments(i) = string_t(trim(arguments(i)))
      +        end do
      +        
      +    end function cct_new  
      +      
      +    !> Cleanup compile command
      +    elemental subroutine compile_command_destroy(self)
      +    
      +        !> Instance of the serializable object
      +        class(compile_command_t), intent(inout) :: self    
      +        
      +        if (allocated(self%directory%s))deallocate(self%directory%s)
      +        if (allocated(self%arguments))deallocate(self%arguments)
      +        if (allocated(self%file%s))deallocate(self%file%s)
      +    
      +    end subroutine compile_command_destroy
      +        
      +    !> Dump compile_command_t to toml table
      +    subroutine compile_command_dump_toml(self, table, error)
      +
      +        !> Instance of the serializable object
      +        class(compile_command_t), intent(inout) :: self
      +
      +        !> Data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        call set_list(table, "arguments", self%arguments, error)
      +        if (allocated(error)) return
      +        call set_string(table, "directory", self%directory, error, 'compile_command_t')
      +        if (allocated(error)) return
      +        call set_string(table, "file", self%file, error, 'compile_command_t')
      +        if (allocated(error)) return    
      +
      +    end subroutine compile_command_dump_toml
      +
      +    !> Read compile_command_t from toml table (no checks made at this stage)
      +    subroutine compile_command_load_toml(self, table, error)
      +
      +        !> Instance of the serializable object
      +        class(compile_command_t), intent(inout) :: self
      +
      +        !> Data structure
      +        type(toml_table), intent(inout) :: table
      +        
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +        
      +        call self%destroy()
      +        
      +        call get_list(table, "arguments", self%arguments, error)
      +        if (allocated(error)) return           
      +        
      +        ! Return unallocated value if not present
      +        call get_value(table, "directory", self%directory%s)
      +        call get_value(table, "file", self%file%s)
      +
      +    end subroutine compile_command_load_toml
      +
      +    !> Check that two compile_command_t objects are equal
      +    logical function compile_command_is_same(this,that)
      +        class(compile_command_t), intent(in) :: this
      +        class(serializable_t), intent(in) :: that
      +
      +        compile_command_is_same = .false.
      +
      +        select type (other=>that)
      +           type is (compile_command_t)
      +
      +              if (.not.this%directory==other%directory) return
      +              if (.not.this%arguments==other%arguments) return
      +              if (.not.this%file==other%file) return
      +
      +           class default
      +              ! Not the same type
      +              return
      +        end select
      +
      +        !> All checks passed!
      +        compile_command_is_same = .true.
      +
      +    end function compile_command_is_same
      +    
      +    !> Dump compile_command_table_t to a toml array
      +    subroutine cct_dump_array(self, array, error)
      +        !> Instance of the serializable object
      +        class(compile_command_table_t), intent(inout) :: self
      +
      +        !> Data structure
      +        type(toml_array), intent(inout) :: array
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error      
      +        
      +        integer :: ii, stat
      +        type(toml_table), pointer :: item  
      +        
      +        if (.not.allocated(self%command)) return
      +        
      +        do ii = 1, size(self%command)
      +            associate (cmd => self%command(ii))
      +            
      +               ! Set node for this command
      +               call add_table(array, item, stat)
      +               if (stat /= toml_stat%success) then
      +                   call fatal_error(error, "Cannot store entry in compile_command_table_t array")
      +                   return
      +               end if                    
      +               call cmd%dump_to_toml(item, error)
      +               if (allocated(error)) return
      +
      +            endassociate
      +        end do                
      +        
      +    end subroutine cct_dump_array
      +            
      +    !> Write compile_commands.json file. Because Jonquil does not support non-named arrays, 
      +    !> create a custom json here. 
      +    subroutine cct_write(self, filename, error)
      +
      +        !> Instance of the serializable object
      +        class(compile_command_table_t), intent(inout) :: self
      +
      +        !> The file name
      +        character(*), intent(in) :: filename
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +        
      +        type(toml_array) :: array
      +        type(json_ser_config) :: cfg
      +        integer :: stat, lun
      +        
      +        ! Init array
      +        array = toml_array()
      +        
      +        ! Dump information to the array
      +        call cct_dump_array(self, array, error)
      +        if (allocated(error)) return
      +        
      +        ! Open file and write to it
      +        open(newunit=lun,file=filename,form='formatted',action='write',status='replace',iostat=stat)
      +        if (stat/=0) then 
      +            call fatal_error(error, 'cannot open file '//filename//' for writing')
      +            return
      +        end if
      +        
      +        ! Ensure the array has no key
      +        if (allocated(array%key)) deallocate(array%key)
      +        
      +        cfg%indent = repeat(' ',3)
      +        write (lun, '(A)', iostat=stat, err=1) json_serialize(array, cfg)                
      +        close(lun,iostat=stat)
      +        
      +        1 if (stat/=0) then 
      +            call fatal_error(error, 'cannot close file '//filename//' after writing')
      +            return
      +        end if
      +
      +    end subroutine cct_write
      +    
      +    !> Cleanup a compile command table
      +    elemental subroutine cct_destroy(self)
      +
      +        !> Instance of the serializable object
      +        class(compile_command_table_t), intent(inout) :: self
      +        
      +        if (allocated(self%command)) deallocate(self%command)
      +        
      +    end subroutine cct_destroy
      +    
      +    !> Register a new compile command
      +    subroutine cct_register(self, command, target_os, error)
      +
      +        !> Instance of the serializable object
      +        class(compile_command_table_t), intent(inout) :: self
      +
      +        !> Data structure
      +        character(len=*), intent(in) :: command
      +        
      +        !> The target OS of the compile_commands.json (may be cross-compiling)
      +        integer, intent(in) :: target_os
      +        
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error    
      +        
      +        ! Local variables
      +        type(compile_command_t) :: cmd
      +        character(len=:), allocatable :: args(:), cwd, source_file
      +        logical :: sh_success
      +        integer :: i,n
      +        
      +        ! Early check
      +        if (len_trim(command) <= 0) then
      +            call syntax_error(error, "compile_command_table_t trying to register an empty command")
      +            return
      +        end if
      +
      +        ! Tokenize the input command into args(:)
      +        if (target_os==OS_WINDOWS) then 
      +            args = ms_split(command, ucrt=.true., success=sh_success)
      +        else
      +            args = sh_split(command, join_spaced=.false., keep_quotes=.true., success=sh_success)
      +        end if
      +        n = size(args)
      +        
      +        if (n==0 .or. .not.sh_success) then 
      +            call syntax_error(error, "compile_command_table_t failed tokenizing: <"//command//">")
      +            return
      +        end if
      +        
      +        ! Get current working directory
      +        call get_current_directory(cwd, error)
      +        if (allocated(error)) return
      +
      +        ! Try to find the source file
      +        allocate(character(len=0) :: source_file)
      +        find_source_file: do i = 1, n-1
      +            if (args(i) == "-c") then
      +                source_file = trim(args(i+1))
      +                exit find_source_file
      +            end if
      +        end do find_source_file
      +
      +        ! Fallback: use last argument if not found
      +        if (len_trim(source_file)==0) source_file = trim(args(n))
      +
      +        ! Fill in the compile_command_t. 
      +        ! Use non-default initializer due to gcc 15 bug
      +        cmd = compile_command_t(cwd, args, source_file)
      +        
      +        ! Add it to the structure
      +        !$omp critical (command_update)
      +        call cct_register_object(self, cmd, error)
      +        !$omp end critical (command_update)
      +
      +    end subroutine cct_register
      +    
      +    pure subroutine cct_register_object(self, command, error)
      +    
      +        !> Instance of the serializable object
      +        class(compile_command_table_t), intent(inout) :: self
      +
      +        !> Data structure
      +        type(compile_command_t), intent(in) :: command
      +        
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error    
      +        
      +        if (allocated(self%command)) then         
      +           self%command = [self%command, command]
      +        else
      +           allocate(self%command(1), source=command) 
      +        end if        
      +        
      +    end subroutine cct_register_object
      +        
      +    !> Dump compile_command_table_t to toml table
      +    subroutine cct_dump_toml(self, table, error)
      +
      +        !> Instance of the serializable object
      +        class(compile_command_table_t), intent(inout) :: self
      +
      +        !> Data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +        
      +        integer :: stat, ii
      +        type(toml_array), pointer :: array
      +        
      +        ! Create array
      +        call add_array(table, 'compile_commands', array, stat=stat)
      +        if (stat/=toml_stat%success .or. .not.associated(array)) then 
      +            call fatal_error(error,"compile_command_table_t cannot create entry")
      +            return
      +        end if
      +        
      +        ! Dump to it
      +        call cct_dump_array(self, array, error)
      +
      +    end subroutine cct_dump_toml        
      +        
      +    !> Read compile_command_table_t from toml table (no checks made at this stage)
      +    subroutine cct_load_toml(self, table, error)
      +
      +        !> Instance of the serializable object
      +        class(compile_command_table_t), intent(inout) :: self
      +
      +        !> Data structure
      +        type(toml_table), intent(inout) :: table
      +        
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +        
      +        integer :: stat, i, n
      +        type(toml_array), pointer :: array
      +        type(toml_table), pointer :: elem
      +                
      +        call self%destroy()
      +        
      +        call get_value(table, key='compile_commands', ptr=array, requested=.true.,stat=stat)
      +
      +        if (stat/=toml_stat%success .or. .not.associated(array)) then 
      +            
      +            call fatal_error(error, "TOML table has no 'compile_commands' key")
      +            return
      +            
      +        else
      +            
      +            n = len(array)               
      +            if (n<=0) return
      +                    
      +            allocate(self%command(n))
      +            
      +            do i = 1, n
      +                call get_value(array, pos=i, ptr=elem, stat=stat)
      +                if (stat /= toml_stat%success .or. .not.associated(elem)) then
      +                    call fatal_error(error, "Entry in 'compile_commands' field cannot be read")
      +                    return
      +                end if
      +                
      +                call self%command(i)%load(elem, error)
      +                if (allocated(error)) return
      +                
      +            end do            
      +            
      +        end if
      +
      +    end subroutine cct_load_toml
      +
      +    !> Check that two compile_command_table_t objects are equal
      +    logical function cct_is_same(this,that)
      +        class(compile_command_table_t), intent(in) :: this
      +        class(serializable_t), intent(in) :: that
      +        
      +        integer :: i
      +
      +        cct_is_same = .false.
      +
      +        select type (other=>that)
      +           type is (compile_command_table_t)
      +            
      +              if (allocated(this%command).neqv.allocated(other%command)) return 
      +              if (allocated(this%command)) then
      +                  if (.not.(size  (this%command)  ==size  (other%command))) return
      +                  if (.not.(ubound(this%command,1)==ubound(other%command,1))) return
      +                  if (.not.(lbound(this%command,1)==lbound(other%command,1))) return
      +                  do i=lbound(this%command,1),ubound(this%command,1)
      +                     if (.not.this%command(i)==other%command(i)) return
      +                  end do
      +              end if
      +
      +           class default
      +              ! Not the same type
      +              return
      +        end select
      +
      +        !> All checks passed!
      +        cct_is_same = .true.
      +
      +    end function cct_is_same        
      +    
      +end module fpm_compile_commands
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/fpm_compiler.f90.html b/sourcefile/fpm_compiler.f90.html new file mode 100644 index 0000000000..60a9bebc95 --- /dev/null +++ b/sourcefile/fpm_compiler.f90.html @@ -0,0 +1,2097 @@ + + + + + + + + + + + + + fpm_compiler.F90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      fpm_compiler.F90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      !># Define compiler command options
      +!!
      +!! This module defines compiler options to use for the debug and release builds.
      +
      +! vendor            Fortran   C         Module output   Module include OpenMP    Free for OSS
      +!                   compiler  compiler  directory       directory
      +! Gnu               gfortran   gcc     -J              -I            -fopenmp   X
      +! Intel             ifort      icc     -module         -I            -qopenmp   X
      +! Intel(Windows)    ifort      icc     /module:path    /I            /Qopenmp   X
      +! Intel oneAPI      ifx        icx     -module         -I            -qopenmp   X
      +! PGI               pgfortran  pgcc    -module         -I            -mp        X
      +! NVIDIA            nvfortran  nvc     -module         -I            -mp        X
      +! LLVM flang        flang      clang   -module         -I            -mp        X
      +! LFortran          lfortran   ---     -J              -I            --openmp   X
      +! Lahey/Futjitsu    lfc        ?       -M              -I            -openmp    ?
      +! NAG               nagfor     ?       -mdir           -I            -openmp    x
      +! Cray              crayftn    craycc  -J              -I            -homp      ?
      +! IBM               xlf90      ?       -qmoddir        -I            -qsmp      X
      +! Oracle/Sun        ?          ?       -moddir=        -M            -xopenmp   ?
      +! Silverfrost FTN95 ftn95      ?       ?               /MOD_PATH     ?          ?
      +! Elbrus            ?          lcc     -J              -I            -fopenmp   ?
      +! Hewlett Packard   ?          ?       ?               ?             ?          discontinued
      +! Watcom            ?          ?       ?               ?             ?          discontinued
      +! PathScale         ?          ?       -module         -I            -mp        discontinued
      +! G95               ?          ?       -fmod=          -I            -fopenmp   discontinued
      +! Open64            ?          ?       -module         -I            -mp        discontinued
      +! Unisys            ?          ?       ?               ?             ?          discontinued
      +module fpm_compiler
      +use,intrinsic :: iso_fortran_env, only: stderr=>error_unit
      +use fpm_environment, only: &
      +        get_os_type, &
      +        OS_LINUX, &
      +        OS_MACOS, &
      +        OS_WINDOWS, &
      +        OS_CYGWIN, &
      +        OS_SOLARIS, &
      +        OS_FREEBSD, &
      +        OS_OPENBSD, &
      +        OS_UNKNOWN, &
      +        library_filename
      +use fpm_filesystem, only: join_path, basename, get_temp_filename, delete_file, unix_path, &
      +    & getline, run
      +use fpm_strings, only: split, string_cat, string_t, str_ends_with, str_begins_with_str, &
      +    & string_array_contains
      +use fpm_manifest, only : package_config_t
      +use fpm_error, only: error_t, fatal_error
      +use tomlf, only: toml_table
      +use fpm_toml, only: serializable_t, set_string, set_value, toml_stat, get_value
      +use fpm_compile_commands, only: compile_command_t, compile_command_table_t
      +use shlex_module, only: sh_split => split, ms_split, quote => ms_quote
      +implicit none
      +public :: compiler_t, new_compiler, archiver_t, new_archiver, get_macros
      +public :: append_clean_flags, append_clean_flags_array
      +public :: debug
      +
      +enum, bind(C)
      +    enumerator :: &
      +        id_unknown, &
      +        id_gcc, &
      +        id_f95, &
      +        id_caf, &
      +        id_intel_classic_nix, &
      +        id_intel_classic_mac, &
      +        id_intel_classic_windows, &
      +        id_intel_llvm_nix, &
      +        id_intel_llvm_windows, &
      +        id_intel_llvm_unknown, &
      +        id_pgi, &
      +        id_nvhpc, &
      +        id_nag, &
      +        id_flang, &
      +        id_flang_new, &
      +        id_f18, &
      +        id_ibmxl, &
      +        id_cray, &
      +        id_lahey, &
      +        id_lfortran
      +end enum
      +integer, parameter :: compiler_enum = kind(id_unknown)
      +
      +!> Definition of compiler object
      +type, extends(serializable_t) :: compiler_t
      +    !> Identifier of the compiler
      +    integer(compiler_enum) :: id = id_unknown
      +    !> Path to the Fortran compiler
      +    character(len=:), allocatable :: fc
      +    !> Path to the C compiler
      +    character(len=:), allocatable :: cc
      +    !> Path to the C++ compiler
      +    character(len=:), allocatable :: cxx
      +    !> Print all commands
      +    logical :: echo = .true.
      +    !> Verbose output of command
      +    logical :: verbose = .true.
      +contains
      +    !> Get default compiler flags
      +    procedure :: get_default_flags
      +    !> Get flag for module output directories
      +    procedure :: get_module_flag
      +    !> Get flag for include directories
      +    procedure :: get_include_flag
      +    !> Get feature flag
      +    procedure :: get_feature_flag
      +    !> Get flags for the main linking command
      +    procedure :: get_main_flags
      +    !> Get library export flags
      +    procedure :: get_export_flags    
      +    !> Get library install name flags
      +    procedure :: get_install_name_flags
      +    !> Generate header padding flags for macOS executables
      +    procedure :: get_headerpad_flags
      +    !> Compile a Fortran object
      +    procedure :: compile_fortran
      +    !> Compile a C object
      +    procedure :: compile_c
      +    !> Compile a CPP object
      +    procedure :: compile_cpp
      +    !> Link a shared library
      +    procedure :: link_shared
      +    !> Link executable
      +    procedure :: link => link_executable
      +    !> Check whether compiler is recognized
      +    procedure :: is_unknown
      +    !> Check whether this is an Intel compiler
      +    procedure :: is_intel
      +    !> Check whether this is a GNU compiler
      +    procedure :: is_gnu
      +    !> Enumerate libraries, based on compiler and platform
      +    procedure :: enumerate_libraries
      +
      +
      +    !> Serialization interface
      +    procedure :: serializable_is_same => compiler_is_same
      +    procedure :: dump_to_toml => compiler_dump
      +    procedure :: load_from_toml => compiler_load
      +    !> Fortran feature support
      +    procedure :: check_fortran_source_runs
      +    procedure :: check_flags_supported
      +    procedure :: with_xdp
      +    procedure :: with_qp
      +    !> Return compiler name
      +    procedure :: name => compiler_name
      +
      +end type compiler_t
      +
      +
      +!> Definition of archiver object
      +type, extends(serializable_t) :: archiver_t
      +    !> Path to archiver
      +    character(len=:), allocatable :: ar
      +    !> Use response files to pass arguments
      +    logical :: use_response_file = .false.
      +    !> Print all command
      +    logical :: echo = .true.
      +    !> Verbose output of command
      +    logical :: verbose = .true.
      +contains
      +    !> Create static archive
      +    procedure :: make_archive
      +
      +    !> Serialization interface
      +    procedure :: serializable_is_same => ar_is_same
      +    procedure :: dump_to_toml
      +    procedure :: load_from_toml
      +
      +end type archiver_t
      +
      +
      +!> Create debug printout
      +interface debug
      +    module procedure :: debug_compiler
      +    module procedure :: debug_archiver
      +end interface debug
      +
      +character(*), parameter :: &
      +    flag_gnu_coarray = " -fcoarray=single", &
      +    flag_gnu_backtrace = " -fbacktrace", &
      +    flag_gnu_opt = " -O3 -funroll-loops", &
      +    flag_gnu_debug = " -g", &
      +    flag_gnu_pic = " -fPIC", &
      +    flag_gnu_warn = " -Wall -Wextra", &
      +    flag_gnu_check = " -fcheck=bounds -fcheck=array-temps", &
      +    flag_gnu_limit = " -fmax-errors=1", &
      +    flag_gnu_external = " -Wimplicit-interface", &
      +    flag_gnu_openmp = " -fopenmp", &
      +    flag_gnu_no_implicit_typing = " -fimplicit-none", &
      +    flag_gnu_no_implicit_external = " -Werror=implicit-interface", &
      +    flag_gnu_free_form = " -ffree-form", &
      +    flag_gnu_fixed_form = " -ffixed-form"
      +
      +character(*), parameter :: &
      +    flag_pgi_backslash = " -Mbackslash", &
      +    flag_pgi_traceback = " -traceback", &
      +    flag_pgi_debug = " -g", &
      +    flag_pgi_check = " -Mbounds -Mchkptr -Mchkstk", &
      +    flag_pgi_warn = " -Minform=inform", &
      +    flag_pgi_openmp = " -mp", &
      +    flag_pgi_free_form = " -Mfree", &
      +    flag_pgi_fixed_form = " -Mfixed"
      +
      +character(*), parameter :: &
      +    flag_ibmxl_backslash = " -qnoescape"
      +
      +character(*), parameter :: &
      +    flag_intel_backtrace = " -traceback", &
      +    flag_intel_warn = " -warn all", &
      +    flag_intel_check = " -check all", &
      +    flag_intel_debug = " -O0 -g", &
      +    flag_intel_opt = " -O3", &
      +    flag_intel_fp = " -fp-model precise -pc64", &
      +    flag_intel_align = " -align all", &
      +    flag_intel_limit = " -error-limit 1", &
      +    flag_intel_pthread = " -reentrancy threaded", &
      +    flag_intel_nogen = " -nogen-interfaces", &
      +    flag_intel_byterecl = " -assume byterecl", &
      +    flag_intel_openmp = " -qopenmp", &
      +    flag_intel_free_form = " -free", &
      +    flag_intel_fixed_form = " -fixed", &
      +    flag_intel_standard_compliance = " -standard-semantics", &
      +    flag_intel_unknown_cmd_err = " -diag-error 10006"
      +
      +character(*), parameter :: &
      +    flag_intel_llvm_check = " -check all,nouninit"
      +
      +character(*), parameter :: &
      +    flag_intel_backtrace_win = " /traceback", &
      +    flag_intel_warn_win = " /warn:all", &
      +    flag_intel_check_win = " /check:all", &
      +    flag_intel_debug_win = " /Od /Z7", &
      +    flag_intel_opt_win = " /O3", &
      +    flag_intel_fp_win = " /fp:precise", &
      +    flag_intel_align_win = " /align:all", &
      +    flag_intel_limit_win = " /error-limit:1", &
      +    flag_intel_pthread_win = " /reentrancy:threaded", &
      +    flag_intel_nogen_win = " /nogen-interfaces", &
      +    flag_intel_byterecl_win = " /assume:byterecl", &
      +    flag_intel_openmp_win = " /Qopenmp", &
      +    flag_intel_free_form_win = " /free", &
      +    flag_intel_fixed_form_win = " /fixed", &
      +    flag_intel_standard_compliance_win = " /standard-semantics", &
      +    flag_intel_unknown_cmd_err_win = " /Qdiag-error:10006"
      +
      +character(*), parameter :: &
      +    flag_nag_coarray = " -coarray=single", &
      +    flag_nag_pic = " -PIC", &
      +    flag_nag_check = " -C", &
      +    flag_nag_debug = " -g -O0", &
      +    flag_nag_opt = " -O4", &
      +    flag_nag_backtrace = " -gline", &
      +    flag_nag_openmp = " -openmp", &
      +    flag_nag_free_form = " -free", &
      +    flag_nag_fixed_form = " -fixed", &
      +    flag_nag_no_implicit_typing = " -u"
      +
      +character(*), parameter :: &
      +    flag_lfortran_opt = " --fast", &
      +    flag_lfortran_openmp = " --openmp", &
      +    flag_lfortran_implicit_typing = " --implicit-typing", &
      +    flag_lfortran_implicit_external = " --implicit-interface", &
      +    flag_lfortran_fixed_form = " --fixed-form"
      +
      +character(*), parameter :: &
      +    flag_cray_no_implicit_typing = " -dl", &
      +    flag_cray_implicit_typing = " -el", &
      +    flag_cray_fixed_form = " -ffixed", &
      +    flag_cray_free_form = " -ffree"
      +
      +character(*), parameter :: &
      +    flag_flang_new_openmp = " -fopenmp"
      +
      +contains
      +
      +
      +function get_default_flags(self, release) result(flags)
      +    class(compiler_t), intent(in) :: self
      +    logical, intent(in) :: release
      +    character(len=:), allocatable :: flags
      +
      +    character(len=:), allocatable :: pic_flag
      +
      +    if (release) then
      +        call get_release_compile_flags(self%id, flags)
      +    else
      +        call get_debug_compile_flags(self%id, flags)
      +    end if
      +
      +    ! Append position-independent code (PIC) flag, that is necessary 
      +    ! building shared libraries
      +    select case (self%id)
      +    case (id_gcc, id_f95, id_caf, id_flang, id_flang_new, id_f18, id_lfortran, &
      +          id_intel_classic_nix, id_intel_classic_mac, id_intel_llvm_nix, &
      +          id_pgi, id_nvhpc, id_nag, id_cray, id_ibmxl)
      +        pic_flag = " -fPIC"
      +    case (id_intel_classic_windows, id_intel_llvm_windows)
      +        pic_flag = ""  ! Windows does not use -fPIC
      +    case default
      +        pic_flag = " -fPIC"  ! Conservative fallback
      +    end select
      +
      +    flags = flags // pic_flag
      +
      +end function get_default_flags
      +
      +subroutine get_release_compile_flags(id, flags)
      +    integer(compiler_enum), intent(in) :: id
      +    character(len=:), allocatable, intent(out) :: flags
      +
      +    select case(id)
      +    case default
      +        flags = ""
      +    case(id_caf)
      +        flags = &
      +            flag_gnu_opt//&
      +            flag_gnu_external//&
      +            flag_gnu_pic//&
      +            flag_gnu_limit
      +
      +    case(id_gcc)
      +        flags = &
      +            flag_gnu_opt//&
      +            flag_gnu_external//&
      +            flag_gnu_pic//&
      +            flag_gnu_limit//&
      +            flag_gnu_coarray
      +
      +    case(id_f95)
      +        flags = &
      +            flag_gnu_opt//&
      +            flag_gnu_external//&
      +            flag_gnu_pic//&
      +            flag_gnu_limit
      +
      +    case(id_nvhpc)
      +        flags = &
      +            flag_pgi_backslash
      +
      +    case(id_ibmxl)
      +        flags = &
      +            flag_ibmxl_backslash
      +
      +    case(id_intel_classic_nix)
      +        flags = &
      +            flag_intel_opt//&
      +            flag_intel_fp//&
      +            flag_intel_align//&
      +            flag_intel_limit//&
      +            flag_intel_pthread//&
      +            flag_intel_nogen//&
      +            flag_intel_byterecl
      +
      +    case(id_intel_classic_mac)
      +        flags = &
      +            flag_intel_opt//&
      +            flag_intel_fp//&
      +            flag_intel_align//&
      +            flag_intel_limit//&
      +            flag_intel_pthread//&
      +            flag_intel_nogen//&
      +            flag_intel_byterecl
      +
      +    case(id_intel_classic_windows)
      +        flags = &
      +            flag_intel_opt_win//&
      +            flag_intel_fp_win//&
      +            flag_intel_align_win//&
      +            flag_intel_limit_win//&
      +            flag_intel_pthread_win//&
      +            flag_intel_nogen_win//&
      +            flag_intel_byterecl_win
      +
      +    case(id_intel_llvm_nix)
      +        flags = &
      +            flag_intel_opt//&
      +            flag_intel_fp//&
      +            flag_intel_align//&
      +            flag_intel_limit//&
      +            flag_intel_pthread//&
      +            flag_intel_nogen//&
      +            flag_intel_byterecl
      +
      +    case(id_intel_llvm_windows)
      +        flags = &
      +            flag_intel_opt_win//&
      +            flag_intel_fp_win//&
      +            flag_intel_align_win//&
      +            flag_intel_limit_win//&
      +            flag_intel_pthread_win//&
      +            flag_intel_nogen_win//&
      +            flag_intel_byterecl_win
      +
      +    case(id_nag)
      +        flags = &
      +            flag_nag_opt//&
      +            flag_nag_coarray//&
      +            flag_nag_pic
      +
      +    case(id_lfortran)
      +        flags = &
      +            flag_lfortran_opt
      +
      +    end select
      +end subroutine get_release_compile_flags
      +
      +subroutine get_debug_compile_flags(id, flags)
      +    integer(compiler_enum), intent(in) :: id
      +    character(len=:), allocatable, intent(out) :: flags
      +
      +    select case(id)
      +    case default
      +        flags = ""
      +    case(id_caf)
      +        flags = &
      +            flag_gnu_warn//&
      +            flag_gnu_pic//&
      +            flag_gnu_limit//&
      +            flag_gnu_debug//&
      +            flag_gnu_check//&
      +            flag_gnu_backtrace
      +    case(id_gcc)
      +        flags = &
      +            flag_gnu_warn//&
      +            flag_gnu_pic//&
      +            flag_gnu_limit//&
      +            flag_gnu_debug//&
      +            flag_gnu_check//&
      +            flag_gnu_backtrace//&
      +            flag_gnu_coarray
      +    case(id_f95)
      +        flags = &
      +            flag_gnu_warn//&
      +            flag_gnu_pic//&
      +            flag_gnu_limit//&
      +            flag_gnu_debug//&
      +            flag_gnu_check//&
      +            ' -Wno-maybe-uninitialized -Wno-uninitialized'//&
      +            flag_gnu_backtrace
      +    case(id_nvhpc)
      +        flags = &
      +            flag_pgi_warn//&
      +            flag_pgi_backslash//&
      +            flag_pgi_check//&
      +            flag_pgi_traceback
      +    case(id_ibmxl)
      +        flags = &
      +            flag_ibmxl_backslash
      +    case(id_intel_classic_nix)
      +        flags = &
      +            flag_intel_warn//&
      +            flag_intel_check//&
      +            flag_intel_limit//&
      +            flag_intel_debug//&
      +            flag_intel_byterecl//&
      +            flag_intel_backtrace
      +
      +    case(id_intel_classic_mac)
      +        flags = &
      +            flag_intel_warn//&
      +            flag_intel_check//&
      +            flag_intel_limit//&
      +            flag_intel_debug//&
      +            flag_intel_byterecl//&
      +            flag_intel_backtrace
      +    case(id_intel_classic_windows)
      +        flags = &
      +            flag_intel_warn_win//&
      +            flag_intel_check_win//&
      +            flag_intel_limit_win//&
      +            flag_intel_debug_win//&
      +            flag_intel_byterecl_win//&
      +            flag_intel_backtrace_win
      +    case(id_intel_llvm_nix)
      +        flags = &
      +            flag_intel_unknown_cmd_err//&
      +            flag_intel_llvm_check//&
      +            flag_intel_limit//&
      +            flag_intel_debug//&
      +            flag_intel_byterecl//&
      +            flag_intel_backtrace
      +    case(id_intel_llvm_windows)
      +        flags = &
      +            flag_intel_unknown_cmd_err_win//&
      +            flag_intel_check_win//&
      +            flag_intel_limit_win//&
      +            flag_intel_debug_win//&
      +            flag_intel_byterecl_win
      +    case(id_nag)
      +        flags = &
      +            flag_nag_debug//&
      +            flag_nag_check//&
      +            flag_nag_backtrace//&
      +            flag_nag_coarray//&
      +            flag_nag_pic
      +
      +    case(id_lfortran)
      +        flags = ""
      +    end select
      +end subroutine get_debug_compile_flags
      +
      +pure subroutine set_cpp_preprocessor_flags(id, flags)
      +    integer(compiler_enum), intent(in) :: id
      +    character(len=:), allocatable, intent(inout) :: flags
      +    character(len=:), allocatable :: flag_cpp_preprocessor
      +
      +    !> Modify the flag_cpp_preprocessor on the basis of the compiler.
      +    select case(id)
      +    case default
      +        flag_cpp_preprocessor = ""
      +    case(id_caf, id_gcc, id_f95, id_nvhpc)
      +        flag_cpp_preprocessor = "-cpp"
      +    case(id_intel_classic_windows, id_intel_llvm_windows)
      +        flag_cpp_preprocessor = "/fpp"
      +    case(id_intel_classic_nix, id_intel_classic_mac, id_intel_llvm_nix, id_nag)
      +        flag_cpp_preprocessor = "-fpp"
      +    case(id_lfortran)
      +        flag_cpp_preprocessor = "--cpp"
      +    end select
      +
      +    flags = flag_cpp_preprocessor// flags
      +
      +end subroutine set_cpp_preprocessor_flags
      +
      +!> This function will parse and read the macros list and
      +!> return them as defined flags.
      +function get_macros(id, macros_list, version) result(macros)
      +    integer(compiler_enum), intent(in) :: id
      +    character(len=:), allocatable, intent(in) :: version
      +    type(string_t), allocatable, intent(in) :: macros_list(:)
      +
      +    character(len=:), allocatable :: macros
      +    character(len=:), allocatable :: macro_definition_symbol
      +    character(:), allocatable :: valued_macros(:)
      +
      +
      +    integer :: i
      +
      +    if (.not.allocated(macros_list)) then
      +        macros = ""
      +        return
      +    end if
      +
      +    !> Set macro defintion symbol on the basis of compiler used
      +    select case(id)
      +    case default
      +        macro_definition_symbol = " -D"
      +    case (id_intel_classic_windows, id_intel_llvm_windows)
      +        macro_definition_symbol = " /D"
      +    end select
      +
      +    !> Check if macros are not allocated.
      +    if (.not.allocated(macros)) then
      +        macros=""
      +    end if
      +
      +    do i = 1, size(macros_list)
      +
      +        !> Split the macro name and value.
      +        call split(macros_list(i)%s, valued_macros, delimiters="=")
      +
      +        if (size(valued_macros) > 1) then
      +            !> Check if the value of macro starts with '{' character.
      +            if (str_begins_with_str(trim(valued_macros(size(valued_macros))), "{")) then
      +
      +                !> Check if the value of macro ends with '}' character.
      +                if (str_ends_with(trim(valued_macros(size(valued_macros))), "}")) then
      +
      +                    !> Check if the string contains "version" as substring.
      +                    if (index(valued_macros(size(valued_macros)), "version") /= 0) then
      +
      +                        !> These conditions are placed in order to ensure proper spacing between the macros.
      +                        macros = macros//macro_definition_symbol//trim(valued_macros(1))//'='//version
      +                        cycle
      +                    end if
      +                end if
      +            end if
      +        end if
      +
      +        macros = macros//macro_definition_symbol//macros_list(i)%s
      +
      +    end do
      +
      +end function get_macros
      +
      +function get_include_flag(self, path) result(flags)
      +    class(compiler_t), intent(in) :: self
      +    character(len=*), intent(in) :: path
      +    character(len=:), allocatable :: flags
      +
      +    select case(self%id)
      +    case default
      +        flags = "-I "//path
      +
      +    case(id_caf, id_gcc, id_f95, id_cray, id_nvhpc, id_pgi, &
      +        & id_flang, id_flang_new, id_f18, &
      +        & id_intel_classic_nix, id_intel_classic_mac, &
      +        & id_intel_llvm_nix, id_lahey, id_nag, id_ibmxl, &
      +        & id_lfortran)
      +        flags = "-I "//path
      +
      +    case(id_intel_classic_windows, id_intel_llvm_windows)
      +        flags = "/I"//path
      +
      +    end select
      +end function get_include_flag
      +
      +function get_module_flag(self, path) result(flags)
      +    class(compiler_t), intent(in) :: self
      +    character(len=*), intent(in) :: path
      +    character(len=:), allocatable :: flags
      +
      +    select case(self%id)
      +    case default
      +        flags = "-module "//path
      +
      +    case(id_caf, id_gcc, id_f95, id_cray, id_lfortran)
      +        flags = "-J "//path
      +
      +    case(id_nvhpc, id_pgi, id_flang)
      +        flags = "-module "//path
      +
      +    case(id_flang_new, id_f18)
      +        flags = "-module-dir "//path
      +
      +    case(id_intel_classic_nix, id_intel_classic_mac, &
      +        & id_intel_llvm_nix)
      +        flags = "-module "//path
      +
      +    case(id_intel_classic_windows, id_intel_llvm_windows)
      +        flags = "/module:"//path
      +
      +    case(id_lahey)
      +        flags = "-M "//path
      +
      +    case(id_nag)
      +        flags = "-mdir "//path
      +
      +    case(id_ibmxl)
      +        flags = "-qmoddir "//path
      +
      +    end select
      +
      +end function get_module_flag
      +
      +
      +function get_shared_flag(self) result(shared_flag)
      +    class(compiler_t), intent(in) :: self
      +    character(len=:), allocatable :: shared_flag
      +
      +    select case (self%id)
      +    case default
      +        shared_flag = "-shared"
      +    case (id_gcc, id_f95, id_flang, id_flang_new, id_lfortran)
      +        shared_flag = "-shared"
      +    case (id_intel_classic_nix, id_intel_llvm_nix, id_pgi, id_nvhpc)
      +        shared_flag = "-shared"
      +    case (id_intel_classic_windows, id_intel_llvm_windows)
      +        shared_flag = "/DLL"
      +    case (id_nag)
      +        shared_flag = "-Wl,-shared"
      +    case (id_ibmxl)
      +        shared_flag = "-qmkshrobj"
      +    case (id_cray, id_lahey)
      +        shared_flag = ""  ! Needs special handling
      +    end select
      +
      +end function get_shared_flag
      +
      +
      +function get_feature_flag(self, feature) result(flags)
      +    class(compiler_t), intent(in) :: self
      +    character(len=*), intent(in) :: feature
      +    character(len=:), allocatable :: flags
      +
      +    flags = ""
      +    select case(feature)
      +    case("no-implicit-typing")
      +       select case(self%id)
      +       case(id_caf, id_gcc, id_f95)
      +           flags = flag_gnu_no_implicit_typing
      +
      +       case(id_nag)
      +           flags = flag_nag_no_implicit_typing
      +
      +       case(id_cray)
      +           flags = flag_cray_no_implicit_typing
      +
      +       end select
      +
      +    case("implicit-typing")
      +       select case(self%id)
      +       case(id_cray)
      +           flags = flag_cray_implicit_typing
      +
      +       case(id_lfortran)
      +           flags = flag_lfortran_implicit_typing
      +
      +       end select
      +
      +    case("no-implicit-external")
      +       select case(self%id)
      +       case(id_caf, id_gcc, id_f95)
      +           flags = flag_gnu_no_implicit_external
      +
      +       end select
      +
      +    case("implicit-external")
      +       select case(self%id)
      +       case(id_lfortran)
      +           flags = flag_lfortran_implicit_external
      +
      +       end select
      +
      +    case("free-form")
      +       select case(self%id)
      +       case(id_caf, id_gcc, id_f95)
      +           flags = flag_gnu_free_form
      +
      +       case(id_pgi, id_nvhpc, id_flang)
      +           flags = flag_pgi_free_form
      +
      +       case(id_nag)
      +           flags = flag_nag_free_form
      +
      +       case(id_intel_classic_nix, id_intel_classic_mac, id_intel_llvm_nix, &
      +             & id_intel_llvm_unknown)
      +           flags = flag_intel_free_form
      +
      +       case(id_intel_classic_windows, id_intel_llvm_windows)
      +           flags = flag_intel_free_form_win
      +
      +       case(id_cray)
      +           flags = flag_cray_free_form
      +
      +       end select
      +
      +    case("fixed-form")
      +       select case(self%id)
      +       case(id_caf, id_gcc, id_f95)
      +           flags = flag_gnu_fixed_form
      +
      +       case(id_pgi, id_nvhpc, id_flang)
      +           flags = flag_pgi_fixed_form
      +
      +       case(id_nag)
      +           flags = flag_nag_fixed_form
      +
      +       case(id_intel_classic_nix, id_intel_classic_mac, id_intel_llvm_nix, &
      +             & id_intel_llvm_unknown)
      +           flags = flag_intel_fixed_form
      +
      +       case(id_intel_classic_windows, id_intel_llvm_windows)
      +           flags = flag_intel_fixed_form_win
      +
      +       case(id_cray)
      +           flags = flag_cray_fixed_form
      +
      +       case(id_lfortran)
      +           flags = flag_lfortran_fixed_form
      +
      +       end select
      +
      +    case("default-form")
      +        continue
      +
      +    case default
      +        error stop "Unknown feature '"//feature//"'"
      +    end select
      +end function get_feature_flag
      +
      +
      +!> Get special flags for the main linker
      +subroutine get_main_flags(self, language, flags)
      +    class(compiler_t), intent(in) :: self
      +    character(len=*), intent(in) :: language
      +    character(len=:), allocatable, intent(out) :: flags
      +
      +    flags = ""
      +    select case(language)
      +
      +    case("fortran")
      +        flags = ""
      +
      +    case("c")
      +
      +        ! If the main program is on a C/C++ source, the Intel Fortran compiler requires option
      +        ! -nofor-main to avoid "duplicate main" errors.
      +        ! https://stackoverflow.com/questions/36221612/p3dfft-compilation-ifort-compiler-error-multiple-definiton-of-main
      +        select case(self%id)
      +           case(id_intel_classic_nix, id_intel_classic_mac, id_intel_llvm_nix)
      +               flags = '-nofor-main'
      +           case(id_intel_classic_windows,id_intel_llvm_windows)
      +               flags = '/nofor-main'
      +           case (id_pgi,id_nvhpc)
      +               flags = '-Mnomain'
      +        end select
      +
      +    case("c++","cpp","cxx")
      +
      +        select case(self%id)
      +           case(id_intel_classic_nix, id_intel_classic_mac, id_intel_llvm_nix)
      +               flags = '-nofor-main'
      +           case(id_intel_classic_windows,id_intel_llvm_windows)
      +               flags = '/nofor-main'
      +           case (id_pgi,id_nvhpc)
      +               flags = '-Mnomain'
      +        end select
      +
      +    case default
      +        error stop "Unknown language '"//language//'", try "fortran", "c", "c++"'
      +    end select
      +
      +end subroutine get_main_flags
      +
      +subroutine get_default_c_compiler(f_compiler, c_compiler)
      +    character(len=*), intent(in) :: f_compiler
      +    character(len=:), allocatable, intent(out) :: c_compiler
      +    integer(compiler_enum) :: id
      +
      +    id = get_compiler_id(f_compiler)
      +
      +    select case(id)
      +
      +    case(id_intel_classic_nix, id_intel_classic_mac, id_intel_classic_windows)
      +        c_compiler = 'icc'
      +
      +    case(id_intel_llvm_nix,id_intel_llvm_windows)
      +        c_compiler = 'icx'
      +
      +    case(id_flang, id_flang_new, id_f18)
      +        c_compiler='clang'
      +
      +    case(id_ibmxl)
      +        c_compiler='xlc'
      +
      +    case(id_lfortran)
      +        c_compiler = 'cc'
      +
      +    case(id_gcc)
      +        c_compiler = 'gcc'
      +
      +    case default
      +        ! Fall-back to using Fortran compiler
      +        c_compiler = f_compiler
      +    end select
      +
      +end subroutine get_default_c_compiler
      +
      +!> Get C++ Compiler.
      +subroutine get_default_cxx_compiler(f_compiler, cxx_compiler)
      +    character(len=*), intent(in) :: f_compiler
      +    character(len=:), allocatable, intent(out) :: cxx_compiler
      +    integer(compiler_enum) :: id
      +
      +    id = get_compiler_id(f_compiler)
      +
      +    select case(id)
      +
      +    case(id_intel_classic_nix, id_intel_classic_mac, id_intel_classic_windows)
      +        cxx_compiler = 'icpc'
      +
      +    case(id_intel_llvm_nix,id_intel_llvm_windows)
      +        cxx_compiler = 'icpx'
      +
      +    case(id_flang, id_flang_new, id_f18)
      +        cxx_compiler='clang++'
      +
      +    case(id_ibmxl)
      +        cxx_compiler='xlc++'
      +
      +    case(id_lfortran)
      +        cxx_compiler = 'cc'
      +
      +    case(id_gcc)
      +        cxx_compiler = 'g++'
      +
      +    case default
      +        ! Fall-back to using Fortran compiler
      +        cxx_compiler = f_compiler
      +    end select
      +
      +end subroutine get_default_cxx_compiler
      +
      +
      +function get_compiler_id(compiler) result(id)
      +    character(len=*), intent(in) :: compiler
      +    integer(kind=compiler_enum) :: id
      +
      +    character(len=:), allocatable :: full_command, full_command_parts(:), command, output
      +    integer :: stat, io
      +
      +    ! Check whether we are dealing with an MPI compiler wrapper first
      +    if (check_compiler(compiler, "mpifort") &
      +        & .or. check_compiler(compiler, "mpif90") &
      +        & .or. check_compiler(compiler, "mpif77")) then
      +        output = get_temp_filename()
      +        call run(compiler//" -show > "//output//" 2>&1", &
      +            & echo=.false., exitstat=stat)
      +        if (stat == 0) then
      +            open(file=output, newunit=io, iostat=stat)
      +            if (stat == 0) call getline(io, full_command, stat)
      +            close(io, iostat=stat)
      +
      +            ! If we get a command from the wrapper, we will try to identify it
      +            call split(full_command, full_command_parts, delimiters=' ')
      +            if(size(full_command_parts) > 0)then
      +               command = trim(full_command_parts(1))
      +            endif
      +            if (allocated(command)) then
      +                id = get_id(command)
      +                if (id /= id_unknown) return
      +            end if
      +        end if
      +    end if
      +
      +    id = get_id(compiler)
      +
      +end function get_compiler_id
      +
      +function get_id(compiler) result(id)
      +    character(len=*), intent(in) :: compiler
      +    integer(kind=compiler_enum) :: id
      +
      +    if (check_compiler(compiler, "gfortran")) then
      +        id = id_gcc
      +        return
      +    end if
      +
      +    if (check_compiler(compiler, "f95")) then
      +        id = id_f95
      +        return
      +    end if
      +
      +    if (check_compiler(compiler, "caf")) then
      +        id = id_caf
      +        return
      +    end if
      +
      +    if (check_compiler(compiler, "ifort")) then
      +        select case (get_os_type())
      +        case default
      +            id = id_intel_classic_nix
      +        case (OS_MACOS)
      +            id = id_intel_classic_mac
      +        case (OS_WINDOWS, OS_CYGWIN)
      +            id = id_intel_classic_windows
      +        end select
      +        return
      +    end if
      +
      +    if (check_compiler(compiler, "ifx")) then
      +        select case (get_os_type())
      +        case default
      +            id = id_intel_llvm_nix
      +        case (OS_WINDOWS, OS_CYGWIN)
      +            id = id_intel_llvm_windows
      +        end select
      +        return
      +    end if
      +
      +    if (check_compiler(compiler, "nvfortran")) then
      +        id = id_nvhpc
      +        return
      +    end if
      +
      +    if (check_compiler(compiler, "pgfortran") &
      +        & .or. check_compiler(compiler, "pgf90") &
      +        & .or. check_compiler(compiler, "pgf95")) then
      +        id = id_pgi
      +        return
      +    end if
      +
      +    if (check_compiler(compiler, "nagfor")) then
      +        id = id_nag
      +        return
      +    end if
      +
      +    if (check_compiler(compiler, "flang-new")) then
      +        id = id_flang_new
      +        return
      +    end if
      +
      +    if (check_compiler(compiler, "f18")) then
      +        id = id_f18
      +        return
      +    end if
      +
      +    if (check_compiler(compiler, "flang")) then
      +        id = id_flang
      +        return
      +    end if
      +
      +    if (check_compiler(compiler, "xlf90")) then
      +        id = id_ibmxl
      +        return
      +    end if
      +
      +    if (check_compiler(compiler, "crayftn")) then
      +        id = id_cray
      +        return
      +    end if
      +
      +    if (check_compiler(compiler, "lfc")) then
      +        id = id_lahey
      +        return
      +    end if
      +
      +    if (check_compiler(compiler, "lfortran")) then
      +        id = id_lfortran
      +        return
      +    end if
      +
      +    id = id_unknown
      +
      +end function get_id
      +
      +function check_compiler(compiler, expected) result(match)
      +    character(len=*), intent(in) :: compiler
      +    character(len=*), intent(in) :: expected
      +    logical :: match
      +    match = compiler == expected
      +    if (.not. match) then
      +        match = index(basename(compiler), expected) > 0
      +    end if
      +end function check_compiler
      +
      +
      +pure function is_unknown(self)
      +    class(compiler_t), intent(in) :: self
      +    logical :: is_unknown
      +    is_unknown = self%id == id_unknown
      +end function is_unknown
      +
      +pure logical function is_intel(self)
      +    class(compiler_t), intent(in) :: self
      +    is_intel = any(self%id == [id_intel_classic_nix,id_intel_classic_mac,id_intel_classic_windows, &
      +                               id_intel_llvm_nix,id_intel_llvm_windows,id_intel_llvm_unknown])
      +end function is_intel
      +
      +pure logical function is_gnu(self)
      +    class(compiler_t), intent(in) :: self
      +    is_gnu = any(self%id == [id_f95,id_gcc,id_caf])
      +end function is_gnu
      +
      +!>
      +!> Enumerate libraries, based on compiler and platform
      +!>
      +function enumerate_libraries(self, prefix, libs) result(r)
      +    class(compiler_t), intent(in) :: self
      +    character(len=*), intent(in) :: prefix
      +    type(string_t), intent(in) :: libs(:)
      +    character(len=:), allocatable :: r
      +
      +    character(len=:), allocatable :: joined
      +
      +    if (size(libs) == 0) then
      +        r = prefix
      +        return
      +    end if
      +
      +    select case (self%id)
      +
      +    case (id_intel_classic_windows, id_intel_llvm_windows)
      +        ! Windows Intel uses `.lib` files directly
      +        joined = string_cat(libs, ".lib ") // ".lib"
      +        r = trim(prefix) // " " // trim(joined)
      +
      +    case (id_nag, id_ibmxl)
      +        ! NAG and IBMXL need -Wl, wrapper around linker flags
      +        joined = string_cat(libs, " -Wl,")
      +        r = trim(prefix) // " -Wl," // trim(joined)
      +
      +    case default
      +        ! Generic Unix-style linker flags: use `-lfoo`
      +        joined = string_cat(libs, " -l")
      +        r = trim(prefix) // " -l" // trim(joined)
      +
      +    end select
      +
      +end function enumerate_libraries
      +
      +!>
      +!> Generate library export flags for a shared library build
      +!>
      +function get_export_flags(self, target_dir, target_name) result(export_flags)
      +    !> Instance of the compiler
      +    class(compiler_t), intent(in) :: self
      +    !> Path and package name
      +    character(len=*), intent(in) :: target_dir, target_name
      +    character(len=:), allocatable :: export_flags
      +
      +    character(len=:), allocatable :: implib_path, def_path
      +
      +    ! Only apply on Windows
      +    if (get_os_type() /= OS_WINDOWS) then
      +        export_flags = ""
      +        return
      +    end if
      +
      +    select case (self%id)
      +
      +    case (id_gcc, id_caf, id_f95)
      +        ! GNU-based: emit both import library and def file
      +        implib_path = quote(join_path(target_dir, target_name // ".dll.a") , for_cmd=.true.)
      +        def_path    = quote(join_path(target_dir, target_name // ".def" ) , for_cmd=.true.)
      +
      +        export_flags = " -Wl,--out-implib," // implib_path // &
      +                       " -Wl,--output-def," // def_path
      +
      +    case (id_intel_classic_windows, id_intel_llvm_windows)
      +        ! Intel/MSVC-style
      +        implib_path = quote(join_path(target_dir, target_name // ".lib") , for_cmd=.true.)
      +        def_path    = quote(join_path(target_dir, target_name // ".def") , for_cmd=.true.)
      +                
      +        export_flags = " /IMPLIB:" // implib_path // &
      +                       " /DEF:" // def_path
      +
      +    case default
      +        
      +        export_flags = ""  ! Do nothing elsewhere
      +
      +    end select
      +
      +end function get_export_flags
      +
      +!>
      +!> Generate `install_name` flag for a shared library build on macOS
      +!>
      +function get_install_name_flags(self, target_dir, target_name) result(flags)
      +    class(compiler_t), intent(in) :: self
      +    character(len=*), intent(in) :: target_dir, target_name
      +    character(len=:), allocatable :: flags
      +    character(len=:), allocatable :: library_file
      +
      +    if (get_os_type() /= OS_MACOS) then
      +        flags = ""
      +        return
      +    end if
      +
      +    ! Shared library basename (e.g., libfoo.dylib)
      +    if (str_ends_with(target_name, ".dylib")) then
      +        library_file = target_name        
      +    else
      +        library_file = library_filename(target_name,.true.,.false.,OS_MACOS)
      +    end if
      +    
      +    flags = " -Wl,-install_name,@rpath/" // library_file
      +
      +end function get_install_name_flags
      +
      +!>
      +!> Generate header padding flags for install_name_tool compatibility on macOS
      +!>
      +function get_headerpad_flags(self) result(flags)
      +    class(compiler_t), intent(in) :: self
      +    character(len=:), allocatable :: flags
      +
      +    if (get_os_type() /= OS_MACOS) then
      +        flags = ""
      +        return
      +    end if
      +
      +    ! Reserve enough space in the Mach-O header to safely add two install_name or rpath later
      +    flags = " -Wl,-headerpad,0x200"
      +
      +end function get_headerpad_flags
      +
      +!> Create new compiler instance
      +subroutine new_compiler(self, fc, cc, cxx, echo, verbose)
      +    !> New instance of the compiler
      +    type(compiler_t), intent(out) :: self
      +    !> Fortran compiler name or path
      +    character(len=*), intent(in) :: fc
      +    !> C compiler name or path
      +    character(len=*), intent(in) :: cc
      +    !> C++ Compiler name or path
      +    character(len=*), intent(in) :: cxx
      +    !> Echo compiler command
      +    logical, intent(in) :: echo
      +    !> Verbose mode: dump compiler output
      +    logical, intent(in) :: verbose
      +
      +    self%id = get_compiler_id(fc)
      +
      +    self%echo = echo
      +    self%verbose = verbose
      +    self%fc = fc
      +    if (len_trim(cc) > 0) then
      +      self%cc = cc
      +    else
      +      call get_default_c_compiler(self%fc, self%cc)
      +    end if
      +
      +    if (len_trim(cxx) > 0) then
      +      self%cxx = cxx
      +    else
      +      call get_default_cxx_compiler(self%fc, self%cxx)
      +    end if
      +
      +end subroutine new_compiler
      +
      +
      +!> Create new archiver instance
      +subroutine new_archiver(self, ar, echo, verbose)
      +    !> New instance of the archiver
      +    type(archiver_t), intent(out) :: self
      +    !> User provided archiver command
      +    character(len=*), intent(in) :: ar
      +    !> Echo compiler command
      +    logical, intent(in) :: echo
      +    !> Verbose mode: dump compiler output
      +    logical, intent(in) :: verbose
      +
      +    integer :: estat, os_type
      +
      +    character(len=*), parameter :: arflags = " -rs ", libflags = " /OUT:"
      +
      +    if (len_trim(ar) > 0) then
      +      ! Check first for ar-like commands
      +      if (check_compiler(ar, "ar")) then
      +        self%ar = ar//arflags
      +      end if
      +
      +      ! Check for lib-like commands
      +      if (check_compiler(ar, "lib")) then
      +        self%ar = ar//libflags
      +      end if
      +
      +      ! Fallback and assume ar-like behaviour
      +      self%ar = ar//arflags
      +    else
      +      os_type = get_os_type()
      +      if (os_type /= OS_WINDOWS .and. os_type /= OS_UNKNOWN) then
      +        self%ar = "ar"//arflags
      +      else
      +        ! Attempt "ar"
      +        call execute_command_line("ar --version > "//get_temp_filename()//" 2>&1", &
      +          & exitstat=estat)
      +
      +        if (estat == 0) then
      +
      +            self%ar = "ar"//arflags
      +
      +        else
      +
      +            ! Then "gcc-ar"
      +            call execute_command_line("gcc-ar --version > "//get_temp_filename()//" 2>&1", &
      +               & exitstat=estat)
      +
      +            if (estat /= 0) then
      +              self%ar = "lib"//libflags
      +            else
      +              self%ar = "gcc-ar"//arflags
      +            end if
      +        endif
      +      end if
      +    end if
      +    self%use_response_file = os_type == OS_WINDOWS
      +    self%echo = echo
      +    self%verbose = verbose
      +end subroutine new_archiver
      +
      +
      +!> Compile a Fortran object
      +subroutine compile_fortran(self, input, output, args, log_file, stat, table, dry_run)
      +    !> Instance of the compiler object
      +    class(compiler_t), intent(in) :: self
      +    !> Source file input
      +    character(len=*), intent(in) :: input
      +    !> Output file of object
      +    character(len=*), intent(in) :: output
      +    !> Arguments for compiler
      +    character(len=*), intent(in) :: args
      +    !> Compiler output log file
      +    character(len=*), intent(in) :: log_file
      +    !> Status flag
      +    integer, intent(out) :: stat
      +    !> Optional compile_commands table
      +    type(compile_command_table_t), optional, intent(inout) :: table    
      +    !> Optional mocking
      +    logical, optional, intent(in) :: dry_run
      +    
      +    character(len=:), allocatable :: command 
      +    type(error_t), allocatable :: error
      +    logical :: mock
      +    
      +    ! Check if we're actually building this file
      +    mock = .false.
      +    if (present(dry_run)) mock = dry_run
      +    
      +    ! Set command
      +    command = self%fc // " -c " // input // " " // args // " -o " // output
      +
      +    ! Execute command
      +    if (.not.mock) then 
      +       call run(command, echo=self%echo, verbose=self%verbose, redirect=log_file, exitstat=stat)
      +       if (stat/=0) return
      +    endif
      +        
      +    ! Optionally register compile command 
      +    if (present(table)) then 
      +        call table%register(command, get_os_type(), error)
      +        stat = merge(-1,0,allocated(error))
      +    endif    
      +        
      +end subroutine compile_fortran
      +
      +
      +!> Compile a C object
      +subroutine compile_c(self, input, output, args, log_file, stat, table, dry_run)
      +    !> Instance of the compiler object
      +    class(compiler_t), intent(in) :: self
      +    !> Source file input
      +    character(len=*), intent(in) :: input
      +    !> Output file of object
      +    character(len=*), intent(in) :: output
      +    !> Arguments for compiler
      +    character(len=*), intent(in) :: args
      +    !> Compiler output log file
      +    character(len=*), intent(in) :: log_file
      +    !> Status flag
      +    integer, intent(out) :: stat
      +    !> Optional compile_commands table
      +    type(compile_command_table_t), optional, intent(inout) :: table    
      +    !> Optional mocking
      +    logical, optional, intent(in) :: dry_run    
      +    
      +    character(len=:), allocatable :: command 
      +    type(error_t), allocatable :: error
      +    logical :: mock
      +    
      +    ! Check if we're actually building this file
      +    mock = .false.
      +    if (present(dry_run)) mock = dry_run    
      +    
      +    ! Set command
      +    command = self%cc // " -c " // input // " " // args // " -o " // output
      +
      +    ! Execute command
      +    if (.not.mock) then 
      +       call run(command, echo=self%echo, verbose=self%verbose, redirect=log_file, exitstat=stat)
      +       if (stat/=0) return
      +    endif
      +        
      +    ! Optionally register compile command 
      +    if (present(table)) then 
      +        call table%register(command, get_os_type(), error)
      +        stat = merge(-1,0,allocated(error))
      +    endif        
      +    
      +end subroutine compile_c
      +
      +!> Compile a CPP object
      +subroutine compile_cpp(self, input, output, args, log_file, stat, table, dry_run)
      +    !> Instance of the compiler object
      +    class(compiler_t), intent(in) :: self
      +    !> Source file input
      +    character(len=*), intent(in) :: input
      +    !> Output file of object
      +    character(len=*), intent(in) :: output
      +    !> Arguments for compiler
      +    character(len=*), intent(in) :: args
      +    !> Compiler output log file
      +    character(len=*), intent(in) :: log_file
      +    !> Status flag
      +    integer, intent(out) :: stat
      +    !> Optional compile_commands table
      +    type(compile_command_table_t), optional, intent(inout) :: table    
      +    !> Optional mocking
      +    logical, optional, intent(in) :: dry_run    
      +    
      +    character(len=:), allocatable :: command 
      +    type(error_t), allocatable :: error
      +    logical :: mock
      +        
      +    ! Check if we're actually building this file
      +    mock = .false.
      +    if (present(dry_run)) mock = dry_run        
      +        
      +    ! Set command
      +    command = self%cxx // " -c " // input // " " // args // " -o " // output
      +
      +    ! Execute command
      +    if (.not.mock) then 
      +       call run(command, echo=self%echo, verbose=self%verbose, redirect=log_file, exitstat=stat)
      +       if (stat/=0) return
      +    endif
      +        
      +    ! Optionally register compile command 
      +    if (present(table)) then 
      +        call table%register(command, get_os_type(), error)
      +        stat = merge(-1,0,allocated(error))
      +    endif               
      +        
      +end subroutine compile_cpp
      +
      +!> Link an executable
      +subroutine link_executable(self, output, args, log_file, stat, dry_run)
      +    !> Instance of the compiler object
      +    class(compiler_t), intent(in) :: self
      +    !> Output file of object
      +    character(len=*), intent(in) :: output
      +    !> Arguments for compiler
      +    character(len=*), intent(in) :: args
      +    !> Compiler output log file
      +    character(len=*), intent(in) :: log_file
      +    !> Status flag
      +    integer, intent(out) :: stat
      +    !> Optional mocking
      +    logical, optional, intent(in) :: dry_run    
      +    
      +    character(len=:), allocatable :: command 
      +    logical :: mock
      +        
      +    ! Check if we're actually linking
      +    mock = .false.
      +    if (present(dry_run)) mock = dry_run                
      +        
      +    ! Set command
      +    command = self%fc // " " // args // " -o " // output    
      +    
      +    ! Execute command
      +    if (.not.mock) &
      +    call run(command, echo=self%echo, verbose=self%verbose, redirect=log_file, exitstat=stat)
      +    
      +end subroutine link_executable
      +
      +!> Link a shared library
      +subroutine link_shared(self, output, args, log_file, stat, dry_run)
      +    !> Instance of the compiler object
      +    class(compiler_t), intent(in) :: self
      +    !> Output file of shared library object
      +    character(len=*), intent(in) :: output
      +    !> Arguments for the compiler
      +    character(len=*), intent(in) :: args
      +    !> Compiler output log file
      +    character(len=*), intent(in) :: log_file
      +    !> Status flag
      +    integer, intent(out) :: stat
      +    !> Optional mocking
      +    logical, optional, intent(in) :: dry_run
      +
      +    character(len=:), allocatable :: command
      +    logical :: mock
      +    character(len=:), allocatable :: shared_flag
      +
      +    mock = .false.
      +    if (present(dry_run)) mock = dry_run
      +
      +    shared_flag = get_shared_flag(self)
      +
      +    command = self%fc // " " // shared_flag // " " // args // " -o " // output
      +
      +    if (.not.mock) &
      +        call run(command, echo=self%echo, verbose=self%verbose, redirect=log_file, exitstat=stat)
      +
      +end subroutine link_shared
      +
      +
      +!> Create an archive
      +!> @todo For Windows OS, use the local `delete_file_win32` in stead of `delete_file`.
      +!> This may be related to a bug in Mingw64-openmp and is expected to be resolved in the future,
      +!> see issue #707, #708 and #808.
      +subroutine make_archive(self, output, args, log_file, stat, dry_run)
      +    !> Instance of the archiver object
      +    class(archiver_t), intent(in) :: self
      +    !> Name of the archive to generate
      +    character(len=*), intent(in) :: output
      +    !> Object files to include into the archive
      +    type(string_t), intent(in) :: args(:)
      +    !> Compiler output log file
      +    character(len=*), intent(in) :: log_file
      +    !> Status flag
      +    integer, intent(out) :: stat
      +    !> Optional mocking
      +    logical, optional, intent(in) :: dry_run    
      +    
      +    logical :: mock
      +        
      +    ! Check if we're actually linking
      +    mock = .false.
      +    if (present(dry_run)) mock = dry_run            
      +    
      +    if (mock) return
      +
      +    if (self%use_response_file) then
      +        call write_response_file(output//".resp" , args)
      +        call run(self%ar // output // " @" // output//".resp", echo=self%echo, &
      +            &  verbose=self%verbose, redirect=log_file, exitstat=stat)
      +        call delete_file_win32(output//".resp")
      +
      +    else
      +        call run(self%ar // output // " " // string_cat(args, " "), &
      +            & echo=self%echo, verbose=self%verbose, redirect=log_file, exitstat=stat)
      +    end if
      +
      +    contains
      +        subroutine delete_file_win32(file)
      +            character(len=*), intent(in) :: file
      +            logical :: exist
      +            integer :: unit, iostat
      +            inquire(file=file, exist=exist)
      +            if (exist) then
      +                open(file=file, newunit=unit)
      +                close(unit, status='delete', iostat=iostat)
      +            end if
      +        end subroutine delete_file_win32
      +end subroutine make_archive
      +
      +
      +!> Response files allow to read command line options from files.
      +!> Whitespace is used to separate the arguments, we will use newlines
      +!> as separator to create readable response files which can be inspected
      +!> in case of errors.
      +subroutine write_response_file(name, argv)
      +    character(len=*), intent(in) :: name
      +    type(string_t), intent(in) :: argv(:)
      +
      +    integer :: iarg, io
      +
      +    open(file=name, newunit=io, status='replace')
      +    do iarg = 1, size(argv)
      +        write(io, '(a)') unix_path(argv(iarg)%s)
      +    end do
      +    close(io)
      +end subroutine write_response_file
      +
      +
      +!> String representation of a compiler object
      +pure function debug_compiler(self) result(repr)
      +    !> Instance of the compiler object
      +    type(compiler_t), intent(in) :: self
      +    !> Representation as string
      +    character(len=:), allocatable :: repr
      +
      +    repr = 'fc="'//self%fc//'", cc="'//self%cc//'"'
      +end function debug_compiler
      +
      +
      +!> String representation of an archiver object
      +pure function debug_archiver(self) result(repr)
      +    !> Instance of the archiver object
      +    type(archiver_t), intent(in) :: self
      +    !> Representation as string
      +    character(len=:), allocatable :: repr
      +
      +    repr = 'ar="'//self%ar//'"'
      +end function debug_archiver
      +
      +!> Check that two archiver_t objects are equal
      +logical function ar_is_same(this,that)
      +    class(archiver_t), intent(in) :: this
      +    class(serializable_t), intent(in) :: that
      +
      +    ar_is_same = .false.
      +
      +    select type (other=>that)
      +       type is (archiver_t)
      +          if (allocated(this%ar).neqv.allocated(other%ar)) return
      +          if (allocated(this%ar)) then
      +            if (.not.(this%ar==other%ar)) return
      +          end if
      +          if (.not.(this%use_response_file.eqv.other%use_response_file)) return
      +          if (.not.(this%echo.eqv.other%echo)) return
      +          if (.not.(this%verbose.eqv.other%verbose)) return
      +
      +       class default
      +          ! Not the same type
      +          return
      +    end select
      +
      +    !> All checks passed!
      +    ar_is_same = .true.
      +
      +end function ar_is_same
      +
      +!> Dump dependency to toml table
      +subroutine dump_to_toml(self, table, error)
      +
      +    !> Instance of the serializable object
      +    class(archiver_t), intent(inout) :: self
      +
      +    !> Data structure
      +    type(toml_table), intent(inout) :: table
      +
      +    !> Error handling
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    !> Path to archiver
      +    call set_string(table, "ar", self%ar, error, 'archiver_t')
      +    if (allocated(error)) return
      +    call set_value(table, "use-response-file", self%use_response_file, error, 'archiver_t')
      +    if (allocated(error)) return
      +    call set_value(table, "echo", self%echo, error, 'archiver_t')
      +    if (allocated(error)) return
      +    call set_value(table, "verbose", self%verbose, error, 'archiver_t')
      +    if (allocated(error)) return
      +
      +end subroutine dump_to_toml
      +
      +!> Read dependency from toml table (no checks made at this stage)
      +subroutine load_from_toml(self, table, error)
      +
      +    !> Instance of the serializable object
      +    class(archiver_t), intent(inout) :: self
      +
      +    !> Data structure
      +    type(toml_table), intent(inout) :: table
      +
      +    !> Error handling
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    call get_value(table, "ar", self%ar)
      +
      +    call get_value(table, "use-response-file", self%use_response_file, error, 'archiver_t')
      +    if (allocated(error)) return
      +    call get_value(table, "echo", self%echo, error, 'archiver_t')
      +    if (allocated(error)) return
      +    call get_value(table, "verbose", self%verbose, error, 'archiver_t')
      +    if (allocated(error)) return
      +
      +end subroutine load_from_toml
      +
      +!> Check that two compiler_t objects are equal
      +logical function compiler_is_same(this,that)
      +    class(compiler_t), intent(in) :: this
      +    class(serializable_t), intent(in) :: that
      +
      +    compiler_is_same = .false.
      +
      +    select type (other=>that)
      +       type is (compiler_t)
      +
      +          if (.not.(this%id==other%id)) return
      +          if (allocated(this%fc).neqv.allocated(other%fc)) return
      +          if (allocated(this%fc)) then
      +            if (.not.(this%fc==other%fc)) return
      +          end if
      +          if (allocated(this%cc).neqv.allocated(other%cc)) return
      +          if (allocated(this%cc)) then
      +            if (.not.(this%cc==other%cc)) return
      +          end if
      +          if (allocated(this%cxx).neqv.allocated(other%cxx)) return
      +          if (allocated(this%cxx)) then
      +            if (.not.(this%cxx==other%cxx)) return
      +          end if
      +          if (.not.(this%echo.eqv.other%echo)) return
      +          if (.not.(this%verbose.eqv.other%verbose)) return
      +
      +       class default
      +          ! Not the same type
      +          return
      +    end select
      +
      +    !> All checks passed!
      +    compiler_is_same = .true.
      +
      +end function compiler_is_same
      +
      +!> Dump dependency to toml table
      +subroutine compiler_dump(self, table, error)
      +
      +    !> Instance of the serializable object
      +    class(compiler_t), intent(inout) :: self
      +
      +    !> Data structure
      +    type(toml_table), intent(inout) :: table
      +
      +    !> Error handling
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    integer :: ierr
      +
      +    call set_value(table, "id", self%id, error, 'compiler_t')
      +    if (allocated(error)) return
      +    call set_string(table, "fc", self%fc, error, 'compiler_t')
      +    if (allocated(error)) return
      +    call set_string(table, "cc", self%cc, error, 'compiler_t')
      +    if (allocated(error)) return
      +    call set_string(table, "cxx", self%cxx, error, 'compiler_t')
      +    if (allocated(error)) return
      +    call set_value(table, "echo", self%echo, error, 'compiler_t')
      +    if (allocated(error)) return
      +    call set_value(table, "verbose", self%verbose, error, 'compiler_t')
      +    if (allocated(error)) return
      +
      +end subroutine compiler_dump
      +
      +!> Read dependency from toml table (no checks made at this stage)
      +subroutine compiler_load(self, table, error)
      +
      +    !> Instance of the serializable object
      +    class(compiler_t), intent(inout) :: self
      +
      +    !> Data structure
      +    type(toml_table), intent(inout) :: table
      +
      +    !> Error handling
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    call get_value(table, "id", self%id, error, 'compiler_t')
      +    if (allocated(error)) return
      +    call get_value(table, "fc", self%fc)
      +    call get_value(table, "cc", self%cc)
      +    call get_value(table, "cxx", self%cxx)
      +    call get_value(table, "echo", self%echo, error, 'compiler_t')
      +    if (allocated(error)) return
      +    call get_value(table, "verbose", self%verbose, error, 'compiler_t')
      +    if (allocated(error)) return
      +
      +end subroutine compiler_load
      +
      +!> Return a compiler name string
      +pure function compiler_name(self) result(name)
      +   !> Instance of the compiler object
      +   class(compiler_t), intent(in) :: self
      +   !> Representation as string
      +   character(len=:), allocatable :: name
      +
      +   select case (self%id)
      +       case(id_gcc); name = "gfortran"
      +       case(id_f95); name = "f95"
      +       case(id_caf); name = "caf"
      +       case(id_intel_classic_nix);     name = "ifort"
      +       case(id_intel_classic_mac);     name = "ifort"
      +       case(id_intel_classic_windows); name = "ifort"
      +       case(id_intel_llvm_nix);     name = "ifx"
      +       case(id_intel_llvm_windows); name = "ifx"
      +       case(id_intel_llvm_unknown); name = "ifx"
      +       case(id_pgi);       name = "pgfortran"
      +       case(id_nvhpc);     name = "nvfortran"
      +       case(id_nag);       name = "nagfor"
      +       case(id_flang);     name = "flang"
      +       case(id_flang_new); name = "flang-new"
      +       case(id_f18);       name = "f18"
      +       case(id_ibmxl);     name = "xlf90"
      +       case(id_cray);      name = "crayftn"
      +       case(id_lahey);     name = "lfc"
      +       case(id_lfortran);  name = "lFortran"
      +       case default;       name = "invalid/unknown"
      +   end select
      +end function compiler_name
      +
      +!> Run a single-source Fortran program using the current compiler
      +!> Compile a Fortran object
      +logical function check_fortran_source_runs(self, input, compile_flags, link_flags) result(success)
      +    !> Instance of the compiler object
      +    class(compiler_t), intent(in) :: self
      +    !> Program Source
      +    character(len=*), intent(in) :: input
      +    !> Optional build and link flags
      +    character(len=*), optional, intent(in) :: compile_flags, link_flags
      +
      +    integer :: stat,unit
      +    character(:), allocatable :: source,object,logf,exe,flags,ldflags
      +
      +    success = .false.
      +
      +    !> Create temporary source file
      +    exe    = get_temp_filename()
      +    source = exe//'.f90'
      +    object = exe//'.o'
      +    logf   = exe//'.log'
      +    open(newunit=unit, file=source, action='readwrite', iostat=stat)
      +    if (stat/=0) return
      +
      +    !> Write contents
      +    write(unit,*) input
      +    close(unit)
      +
      +    !> Get flags
      +    flags    = self%get_default_flags(release=.false.)
      +    ldflags  = self%get_default_flags(release=.false.)
      +
      +    if (present(compile_flags)) flags = flags//" "//compile_flags
      +    if (present(link_flags)) ldflags = ldflags//" "//link_flags
      +
      +    !> Intel: Needs -warn last for error on unknown command line arguments to work
      +    if (self%id == id_intel_llvm_nix) then
      +        flags = flags//" "//flag_intel_warn
      +        ldflags = ldflags//" "//flag_intel_warn
      +    elseif (self%id == id_intel_llvm_windows) then
      +        flags = flags//" "//flag_intel_warn_win
      +        ldflags = ldflags//" "//flag_intel_warn_win
      +    end if
      +
      +    !> Compile and link program
      +    call self%compile_fortran(source, object, flags, logf, stat)
      +    if (stat==0) &
      +    call self%link(exe, ldflags//" "//object, logf, stat)
      +
      +    !> Run and retrieve exit code
      +    if (stat==0) &
      +    call run(exe,echo=.false., exitstat=stat, verbose=.false., redirect=logf)
      +
      +    !> Successful exit on 0 exit code
      +    success = stat==0
      +
      +    !> Delete files
      +    open(newunit=unit, file=source, action='readwrite', iostat=stat)
      +    close(unit,status='delete')
      +    open(newunit=unit, file=object, action='readwrite', iostat=stat)
      +    close(unit,status='delete')
      +    open(newunit=unit, file=logf, action='readwrite', iostat=stat)
      +    close(unit,status='delete')
      +    open(newunit=unit, file=exe, action='readwrite', iostat=stat)
      +    close(unit,status='delete')
      +
      +end function check_fortran_source_runs
      +
      +!> Check if the given compile and/or link flags are accepted by the compiler
      +logical function check_flags_supported(self, compile_flags, link_flags)
      +    class(compiler_t), intent(in) :: self
      +    character(len=*), optional, intent(in) :: compile_flags, link_flags
      +
      +    ! Minimal program that always compiles
      +    character(len=*), parameter :: hello_world = "print *, 'Hello, World!'; end"
      +
      +    check_flags_supported = self%check_fortran_source_runs(hello_world, compile_flags, link_flags)
      +
      +end function check_flags_supported
      +
      +!> Check if the current compiler supports 128-bit real precision
      +logical function with_qp(self)
      +    !> Instance of the compiler object
      +    class(compiler_t), intent(in) :: self
      +    with_qp = self%check_fortran_source_runs &
      +              ('if (selected_real_kind(33) == -1) stop 1; end')
      +end function with_qp
      +
      +!> Check if the current compiler supports 80-bit "extended" real precision
      +logical function with_xdp(self)
      +    !> Instance of the compiler object
      +    class(compiler_t), intent(in) :: self
      +    with_xdp = self%check_fortran_source_runs &
      +               ('if (any(selected_real_kind(18) == [-1, selected_real_kind(33)])) stop 1; end')
      +end function with_xdp
      +
      +!> Append new flags to existing flags, removing duplicates and empty flags (string version)
      +subroutine append_clean_flags(flags, new_flags)
      +    character(:), intent(inout), allocatable :: flags
      +    character(*), intent(in) :: new_flags
      +
      +    type(string_t), allocatable :: flags_array(:), new_flags_array(:)
      +    integer :: i
      +
      +    call tokenize_flags(flags, flags_array)
      +    call tokenize_flags(new_flags, new_flags_array)
      +
      +    call append_clean_flags_array(flags_array, new_flags_array)
      +
      +    do i = 1, size(flags_array)
      +        flags = flags // " " // flags_array(i)%s
      +    end do
      +end subroutine append_clean_flags
      +
      +!> Append new flags to existing flags, removing duplicates and empty flags (array version)
      +subroutine append_clean_flags_array(flags_array, new_flags_array)
      +    type(string_t), allocatable, intent(inout) :: flags_array(:)
      +    type(string_t), intent(in) :: new_flags_array(:)
      +
      +    integer :: i
      +
      +    do i = 1, size(new_flags_array)
      +        if (string_array_contains(new_flags_array(i)%s, flags_array)) cycle
      +        ! Filter out empty flags and arguments
      +        if (new_flags_array(i)%s == "") cycle
      +        if (trim(new_flags_array(i)%s) == "-l") cycle
      +        if (trim(new_flags_array(i)%s) == "-L") cycle
      +        if (trim(new_flags_array(i)%s) == "-I") cycle
      +        if (trim(new_flags_array(i)%s) == "-J") cycle
      +        if (trim(new_flags_array(i)%s) == "-M") cycle
      +        flags_array = [flags_array, new_flags_array(i)]
      +    end do
      +end subroutine append_clean_flags_array
      +
      +!> Tokenize a string into an array of compiler flags
      +subroutine tokenize_flags(flags, flags_array)
      +    character(*), intent(in) :: flags
      +    type(string_t), allocatable, intent(out) :: flags_array(:)
      +    character(len=:), allocatable :: flags_char_array(:)
      +
      +    integer :: i
      +    logical :: success
      +
      +    flags_char_array = sh_split(flags, join_spaced=.true., keep_quotes=.true., success=success)
      +    if (.not. success) then
      +        allocate(flags_array(0))
      +        return
      +    end if
      +    allocate(flags_array(size(flags_char_array)))
      +    do i = 1, size(flags_char_array)
      +        flags_array(i)%s = trim(adjustl(flags_char_array(i)))
      +    end do
      +end subroutine tokenize_flags
      +
      +end module fpm_compiler
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/fpm_environment.f90.html b/sourcefile/fpm_environment.f90.html new file mode 100644 index 0000000000..c97885d40c --- /dev/null +++ b/sourcefile/fpm_environment.f90.html @@ -0,0 +1,677 @@ + + + + + + + + + + + + + fpm_environment.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      fpm_environment.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      !> This module contains procedures that interact with the programming environment.
      +!!
      +!! * [get_os_type] -- Determine the OS type
      +!! * [get_env] -- return the value of an environment variable
      +module fpm_environment
      +    use,intrinsic :: iso_fortran_env, only : stdin=>input_unit,   &
      +                                           & stdout=>output_unit, &
      +                                           & stderr=>error_unit
      +    use,intrinsic :: iso_c_binding, only: c_char,c_int,c_null_char
      +    use fpm_error, only : fpm_stop
      +    implicit none
      +    private
      +    public :: get_os_type
      +    public :: os_is_unix
      +    public :: get_env
      +    public :: set_env
      +    public :: delete_env
      +    public :: get_command_arguments_quoted
      +    public :: separator
      +    public :: library_filename
      +    
      +                        public :: OS_NAME
      +    integer, parameter, public :: OS_UNKNOWN = 0
      +    integer, parameter, public :: OS_LINUX   = 1
      +    integer, parameter, public :: OS_MACOS   = 2
      +    integer, parameter, public :: OS_WINDOWS = 3
      +    integer, parameter, public :: OS_CYGWIN  = 4
      +    integer, parameter, public :: OS_SOLARIS = 5
      +    integer, parameter, public :: OS_FREEBSD = 6
      +    integer, parameter, public :: OS_OPENBSD = 7
      +contains
      +
      +    !> Utility function: return library filename
      +    pure function library_filename(package_name, shared, import, target_os) result(name)
      +        character(*), intent(in) :: package_name    
      +        !> Whether it's a shared library
      +        logical, intent(in) :: shared       
      +        !> Whether it's for linking (import library) or actual library
      +        logical, intent(in) :: import       
      +        !> Build target OS: one of OS_WINDOWS, OS_MACOS, ...
      +        integer, intent(in) :: target_os        
      +
      +        character(len=:), allocatable :: name
      +
      +        if (shared) then
      +            select case (target_os)
      +            case (OS_WINDOWS)
      +                if (import) then
      +                    ! Linking requires the import library
      +                    name = 'lib' // package_name // '.lib'
      +                else
      +                    ! The actual shared object is a DLL
      +                    name = 'lib' // package_name // '.dll'
      +                end if
      +            case (OS_MACOS)
      +                name = 'lib' // package_name // '.dylib'
      +            case default
      +                name = 'lib' // package_name // '.so'
      +            end select
      +        else
      +            ! Static library (same for all platforms)
      +            name = 'lib' // package_name // '.a'
      +        end if
      +
      +    end function library_filename
      +
      +    !> Return string describing the OS type flag
      +    pure function OS_NAME(os)
      +        integer, intent(in) :: os
      +        character(len=:), allocatable :: OS_NAME
      +
      +        select case (os)
      +            case (OS_LINUX);   OS_NAME =  "Linux"
      +            case (OS_MACOS);   OS_NAME =  "macOS"
      +            case (OS_WINDOWS); OS_NAME =  "Windows"
      +            case (OS_CYGWIN);  OS_NAME =  "Cygwin"
      +            case (OS_SOLARIS); OS_NAME =  "Solaris"
      +            case (OS_FREEBSD); OS_NAME =  "FreeBSD"
      +            case (OS_OPENBSD); OS_NAME =  "OpenBSD"
      +            case (OS_UNKNOWN); OS_NAME =  "Unknown"
      +            case default     ; OS_NAME =  "UNKNOWN"
      +        end select
      +    end function OS_NAME
      +
      +    !> Determine the OS type
      +    integer function get_os_type() result(r)
      +        !!
      +        !! Returns one of OS_UNKNOWN, OS_LINUX, OS_MACOS, OS_WINDOWS, OS_CYGWIN,
      +        !! OS_SOLARIS, OS_FREEBSD, OS_OPENBSD.
      +        !!
      +        !! At first, the environment variable `OS` is checked, which is usually
      +        !! found on Windows. Then, `OSTYPE` is read in and compared with common
      +        !! names. If this fails too, check the existence of files that can be
      +        !! found on specific system types only.
      +        !!
      +        !! Returns OS_UNKNOWN if the operating system cannot be determined.
      +        character(len=255) :: val
      +        integer            :: length, rc
      +        logical            :: file_exists
      +        logical, save      :: first_run = .true.
      +        integer, save      :: ret = OS_UNKNOWN
      +        !$omp threadprivate(ret, first_run)
      +
      +        if (.not. first_run) then
      +            r = ret
      +            return
      +        end if
      +
      +        first_run = .false.
      +        r = OS_UNKNOWN
      +
      +        ! Check environment variable `OSTYPE`.
      +        call get_environment_variable('OSTYPE', val, length, rc)
      +
      +        if (rc == 0 .and. length > 0) then
      +            ! Linux
      +            if (index(val, 'linux') > 0) then
      +                r = OS_LINUX
      +                ret = r
      +                return
      +            end if
      +
      +            ! macOS
      +            if (index(val, 'darwin') > 0) then
      +                r = OS_MACOS
      +                ret = r
      +                return
      +            end if
      +
      +            ! Windows, MSYS, MinGW, Git Bash
      +            if (index(val, 'win') > 0 .or. index(val, 'msys') > 0) then
      +                r = OS_WINDOWS
      +                ret = r
      +                return
      +            end if
      +
      +            ! Cygwin
      +            if (index(val, 'cygwin') > 0) then
      +                r = OS_CYGWIN
      +                ret = r
      +                return
      +            end if
      +
      +            ! Solaris, OpenIndiana, ...
      +            if (index(val, 'SunOS') > 0 .or. index(val, 'solaris') > 0) then
      +                r = OS_SOLARIS
      +                ret = r
      +                return
      +            end if
      +
      +            ! FreeBSD
      +            if (index(val, 'FreeBSD') > 0 .or. index(val, 'freebsd') > 0) then
      +                r = OS_FREEBSD
      +                ret = r
      +                return
      +            end if
      +
      +            ! OpenBSD
      +            if (index(val, 'OpenBSD') > 0 .or. index(val, 'openbsd') > 0) then
      +                r = OS_OPENBSD
      +                ret = r
      +                return
      +            end if
      +        end if
      +
      +        ! Check environment variable `OS`.
      +        call get_environment_variable('OS', val, length, rc)
      +
      +        if (rc == 0 .and. length > 0 .and. index(val, 'Windows_NT') > 0) then
      +            r = OS_WINDOWS
      +            ret = r
      +            return
      +        end if
      +
      +        ! Linux
      +        inquire (file='/etc/os-release', exist=file_exists)
      +
      +        if (file_exists) then
      +            r = OS_LINUX
      +            ret = r
      +            return
      +        end if
      +
      +        ! macOS
      +        inquire (file='/usr/bin/sw_vers', exist=file_exists)
      +
      +        if (file_exists) then
      +            r = OS_MACOS
      +            ret = r
      +            return
      +        end if
      +
      +        ! FreeBSD
      +        inquire (file='/bin/freebsd-version', exist=file_exists)
      +
      +        if (file_exists) then
      +            r = OS_FREEBSD
      +            ret = r
      +            return
      +        end if
      +    end function get_os_type
      +
      +    !> Compare the output of [[get_os_type]] or the optional
      +    !! passed INTEGER value to the value for OS_WINDOWS
      +    !! and return .TRUE. if they match and .FALSE. otherwise
      +    logical function os_is_unix(os)
      +        integer, intent(in), optional :: os
      +        integer :: build_os
      +        if (present(os)) then
      +            build_os = os
      +        else
      +            build_os = get_os_type()
      +        end if
      +        os_is_unix = build_os /= OS_WINDOWS
      +    end function os_is_unix
      +
      +    !> get named environment variable value. It it is blank or
      +    !! not set return the optional default value
      +    function get_env(NAME,DEFAULT) result(VALUE)
      +    implicit none
      +    !> name of environment variable to get the value of
      +    character(len=*),intent(in)          :: NAME
      +    !> default value to return if the requested value is undefined or blank
      +    character(len=*),intent(in),optional :: DEFAULT
      +    !> the returned value
      +    character(len=:),allocatable         :: VALUE
      +    integer                              :: howbig
      +    integer                              :: stat
      +    integer                              :: length
      +        ! get length required to hold value
      +        length=0
      +        if(NAME/='')then
      +           call get_environment_variable(NAME, length=howbig,status=stat,trim_name=.true.)
      +           select case (stat)
      +           case (1)
      +               !*!print *, NAME, " is not defined in the environment. Strange..."
      +               VALUE=''
      +           case (2)
      +               !*!print *, "This processor doesn't support environment variables. Boooh!"
      +               VALUE=''
      +           case default
      +               ! make string to hold value of sufficient size
      +               allocate(character(len=max(howbig,1)) :: VALUE)
      +               ! get value
      +               call get_environment_variable(NAME,VALUE,status=stat,trim_name=.true.)
      +               if(stat/=0)VALUE=''
      +           end select
      +        else
      +           VALUE=''
      +        endif
      +        if(VALUE==''.and.present(DEFAULT))VALUE=DEFAULT
      +     end function get_env
      +
      +    function get_command_arguments_quoted() result(args)
      +    character(len=:),allocatable :: args
      +    character(len=:),allocatable :: arg
      +    character(len=1)             :: quote
      +    integer                      :: ilength, istatus, i
      +    ilength=0
      +    args=''
      +        quote=merge('"',"'",separator()=='\')
      +        do i=2,command_argument_count() ! look at all arguments after subcommand
      +            call get_command_argument(number=i,length=ilength,status=istatus)
      +            if(istatus /= 0) then
      +                write(stderr,'(*(g0,1x))')'<ERROR>*get_command_arguments_stack* error obtaining argument ',i
      +                exit
      +            else
      +                if(allocated(arg))deallocate(arg)
      +                allocate(character(len=ilength) :: arg)
      +                call get_command_argument(number=i,value=arg,length=ilength,status=istatus)
      +                if(istatus /= 0) then
      +                    write(stderr,'(*(g0,1x))')'<ERROR>*get_command_arguments_stack* error obtaining argument ',i
      +                    exit
      +                elseif(ilength>0)then
      +                    if(index(arg//' ','-')/=1)then
      +                        args=args//quote//arg//quote//' '
      +                    elseif(index(arg,' ')/=0)then
      +                        args=args//quote//arg//quote//' '
      +                    else
      +                        args=args//arg//' '
      +                    endif
      +                else
      +                    args=args//repeat(quote,2)//' '
      +                endif
      +             endif
      +         enddo
      +    end function get_command_arguments_quoted
      +
      +function separator() result(sep)
      +!>
      +!!##NAME
      +!!    separator(3f) - [M_io:ENVIRONMENT] try to determine pathname directory separator character
      +!!    (LICENSE:PD)
      +!!
      +!!##SYNOPSIS
      +!!
      +!!    function separator() result(sep)
      +!!
      +!!     character(len=1) :: sep
      +!!
      +!!##DESCRIPTION
      +!!    First using the name the program was invoked with, then the name
      +!!    returned by an INQUIRE(3f) of that name, then ".\NAME" and "./NAME"
      +!!    try to determine the separator character used to separate directory
      +!!    names from file basenames.
      +!!
      +!!    If a slash or backslash is not found in the name, the environment
      +!!    variable PATH is examined first for a backslash, then a slash.
      +!!
      +!!    Can be very system dependent. If the queries fail the default returned
      +!!    is "/".
      +!!
      +!!##EXAMPLE
      +!!
      +!!   sample usage
      +!!
      +!!    program demo_separator
      +!!    use M_io, only : separator
      +!!    implicit none
      +!!       write(*,*)'separator=',separator()
      +!!    end program demo_separator
      +
      +! use the pathname returned as arg0 to determine pathname separator
      +implicit none
      +character(len=:),allocatable :: arg0
      +integer                      :: arg0_length
      +integer                      :: istat
      +logical                      :: existing
      +character(len=1)             :: sep
      +!*ifort_bug*!character(len=1),save        :: sep_cache=' '
      +character(len=4096)          :: name
      +character(len=:),allocatable :: fname
      +
      +   !*ifort_bug*!   if(sep_cache/=' ')then  ! use cached value. NOTE:  A parallel code might theoretically use multiple OS
      +   !*ifort_bug*!      sep=sep_cache
      +   !*ifort_bug*!      return
      +   !*ifort_bug*!   endif
      +
      +   arg0_length=0
      +   name=' '
      +   call get_command_argument(0,length=arg0_length,status=istat)
      +   if(allocated(arg0))deallocate(arg0)
      +   allocate(character(len=arg0_length) :: arg0)
      +   call get_command_argument(0,arg0,status=istat)
      +   ! check argument name
      +   if(index(arg0,'\')/=0)then
      +      sep='\'
      +   elseif(index(arg0,'/')/=0)then
      +      sep='/'
      +   else
      +      ! try name returned by INQUIRE(3f)
      +      existing=.false.
      +      name=' '
      +      inquire(file=arg0,iostat=istat,exist=existing,name=name)
      +      if(index(name,'\')/=0)then
      +         sep='\'
      +      elseif(index(name,'/')/=0)then
      +         sep='/'
      +      else
      +         ! well, try some common syntax and assume in current directory
      +         fname='.\'//arg0
      +         inquire(file=fname,iostat=istat,exist=existing)
      +         if(existing)then
      +            sep='\'
      +         else
      +            fname='./'//arg0
      +            inquire(file=fname,iostat=istat,exist=existing)
      +            if(existing)then
      +               sep='/'
      +            else ! check environment variable PATH
      +               sep=merge('\','/',index(get_env('PATH'),'\')/=0)
      +               !*!write(*,*)'<WARNING>unknown system directory path separator'
      +            endif
      +         endif
      +      endif
      +   endif
      +   !*ifort_bug*!sep_cache=sep
      +end function separator
      +
      +!> Set an environment variable for the current environment using the C standard library
      +logical function set_env(name,value,overwrite)
      +
      +   !> Variable name
      +   character(*), intent(in) :: name
      +   
      +   !> Variable value
      +   character(*), intent(in) :: value
      +   
      +   !> Should a former value be overwritten? default = .true.
      +   logical, optional, intent(in) :: overwrite
      +   
      +   ! Local variables
      +   logical :: can_overwrite
      +   integer(c_int) :: cover,cerr
      +   character(kind=c_char,len=1), allocatable :: c_value(:),c_name(:)
      +   
      +   interface
      +      integer(c_int) function c_setenv(envname, envval, overwrite) &
      +                     bind(C,name="c_setenv")
      +         import c_int, c_char
      +         implicit none
      +         !> Pointer to the name string
      +         character(kind=c_char,len=1), intent(in) :: envname(*)
      +         !> Pointer to the value string 
      +         character(kind=c_char,len=1), intent(in) :: envval(*)
      +         !> Overwrite option
      +         integer(c_int), intent(in), value :: overwrite
      +      end function c_setenv 
      +   end interface
      +   
      +   !> Overwrite setting
      +   cerr = 0_c_int
      +   can_overwrite = .true.
      +   if (present(overwrite)) can_overwrite = overwrite
      +   cover = merge(1_c_int,0_c_int,can_overwrite)
      +   
      +   !> C strings
      +   call f2cs(name,c_name)
      +   call f2cs(value,c_value)
      +   
      +   !> Call setenv
      +#ifndef FPM_BOOTSTRAP   
      +   cerr = c_setenv(c_name,c_value,cover)
      +#endif
      +   set_env = cerr==0_c_int
      +   
      +end function set_env
      +
      +!> Deletes an environment variable for the current environment using the C standard library
      +!> Returns an error if the variable did not exist in the first place
      +logical function delete_env(name) result(success)
      +
      +   !> Variable name
      +   character(*), intent(in) :: name
      +   
      +   ! Local variables
      +   integer(c_int) :: cerr
      +   character(kind=c_char,len=1), allocatable :: c_name(:)
      +   
      +   interface
      +      integer(c_int) function c_unsetenv(envname) bind(C,name="c_unsetenv")
      +         import c_int, c_char
      +         implicit none
      +         !> Pointer to the name string
      +         character(kind=c_char,len=1), intent(in) :: envname(*)
      +      end function c_unsetenv      
      +   end interface
      +   
      +   !> C strings
      +   call f2cs(name,c_name)
      +   
      +   !> Call setenv
      +#ifndef FPM_BOOTSTRAP   
      +   cerr = c_unsetenv(c_name)
      +#endif
      +   success = cerr==0_c_int
      +   
      +end function delete_env
      +
      +!> Fortran to C allocatable string
      +pure subroutine f2cs(f,c)
      +  use iso_c_binding, only: c_char,c_null_char
      +  character(*), intent(in) :: f
      +  character(len=1,kind=c_char), allocatable, intent(out) :: c(:)
      +  
      +  integer :: lf,i
      +  
      +  lf = len(f)
      +  allocate(c(lf+1))
      +  c(lf+1) = c_null_char 
      +  forall(i=1:lf) c(i) = f(i:i)
      +  
      +end subroutine f2cs 
      +
      +end module fpm_environment
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/fpm_filesystem.f90.html b/sourcefile/fpm_filesystem.f90.html new file mode 100644 index 0000000000..276248959a --- /dev/null +++ b/sourcefile/fpm_filesystem.f90.html @@ -0,0 +1,1458 @@ + + + + + + + + + + + + + fpm_filesystem.F90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      fpm_filesystem.F90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      !> This module contains general routines for interacting with the file system
      +!!
      +module fpm_filesystem
      +    use,intrinsic :: iso_fortran_env, only : stdin=>input_unit, stdout=>output_unit, stderr=>error_unit
      +    use,intrinsic :: iso_c_binding, only: c_new_line
      +    use fpm_environment, only: get_os_type, &
      +                               OS_UNKNOWN, OS_LINUX, OS_MACOS, OS_WINDOWS, &
      +                               OS_CYGWIN, OS_SOLARIS, OS_FREEBSD, OS_OPENBSD
      +    use fpm_environment, only: separator, get_env, os_is_unix
      +    use fpm_strings, only: f_string, replace, string_t, split, split_lines_first_last, dilate, str_begins_with_str
      +    use iso_c_binding, only: c_char, c_ptr, c_int, c_null_char, c_associated, c_f_pointer
      +    use fpm_error, only : fpm_stop, error_t, fatal_error
      +    implicit none
      +    private
      +    public :: basename, canon_path, dirname, is_dir, join_path, number_of_rows, list_files, get_local_prefix, &
      +            mkdir, exists, get_temp_filename, windows_path, unix_path, getline, delete_file, fileopen, fileclose, &
      +            filewrite, warnwrite, parent_dir, is_hidden_file, read_lines, read_lines_expanded, which, run, &
      +            os_delete_dir, is_absolute_path, get_home, execute_and_read_output, get_dos_path
      +
      +#ifndef FPM_BOOTSTRAP
      +    interface
      +        function c_opendir(dir) result(r) bind(c, name="c_opendir")
      +            import c_char, c_ptr
      +            character(kind=c_char), intent(in) :: dir(*)
      +            type(c_ptr) :: r
      +        end function c_opendir
      +
      +        function c_readdir(dir) result(r) bind(c, name="c_readdir")
      +            import c_ptr
      +            type(c_ptr), intent(in), value :: dir
      +            type(c_ptr) :: r
      +        end function c_readdir
      +
      +        function c_closedir(dir) result(r) bind(c, name="closedir")
      +            import c_ptr, c_int
      +            type(c_ptr), intent(in), value :: dir
      +            integer(kind=c_int) :: r
      +        end function c_closedir
      +
      +        function c_get_d_name(dir) result(r) bind(c, name="get_d_name")
      +            import c_ptr
      +            type(c_ptr), intent(in), value :: dir
      +            type(c_ptr) :: r
      +        end function c_get_d_name
      +
      +        function c_is_dir(path) result(r) bind(c, name="c_is_dir")
      +            import c_char, c_int
      +            character(kind=c_char), intent(in) :: path(*)
      +            integer(kind=c_int) :: r
      +        end function c_is_dir
      +    end interface
      +#endif
      +
      +contains
      +
      +!> Extract filename from path with/without suffix
      +function basename(path,suffix) result (base)
      +
      +    character(*), intent(In) :: path
      +    logical, intent(in), optional :: suffix
      +    character(:), allocatable :: base
      +
      +    character(:), allocatable :: file_parts(:)
      +    logical :: with_suffix
      +
      +    if (.not.present(suffix)) then
      +        with_suffix = .true.
      +    else
      +        with_suffix = suffix
      +    end if
      +
      +    call split(path,file_parts,delimiters='\/')
      +    if(size(file_parts)>0)then
      +       base = trim(file_parts(size(file_parts)))
      +    else
      +       base = ''
      +    endif
      +    if(.not.with_suffix)then
      +        call split(base,file_parts,delimiters='.')
      +        if(size(file_parts)>=2)then
      +           base = trim(file_parts(size(file_parts)-1))
      +        endif
      +    endif
      +
      +end function basename
      +
      +
      +!> Canonicalize path for comparison
      +!! * Handles path string redundancies
      +!! * Does not test existence of path
      +!!
      +!! To be replaced by realpath/_fullname in stdlib_os
      +!!
      +!! FIXME: Lot's of ugly hacks following here
      +function canon_path(path)
      +    character(len=*), intent(in) :: path
      +    character(len=:), allocatable :: canon_path
      +    character(len=:), allocatable :: nixpath
      +
      +    integer :: istart, iend, nn, last
      +    logical :: is_path, absolute
      +
      +    nixpath = unix_path(path)
      +
      +    istart = 0
      +    nn = 0
      +    iend = 0
      +    absolute = nixpath(1:1) == "/"
      +    if (absolute) then
      +        canon_path = "/"
      +    else
      +        canon_path = ""
      +    end if
      +
      +    do while(iend < len(nixpath))
      +        call next(nixpath, istart, iend, is_path)
      +        if (is_path) then
      +            select case(nixpath(istart:iend))
      +            case(".", "") ! always drop empty paths
      +            case("..")
      +                if (nn > 0) then
      +                    last = scan(canon_path(:len(canon_path)-1), "/", back=.true.)
      +                    canon_path = canon_path(:last)
      +                    nn = nn - 1
      +                else
      +                    if (.not. absolute) then
      +                        canon_path = canon_path // nixpath(istart:iend) // "/"
      +                    end if
      +                end if
      +            case default
      +                nn = nn + 1
      +                canon_path = canon_path // nixpath(istart:iend) // "/"
      +            end select
      +        end if
      +    end do
      +
      +    if (len(canon_path) == 0) canon_path = "."
      +    if (len(canon_path) > 1 .and. canon_path(len(canon_path):) == "/") then
      +        canon_path = canon_path(:len(canon_path)-1)
      +    end if
      +
      +contains
      +
      +    subroutine next(string, istart, iend, is_path)
      +        character(len=*), intent(in) :: string
      +        integer, intent(inout) :: istart
      +        integer, intent(inout) :: iend
      +        logical, intent(inout) :: is_path
      +
      +        integer :: ii, nn
      +        character :: tok
      +
      +        nn = len(string)
      +
      +        if (iend >= nn) then
      +            istart = nn
      +            iend = nn
      +            return
      +        end if
      +
      +        ii = min(iend + 1, nn)
      +        tok = string(ii:ii)
      +
      +        is_path = tok /= '/'
      +
      +        if (.not.is_path) then
      +            is_path = .false.
      +            istart = ii
      +            iend = ii
      +            return
      +        end if
      +
      +        istart = ii
      +        do ii = min(iend + 1, nn), nn
      +            tok = string(ii:ii)
      +            select case(tok)
      +            case('/')
      +                exit
      +            case default
      +                iend = ii
      +                cycle
      +            end select
      +        end do
      +
      +    end subroutine next
      +end function canon_path
      +
      +
      +!> Extract dirname from path
      +function dirname(path) result (dir)
      +    character(*), intent(in) :: path
      +    character(:), allocatable :: dir
      +
      +    dir = path(1:scan(path,'/\',back=.true.))
      +
      +end function dirname
      +
      +!> Extract dirname from path
      +function parent_dir(path) result (dir)
      +    character(*), intent(in) :: path
      +    character(:), allocatable :: dir
      +
      +    dir = path(1:scan(path,'/\',back=.true.)-1)
      +
      +end function parent_dir
      +
      +
      +!> test if a name matches an existing directory path
      +logical function is_dir(dir)
      +    character(*), intent(in) :: dir
      +    integer :: stat
      +
      +    select case (get_os_type())
      +
      +    case (OS_UNKNOWN, OS_LINUX, OS_MACOS, OS_CYGWIN, OS_SOLARIS, OS_FREEBSD, OS_OPENBSD)
      +        call run( "test -d " // dir , &
      +                & exitstat=stat,echo=.false.,verbose=.false.)
      +
      +    case (OS_WINDOWS)
      +        call run('cmd /c "if not exist ' // windows_path(dir) // '\ exit /B 1"', &
      +                & exitstat=stat,echo=.false.,verbose=.false.)
      +
      +    end select
      +
      +    is_dir = (stat == 0)
      +
      +end function is_dir
      +
      +!> test if a file is hidden
      +logical function is_hidden_file(file_basename) result(r)
      +    character(*), intent(in) :: file_basename
      +    if (len(file_basename) <= 2) then
      +        r = .false.
      +    else
      +        r = str_begins_with_str(file_basename, '.')
      +    end if
      +end function is_hidden_file
      +
      +!> Construct path by joining strings with os file separator
      +function join_path(a1,a2,a3,a4,a5) result(path)
      +
      +    character(len=*), intent(in)           :: a1, a2
      +    character(len=*), intent(in), optional :: a3, a4, a5
      +    character(len=:), allocatable          :: path
      +    character(len=1)                       :: filesep
      +    logical, save                          :: has_cache = .false.
      +    character(len=1), save                 :: cache = '/'
      +    !$omp threadprivate(has_cache, cache)
      +
      +    if (has_cache) then
      +        filesep = cache
      +    else
      +        select case (get_os_type())
      +            case default
      +                filesep = '/'
      +            case (OS_WINDOWS)
      +                filesep = '\'
      +        end select
      +
      +        cache = filesep
      +        has_cache = .true.
      +    end if
      +
      +    if (a1 == "") then
      +        path = a2
      +    else
      +        path = a1 // filesep // a2
      +    end if
      +
      +    if (present(a3)) then
      +        path = path // filesep // a3
      +    else
      +        return
      +    end if
      +
      +    if (present(a4)) then
      +        path = path // filesep // a4
      +    else
      +        return
      +    end if
      +
      +    if (present(a5)) then
      +        path = path // filesep // a5
      +    else
      +        return
      +    end if
      +
      +end function join_path
      +
      +
      +!> Determine number or rows in a file given a LUN
      +integer function number_of_rows(s) result(nrows)
      +    integer,intent(in)::s
      +    integer :: ios
      +    rewind(s)
      +    nrows = 0
      +    do
      +        read(s, *, iostat=ios)
      +        if (ios /= 0) exit
      +        nrows = nrows + 1
      +    end do
      +    rewind(s)
      +end function number_of_rows
      +
      +!> read lines into an array of TYPE(STRING_T) variables expanding tabs
      +function read_lines_expanded(filename) result(lines)
      +    character(len=*), intent(in) :: filename
      +    type(string_t), allocatable :: lines(:)
      +
      +    integer :: i
      +    character(len=:), allocatable :: content
      +    integer, allocatable :: first(:), last(:)
      +
      +    content = read_text_file(filename)
      +    if (len(content) == 0) then
      +        allocate (lines(0))
      +        return
      +    end if
      +
      +    call split_lines_first_last(content, first, last)  
      +
      +    ! allocate lines from file content string
      +    allocate (lines(size(first)))
      +    do i = 1, size(first)
      +        allocate(lines(i)%s, source=dilate(content(first(i):last(i))))
      +    end do
      +
      +end function read_lines_expanded
      +
      +!> read lines into an array of TYPE(STRING_T) variables
      +function read_lines(filename) result(lines)
      +    character(len=*), intent(in) :: filename
      +    type(string_t), allocatable :: lines(:)
      +
      +    integer :: i
      +    character(len=:), allocatable :: content
      +    integer, allocatable :: first(:), last(:)
      +
      +    content = read_text_file(filename)
      +    if (len(content) == 0) then
      +        allocate (lines(0))
      +        return
      +    end if
      +
      +    call split_lines_first_last(content, first, last) 
      +
      +    ! allocate lines from file content string
      +    allocate (lines(size(first)))
      +    do i = 1, size(first)
      +        allocate(lines(i)%s, source=content(first(i):last(i)))
      +    end do
      +
      +end function read_lines
      +
      +!> read text file into a string
      +function read_text_file(filename) result(string)
      +    character(len=*), intent(in) :: filename
      +    character(len=:), allocatable :: string
      +    integer :: fh, length
      +
      +    open (newunit=fh, file=filename, status='old', action='read', &
      +            access='stream', form='unformatted')
      +    inquire (fh, size=length)
      +    allocate (character(len=length) :: string)
      +    if (length == 0) return
      +    read (fh) string
      +    close (fh)
      +
      +end function read_text_file
      +
      +!> Create a directory. Create subdirectories as needed
      +subroutine mkdir(dir, echo)
      +    character(len=*), intent(in) :: dir
      +    logical, intent(in), optional :: echo
      +
      +    integer :: stat
      +
      +    if (is_dir(dir)) return
      +
      +    select case (get_os_type())
      +        case (OS_UNKNOWN, OS_LINUX, OS_MACOS, OS_CYGWIN, OS_SOLARIS, OS_FREEBSD, OS_OPENBSD)
      +            call run('mkdir -p ' // dir, exitstat=stat,echo=echo,verbose=.false.)
      +
      +        case (OS_WINDOWS)
      +            call run("mkdir " // windows_path(dir), &
      +                    & echo=echo, exitstat=stat,verbose=.false.)
      +
      +    end select
      +
      +    if (stat /= 0) then
      +        call fpm_stop(1, '*mkdir*:directory creation failed')
      +    end if
      +end subroutine mkdir
      +
      +#ifndef FPM_BOOTSTRAP
      +!> Get file & directory names in directory `dir` using iso_c_binding.
      +!!
      +!!  - File/directory names return are relative to cwd, ie. preprended with `dir`
      +!!  - Includes files starting with `.` except current directory and parent directory
      +!!
      +recursive subroutine list_files(dir, files, recurse)
      +    character(len=*), intent(in) :: dir
      +    type(string_t), allocatable, intent(out) :: files(:)
      +    logical, intent(in), optional :: recurse
      +
      +    integer :: i
      +    type(string_t), allocatable :: dir_files(:)
      +    type(string_t), allocatable :: sub_dir_files(:)
      +
      +    type(c_ptr) :: dir_handle
      +    type(c_ptr) :: dir_entry_c
      +    character(len=:,kind=c_char), allocatable :: fortran_name
      +    character(len=:), allocatable :: string_fortran
      +    integer, parameter :: N_MAX = 256
      +    type(string_t) :: files_tmp(N_MAX)
      +    integer(kind=c_int) :: r
      +
      +    if (c_is_dir(dir(1:len_trim(dir))//c_null_char) == 0) then
      +        allocate (files(0))
      +        return
      +    end if
      +
      +    dir_handle = c_opendir(dir(1:len_trim(dir))//c_null_char)
      +    if (.not. c_associated(dir_handle)) then
      +        print *, 'c_opendir() failed'
      +        error stop
      +    end if
      +
      +    i = 0
      +    allocate(files(0))
      +
      +    do
      +        dir_entry_c = c_readdir(dir_handle)
      +        if (.not. c_associated(dir_entry_c)) then
      +            exit
      +        else
      +            string_fortran = f_string(c_get_d_name(dir_entry_c))
      +
      +            if ((string_fortran == '.' .or. string_fortran == '..')) then
      +                cycle
      +            end if
      +
      +            i = i + 1
      +
      +            if (i > N_MAX) then
      +                files = [files, files_tmp]
      +                i = 1
      +            end if
      +
      +            files_tmp(i)%s = join_path(dir, string_fortran)
      +        end if
      +    end do
      +
      +    r = c_closedir(dir_handle)
      +
      +    if (r /= 0) then
      +        print *, 'c_closedir() failed'
      +        error stop
      +    end if
      +
      +    if (i > 0) then
      +        files = [files, files_tmp(1:i)]
      +    end if
      +
      +    if (present(recurse)) then
      +        if (recurse) then
      +
      +            allocate(sub_dir_files(0))
      +
      +            do i=1,size(files)
      +                if (c_is_dir(files(i)%s//c_null_char) /= 0) then
      +                    call list_files(files(i)%s, dir_files, recurse=.true.)
      +                    sub_dir_files = [sub_dir_files, dir_files]
      +                end if
      +            end do
      +
      +            files = [files, sub_dir_files]
      +        end if
      +    end if
      +end subroutine list_files
      +
      +#else
      +!> Get file & directory names in directory `dir`.
      +!!
      +!!  - File/directory names return are relative to cwd, ie. preprended with `dir`
      +!!  - Includes files starting with `.` except current directory and parent directory
      +!!
      +recursive subroutine list_files(dir, files, recurse)
      +    character(len=*), intent(in) :: dir
      +    type(string_t), allocatable, intent(out) :: files(:)
      +    logical, intent(in), optional :: recurse
      +
      +    integer :: stat, fh, i
      +    character(:), allocatable :: temp_file
      +    type(string_t), allocatable :: dir_files(:)
      +    type(string_t), allocatable :: sub_dir_files(:)
      +
      +    if (.not. is_dir(dir)) then
      +        allocate (files(0))
      +        return
      +    end if
      +
      +    allocate (temp_file, source=get_temp_filename())
      +
      +    select case (get_os_type())
      +        case (OS_UNKNOWN, OS_LINUX, OS_MACOS, OS_CYGWIN, OS_SOLARIS, OS_FREEBSD, OS_OPENBSD)
      +            call run('ls -A ' // dir , &
      +                    & redirect=temp_file, exitstat=stat,echo=.false.,verbose=.false.)
      +        case (OS_WINDOWS)
      +            call run('dir /b ' // windows_path(dir), &
      +                    & redirect=temp_file, exitstat=stat,echo=.false.,verbose=.false.)
      +    end select
      +
      +    if (stat /= 0) then
      +        call fpm_stop(2,'*list_files*:directory listing failed')
      +    end if
      +
      +    files = read_lines(temp_file)
      +    call delete_file(temp_file)
      +
      +    do i=1,size(files)
      +        files(i)%s = join_path(dir,files(i)%s)
      +    end do
      +
      +    if (present(recurse)) then
      +        if (recurse) then
      +
      +            allocate(sub_dir_files(0))
      +
      +            do i=1,size(files)
      +                if (is_dir(files(i)%s)) then
      +
      +                    call list_files(files(i)%s, dir_files, recurse=.true.)
      +                    sub_dir_files = [sub_dir_files, dir_files]
      +
      +                end if
      +            end do
      +
      +            files = [files, sub_dir_files]
      +
      +        end if
      +    end if
      +
      +end subroutine list_files
      +
      +#endif
      +
      +
      +!> test if pathname already exists
      +logical function exists(filename) result(r)
      +    character(len=*), intent(in) :: filename
      +    inquire(file=filename, exist=r)
      +
      +    !> Directories are not files for the Intel compilers. If so, also use this compiler-dependent extension
      +#if defined(__INTEL_COMPILER)
      +    if (.not.r) inquire(directory=filename, exist=r)
      +#endif
      +
      +end function
      +
      +
      +!> Get a unused temporary filename
      +!!  Calls posix 'tempnam' - not recommended, but
      +!!   we have no security concerns for this application
      +!!   and use here is temporary.
      +!! Works with MinGW
      +function get_temp_filename() result(tempfile)
      +    !
      +    use iso_c_binding, only: c_ptr, C_NULL_PTR, c_f_pointer
      +    integer, parameter :: MAX_FILENAME_LENGTH = 32768
      +    character(:), allocatable :: tempfile
      +
      +    type(c_ptr) :: c_tempfile_ptr
      +    character(len=1), pointer :: c_tempfile(:)
      +
      +    interface
      +
      +        function c_tempnam(dir,pfx) result(tmp) bind(c,name="tempnam")
      +            import
      +            type(c_ptr), intent(in), value :: dir
      +            type(c_ptr), intent(in), value :: pfx
      +            type(c_ptr) :: tmp
      +        end function c_tempnam
      +
      +        subroutine c_free(ptr) BIND(C,name="free")
      +            import
      +            type(c_ptr), value :: ptr
      +        end subroutine c_free
      +
      +    end interface
      +
      +    c_tempfile_ptr = c_tempnam(C_NULL_PTR, C_NULL_PTR)
      +    call c_f_pointer(c_tempfile_ptr,c_tempfile,[MAX_FILENAME_LENGTH])
      +
      +    tempfile = f_string(c_tempfile)
      +
      +    call c_free(c_tempfile_ptr)
      +
      +end function get_temp_filename
      +
      +
      +!> Replace file system separators for windows
      +function windows_path(path) result(winpath)
      +
      +    character(*), intent(in) :: path
      +    character(:), allocatable :: winpath
      +
      +    integer :: idx
      +
      +    winpath = path
      +
      +    idx = index(winpath,'/')
      +    do while(idx > 0)
      +        winpath(idx:idx) = '\'
      +        idx = index(winpath,'/')
      +    end do
      +
      +end function windows_path
      +
      +
      +!> Replace file system separators for unix
      +function unix_path(path) result(nixpath)
      +
      +    character(*), intent(in) :: path
      +    character(:), allocatable :: nixpath
      +
      +    integer :: idx
      +
      +    nixpath = path
      +
      +    idx = index(nixpath,'\')
      +    do while(idx > 0)
      +        nixpath(idx:idx) = '/'
      +        idx = index(nixpath,'\')
      +    end do
      +
      +end function unix_path
      +
      +!>AUTHOR: fpm(1) contributors
      +!!LICENSE: MIT
      +!>
      +!!##NAME
      +!!     getline(3f) - [M_io:READ] read a line of arbintrary length from specified
      +!!     LUN into allocatable string (up to system line length limit)
      +!!    (LICENSE:PD)
      +!!
      +!!##SYNTAX
      +!!   subroutine getline(unit,line,iostat,iomsg)
      +!!
      +!!    integer,intent(in)                       :: unit
      +!!    character(len=:),allocatable,intent(out) :: line
      +!!    integer,intent(out)                      :: iostat
      +!!    character(len=:), allocatable, optional  :: iomsg
      +!!
      +!!##DESCRIPTION
      +!!    Read a line of any length up to programming environment maximum
      +!!    line length. Requires Fortran 2003+.
      +!!
      +!!    It is primarily expected to be used when reading input which will
      +!!    then be parsed or echoed.
      +!!
      +!!    The input file must have a PAD attribute of YES for the function
      +!!    to work properly, which is typically true.
      +!!
      +!!    The simple use of a loop that repeatedly re-allocates a character
      +!!    variable in addition to reading the input file one buffer at a
      +!!    time could (depending on the programming environment used) be
      +!!    inefficient, as it could reallocate and allocate memory used for
      +!!    the output string with each buffer read.
      +!!
      +!!##OPTIONS
      +!!    LINE    The line read when IOSTAT returns as zero.
      +!!    LUN     LUN (Fortran logical I/O unit) number of file open and ready
      +!!            to read.
      +!!    IOSTAT  status returned by READ(IOSTAT=IOS). If not zero, an error
      +!!            occurred or an end-of-file or end-of-record was encountered.
      +!!    IOMSG   error message returned by system when IOSTAT is not zero.
      +!!
      +!!##EXAMPLE
      +!!
      +!!   Sample program:
      +!!
      +!!    program demo_getline
      +!!    use,intrinsic :: iso_fortran_env, only : stdin=>input_unit
      +!!    use,intrinsic :: iso_fortran_env, only : iostat_end
      +!!    use FPM_filesystem, only : getline
      +!!    implicit none
      +!!    integer :: iostat
      +!!    character(len=:),allocatable :: line, iomsg
      +!!       open(unit=stdin,pad='yes')
      +!!       INFINITE: do
      +!!          call getline(stdin,line,iostat,iomsg)
      +!!          if(iostat /= 0) exit INFINITE
      +!!          write(*,'(a)')'['//line//']'
      +!!       enddo INFINITE
      +!!       if(iostat /= iostat_end)then
      +!!          write(*,*)'error reading input:',iomsg
      +!!       endif
      +!!    end program demo_getline
      +!!
      +subroutine getline(unit, line, iostat, iomsg)
      +
      +    !> Formatted IO unit
      +    integer, intent(in) :: unit
      +
      +    !> Line to read
      +    character(len=:), allocatable, intent(out) :: line
      +
      +    !> Status of operation
      +    integer, intent(out) :: iostat
      +
      +    !> Error message
      +    character(len=:), allocatable, optional :: iomsg
      +
      +    integer, parameter :: BUFFER_SIZE = 1024
      +    character(len=BUFFER_SIZE)       :: buffer
      +    character(len=256)               :: msg
      +    integer :: size
      +    integer :: stat
      +
      +    allocate(character(len=0) :: line)
      +    do
      +        read(unit, '(a)', advance='no', iostat=stat, iomsg=msg, size=size) &
      +            & buffer
      +        if (stat > 0) exit
      +        line = line // buffer(:size)
      +        if (stat < 0) then
      +            if (is_iostat_eor(stat)) then
      +                stat = 0
      +            end if
      +            exit
      +        end if
      +    end do
      +
      +    if (stat /= 0) then
      +        if (present(iomsg)) iomsg = trim(msg)
      +    end if
      +    iostat = stat
      +
      +end subroutine getline
      +
      +
      +!> delete a file by filename
      +subroutine delete_file(file)
      +    character(len=*), intent(in) :: file
      +    logical :: exist
      +    integer :: unit
      +    inquire(file=file, exist=exist)
      +    if (exist) then
      +        open(file=file, newunit=unit)
      +        close(unit, status="delete")
      +    end if
      +end subroutine delete_file
      +
      +!> write trimmed character data to a file if it does not exist
      +subroutine warnwrite(fname,data)
      +character(len=*),intent(in) :: fname
      +character(len=*),intent(in) :: data(:)
      +
      +    if(.not.exists(fname))then
      +        call filewrite(fname,data)
      +    else
      +        write(stderr,'(*(g0,1x))')'<INFO>  ',fname,&
      +        & 'already exists. Not overwriting'
      +    endif
      +
      +end subroutine warnwrite
      +
      +!> procedure to open filename as a sequential "text" file
      +subroutine fileopen(filename,lun,ier)
      +
      +character(len=*),intent(in)   :: filename
      +integer,intent(out)           :: lun
      +integer,intent(out),optional  :: ier
      +integer                       :: ios
      +character(len=256)            :: message
      +
      +    message=' '
      +    ios=0
      +    if(filename/=' ')then
      +        open(file=filename, &
      +        & newunit=lun, &
      +        & form='formatted', &    ! FORM    = FORMATTED | UNFORMATTED
      +        & access='sequential', & ! ACCESS  = SEQUENTIAL| DIRECT | STREAM
      +        & action='write', &      ! ACTION  = READ|WRITE| READWRITE
      +        & position='rewind', &   ! POSITION= ASIS      | REWIND | APPEND
      +        & status='new', &        ! STATUS  = NEW| REPLACE| OLD| SCRATCH| UNKNOWN
      +        & iostat=ios, &
      +        & iomsg=message)
      +    else
      +        lun=stdout
      +        ios=0
      +    endif
      +    if(ios/=0)then
      +        lun=-1
      +        if(present(ier))then
      +           ier=ios
      +        else
      +           call fpm_stop(3,'*fileopen*:'//filename//':'//trim(message))
      +        endif
      +    endif
      +
      +end subroutine fileopen
      +
      +!> simple close of a LUN.  On error show message and stop (by default)
      +subroutine fileclose(lun,ier)
      +integer,intent(in)    :: lun
      +integer,intent(out),optional :: ier
      +character(len=256)    :: message
      +integer               :: ios
      +    if(lun/=-1)then
      +        close(unit=lun,iostat=ios,iomsg=message)
      +        if(ios/=0)then
      +            if(present(ier))then
      +               ier=ios
      +            else
      +               call fpm_stop(4,'*fileclose*:'//trim(message))
      +            endif
      +        endif
      +    endif
      +end subroutine fileclose
      +
      +!> procedure to write filedata to file filename
      +subroutine filewrite(filename,filedata)
      +
      +character(len=*),intent(in)           :: filename
      +character(len=*),intent(in)           :: filedata(:)
      +integer                               :: lun, i, ios
      +character(len=256)                    :: message
      +    call fileopen(filename,lun)
      +    if(lun/=-1)then ! program currently stops on error on open, but might
      +                      ! want it to continue so -1 (unallowed LUN) indicates error
      +       ! write file
      +       do i=1,size(filedata)
      +           write(lun,'(a)',iostat=ios,iomsg=message)trim(filedata(i))
      +           if(ios/=0)then
      +               call fpm_stop(5,'*filewrite*:'//filename//':'//trim(message))
      +           endif
      +       enddo
      +    endif
      +    ! close file
      +    call fileclose(lun)
      +
      +end subroutine filewrite
      +
      +!>AUTHOR: John S. Urban
      +!!LICENSE: Public Domain
      +!>
      +!!##Name
      +!!     which(3f) - [M_io:ENVIRONMENT] given a command name find the pathname by searching
      +!!                 the directories in the environment variable $PATH
      +!!     (LICENSE:PD)
      +!!
      +!!##Syntax
      +!!   function which(command) result(pathname)
      +!!
      +!!    character(len=*),intent(in)  :: command
      +!!    character(len=:),allocatable :: pathname
      +!!
      +!!##Description
      +!!    Given a command name find the first file with that name in the directories
      +!!    specified by the environment variable $PATH.
      +!!
      +!!##options
      +!!    COMMAND   the command to search for
      +!!
      +!!##Returns
      +!!    PATHNAME  the first pathname found in the current user path. Returns blank
      +!!              if the command is not found.
      +!!
      +!!##Example
      +!!
      +!!   Sample program:
      +!!
      +!!   Checking the error message and counting lines:
      +!!
      +!!     program demo_which
      +!!     use M_io, only : which
      +!!     implicit none
      +!!        write(*,*)'ls is ',which('ls')
      +!!        write(*,*)'dir is ',which('dir')
      +!!        write(*,*)'install is ',which('install')
      +!!     end program demo_which
      +!!
      +function which(command) result(pathname)
      +character(len=*),intent(in)     :: command
      +character(len=:),allocatable    :: pathname, checkon, paths(:), exts(:)
      +integer                         :: i, j
      +   pathname=''
      +   call split(get_env('PATH'),paths,delimiters=merge(';',':',separator()=='\'))
      +   SEARCH: do i=1,size(paths)
      +      checkon=trim(join_path(trim(paths(i)),command))
      +      select case(separator())
      +      case('/')
      +         if(exists(checkon))then
      +            pathname=checkon
      +            exit SEARCH
      +         endif
      +      case('\')
      +         if(exists(checkon))then
      +            pathname=checkon
      +            exit SEARCH
      +         endif
      +         if(exists(checkon//'.bat'))then
      +            pathname=checkon//'.bat'
      +            exit SEARCH
      +         endif
      +         if(exists(checkon//'.exe'))then
      +            pathname=checkon//'.exe'
      +            exit SEARCH
      +         endif
      +         call split(get_env('PATHEXT'),exts,delimiters=';')
      +         do j=1,size(exts)
      +            if(exists(checkon//'.'//trim(exts(j))))then
      +               pathname=checkon//'.'//trim(exts(j))
      +               exit SEARCH
      +            endif
      +         enddo
      +      end select
      +   enddo SEARCH
      +end function which
      +
      +!>AUTHOR: fpm(1) contributors
      +!!LICENSE: MIT
      +!>
      +!!##Name
      +!!    run(3f) -  execute specified system command and selectively echo
      +!!    command and output to a file and/or stdout.
      +!!    (LICENSE:MIT)
      +!!
      +!!##Syntax
      +!!    subroutine run(cmd,echo,exitstat,verbose,redirect)
      +!!
      +!!     character(len=*), intent(in)       :: cmd
      +!!     logical,intent(in),optional        :: echo
      +!!     integer, intent(out),optional      :: exitstat
      +!!     logical, intent(in), optional      :: verbose
      +!!     character(*), intent(in), optional :: redirect
      +!!
      +!!##Description
      +!!   Execute the specified system command. Optionally
      +!!
      +!!   +  echo the command before execution
      +!!   +  return the system exit status of the command.
      +!!   +  redirect the output of the command to a file.
      +!!   +  echo command output to stdout
      +!!
      +!!   Calling run(3f) is preferred to direct calls to
      +!!   execute_command_line(3f) in the fpm(1) source to provide a standard
      +!!   interface where output modes can be specified.
      +!!
      +!!##Options
      +!!    CMD       System command to execute
      +!!    ECHO      Whether to echo the command being executed or not
      +!!              Defaults to .TRUE. .
      +!!    VERBOSE   Whether to redirect the command output to a null device or not
      +!!              Defaults to .TRUE. .
      +!!    REDIRECT  Filename to redirect stdout and stderr of the command into.
      +!!              If generated it is closed before run(3f) returns.
      +!!    EXITSTAT  The system exit status of the command when supported by
      +!!              the system. If not present and a non-zero status is
      +!!              generated program termination occurs.
      +!!
      +!!##Example
      +!!
      +!!   Sample program:
      +!!
      +!!   Checking the error message and counting lines:
      +!!
      +!!     program demo_run
      +!!     use fpm_filesystem, only : run
      +!!     implicit none
      +!!     logical,parameter :: T=.true., F=.false.
      +!!     integer :: exitstat
      +!!     character(len=:),allocatable :: cmd
      +!!        cmd='ls -ltrasd *.md'
      +!!        call run(cmd)
      +!!        call run(cmd,exitstat=exitstat)
      +!!        call run(cmd,echo=F)
      +!!        call run(cmd,verbose=F)
      +!!     end program demo_run
      +!!
      +subroutine run(cmd,echo,exitstat,verbose,redirect)
      +    character(len=*), intent(in) :: cmd
      +    logical,intent(in),optional  :: echo
      +    integer, intent(out),optional :: exitstat
      +    logical, intent(in), optional :: verbose
      +    character(*), intent(in), optional :: redirect
      +
      +    integer            :: cmdstat
      +    character(len=256) :: cmdmsg, iomsg
      +    logical :: echo_local, verbose_local
      +    character(:), allocatable :: redirect_str
      +    character(:), allocatable :: line
      +    integer :: stat, fh, iostat
      +
      +    if(present(echo))then
      +       echo_local=echo
      +    else
      +       echo_local=.true.
      +    end if
      +
      +    if(present(verbose))then
      +        verbose_local=verbose
      +    else
      +        verbose_local=.true.
      +    end if
      +
      +    if (present(redirect)) then
      +        if(redirect /= '')then
      +           redirect_str =  ">"//redirect//" 2>&1"
      +        else
      +           redirect_str = "" 
      +        endif
      +    else
      +        if(verbose_local)then
      +            ! No redirection but verbose output
      +            redirect_str = ""
      +        else
      +            ! No redirection and non-verbose output
      +            if (os_is_unix()) then
      +                redirect_str = " >/dev/null 2>&1"
      +            else
      +                redirect_str = " >NUL 2>&1"
      +            end if
      +        end if
      +    end if
      +
      +    if(echo_local) print *, '+ ', cmd !//redirect_str
      +
      +    call execute_command_line(cmd//redirect_str, exitstat=stat,cmdstat=cmdstat,cmdmsg=cmdmsg)
      +    if(cmdstat /= 0)then
      +        write(*,'(a)')'<ERROR>:failed command '//cmd//redirect_str
      +        call fpm_stop(1,'*run*:'//trim(cmdmsg))
      +    endif
      +
      +    if (verbose_local.and.present(redirect)) then
      +
      +        open(newunit=fh,file=redirect,status='old',iostat=iostat,iomsg=iomsg)
      +        if(iostat == 0)then
      +           do
      +               call getline(fh, line, iostat)
      +               if (iostat /= 0) exit
      +               write(*,'(A)') trim(line)
      +           end do
      +        else
      +           write(*,'(A)') trim(iomsg)
      +        endif
      +
      +        close(fh)
      +
      +    end if
      +
      +    if (present(exitstat)) then
      +        exitstat = stat
      +    elseif (stat /= 0) then
      +        call fpm_stop(stat,'*run*: Command '//cmd//redirect_str//' returned a non-zero status code')
      +    end if
      +
      +end subroutine run
      +
      +!> Delete directory using system OS remove directory commands
      +subroutine os_delete_dir(is_unix, dir, echo)
      +    logical, intent(in) :: is_unix
      +    character(len=*), intent(in) :: dir
      +    logical, intent(in), optional :: echo
      +
      +    if (is_unix) then
      +        call run('rm -rf ' // dir, echo=echo,verbose=.false.)
      +    else
      +        call run('rmdir /s/q ' // dir, echo=echo,verbose=.false.)
      +    end if
      +
      +end subroutine os_delete_dir
      +
      +    !> Determine the path prefix to the local folder. Used for installation, registry etc.
      +    function get_local_prefix(os) result(prefix)
      +        !> Installation prefix
      +        character(len=:), allocatable :: prefix
      +        !> Platform identifier
      +        integer, intent(in), optional :: os
      +
      +        !> Default installation prefix on Unix platforms
      +        character(len=*), parameter :: default_prefix_unix = "/usr/local"
      +        !> Default installation prefix on Windows platforms
      +        character(len=*), parameter :: default_prefix_win = "C:\"
      +
      +        character(len=:), allocatable :: home
      +
      +        if (os_is_unix(os)) then
      +            home=get_env('HOME','')
      +            if (home /= '' ) then
      +                prefix = join_path(home, ".local")
      +            else
      +                prefix = default_prefix_unix
      +            end if
      +        else
      +            home=get_env('APPDATA','')
      +            if (home /= '' ) then
      +                prefix = join_path(home, "local")
      +            else
      +                prefix = default_prefix_win
      +            end if
      +        end if
      +
      +    end function get_local_prefix
      +
      +    !> Returns .true. if provided path is absolute.
      +    !>
      +    !> `~` not treated as absolute.
      +    logical function is_absolute_path(path, is_unix)
      +        character(len=*), intent(in) :: path
      +        logical, optional, intent(in):: is_unix
      +        character(len=*), parameter :: letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
      +        logical :: is_unix_os
      +
      +        if (present(is_unix)) then
      +            is_unix_os = is_unix
      +        else
      +            is_unix_os = os_is_unix()
      +        end if
      +
      +        if (is_unix_os) then
      +            is_absolute_path = path(1:1) == '/'
      +        else
      +            if (len(path) < 2) then
      +                is_absolute_path = .false.
      +                return
      +            end if
      +
      +            is_absolute_path = index(letters, path(1:1)) /= 0 .and. path(2:2) == ':'
      +        end if
      +
      +    end function is_absolute_path
      +
      +    !> Get the HOME directory on Unix and the %USERPROFILE% directory on Windows.
      +    subroutine get_home(home, error)
      +        character(len=:), allocatable, intent(out) :: home
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        if (os_is_unix()) then
      +            home=get_env('HOME','')
      +            if ( home == '' ) then
      +                call fatal_error(error, "Couldn't retrieve 'HOME' variable")
      +                return
      +            end if
      +        else
      +            home=get_env('USERPROFILE','')
      +            if ( home == '' ) then
      +                call fatal_error(error, "Couldn't retrieve '%USERPROFILE%' variable")
      +                return
      +            end if
      +        end if
      +    end subroutine get_home
      +
      +    !> Execute command line and return output as a string.
      +    subroutine execute_and_read_output(cmd, output, error, verbose)
      +        !> Command to execute.
      +        character(len=*), intent(in) :: cmd
      +        !> Command line output.
      +        character(len=:), allocatable, intent(out) :: output
      +        !> Error to handle.
      +        type(error_t), allocatable, intent(out) :: error
      +        !> Print additional information if true.
      +        logical, intent(in), optional :: verbose
      +
      +        integer :: exitstat, unit, stat
      +        character(len=:), allocatable :: cmdmsg, tmp_file, output_line
      +        logical :: is_verbose
      +
      +        if (present(verbose)) then
      +          is_verbose = verbose
      +        else
      +          is_verbose = .false.
      +        end if
      +
      +        tmp_file = get_temp_filename()
      +
      +        call run(cmd//' > '//tmp_file, exitstat=exitstat, echo=is_verbose)
      +        if (exitstat /= 0) call fatal_error(error, '*run*: '//"Command failed: '"//cmd//"'. Message: '"//trim(cmdmsg)//"'.")
      +
      +        open(newunit=unit, file=tmp_file, action='read', status='old')
      +        output = ''
      +        do
      +           call getline(unit, output_line, stat)
      +           if (stat /= 0) exit
      +           output = output//output_line//' '
      +        end do
      +        if (is_verbose) print *, output
      +        close(unit, status='delete')
      +    end
      +
      +    !> Ensure a windows path is converted to an 8.3 DOS path if it contains spaces
      +    function get_dos_path(path,error)
      +        character(len=*), intent(in) :: path
      +        type(error_t), allocatable, intent(out) :: error
      +        character(len=:), allocatable :: get_dos_path
      +
      +        character(:), allocatable :: redirect,screen_output,line
      +        integer :: stat,cmdstat,iunit,last
      +
      +        ! Non-Windows OS
      +        if (get_os_type()/=OS_WINDOWS) then
      +            get_dos_path = path
      +            return
      +        end if
      +
      +        ! Trim path first
      +        get_dos_path = trim(path)
      +
      +        !> No need to convert if there are no spaces
      +        has_spaces: if (scan(get_dos_path,' ')>0) then
      +
      +            redirect = get_temp_filename()
      +            call execute_command_line('cmd /c for %A in ("'//path//'") do @echo %~sA >'//redirect//' 2>&1',&
      +                                      exitstat=stat,cmdstat=cmdstat)
      +
      +            !> Read screen output
      +            command_OK: if (cmdstat==0 .and. stat==0) then
      +
      +                allocate(character(len=0) :: screen_output)
      +                open(newunit=iunit,file=redirect,status='old',iostat=stat)
      +                if (stat == 0)then
      +
      +                   do
      +                       call getline(iunit, line, stat)
      +                       if (stat /= 0) exit
      +                       screen_output = screen_output//line//' '
      +                   end do
      +
      +                   ! Close and delete file
      +                   close(iunit,status='delete')
      +
      +                else
      +                   call fatal_error(error,'cannot read temporary file from successful DOS path evaluation')
      +                   return
      +                endif
      +
      +            else command_OK
      +
      +                call fatal_error(error,'unsuccessful Windows->DOS path command')
      +                return
      +
      +            end if command_OK
      +
      +            get_dos_path = trim(adjustl(screen_output))
      +
      +        endif has_spaces
      +
      +        !> Ensure there are no trailing slashes
      +        last = len_trim(get_dos_path)
      +        if (last>1 .and. get_dos_path(last:last)=='/' .or. get_dos_path(last:last)=='\') get_dos_path = get_dos_path(1:last-1)
      +
      +    end function get_dos_path
      +
      +end module fpm_filesystem
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/fpm_meta.f90.html b/sourcefile/fpm_meta.f90.html new file mode 100644 index 0000000000..973395c6c2 --- /dev/null +++ b/sourcefile/fpm_meta.f90.html @@ -0,0 +1,344 @@ + + + + + + + + + + + + + fpm_meta.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      fpm_meta.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      !># The fpm meta-package model
      +!>
      +!> This is a wrapper data type that encapsulate all pre-processing information
      +!> (compiler flags, linker libraries, etc.) required to correctly enable a package
      +!> to use a core library.
      +!>
      +!>
      +!>### Available core libraries
      +!>
      +!> - OpenMP
      +!> - MPI
      +!> - HDF5
      +!> - fortran-lang stdlib
      +!> - fortran-lang minpack
      +!>
      +!>
      +!> @note Core libraries are enabled in the [build] section of the fpm.toml manifest
      +!>
      +!>
      +module fpm_meta
      +    use fpm_compiler, only: compiler_t
      +    use fpm_manifest, only: package_config_t
      +    use fpm_model, only: fpm_model_t
      +    use fpm_command_line, only: fpm_cmd_settings, fpm_build_settings, fpm_run_settings
      +    use fpm_error, only: error_t, syntax_error, fatal_error
      +
      +    use fpm_meta_base, only: metapackage_t, destroy
      +    use fpm_meta_openmp, only: init_openmp
      +    use fpm_meta_stdlib, only: init_stdlib
      +    use fpm_meta_minpack, only: init_minpack
      +    use fpm_meta_mpi, only: init_mpi
      +    use fpm_meta_hdf5, only: init_hdf5
      +    use fpm_meta_netcdf, only: init_netcdf
      +    use fpm_meta_blas, only: init_blas
      +    use fpm_manifest_metapackages, only: metapackage_request_t
      +
      +    use shlex_module, only: shlex_split => split
      +    use regex_module, only: regex
      +    use iso_fortran_env, only: stdout => output_unit
      +
      +    implicit none
      +
      +    private
      +
      +    public :: resolve_metapackages
      +
      +    interface resolve_metapackages
      +        module procedure resolve_metapackage_model
      +    end interface resolve_metapackages
      +
      +    contains
      +
      +    !> Initialize a metapackage from the given name
      +    subroutine init_from_request(this,request,compiler,all_meta,error)
      +        class(metapackage_t), intent(inout) :: this
      +        type(metapackage_request_t), intent(in) :: request
      +        type(compiler_t), intent(in) :: compiler
      +        !> Pass a list of all metapackage requests so dependencies can be sorted out
      +        type(metapackage_request_t), intent(in) :: all_meta(:)
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        !> Initialize metapackage by name
      +        select case(request%name)
      +            case("openmp");  call init_openmp (this,compiler,all_meta,error)
      +            case("stdlib");  call init_stdlib (this,compiler,all_meta,error)
      +            case("minpack"); call init_minpack(this,compiler,all_meta,error)
      +            case("mpi");     call init_mpi    (this,compiler,all_meta,error)
      +            case("hdf5");    call init_hdf5   (this,compiler,all_meta,error)
      +            case("netcdf");  call init_netcdf (this,compiler,all_meta,error)
      +            case("blas");    call init_blas   (this,compiler,all_meta,error)
      +            case default
      +                call syntax_error(error, "Package "//request%name//" is not supported in [metapackages]")
      +                return
      +        end select
      +
      +    end subroutine init_from_request
      +
      +    !> Add named metapackage dependency to the model
      +    subroutine add_metapackage_model(model,package,settings,meta,error)
      +        type(fpm_model_t), intent(inout) :: model
      +        type(package_config_t), intent(inout) :: package
      +        class(fpm_cmd_settings), intent(inout) :: settings
      +        type(metapackage_t), intent(inout) :: meta
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        !> Add it into the model
      +        call meta%resolve(model,error)
      +        if (allocated(error)) return
      +
      +        !> Add it into the package
      +        call meta%resolve(package,error)
      +        if (allocated(error)) return
      +
      +        !> Add it into the settings
      +        call meta%resolve(settings,error)
      +        if (allocated(error)) return
      +
      +        ! If we need to run executables, there should be an MPI runner
      +        if (meta%name=="mpi") then
      +            select type (settings)
      +               class is (fpm_run_settings) ! run, test
      +                  if (.not.meta%has_run_command) &
      +                  call fatal_error(error,"cannot find a valid mpi runner on the local host")
      +            end select
      +        endif
      +
      +    end subroutine add_metapackage_model
      +
      +    !> Resolve all metapackages into the package config
      +    subroutine resolve_metapackage_model(model,package,settings,error)
      +        type(fpm_model_t), intent(inout) :: model
      +        type(package_config_t), intent(inout) :: package
      +        class(fpm_build_settings), intent(inout) :: settings
      +        type(error_t), allocatable, intent(out) :: error
      +        
      +        integer :: m
      +        type(metapackage_t) :: meta
      +        type(metapackage_request_t), allocatable :: requested(:)
      +
      +        ! Dependencies are added to the package config, so they're properly resolved
      +        ! into the dependency tree later.
      +        ! Flags are added to the model (whose compiler needs to be already initialized)
      +        if (model%compiler%is_unknown()) &
      +        write(stdout,'(a)') '<WARNING> compiler not initialized: metapackages may not be available'
      +        
      +        ! Get all requested metapackages
      +        requested = package%meta%get_requests()
      +        if (size(requested)<1) return
      +        
      +        do m=1,size(requested)
      +            
      +            call init_from_request(meta,requested(m),model%compiler,requested,error)
      +            if (allocated(error)) return
      +            
      +            call add_metapackage_model(model,package,settings,meta,error)
      +            if (allocated(error)) return
      +            
      +        end do
      +        
      +    end subroutine resolve_metapackage_model
      +
      +end module fpm_meta
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/fpm_meta_base.f90.html b/sourcefile/fpm_meta_base.f90.html new file mode 100644 index 0000000000..b7cf734761 --- /dev/null +++ b/sourcefile/fpm_meta_base.f90.html @@ -0,0 +1,439 @@ + + + + + + + + + + + + + fpm_meta_base.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      fpm_meta_base.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      module fpm_meta_base
      +    use fpm_error, only: error_t, fatal_error
      +    use fpm_versioning, only: version_t
      +    use fpm_model, only: fpm_model_t, fortran_features_t
      +    use fpm_command_line, only: fpm_cmd_settings, fpm_run_settings
      +    use fpm_manifest_dependency, only: dependency_config_t
      +    use fpm_manifest_preprocess, only: preprocess_config_t
      +    use fpm_manifest, only: package_config_t
      +    use fpm_strings, only: string_t, len_trim, split, join
      +    use fpm_compiler, only: append_clean_flags, append_clean_flags_array
      +
      +    implicit none
      +
      +    private
      +
      +    public :: destroy
      +
      +    !> Type for describing a source file
      +    type, public :: metapackage_t
      +        
      +        !> Package name
      +        character(:), allocatable :: name
      +
      +        !> Package version (if supported)
      +        type(version_t), allocatable :: version
      +
      +        logical :: has_link_libraries   = .false.
      +        logical :: has_link_flags       = .false.
      +        logical :: has_build_flags      = .false.
      +        logical :: has_fortran_flags    = .false.
      +        logical :: has_c_flags          = .false.
      +        logical :: has_cxx_flags        = .false.
      +        logical :: has_include_dirs     = .false.
      +        logical :: has_dependencies     = .false.
      +        logical :: has_run_command      = .false.
      +        logical :: has_external_modules = .false.
      +
      +        !> List of compiler flags and options to be added
      +        type(string_t) :: flags
      +        type(string_t) :: fflags
      +        type(string_t) :: cflags
      +        type(string_t) :: cxxflags
      +        type(string_t) :: link_flags
      +        type(string_t) :: run_command
      +        type(string_t), allocatable :: incl_dirs(:)
      +        type(string_t), allocatable :: link_libs(:)
      +        type(string_t), allocatable :: external_modules(:)
      +
      +        !> Special fortran features
      +        type(fortran_features_t), allocatable :: fortran
      +        
      +        !> Preprocessor configuration
      +        type(preprocess_config_t), allocatable :: preprocess
      +
      +        !> List of Development dependency meta data.
      +        !> Metapackage dependencies are never exported from the model
      +        type(dependency_config_t), allocatable :: dependency(:)
      +
      +        contains
      +
      +            !> Clean metapackage structure
      +            procedure :: destroy
      +
      +            !> Add metapackage dependencies to the model
      +            procedure, private :: resolve_cmd
      +            procedure, private :: resolve_model
      +            procedure, private :: resolve_package_config
      +            generic :: resolve => resolve_cmd,resolve_model,resolve_package_config
      +
      +    end type metapackage_t
      +
      +    contains
      +
      +    elemental subroutine destroy(this)
      +        class(metapackage_t), intent(inout) :: this
      +        this%has_link_libraries = .false.
      +        this%has_link_flags = .false.
      +        this%has_build_flags = .false.
      +        this%has_fortran_flags = .false.
      +        this%has_c_flags = .false.
      +        this%has_cxx_flags = .false.
      +        this%has_include_dirs = .false.
      +        this%has_dependencies = .false.
      +        this%has_run_command = .false.
      +        this%has_external_modules = .false.
      +        if (allocated(this%fortran)) deallocate(this%fortran)
      +        if (allocated(this%preprocess)) deallocate(this%preprocess)
      +        if (allocated(this%name)) deallocate(this%name)
      +        if (allocated(this%version)) deallocate(this%version)
      +        if (allocated(this%flags%s)) deallocate(this%flags%s)
      +        if (allocated(this%link_libs)) deallocate(this%link_libs)
      +        if (allocated(this%incl_dirs)) deallocate(this%incl_dirs)
      +        if (allocated(this%external_modules)) deallocate(this%external_modules)
      +    end subroutine destroy
      +
      +    !> Resolve metapackage dependencies into the command line settings
      +    subroutine resolve_cmd(self,settings,error)
      +        class(metapackage_t), intent(in) :: self
      +        class(fpm_cmd_settings), intent(inout) :: settings
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        ! Add customize run commands
      +        if (self%has_run_command) then
      +
      +            select type (cmd=>settings)
      +               class is (fpm_run_settings) ! includes fpm_test_settings
      +
      +                  ! Only override runner if user has not provided a custom one
      +                  if (.not.len_trim(cmd%runner)>0) cmd%runner = self%run_command%s
      +
      +            end select
      +
      +        endif
      +
      +    end subroutine resolve_cmd
      +
      +    !> Resolve metapackage dependencies into the model
      +    subroutine resolve_model(self,model,error)
      +        class(metapackage_t), intent(in) :: self
      +        type(fpm_model_t), intent(inout) :: model
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        ! Add global build flags, to apply to all sources
      +        if (self%has_build_flags) then
      +            call append_clean_flags(model%fortran_compile_flags, self%flags%s)
      +            call append_clean_flags(model%c_compile_flags, self%flags%s)
      +            call append_clean_flags(model%cxx_compile_flags, self%flags%s)
      +        endif
      +
      +        ! Add language-specific flags
      +        if (self%has_fortran_flags) call append_clean_flags(model%fortran_compile_flags, self%fflags%s)
      +        if (self%has_c_flags)       call append_clean_flags(model%c_compile_flags, self%cflags%s)
      +        if (self%has_cxx_flags)     call append_clean_flags(model%cxx_compile_flags, self%cxxflags%s)
      +
      +        if (self%has_link_flags) then
      +            call append_clean_flags(model%link_flags, self%link_flags%s)
      +        end if
      +
      +        if (self%has_link_libraries) then
      +            call append_clean_flags_array(model%link_libraries, self%link_libs)
      +        end if
      +
      +        if (self%has_include_dirs) then
      +            call append_clean_flags_array(model%include_dirs, self%incl_dirs)
      +        end if
      +
      +        if (self%has_external_modules) then
      +            call append_clean_flags_array(model%external_modules, self%external_modules)
      +        end if
      +
      +    end subroutine resolve_model
      +
      +    subroutine resolve_package_config(self,package,error)
      +        class(metapackage_t), intent(in) :: self
      +        type(package_config_t), intent(inout) :: package
      +        type(error_t), allocatable, intent(out) :: error
      +        
      +        integer :: i
      +
      +        ! All metapackage dependencies are added as dev-dependencies,
      +        ! as they may change if built upstream
      +        if (self%has_dependencies) then
      +            if (allocated(package%dev_dependency)) then
      +               package%dev_dependency = [package%dev_dependency,self%dependency]
      +            else
      +               package%dev_dependency = self%dependency
      +            end if
      +        end if
      +        
      +        ! Check if there are any special fortran requests which the package does not comply to
      +        if (allocated(self%fortran)) then
      +
      +            if (self%fortran%implicit_external.neqv.package%fortran%implicit_external) then
      +                call fatal_error(error,'metapackage fortran error: metapackage '// &
      +                                       dn(self%fortran%implicit_external)//' require implicit-external, main package '//&
      +                                       dn(package%fortran%implicit_external))
      +                return
      +            end if
      +
      +            if (self%fortran%implicit_typing.neqv.package%fortran%implicit_typing) then
      +                call fatal_error(error,'metapackage fortran error: metapackage '// &
      +                                       dn(self%fortran%implicit_external)//' require implicit-typing, main package '//&
      +                                       dn(package%fortran%implicit_external))
      +                return
      +            end if
      +
      +        end if
      +        
      +        ! Check if there are preprocessor configurations
      +        if (allocated(self%preprocess)) then 
      +            
      +            if (self%preprocess%is_cpp()) then 
      +                
      +                if (allocated(package%preprocess)) then 
      +                    
      +                    if (size(package%preprocess)<1) then 
      +                        deallocate(package%preprocess)
      +                        allocate(package%preprocess(1),source=self%preprocess)
      +                    else
      +                        do i=1,size(package%preprocess)
      +                            if (package%preprocess(i)%is_cpp()) then                             
      +                                call package%preprocess(i)%add_config(self%preprocess)
      +                                exit                            
      +                            end if
      +                        end do                        
      +                    end if
      +                else
      +                    ! Copy configuration
      +                    allocate(package%preprocess(1),source=self%preprocess)
      +                    
      +                end if                
      +            
      +            else
      +
      +                call fatal_error(error,'non-cpp preprocessor configuration '// &
      +                                       self%preprocess%name//' is not supported')
      +                return            
      +            
      +            end if
      +            
      +        end if
      +
      +        contains
      +
      +        pure function dn(bool)
      +           logical, intent(in) :: bool
      +           character(len=:), allocatable :: dn
      +           if (bool) then
      +              dn = "does"
      +           else
      +              dn = "does not"
      +           end if
      +        end function dn
      +
      +    end subroutine resolve_package_config
      +
      +end module fpm_meta_base
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/fpm_meta_blas.f90.html b/sourcefile/fpm_meta_blas.f90.html new file mode 100644 index 0000000000..9c6e1093fc --- /dev/null +++ b/sourcefile/fpm_meta_blas.f90.html @@ -0,0 +1,300 @@ + + + + + + + + + + + + + fpm_meta_blas.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      fpm_meta_blas.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      module fpm_meta_blas
      +    use fpm_compiler, only: compiler_t, get_include_flag
      +    use fpm_environment, only: get_os_type, OS_MACOS, OS_WINDOWS
      +    use fpm_meta_base, only: metapackage_t, destroy
      +    use fpm_meta_util, only: add_pkg_config_compile_options
      +    use fpm_pkg_config, only: assert_pkg_config, pkgcfg_has_package
      +    use fpm_manifest_metapackages, only: metapackage_request_t
      +    use fpm_strings, only: string_t
      +    use fpm_error, only: error_t, fatal_error
      +
      +    implicit none
      +
      +    private
      +
      +    public :: init_blas
      +
      +contains
      +
      +    !> Initialize blas metapackage for the current system
      +    subroutine init_blas(this, compiler, all_meta, error)
      +        class(metapackage_t), intent(inout) :: this
      +        type(compiler_t), intent(in) :: compiler
      +        type(metapackage_request_t), intent(in) :: all_meta(:)
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        integer :: i
      +        character(len=:), allocatable :: include_flag, libdir
      +        character(*), parameter :: candidates(*) = &
      +                                   [character(20) :: 'mkl-dynamic-lp64-tbb', 'openblas', 'blas']
      +
      +        include_flag = get_include_flag(compiler, "")
      +
      +        !> Cleanup
      +        call destroy(this)
      +        allocate (this%link_libs(0), this%incl_dirs(0), this%external_modules(0))
      +        this%link_flags = string_t("")
      +        this%flags = string_t("")
      +        this%has_external_modules = .false.
      +        
      +        !> Set name
      +        this%name = ""
      +
      +        if (get_os_type() == OS_MACOS) then
      +            if (compile_and_link_flags_supported(compiler, "-framework Accelerate")) then
      +                call set_compile_and_link_flags(this, compiler, "-framework Accelerate")
      +                return
      +            end if
      +        end if
      +
      +        if (compiler%is_intel()) then
      +            if (get_os_type() == OS_WINDOWS) then
      +                if (compile_and_link_flags_supported(compiler, "/Qmkl")) then
      +                    call set_compile_and_link_flags(this, compiler, "/Qmkl")
      +                    return
      +                end if
      +            else if (compile_and_link_flags_supported(compiler, "-qmkl")) then
      +                call set_compile_and_link_flags(this, compiler, "-qmkl")
      +                return
      +            endif
      +        end if
      +
      +        !> Assert pkg-config is installed
      +        if (.not. assert_pkg_config()) then
      +            call fatal_error(error, 'blas metapackage requires pkg-config to continue lookup')
      +            return
      +        end if
      +
      +        do i = 1, size(candidates)
      +            if (pkgcfg_has_package(trim(candidates(i)))) then
      +                call add_pkg_config_compile_options( &
      +                    this, trim(candidates(i)), include_flag, libdir, error)
      +                print *, 'found blas package: ', trim(candidates(i))
      +                return
      +            end if
      +        end do
      +
      +        call fatal_error(error, 'pkg-config could not find a suitable blas package.')
      +    end subroutine init_blas
      +
      +    function compile_and_link_flags_supported(compiler, flags) result(is_supported)
      +        type(compiler_t), intent(in) :: compiler
      +        character(len=*), intent(in) :: flags
      +        logical :: is_supported
      +
      +        is_supported = compiler%check_flags_supported(compile_flags=flags, link_flags=flags)
      +    end function compile_and_link_flags_supported
      +
      +    subroutine set_compile_and_link_flags(this, compiler, flags)
      +        class(metapackage_t), intent(inout) :: this
      +        type(compiler_t), intent(in) :: compiler
      +        character(len=*), intent(in) :: flags
      +
      +        this%flags = string_t(flags)
      +        this%link_flags = string_t(flags)
      +        this%has_build_flags = .true.
      +        this%has_link_flags = .true.
      +    end subroutine set_compile_and_link_flags
      +end module fpm_meta_blas
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/fpm_meta_hdf5.f90.html b/sourcefile/fpm_meta_hdf5.f90.html new file mode 100644 index 0000000000..23bdbeb5a0 --- /dev/null +++ b/sourcefile/fpm_meta_hdf5.f90.html @@ -0,0 +1,352 @@ + + + + + + + + + + + + + fpm_meta_hdf5.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      fpm_meta_hdf5.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      module fpm_meta_hdf5
      +    use fpm_compiler, only: compiler_t, get_include_flag
      +    use fpm_strings, only: str_begins_with_str, str_ends_with, string_t
      +    use fpm_filesystem, only: join_path
      +    use fpm_pkg_config, only: assert_pkg_config, pkgcfg_has_package, pkgcfg_list_all
      +    use fpm_meta_base, only: metapackage_t, destroy
      +    use fpm_meta_util, only: add_pkg_config_compile_options, lib_get_trailing
      +    use fpm_manifest_metapackages, only: metapackage_request_t
      +    use fpm_error, only: error_t, fatal_error
      +
      +    implicit none
      +
      +    private
      +
      +    public :: init_hdf5
      +
      +    contains
      +
      +    !> Initialize HDF5 metapackage for the current system
      +    subroutine init_hdf5(this,compiler,all_meta,error)
      +        class(metapackage_t), intent(inout) :: this
      +        type(compiler_t), intent(in) :: compiler
      +        type(metapackage_request_t), intent(in) :: all_meta(:)
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        character(*), parameter :: find_hl(*) = &
      +                     [character(11) :: '_hl_fortran','hl_fortran','_fortran','_hl']
      +        character(*), parameter :: candidates(*) = &
      +                     [character(15) :: 'hdf5_hl_fortran','hdf5-hl-fortran','hdf5_fortran','hdf5-fortran',&
      +                                       'hdf5_hl','hdf5','hdf5-serial']
      +
      +        integer :: i,j,k,l
      +        logical :: s,found_hl(size(find_hl)),found
      +        type(string_t) :: log,this_lib
      +        type(string_t), allocatable :: libs(:),flags(:),modules(:),non_fortran(:)
      +        character(len=:), allocatable :: name, include_flag, libdir, ext, pref
      +
      +        include_flag = get_include_flag(compiler,"")
      +
      +        !> Cleanup
      +        call destroy(this)
      +        allocate(this%link_libs(0),this%incl_dirs(0),this%external_modules(0),non_fortran(0))
      +        this%link_flags = string_t("")
      +        this%flags = string_t("")
      +        
      +        !> Set name
      +        this%name = "hdf5"
      +
      +        !> Assert pkg-config is installed
      +        if (.not.assert_pkg_config()) then
      +            call fatal_error(error,'hdf5 metapackage requires pkg-config')
      +            return
      +        end if
      +
      +        !> Find pkg-config package file by priority
      +        name = 'NOT_FOUND'
      +        find_package: do i=1,size(candidates)
      +            if (pkgcfg_has_package(trim(candidates(i)))) then
      +                name = trim(candidates(i))
      +                exit find_package
      +            end if
      +        end do find_package
      +
      +        !> some distros put hdf5-1.2.3.pc with version number in .pc filename.
      +        if (name=='NOT_FOUND') then
      +            modules = pkgcfg_list_all(error)
      +            find_global_package: do i=1,size(modules)
      +                if (str_begins_with_str(modules(i)%s,'hdf5')) then
      +                    name = modules(i)%s
      +                    exit find_global_package
      +                end if
      +            end do find_global_package
      +        end if
      +
      +        if (name=='NOT_FOUND') then
      +            call fatal_error(error,'pkg-config could not find a suitable hdf5 package.')
      +            return
      +        end if
      +
      +        call add_pkg_config_compile_options(this, name, include_flag, libdir, error)
      +        if (allocated(error)) return
      +
      +        ! Some pkg-config hdf5.pc (e.g. Ubuntu) don't include the commonly-used HL HDF5 libraries,
      +        ! so let's add them if they exist
      +        if (len_trim(libdir)>0) then
      +            do i=1,size(this%link_libs)
      +
      +                found_hl = .false.
      +
      +                if (.not.str_ends_with(this%link_libs(i)%s, find_hl)) then
      +
      +                   ! Extract name with no extension
      +                   call lib_get_trailing(this%link_libs(i)%s, libdir, pref, ext, found)
      +
      +                   ! Search how many versions with the Fortran endings there are
      +                   finals: do k=1,size(find_hl)
      +                      do j=1,size(this%link_libs)
      +                       if (str_begins_with_str(this%link_libs(j)%s,this%link_libs(i)%s) .and. &
      +                           str_ends_with(this%link_libs(j)%s,trim(find_hl(k)))) then
      +                           found_hl(k) = .true.
      +                           cycle finals
      +                       end if
      +                      end do
      +                   end do finals
      +
      +                   ! For each of the missing ones, if there is a file, add it
      +                   add_missing: do k=1,size(find_hl)
      +                      if (found_hl(k)) cycle add_missing
      +
      +                      ! Build file name
      +                      this_lib%s = join_path(libdir,pref//this%link_libs(i)%s//trim(find_hl(k))//ext)
      +                      inquire(file=this_lib%s,exist=found)
      +
      +                      ! File exists, but it is not linked against
      +                      if (found) this%link_libs = [this%link_libs, &
      +                                                   string_t(this%link_libs(i)%s//trim(find_hl(k)))]
      +
      +                   end do add_missing
      +
      +                end if
      +
      +            end do
      +        endif
      +
      +        !> Add HDF5 modules as external
      +        this%has_external_modules = .true.
      +        this%external_modules = [string_t('h5a'), &
      +                                 string_t('h5d'), &
      +                                 string_t('h5es'), &
      +                                 string_t('h5e'), &
      +                                 string_t('h5f'), &
      +                                 string_t('h5g'), &
      +                                 string_t('h5i'), &
      +                                 string_t('h5l'), &
      +                                 string_t('h5o'), &
      +                                 string_t('h5p'), &
      +                                 string_t('h5r'), &
      +                                 string_t('h5s'), &
      +                                 string_t('h5t'), &
      +                                 string_t('h5vl'), &
      +                                 string_t('h5z'), &
      +                                 string_t('h5lt'), &
      +                                 string_t('h5lib'), &
      +                                 string_t('h5global'), &
      +                                 string_t('h5_gen'), &
      +                                 string_t('h5fortkit'), &
      +                                 string_t('hdf5')]
      +
      +    end subroutine init_hdf5
      +end module fpm_meta_hdf5
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/fpm_meta_minpack.f90.html b/sourcefile/fpm_meta_minpack.f90.html new file mode 100644 index 0000000000..4f02a6b245 --- /dev/null +++ b/sourcefile/fpm_meta_minpack.f90.html @@ -0,0 +1,245 @@ + + + + + + + + + + + + + fpm_meta_minpack.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      fpm_meta_minpack.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      module fpm_meta_minpack
      +    use fpm_compiler, only: compiler_t
      +    use fpm_meta_base, only: metapackage_t, destroy
      +    use fpm_error, only: error_t, fatal_error
      +    use fpm_git, only: git_target_tag
      +    use fpm_manifest_metapackages, only: metapackage_request_t
      +
      +    implicit none
      +
      +    private
      +
      +    public :: init_minpack
      +
      +    contains
      +
      +    !> Initialize minpack metapackage for the current system
      +    subroutine init_minpack(this,compiler,all_meta,error)
      +        class(metapackage_t), intent(inout) :: this
      +        type(compiler_t), intent(in) :: compiler
      +        type(metapackage_request_t), intent(in) :: all_meta(:)
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        !> Cleanup
      +        call destroy(this)
      +        
      +        !> Set name
      +        this%name = "minpack"
      +
      +        !> minpack is queried as a dependency from the official repository
      +        this%has_dependencies = .true.
      +
      +        allocate(this%dependency(1))
      +
      +        !> 1) minpack. There are no true releases currently. Fetch HEAD
      +        this%dependency(1)%name = "minpack"
      +        this%dependency(1)%git = git_target_tag("https://github.com/fortran-lang/minpack", "v2.0.0-rc.1")
      +        if (.not.allocated(this%dependency(1)%git)) then
      +            call fatal_error(error,'cannot initialize git repo dependency for minpack metapackage')
      +            return
      +        end if
      +
      +    end subroutine init_minpack
      +end module fpm_meta_minpack
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/fpm_meta_mpi.f90.html b/sourcefile/fpm_meta_mpi.f90.html new file mode 100644 index 0000000000..679669a604 --- /dev/null +++ b/sourcefile/fpm_meta_mpi.f90.html @@ -0,0 +1,1495 @@ + + + + + + + + + + + + + fpm_meta_mpi.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      fpm_meta_mpi.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      module fpm_meta_mpi
      +    use fpm_compiler, only: compiler_t, id_gcc, get_os_type, OS_WINDOWS, get_include_flag, &
      +        get_module_flag, new_compiler, compiler_name, id_f95, id_intel_classic_windows, &
      +        id_intel_llvm_windows, id_intel_classic_nix, id_intel_llvm_nix, id_intel_classic_mac, &
      +        id_intel_llvm_unknown, id_pgi, id_nvhpc, id_cray
      +    use fpm_filesystem, only: join_path, exists, get_dos_path, run, getline, is_dir, &
      +        get_temp_filename
      +    use fpm_os, only: get_absolute_path
      +    use fpm_error, only: error_t, fatal_error, syntax_error
      +    use fpm_versioning, only: version_t, new_version, regex_version_from_text
      +    use fpm_strings, only: string_t, len_trim, split, str_begins_with_str, str_ends_with, &
      +        remove_newline_characters
      +    use fpm_environment, only: get_env, get_os_type, os_is_unix, OS_MACOS, OS_WINDOWS
      +    use fpm_meta_base, only: metapackage_t, destroy
      +    use fpm_manifest_metapackages, only: metapackage_request_t
      +    use fpm_pkg_config, only: run_wrapper
      +    use shlex_module, only: shlex_split => split
      +
      +    implicit none
      +
      +    private
      +
      +    public :: init_mpi, MPI_TYPE_NAME
      +
      +    integer, parameter :: MPI_TYPE_NONE    = 0
      +    integer, parameter :: MPI_TYPE_OPENMPI = 1
      +    integer, parameter :: MPI_TYPE_MPICH   = 2
      +    integer, parameter :: MPI_TYPE_INTEL   = 3
      +    integer, parameter :: MPI_TYPE_MSMPI   = 4
      +
      +    !> Debugging information
      +    logical, parameter, private :: verbose = .false.
      +
      +    integer, parameter, private :: LANG_FORTRAN = 1
      +    integer, parameter, private :: LANG_C       = 2
      +    integer, parameter, private :: LANG_CXX     = 3
      +
      +    character(*), parameter :: LANG_NAME(*) = [character(7) :: 'Fortran','C','C++']
      +
      +contains
      +
      +    !> Initialize MPI metapackage for the current system
      +    subroutine init_mpi(this,compiler,all_meta,error)
      +        class(metapackage_t), intent(inout) :: this
      +        type(compiler_t), intent(in) :: compiler
      +        type(metapackage_request_t), intent(in) :: all_meta(:)
      +        type(error_t), allocatable, intent(out) :: error
      +
      +
      +        type(string_t), allocatable :: c_wrappers(:),cpp_wrappers(:),fort_wrappers(:)
      +        type(string_t) :: output,fwrap,cwrap,cxxwrap
      +        character(256) :: msg_out
      +        character(len=:), allocatable :: tokens(:)
      +        integer :: wcfit(3),mpilib(3),ic,icpp,i
      +        logical :: found
      +
      +        !> Cleanup
      +        call destroy(this)
      +        
      +        !> Set name
      +        this%name = "mpi"
      +
      +        !> Get all candidate MPI wrappers
      +        call mpi_wrappers(compiler,fort_wrappers,c_wrappers,cpp_wrappers)
      +        if (verbose) print 1, size(fort_wrappers),size(c_wrappers),size(cpp_wrappers)
      +
      +        call wrapper_compiler_fit(fort_wrappers,c_wrappers,cpp_wrappers,compiler,wcfit,mpilib,error)
      +
      +        if (allocated(error) .or. all(wcfit==0)) then
      +
      +            !> No wrapper compiler fit. Are we on Windows? use MSMPI-specific search
      +            found = msmpi_init(this,compiler,error)
      +            if (allocated(error)) return
      +
      +            !> All attempts failed
      +            if (.not.found) then
      +                call fatal_error(error,"cannot find MPI wrappers or libraries for "//compiler%name()//" compiler")
      +                return
      +            endif
      +
      +        else
      +
      +            if (wcfit(LANG_FORTRAN)>0) fwrap   = fort_wrappers(wcfit(LANG_FORTRAN))
      +            if (wcfit(LANG_C)>0)       cwrap   = c_wrappers   (wcfit(LANG_C))
      +            if (wcfit(LANG_CXX)>0)     cxxwrap = cpp_wrappers (wcfit(LANG_CXX))
      +
      +            !> If there's only an available Fortran wrapper, and the compiler's different than fpm's baseline
      +            !> fortran compiler suite, we still want to enable C language flags as that is most likely being
      +            !> ABI-compatible anyways. However, issues may arise.
      +            !> see e.g. Homebrew with clabng C/C++ and GNU fortran at https://gitlab.kitware.com/cmake/cmake/-/issues/18139
      +            if (wcfit(LANG_FORTRAN)>0 .and. all(wcfit([LANG_C,LANG_CXX])==0)) then
      +                cwrap   = fort_wrappers(wcfit(LANG_FORTRAN))
      +                cxxwrap = fort_wrappers(wcfit(LANG_FORTRAN))
      +            end if
      +
      +            if (verbose) print *, '+ MPI fortran wrapper: ',fwrap%s
      +            if (verbose) print *, '+ MPI c       wrapper: ',cwrap%s
      +            if (verbose) print *, '+ MPI c++     wrapper: ',cxxwrap%s
      +
      +            !> Initialize MPI package from wrapper command
      +            call init_mpi_from_wrappers(this,compiler,mpilib(LANG_FORTRAN),fwrap,cwrap,cxxwrap,error)
      +            if (allocated(error)) return
      +
      +            !> Request Fortran implicit typing
      +            if (mpilib(LANG_FORTRAN)/=MPI_TYPE_INTEL) then
      +                allocate(this%fortran)
      +                this%fortran%implicit_typing   = .true.
      +                this%fortran%implicit_external = .true.
      +            endif
      +
      +        end if
      +
      +        !> Not all MPI implementations offer modules mpi and mpi_f08: hence, include them
      +        !> to the list of external modules, so they won't be requested as standard source files
      +        this%has_external_modules = .true.
      +        this%external_modules = [string_t("mpi"),string_t("mpi_f08")]
      +
      +        1 format('MPI wrappers found: fortran=',i0,' c=',i0,' c++=',i0)
      +
      +    end subroutine init_mpi
      +
      +    !> Check if we're on a 64-bit environment
      +    !> Accept answer from https://stackoverflow.com/questions/49141093/get-system-information-with-fortran
      +    logical function is_64bit_environment()
      +       use iso_c_binding, only: c_intptr_t
      +       integer, parameter :: nbits = bit_size(0_c_intptr_t)
      +       is_64bit_environment = nbits==64
      +    end function is_64bit_environment
      +
      +    !> Return a name for the MPI library
      +    pure function MPI_TYPE_NAME(mpilib) result(name)
      +       integer, intent(in) :: mpilib
      +       character(len=:), allocatable :: name
      +       select case (mpilib)
      +          case (MPI_TYPE_NONE);    name = "none"
      +          case (MPI_TYPE_OPENMPI); name = "OpenMPI"
      +          case (MPI_TYPE_MPICH);   name = "MPICH"
      +          case (MPI_TYPE_INTEL);   name = "INTELMPI"
      +          case (MPI_TYPE_MSMPI);   name = "MS-MPI"
      +          case default;            name = "UNKNOWN"
      +       end select
      +    end function MPI_TYPE_NAME
      +
      +    !> Check if there is a wrapper-compiler fit
      +    subroutine wrapper_compiler_fit(fort_wrappers,c_wrappers,cpp_wrappers,compiler,wrap,mpi,error)
      +       type(string_t), allocatable, intent(in) :: fort_wrappers(:),c_wrappers(:),cpp_wrappers(:)
      +       type(compiler_t), intent(in) :: compiler
      +       type(error_t), allocatable, intent(out) :: error
      +       integer, intent(out), dimension(3) :: wrap, mpi
      +
      +       type(error_t), allocatable :: wrap_error
      +
      +       wrap = 0
      +       mpi  = MPI_TYPE_NONE
      +
      +       if (size(fort_wrappers)>0) &
      +       call mpi_compiler_match(LANG_FORTRAN,fort_wrappers,compiler,wrap(LANG_FORTRAN),mpi(LANG_FORTRAN),wrap_error)
      +
      +       if (size(c_wrappers)>0) &
      +       call mpi_compiler_match(LANG_C,c_wrappers,compiler,wrap(LANG_C),mpi(LANG_C),wrap_error)
      +
      +       if (size(cpp_wrappers)>0) &
      +       call mpi_compiler_match(LANG_CXX,cpp_wrappers,compiler,wrap(LANG_CXX),mpi(LANG_CXX),wrap_error)
      +
      +       !> Find a Fortran wrapper for the current compiler
      +       if (all(wrap==0)) then
      +            call fatal_error(error,'no valid wrappers match current compiler, '//compiler_name(compiler))
      +            return
      +       end if
      +
      +    end subroutine wrapper_compiler_fit
      +
      +    !> Check if a local MS-MPI SDK build is found
      +    logical function msmpi_init(this,compiler,error) result(found)
      +        class(metapackage_t), intent(inout) :: this
      +        type(compiler_t), intent(in) :: compiler
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        character(len=:), allocatable :: incdir,windir,libdir,bindir,post,reall,msysdir
      +        type(version_t) :: ver,ver10
      +        type(string_t) :: cpath,msys_path,runner_path
      +        logical :: msys2
      +
      +        !> Default: not found
      +        found = .false.
      +
      +        if (get_os_type()==OS_WINDOWS) then
      +
      +            ! to run MSMPI on Windows,
      +            is_minGW: if (compiler%id==id_gcc) then
      +
      +                call compiler_get_version(compiler,ver,msys2,error)
      +                if (allocated(error)) return
      +
      +            endif is_minGW
      +
      +            ! Check we're on a 64-bit environment
      +            if (is_64bit_environment()) then
      +                libdir = get_env('MSMPI_LIB64')
      +                post   = 'x64'
      +            else
      +                libdir = get_env('MSMPI_LIB32')
      +                post   = 'x86'
      +
      +                !> Not working on 32-bit Windows yet
      +                call fatal_error(error,'MS-MPI error: this package requires 64-bit Windows environment')
      +                return
      +
      +            end if
      +
      +            ! Check that the runtime is installed
      +            bindir = ""
      +            call get_absolute_path(get_env('MSMPI_BIN'),bindir,error)
      +            if (verbose) print *, '+ %MSMPI_BIN%=',bindir
      +
      +            ! In some environments, variable %MSMPI_BIN% is missing (i.e. in GitHub Action images).
      +            ! Do a second attempt: search for the default location
      +            if (len_trim(bindir)<=0 .or. allocated(error)) then
      +                if (verbose) print *, '+ %MSMPI_BIN% empty, searching C:\Program Files\Microsoft MPI\Bin\ ...'
      +                call get_absolute_path('C:\Program Files\Microsoft MPI\Bin\mpiexec.exe',bindir,error)
      +            endif
      +
      +            ! Third attempt for bash-style shell
      +            if (len_trim(bindir)<=0 .or. allocated(error)) then
      +                if (verbose) print *, '+ %MSMPI_BIN% empty, searching /c/Program Files/Microsoft MPI/Bin/ ...'
      +                call get_absolute_path('/c/Program Files/Microsoft MPI/Bin/mpiexec.exe',bindir,error)
      +            endif
      +
      +            ! Do a fourth attempt: search for mpiexec.exe in PATH location
      +            if (len_trim(bindir)<=0 .or. allocated(error)) then
      +                if (verbose) print *, '+ C:\Program Files\Microsoft MPI\Bin\ not found. searching %PATH%...'
      +
      +                call get_mpi_runner(runner_path,verbose,error)
      +
      +                if (.not.allocated(error)) then
      +                   if (verbose) print *, '+ mpiexec found: ',runner_path%s
      +                   call find_command_location(runner_path%s,bindir,verbose=verbose,error=error)
      +                endif
      +
      +            endif
      +
      +            if (allocated(error)) then
      +                call fatal_error(error,'MS-MPI error: MS-MPI Runtime directory is missing. '//&
      +                                       'check environment variable %MSMPI_BIN% or that the folder is in %PATH%.')
      +                return
      +            end if
      +
      +            ! Success!
      +            found = .true.
      +
      +            ! Init ms-mpi
      +            call destroy(this)
      +
      +            ! MSYS2 provides a pre-built static msmpi.dll.a library. Use that if possible
      +            use_prebuilt: if (msys2) then
      +
      +                ! MSYS executables are in %MSYS_ROOT%/bin
      +                call compiler_get_path(compiler,cpath,error)
      +                if (allocated(error)) return
      +
      +                call get_absolute_path(join_path(cpath%s,'..'),msys_path%s,error)
      +                if (allocated(error)) return
      +
      +                call get_absolute_path(join_path(msys_path%s,'include'),incdir,error)
      +                if (allocated(error)) return
      +
      +                call get_absolute_path(join_path(msys_path%s,'lib'),libdir,error)
      +                if (allocated(error)) return
      +
      +                if (verbose) print 1, 'include',incdir,exists(incdir)
      +                if (verbose) print 1, 'library',libdir,exists(libdir)
      +
      +                ! Check that the necessary files exist
      +                call get_absolute_path(join_path(libdir,'libmsmpi.dll.a'),post,error)
      +                if (allocated(error)) return
      +
      +                if (len_trim(post)<=0 .or. .not.exists(post)) then
      +                    call fatal_error(error,'MS-MPI available through the MSYS2 system not found. '// &
      +                                           'Run <pacman -Sy mingw64/mingw-w64-x86_64-msmpi> '// &
      +                                           'or your system-specific version to install.')
      +                    return
      +                end if
      +
      +                ! Add dir cpath
      +                this%has_link_flags = .true.
      +                this%link_flags = string_t(' -L'//get_dos_path(libdir,error))
      +
      +                this%has_link_libraries = .true.
      +                this%link_libs = [string_t('msmpi.dll')]
      +
      +                if (allocated(error)) return
      +
      +                this%has_include_dirs = .true.
      +                this%incl_dirs = [string_t(get_dos_path(incdir,error))]
      +                if (allocated(error)) return
      +
      +            else
      +
      +                call fatal_error(error,'MS-MPI cannot work with non-MSYS2 GNU compilers yet')
      +                return
      +
      +                ! Add dir path
      +                this%has_link_flags = .true.
      +                this%link_flags = string_t(' -L'//get_dos_path(libdir,error))
      +
      +                this%has_link_libraries = .true.
      +                this%link_libs = [string_t('msmpi'),string_t('msmpifec'),string_t('msmpifmc')]
      +
      +                if (allocated(error)) return
      +
      +                this%has_include_dirs = .true.
      +                this%incl_dirs = [string_t(get_dos_path(incdir,error)), &
      +                                  string_t(get_dos_path(incdir//post,error))]
      +                if (allocated(error)) return
      +
      +
      +            end if use_prebuilt
      +
      +            !> Request Fortran implicit typing
      +            allocate(this%fortran)
      +            this%fortran%implicit_typing = .true.
      +            this%fortran%implicit_external = .true.
      +
      +            ! gfortran>=10 is incompatible with the old-style mpif.h MS-MPI headers.
      +            ! If so, add flags to allow old-style BOZ constants in mpif.h
      +            allow_BOZ: if (compiler%id==id_gcc) then
      +
      +                call new_version(ver10,'10.0.0',error)
      +                if (allocated(error)) return
      +
      +                if (ver>=ver10) then
      +                    this%has_build_flags = .true.
      +                    this%flags = string_t(' -fallow-invalid-boz')
      +                end if
      +
      +            endif allow_BOZ
      +
      +            !> Add default run command
      +            this%has_run_command = .true.
      +            this%run_command = string_t(join_path(get_dos_path(bindir,error),'mpiexec.exe')//' -np * ')
      +
      +        else
      +
      +            !> Not on Windows
      +            found = .false.
      +
      +        end if
      +
      +        1 format('MSMSPI ',a,' directory: PATH=',a,' EXISTS=',l1)
      +
      +    end function msmpi_init
      +
      +    !> Check if we're under a WSL bash shell
      +    logical function wsl_shell()
      +        if (get_os_type()==OS_WINDOWS) then
      +            wsl_shell = exists('/proc/sys/fs/binfmt_misc/WSLInterop')
      +        else
      +            wsl_shell = .false.
      +        endif
      +    end function wsl_shell
      +
      +    !> Find the location of a valid command
      +    subroutine find_command_location(command,path,echo,verbose,error)
      +        character(*), intent(in) :: command
      +        character(len=:), allocatable, intent(out) :: path
      +        logical, optional, intent(in) :: echo,verbose
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        character(:), allocatable :: tmp_file,screen_output,line,fullpath,search_command
      +        integer :: stat,iunit,ire,length,try
      +        character(*), parameter :: search(2) = ["where ","which "]
      +
      +        if (len_trim(command)<=0) then
      +            call fatal_error(error,'empty command provided in find_command_location')
      +            return
      +        end if
      +
      +        tmp_file = get_temp_filename()
      +
      +        ! On Windows, we try both commands because we may be on WSL
      +        do try=merge(1,2,get_os_type()==OS_WINDOWS),2
      +           search_command = search(try)//command
      +           call run(search_command, echo=echo, exitstat=stat, verbose=verbose, redirect=tmp_file)
      +           if (stat==0) exit
      +        end do
      +        if (stat/=0) then
      +            call fatal_error(error,'find_command_location failed for '//command)
      +            return
      +        end if
      +
      +        ! Only read first instance (first line)
      +        allocate(character(len=0) :: screen_output)
      +        open(newunit=iunit,file=tmp_file,status='old',iostat=stat)
      +        if (stat == 0)then
      +           do
      +               call getline(iunit, line, stat)
      +               if (stat /= 0) exit
      +               if (len(screen_output)>0) then
      +                    screen_output = screen_output//new_line('a')//line
      +               else
      +                    screen_output = line
      +               endif
      +           end do
      +           ! Close and delete file
      +           close(iunit,status='delete')
      +        else
      +           call fatal_error(error,'cannot read temporary file from successful find_command_location')
      +           return
      +        endif
      +
      +        ! Only use the first instance
      +        length = index(screen_output,new_line('a'))
      +
      +        multiline: if (length>1) then
      +            fullpath = screen_output(1:length-1)
      +        else
      +            fullpath = screen_output
      +        endif multiline
      +        if (len_trim(fullpath)<1) then
      +            call fatal_error(error,'no paths found to command ('//command//')')
      +            return
      +        end if
      +
      +        ! Extract path only
      +        length = index(fullpath,command,BACK=.true.)
      +        if (length<=0) then
      +            call fatal_error(error,'full path to command ('//command//') does not include command name')
      +            return
      +        elseif (length==1) then
      +            ! Compiler is in the current folder
      +            path = '.'
      +        else
      +            path = fullpath(1:length-1)
      +        end if
      +        if (allocated(error)) return
      +
      +        ! On Windows, be sure to return a path with no spaces
      +        if (get_os_type()==OS_WINDOWS) path = get_dos_path(path,error)
      +
      +        if (allocated(error) .or. .not.is_dir(path)) then
      +            call fatal_error(error,'full path ('//path//') to command ('//command//') is not a directory')
      +            return
      +        end if
      +
      +    end subroutine find_command_location
      +
      +    !> Get MPI runner in $PATH
      +    subroutine get_mpi_runner(command,verbose,error)
      +        type(string_t), intent(out) :: command
      +        logical, intent(in) :: verbose
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        character(*), parameter :: try(*) = [character(11) :: 'mpiexec','mpirun','mpiexec.exe','mpirun.exe','srun']
      +        character(:), allocatable :: bindir
      +        integer :: itri
      +        logical :: success
      +
      +        ! Try several commands
      +        do itri=1,size(try)
      +           call find_command_location(trim(try(itri)),command%s,verbose=verbose,error=error)
      +           if (allocated(error)) cycle
      +
      +           ! Success!
      +           success = len_trim(command%s)>0
      +           if (success) then
      +               if (verbose) print *, '+ runner folder found: '//command%s
      +               command%s = join_path(command%s,trim(try(itri)))
      +               return
      +           endif
      +        end do
      +
      +        ! On windows, also search in %MSMPI_BIN%
      +        if (get_os_type()==OS_WINDOWS) then
      +            ! Check that the runtime is installed
      +            bindir = ""
      +            call get_absolute_path(get_env('MSMPI_BIN'),bindir,error)
      +            if (verbose) print *, '+ %MSMPI_BIN%=',bindir
      +            ! In some environments, variable %MSMPI_BIN% is missing (i.e. in GitHub Action images).
      +            ! Do a second attempt: search for the default location
      +            if (len_trim(bindir)<=0 .or. allocated(error)) then
      +                if (verbose) print *, '+ %MSMPI_BIN% empty, searching C:\Program Files\Microsoft MPI\Bin\ ...'
      +                call get_absolute_path('C:\Program Files\Microsoft MPI\Bin\mpiexec.exe',bindir,error)
      +            endif
      +            if (len_trim(bindir)>0 .and. .not.allocated(error)) then
      +                ! MSMPI_BIN directory found
      +                command%s = join_path(bindir,'mpiexec.exe')
      +                return
      +            endif
      +        endif
      +
      +        ! No valid command found
      +        call fatal_error(error,'cannot find a valid mpi runner command')
      +        return
      +
      +    end subroutine get_mpi_runner
      +
      +    !> Return compiler path
      +    subroutine compiler_get_path(self,path,error)
      +        type(compiler_t), intent(in) :: self
      +        type(string_t), intent(out) :: path
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        call find_command_location(self%fc,path%s,self%echo,self%verbose,error)
      +
      +    end subroutine compiler_get_path
      +
      +    !> Return compiler version
      +    subroutine compiler_get_version(self,version,is_msys2,error)
      +        type(compiler_t), intent(in) :: self
      +        type(version_t), intent(out) :: version
      +        logical, intent(out) :: is_msys2
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        character(:), allocatable :: tmp_file,screen_output,line
      +        type(string_t) :: ver
      +        integer :: stat,iunit,ire,length
      +
      +        is_msys2 = .false.
      +
      +        select case (self%id)
      +           case (id_gcc)
      +
      +                tmp_file = get_temp_filename()
      +
      +                call run(self%fc // " --version ", echo=self%echo, verbose=self%verbose, redirect=tmp_file, exitstat=stat)
      +                if (stat/=0) then
      +                    call fatal_error(error,'compiler_get_version failed for '//self%fc)
      +                    return
      +                end if
      +
      +                allocate(character(len=0) :: screen_output)
      +                open(newunit=iunit,file=tmp_file,status='old',iostat=stat)
      +                if (stat == 0)then
      +                   do
      +                       call getline(iunit, line, stat)
      +                       if (stat /= 0) exit
      +                       screen_output = screen_output//' '//line//' '
      +                   end do
      +                   ! Close and delete file
      +                   close(iunit,status='delete')
      +                else
      +                   call fatal_error(error,'cannot read temporary file from successful compiler_get_version')
      +                   return
      +                endif
      +
      +                ! Check if this gcc is from the MSYS2 project
      +                is_msys2 = index(screen_output,'MSYS2')>0
      +
      +                ver = regex_version_from_text(screen_output,self%fc//' compiler',error)
      +                if (allocated(error)) return
      +
      +                ! Extract version
      +                call new_version(version,ver%s,error)
      +
      +
      +           case default
      +                call fatal_error(error,'compiler_get_version not yet implemented for compiler '//self%fc)
      +                return
      +        end select
      +
      +    end subroutine compiler_get_version
      +
      +    !> Initialize an MPI metapackage from a valid wrapper command ('mpif90', etc...)
      +    subroutine init_mpi_from_wrappers(this,compiler,mpilib,fort_wrapper,c_wrapper,cxx_wrapper,error)
      +        class(metapackage_t), intent(inout) :: this
      +        type(compiler_t), intent(in) :: compiler
      +        integer, intent(in) :: mpilib
      +        type(string_t), intent(in) :: fort_wrapper,c_wrapper,cxx_wrapper
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        type(version_t) :: version
      +        type(error_t), allocatable :: runner_error
      +
      +        ! Cleanup structure
      +        call destroy(this)
      +
      +        ! Get linking flags
      +        this%link_flags = mpi_wrapper_query(mpilib,fort_wrapper,'link',verbose,error)
      +        if (allocated(error)) return
      +
      +        ! Remove useless/dangerous flags
      +        call filter_link_arguments(compiler,this%link_flags)
      +
      +        this%has_link_flags = len_trim(this%link_flags)>0
      +
      +        ! Request to use libs in arbitrary order
      +        if (this%has_link_flags .and. compiler%is_gnu() .and. os_is_unix() .and. get_os_type()/=OS_MACOS) then
      +            this%link_flags = string_t(' -Wl,--start-group '//this%link_flags%s)
      +        end if
      +
      +        ! Add language-specific flags
      +        call set_language_flags(compiler,mpilib,fort_wrapper,this%has_fortran_flags,this%fflags,verbose,error)
      +        if (allocated(error)) return
      +        call set_language_flags(compiler,mpilib,c_wrapper,this%has_c_flags,this%cflags,verbose,error)
      +        if (allocated(error)) return
      +        call set_language_flags(compiler,mpilib,cxx_wrapper,this%has_cxx_flags,this%cxxflags,verbose,error)
      +        if (allocated(error)) return
      +
      +        ! Get library version
      +        version = mpi_version_get(mpilib,fort_wrapper,error)
      +        if (allocated(error)) then
      +           return
      +        else
      +           allocate(this%version,source=version)
      +        end if
      +
      +        !> Add default run command, if present
      +        this%run_command = mpi_wrapper_query(mpilib,fort_wrapper,'runner',verbose,runner_error)
      +        this%has_run_command = (len_trim(this%run_command)>0) .and. .not.allocated(runner_error)
      +
      +        contains
      +
      +        subroutine set_language_flags(compiler,mpilib,wrapper,has_flags,flags,verbose,error)
      +            type(compiler_t), intent(in) :: compiler
      +            integer, intent(in) :: mpilib
      +            type(string_t), intent(in) :: wrapper
      +            logical, intent(inout) :: has_flags
      +            type(string_t), intent(inout) :: flags
      +            logical, intent(in) :: verbose
      +            type(error_t), allocatable, intent(out) :: error
      +
      +            ! Get build flags for each language
      +            if (len_trim(wrapper)>0) then
      +                flags = mpi_wrapper_query(mpilib,wrapper,'flags',verbose,error)
      +
      +                if (allocated(error)) return
      +                has_flags = len_trim(flags)>0
      +
      +                ! Add heading space
      +                flags = string_t(' '//flags%s)
      +
      +                if (verbose) print *, '+ MPI language flags from wrapper <',wrapper%s,'>: flags=',flags%s
      +
      +                call filter_build_arguments(compiler,flags)
      +
      +            endif
      +
      +        end subroutine set_language_flags
      +
      +    end subroutine init_mpi_from_wrappers
      +
      +    !> Match one of the available compiler wrappers with the current compiler
      +    subroutine mpi_compiler_match(language,wrappers,compiler,which_one,mpilib,error)
      +        integer, intent(in) :: language
      +        type(string_t), intent(in) :: wrappers(:)
      +        type(compiler_t), intent(in) :: compiler
      +        integer, intent(out) :: which_one, mpilib
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        integer :: i, same_vendor, vendor_mpilib
      +        type(string_t) :: screen
      +        character(128) :: msg_out
      +        type(compiler_t) :: mpi_compiler
      +
      +        which_one   = 0
      +        same_vendor = 0
      +        mpilib      = MPI_TYPE_NONE
      +
      +        if (verbose) print *, '+ Trying to match available ',LANG_NAME(language),' MPI wrappers to ',compiler%fc,'...'
      +
      +        do i=1,size(wrappers)
      +
      +            mpilib = which_mpi_library(wrappers(i),compiler,verbose=.false.)
      +
      +            screen = mpi_wrapper_query(mpilib,wrappers(i),'compiler',verbose=.false.,error=error)
      +            if (allocated(error)) return
      +
      +            if (verbose) print *, '  Wrapper ',wrappers(i)%s,' lib=',MPI_TYPE_NAME(mpilib),' uses ',screen%s
      +
      +            select case (language)
      +               case (LANG_FORTRAN)
      +                   ! Build compiler type. The ID is created based on the Fortran name
      +                   call new_compiler(mpi_compiler,screen%s,'','',echo=.true.,verbose=.false.)
      +
      +                   ! Fortran match found!
      +                   if (mpi_compiler%id == compiler%id) then
      +                       which_one = i
      +                       return
      +                   end if
      +               case (LANG_C)
      +                   ! For other languages, we can only hope that the name matches the expected one
      +                   if (screen%s==compiler%cc .or. screen%s==compiler%fc) then
      +                       which_one = i
      +                       return
      +                   end if
      +               case (LANG_CXX)
      +                   if (screen%s==compiler%cxx .or. screen%s==compiler%fc) then
      +                       which_one = i
      +                       return
      +                   end if
      +            end select
      +
      +            ! Because the intel mpi library does not support llvm_ compiler wrappers yet,
      +            ! we must check for that manually
      +            if (is_intel_classic_option(language,same_vendor,screen,compiler,mpi_compiler)) then
      +                same_vendor = i
      +                vendor_mpilib = mpilib
      +            end if
      +        end do
      +
      +        ! Intel compiler: if an exact match is not found, attempt closest wrapper
      +        if (which_one==0 .and. same_vendor>0) then
      +            which_one = same_vendor
      +            mpilib    = vendor_mpilib
      +        end if
      +
      +        ! None of the available wrappers matched the current Fortran compiler
      +        write(msg_out,1) size(wrappers),compiler%fc
      +        call fatal_error(error,trim(msg_out))
      +        1 format('<ERROR> None out of ',i0,' valid MPI wrappers matches compiler ',a)
      +
      +    end subroutine mpi_compiler_match
      +
      +    !> Because the Intel mpi library does not support llvm_ compiler wrappers yet,
      +    !> we must save the Intel-classic option and later manually replace it
      +    logical function is_intel_classic_option(language,same_vendor_ID,screen_out,compiler,mpi_compiler)
      +        integer, intent(in) :: language,same_vendor_ID
      +        type(string_t), intent(in) :: screen_out
      +        type(compiler_t), intent(in) :: compiler,mpi_compiler
      +
      +        if (same_vendor_ID/=0) then
      +            is_intel_classic_option = .false.
      +        else
      +            select case (language)
      +               case (LANG_FORTRAN)
      +                   is_intel_classic_option = mpi_compiler%is_intel() .and. compiler%is_intel()
      +               case (LANG_C)
      +                   is_intel_classic_option = screen_out%s=='icc' .and. compiler%cc=='icx'
      +               case (LANG_CXX)
      +                   is_intel_classic_option = screen_out%s=='icpc' .and. compiler%cc=='icpx'
      +            end select
      +        end if
      +
      +    end function is_intel_classic_option
      +
      +    !> Return library version from the MPI wrapper command
      +    type(version_t) function mpi_version_get(mpilib,wrapper,error)
      +       integer, intent(in) :: mpilib
      +       type(string_t), intent(in) :: wrapper
      +       type(error_t), allocatable, intent(out) :: error
      +
      +       type(string_t) :: version_line
      +
      +       ! Get version string
      +       version_line = mpi_wrapper_query(mpilib,wrapper,'version',error=error)
      +       if (allocated(error)) return
      +
      +       ! Wrap to object
      +       call new_version(mpi_version_get,version_line%s,error)
      +
      +    end function mpi_version_get
      +
      +    !> Return several mpi wrappers, and return
      +    subroutine mpi_wrappers(compiler,fort_wrappers,c_wrappers,cpp_wrappers)
      +        type(compiler_t), intent(in) :: compiler
      +        type(string_t), allocatable, intent(out) :: c_wrappers(:),cpp_wrappers(:),fort_wrappers(:)
      +
      +        character(len=:), allocatable :: mpi_root,intel_wrap
      +        type(error_t), allocatable :: error
      +
      +        ! Attempt gathering MPI wrapper names from the environment variables
      +        c_wrappers    = [string_t(get_env('MPICC' ,'mpicc'))]
      +        cpp_wrappers  = [string_t(get_env('MPICXX','mpic++'))]
      +        fort_wrappers = [string_t(get_env('MPIFC' ,'mpifc' )),&
      +                         string_t(get_env('MPIf90','mpif90')),&
      +                         string_t(get_env('MPIf77','mpif77'))]
      +
      +        if (get_os_type()==OS_WINDOWS) then
      +            c_wrappers    = [c_wrappers,string_t('mpicc.bat')]
      +            cpp_wrappers  = [cpp_wrappers,string_t('mpicxx.bat')]
      +            fort_wrappers = [fort_wrappers,string_t('mpifc.bat')]
      +        endif
      +
      +        ! Add compiler-specific wrappers
      +        compiler_specific: select case (compiler%id)
      +           case (id_gcc,id_f95)
      +
      +                c_wrappers = [c_wrappers,string_t('mpigcc'),string_t('mpgcc')]
      +              cpp_wrappers = [cpp_wrappers,string_t('mpig++'),string_t('mpg++')]
      +             fort_wrappers = [fort_wrappers,string_t('mpigfortran'),string_t('mpgfortran'),&
      +                              string_t('mpig77'),string_t('mpg77')]
      +
      +           case (id_intel_classic_windows,id_intel_classic_nix,id_intel_classic_mac)
      +                 
      +                c_wrappers = [string_t(get_env('I_MPI_CC' ,'mpiicc'))]
      +              cpp_wrappers = [string_t(get_env('I_MPI_CXX','mpiicpc'))]
      +             fort_wrappers = [string_t(get_env('I_MPI_F90','mpiifort'))]
      +
      +             ! Also search MPI wrappers via the base MPI folder
      +             mpi_root = get_env('I_MPI_ROOT')
      +             if (mpi_root/="") then
      +
      +                 mpi_root = join_path(mpi_root,'bin')
      +
      +                 intel_wrap = join_path(mpi_root,'mpiifort')
      +                 if (get_os_type()==OS_WINDOWS) intel_wrap = get_dos_path(intel_wrap,error)
      +                 if (intel_wrap/="") fort_wrappers = [fort_wrappers,string_t(intel_wrap)]
      +
      +                 intel_wrap = join_path(mpi_root,'mpiicc')
      +                 if (get_os_type()==OS_WINDOWS) intel_wrap = get_dos_path(intel_wrap,error)
      +                 if (intel_wrap/="") c_wrappers = [c_wrappers,string_t(intel_wrap)]
      +
      +                 intel_wrap = join_path(mpi_root,'mpiicpc')
      +                 if (get_os_type()==OS_WINDOWS) intel_wrap = get_dos_path(intel_wrap,error)
      +                 if (intel_wrap/="") cpp_wrappers = [cpp_wrappers,string_t(intel_wrap)]
      +
      +             end if
      +
      +           case (id_intel_llvm_windows,id_intel_llvm_nix,id_intel_llvm_unknown)
      +                 
      +                c_wrappers = [string_t(get_env('I_MPI_CC' ,'mpiicx'))]
      +              cpp_wrappers = [string_t(get_env('I_MPI_CXX','mpiicpx'))]
      +             fort_wrappers = [string_t(get_env('I_MPI_F90','mpiifx'))]
      +
      +             ! Also search MPI wrappers via the base MPI folder
      +             mpi_root = get_env('I_MPI_ROOT')
      +             if (mpi_root/="") then
      +
      +                 mpi_root = join_path(mpi_root,'bin')
      +
      +                 intel_wrap = join_path(mpi_root,'mpiifx')
      +                 if (get_os_type()==OS_WINDOWS) intel_wrap = get_dos_path(intel_wrap,error)
      +                 if (intel_wrap/="") fort_wrappers = [fort_wrappers,string_t(intel_wrap)]
      +
      +                 intel_wrap = join_path(mpi_root,'mpiicx')
      +                 if (get_os_type()==OS_WINDOWS) intel_wrap = get_dos_path(intel_wrap,error)
      +                 if (intel_wrap/="") c_wrappers = [c_wrappers,string_t(intel_wrap)]
      +
      +                 intel_wrap = join_path(mpi_root,'mpiicpx')
      +                 if (get_os_type()==OS_WINDOWS) intel_wrap = get_dos_path(intel_wrap,error)
      +                 if (intel_wrap/="") cpp_wrappers = [cpp_wrappers,string_t(intel_wrap)]
      +
      +             end if
      +
      +           case (id_pgi,id_nvhpc)
      +
      +                c_wrappers = [c_wrappers,string_t('mpipgicc'),string_t('mpgcc')]
      +              cpp_wrappers = [cpp_wrappers,string_t('mpipgic++')]
      +             fort_wrappers = [fort_wrappers,string_t('mpipgifort'),string_t('mpipgf90')]
      +
      +           case (id_cray)
      +
      +                c_wrappers = [c_wrappers,string_t('cc')]
      +              cpp_wrappers = [cpp_wrappers,string_t('CC')]
      +             fort_wrappers = [fort_wrappers,string_t('ftn')]
      +
      +        end select compiler_specific
      +
      +        call assert_mpi_wrappers(fort_wrappers,compiler)
      +        call assert_mpi_wrappers(c_wrappers,compiler)
      +        call assert_mpi_wrappers(cpp_wrappers,compiler)
      +
      +    end subroutine mpi_wrappers
      +
      +    !> Filter out invalid/unavailable mpi wrappers
      +    subroutine assert_mpi_wrappers(wrappers,compiler,verbose)
      +        type(string_t), allocatable, intent(inout) :: wrappers(:)
      +        type(compiler_t), intent(in) :: compiler
      +        logical, optional, intent(in) :: verbose
      +
      +        integer :: i
      +        integer, allocatable :: works(:)
      +
      +        allocate(works(size(wrappers)))
      +
      +        do i=1,size(wrappers)
      +            if (present(verbose)) then
      +                if (verbose) print *, '+ MPI test wrapper <',wrappers(i)%s,'>'
      +            endif
      +            works(i) = which_mpi_library(wrappers(i),compiler,verbose)
      +        end do
      +
      +        ! Filter out non-working wrappers
      +        wrappers = pack(wrappers,works/=MPI_TYPE_NONE)
      +
      +    end subroutine assert_mpi_wrappers
      +
      +    !> Get MPI library type from the wrapper command. Currently, only OpenMPI is supported
      +    integer function which_mpi_library(wrapper,compiler,verbose)
      +        type(string_t), intent(in) :: wrapper
      +        type(compiler_t), intent(in) :: compiler
      +        logical, intent(in), optional :: verbose
      +
      +        logical :: is_mpi_wrapper
      +        integer :: stat
      +
      +        ! Init as currently unsupported library
      +        which_mpi_library = MPI_TYPE_NONE
      +
      +        if (len_trim(wrapper)<=0) return
      +
      +        ! Run mpi wrapper first
      +        call run_wrapper(wrapper,verbose=verbose,cmd_success=is_mpi_wrapper)
      +
      +        if (is_mpi_wrapper) then
      +
      +            if (compiler%is_intel()) then
      +                which_mpi_library = MPI_TYPE_INTEL
      +                return
      +            end if
      +
      +            ! Attempt to decipher which library this wrapper comes from.
      +
      +            ! OpenMPI responds to '--showme' calls
      +            call run_wrapper(wrapper,[string_t('--showme')],verbose,&
      +                                 exitcode=stat,cmd_success=is_mpi_wrapper)
      +            if (stat==0 .and. is_mpi_wrapper) then
      +                which_mpi_library = MPI_TYPE_OPENMPI
      +                return
      +            endif
      +
      +            ! MPICH responds to '-show' calls
      +            call run_wrapper(wrapper,[string_t('-show')],verbose,&
      +                                 exitcode=stat,cmd_success=is_mpi_wrapper)
      +            if (stat==0 .and. is_mpi_wrapper) then
      +                which_mpi_library = MPI_TYPE_MPICH
      +                return
      +            endif
      +
      +        end if
      +
      +    end function which_mpi_library
      +
      +    !> Test if an MPI wrapper works
      +    type(string_t) function mpi_wrapper_query(mpilib,wrapper,command,verbose,error) result(screen)
      +        integer, intent(in) :: mpilib
      +        type(string_t), intent(in) :: wrapper
      +        character(*), intent(in) :: command
      +        logical, intent(in), optional :: verbose
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        logical :: success
      +        character(:), allocatable :: redirect_str,tokens(:),unsupported_msg
      +        type(string_t) :: cmdstr
      +        type(compiler_t) :: mpi_compiler
      +        integer :: stat,cmdstat,ire,length
      +
      +        unsupported_msg = 'the MPI library of wrapper '//wrapper%s//' does not support task '//trim(command)
      +
      +        select case (command)
      +
      +           ! Get MPI compiler name
      +           case ('compiler')
      +
      +               select case (mpilib)
      +                  case (MPI_TYPE_OPENMPI); cmdstr = string_t('--showme:command')
      +                  case (MPI_TYPE_MPICH);   cmdstr = string_t('-compile-info')
      +                  case (MPI_TYPE_INTEL);   cmdstr = string_t('-show')
      +                  case default
      +                     call fatal_error(error,unsupported_msg)
      +                     return
      +               end select
      +
      +               call run_wrapper(wrapper,[cmdstr],verbose=verbose, &
      +                                    exitcode=stat,cmd_success=success,screen_output=screen)
      +
      +               if (stat/=0 .or. .not.success) then
      +                  call syntax_error(error,'local '//MPI_TYPE_NAME(mpilib)//&
      +                                          ' library wrapper does not support flag '//cmdstr%s)
      +                  return
      +               end if
      +
      +               ! Take out the first command from the whole line
      +               call remove_newline_characters(screen)
      +               call split(screen%s,tokens,delimiters=' ')
      +               screen%s = trim(adjustl(tokens(1)))
      +
      +           ! Get a list of additional compiler flags
      +           case ('flags')
      +
      +               select case (mpilib)
      +                  case (MPI_TYPE_OPENMPI); cmdstr = string_t('--showme:compile')
      +                  case (MPI_TYPE_MPICH);   cmdstr = string_t('-compile-info')
      +                  case (MPI_TYPE_INTEL);   cmdstr = string_t('-show')
      +                  case default
      +                     call fatal_error(error,unsupported_msg)
      +                     return
      +               end select
      +
      +               call run_wrapper(wrapper,[cmdstr],verbose=verbose, &
      +                                    exitcode=stat,cmd_success=success,screen_output=screen)
      +
      +               if (stat/=0 .or. .not.success) then
      +                  call syntax_error(error,'local '//MPI_TYPE_NAME(mpilib)//&
      +                                          ' library wrapper does not support flag '//cmdstr%s)
      +                  return
      +               end if
      +
      +               ! Post-process output
      +               select case (mpilib)
      +                  case (MPI_TYPE_OPENMPI)
      +                     ! This library reports the compiler name only
      +                     call remove_newline_characters(screen)
      +                  case (MPI_TYPE_MPICH,MPI_TYPE_INTEL)
      +                     ! These libraries report the full command including the compiler name. Remove it if so
      +                     call remove_newline_characters(screen)
      +                     call split(screen%s,tokens)
      +                     ! Remove trailing compiler name
      +                     screen%s = screen%s(len_trim(tokens(1))+1:)
      +                  case default
      +                     call fatal_error(error,'invalid MPI library type')
      +                     return
      +               end select
      +
      +           ! Get a list of additional linker flags
      +           case ('link')
      +
      +               select case (mpilib)
      +                  case (MPI_TYPE_OPENMPI); cmdstr = string_t('--showme:link')
      +                  case (MPI_TYPE_MPICH);   cmdstr = string_t('-link-info')
      +                  case (MPI_TYPE_INTEL);   cmdstr = string_t('-show')
      +                  case default
      +                     call fatal_error(error,unsupported_msg)
      +                     return
      +               end select
      +
      +               call run_wrapper(wrapper,[cmdstr],verbose=verbose, &
      +                                    exitcode=stat,cmd_success=success,screen_output=screen)
      +
      +               if (stat/=0 .or. .not.success) then
      +                  call syntax_error(error,'local '//MPI_TYPE_NAME(mpilib)//&
      +                                          ' library wrapper does not support flag '//cmdstr%s)
      +                  return
      +               end if
      +
      +               select case (mpilib)
      +                  case (MPI_TYPE_OPENMPI)
      +                     call remove_newline_characters(screen)
      +                  case (MPI_TYPE_MPICH,MPI_TYPE_INTEL)
      +                     ! MPICH reports the full command including the compiler name. Remove it if so
      +                     call remove_newline_characters(screen)
      +                     call split(screen%s,tokens)
      +                     ! Remove trailing compiler name
      +                     screen%s = screen%s(len_trim(tokens(1))+1:)
      +                  case default
      +                     call fatal_error(error,unsupported_msg)
      +                     return
      +               end select
      +
      +           ! Get a list of MPI library directories
      +           case ('link_dirs')
      +
      +               select case (mpilib)
      +                  case (MPI_TYPE_OPENMPI)
      +
      +                     ! --showme:command returns the build command of this wrapper
      +                     call run_wrapper(wrapper,[string_t('--showme:libdirs')],verbose=verbose, &
      +                                          exitcode=stat,cmd_success=success,screen_output=screen)
      +
      +                     if (stat/=0 .or. .not.success) then
      +                        call syntax_error(error,'local OpenMPI library does not support --showme:libdirs')
      +                        return
      +                     end if
      +
      +                  case default
      +
      +                     call fatal_error(error,unsupported_msg)
      +                     return
      +
      +               end select
      +
      +           ! Get a list of include directories for the MPI headers/modules
      +           case ('incl_dirs')
      +
      +               select case (mpilib)
      +                  case (MPI_TYPE_OPENMPI)
      +                     ! --showme:command returns the build command of this wrapper
      +                     call run_wrapper(wrapper,[string_t('--showme:incdirs')],verbose=verbose, &
      +                                          exitcode=stat,cmd_success=success,screen_output=screen)
      +                     if (stat/=0 .or. .not.success) then
      +                        call syntax_error(error,'local OpenMPI library does not support --showme:incdirs')
      +                        return
      +                     end if
      +                  case default
      +                     call fatal_error(error,unsupported_msg)
      +                     return
      +               end select
      +
      +               call remove_newline_characters(screen)
      +
      +           ! Retrieve library version
      +           case ('version')
      +
      +               select case (mpilib)
      +                  case (MPI_TYPE_OPENMPI)
      +
      +                     ! --showme:command returns the build command of this wrapper
      +                     call run_wrapper(wrapper,[string_t('--showme:version')],verbose=verbose, &
      +                                          exitcode=stat,cmd_success=success,screen_output=screen)
      +
      +                     if (stat/=0 .or. .not.success) then
      +                        call syntax_error(error,'local OpenMPI library does not support --showme:version')
      +                        return
      +                     else
      +                        call remove_newline_characters(screen)
      +                     end if
      +
      +                  case (MPI_TYPE_MPICH)
      +
      +                     !> MPICH offers command "mpichversion" in the same system folder as the MPI wrappers.
      +                     !> So, attempt to run that first
      +                     cmdstr = string_t('mpichversion')
      +                     call run_wrapper(cmdstr,verbose=verbose, &
      +                                          exitcode=stat,cmd_success=success,screen_output=screen)
      +
      +                     ! Second option: run mpich wrapper + "-v"
      +                     if (stat/=0 .or. .not.success) then
      +                        call run_wrapper(wrapper,[string_t('-v')],verbose=verbose, &
      +                                             exitcode=stat,cmd_success=success,screen_output=screen)
      +                        call remove_newline_characters(screen)
      +                     endif
      +
      +                     ! Third option: mpiexec --version
      +                     if (stat/=0 .or. .not.success) then
      +                         cmdstr = string_t('mpiexec --version')
      +                         call run_wrapper(cmdstr,verbose=verbose, &
      +                                              exitcode=stat,cmd_success=success,screen_output=screen)
      +                     endif
      +
      +                     if (stat/=0 .or. .not.success) then
      +                        call syntax_error(error, &
      +                            'cannot retrieve MPICH library version from <mpichversion, '//wrapper%s//', mpiexec>')
      +                        return
      +                     end if
      +
      +                  case (MPI_TYPE_INTEL)
      +
      +                     ! -v returns the build command of this wrapper
      +                     call run_wrapper(wrapper,[string_t('-v')],verbose=verbose, &
      +                                          exitcode=stat,cmd_success=success,screen_output=screen)
      +
      +                     ! LLVM wrappers bug: non-zero exit code when checking for "-v" -> only check for 
      +                     ! successful command: https://github.com/spack/spack/issues/47672
      +                     if (.not.success) then
      +                        call syntax_error(error,'local INTEL MPI library does not support -v')
      +                        return
      +                     else
      +                        call remove_newline_characters(screen)
      +                     end if
      +
      +                  case default
      +
      +                     call fatal_error(error,unsupported_msg)
      +                     return
      +
      +               end select
      +
      +               ! Extract version
      +               screen = regex_version_from_text(screen%s,MPI_TYPE_NAME(mpilib)//' library',error)
      +               if (allocated(error)) return
      +
      +           ! Get path to the MPI runner command
      +           case ('runner')
      +
      +               select case (mpilib)
      +                  case (MPI_TYPE_OPENMPI,MPI_TYPE_MPICH,MPI_TYPE_MSMPI,MPI_TYPE_INTEL)
      +                     call get_mpi_runner(screen,verbose,error)
      +                  case default
      +                     call fatal_error(error,unsupported_msg)
      +                     return
      +               end select
      +
      +           case default;
      +               call fatal_error(error,'an invalid MPI wrapper command ('//command//&
      +                                      ') was invoked for wrapper <'//wrapper%s//'>.')
      +               return
      +        end select
      +
      +
      +    end function mpi_wrapper_query
      +
      +
      +
      +    !> Check if input is a useful linker argument
      +    logical function is_link_argument(compiler,string)
      +       type(compiler_t), intent(in) :: compiler
      +       character(*), intent(in) :: string
      +
      +       select case (compiler%id)
      +          case (id_intel_classic_windows,id_intel_llvm_windows)
      +              is_link_argument = string=='/link' &
      +                                 .or. str_begins_with_str(string,'/LIBPATH')&
      +                                 .or. str_ends_with(string,'.lib') ! always .lib whether static or dynamic
      +          case default
      +
      +              ! fix OpenMPI's Fortran wrapper bug (https://github.com/open-mpi/ompi/issues/11636) here
      +              is_link_argument = (    str_begins_with_str(string,'-L') &
      +                                 .or. str_begins_with_str(string,'-l') &
      +                                 .or. str_begins_with_str(string,'-Xlinker') &
      +                                 .or. string=='-pthread' &
      +                                 .or. (str_begins_with_str(string,'-W') .and. &
      +                                       (string/='-Wall') .and. (.not.str_begins_with_str(string,'-Werror'))) ) &
      +                                 .and. .not. ( &
      +                                     (get_os_type()==OS_MACOS .and. index(string,'-commons,use_dylibs')>0) )
      +       end select
      +
      +    end function is_link_argument
      +
      +    !> From build, remove optimization and other unnecessary flags
      +    subroutine filter_build_arguments(compiler,command)
      +        type(compiler_t), intent(in) :: compiler
      +        type(string_t), intent(inout) :: command
      +        character(len=:), allocatable :: tokens(:)
      +
      +        integer :: i,n,re_i,re_l
      +        logical, allocatable :: keep(:)
      +        logical :: keep_next
      +        character(len=:), allocatable :: module_flag,include_flag
      +
      +        if (len_trim(command)<=0) return
      +
      +        ! Split command into arguments
      +        tokens = shlex_split(command%s)
      +
      +        module_flag  = get_module_flag(compiler,"")
      +        include_flag = get_include_flag(compiler,"")
      +
      +        n = size(tokens)
      +        allocate(keep(n),source=.false.)
      +        keep_next = .false.
      +
      +        do i=1,n
      +
      +            if (get_os_type()==OS_MACOS .and. index(tokens(i),'-commons,use_dylibs')>0) then
      +                keep(i) = .false.
      +                keep_next = .false.
      +            elseif (str_begins_with_str(tokens(i),'-D') .or. &
      +                    str_begins_with_str(tokens(i),'-f') .or. &
      +                    str_begins_with_str(tokens(i),'-I') .or. &
      +                    str_begins_with_str(tokens(i),module_flag) .or. &
      +                    str_begins_with_str(tokens(i),include_flag) .or. &
      +                    tokens(i)=='-pthread' .or. &
      +                    (str_begins_with_str(tokens(i),'-W') .and. tokens(i)/='-Wall' .and. &
      +                        .not.str_begins_with_str(tokens(i),'-Werror')) &
      +                    ) then
      +                       keep(i) = .true.
      +                       if (tokens(i)==module_flag .or. tokens(i)==include_flag .or. tokens(i)=='-I') keep_next = .true.
      +            elseif (keep_next) then
      +                keep(i) = .true.
      +                keep_next = .false.
      +            end if
      +        end do
      +
      +        ! Backfill
      +        command = string_t("")
      +        do i=1,n
      +            if (.not.keep(i)) cycle
      +
      +            command%s = command%s//' '//trim(tokens(i))
      +        end do
      +
      +
      +    end subroutine filter_build_arguments
      +
      +    !> From the linker flags, remove optimization and other unnecessary flags
      +    subroutine filter_link_arguments(compiler,command)
      +        type(compiler_t), intent(in) :: compiler
      +        type(string_t), intent(inout) :: command
      +        character(len=:), allocatable :: tokens(:)
      +
      +        integer :: i,n
      +        logical, allocatable :: keep(:)
      +        logical :: keep_next
      +
      +        if (len_trim(command)<=0) return
      +
      +        ! Split command into arguments
      +        tokens = shlex_split(command%s)
      +
      +        n = size(tokens)
      +        allocate(keep(n),source=.false.)
      +        keep_next = .false.
      +
      +        do i=1,n
      +           if (is_link_argument(compiler,tokens(i))) then
      +               keep(i) = .true.
      +               if (tokens(i)=='-L' .or. tokens(i)=='-Xlinker') keep_next = .true.
      +           elseif (keep_next) then
      +               keep(i) = .true.
      +               keep_next = .false.
      +           end if
      +        end do
      +
      +        ! Backfill
      +        command = string_t("")
      +        do i=1,n
      +            if (.not.keep(i)) cycle
      +            command%s = command%s//' '//trim(tokens(i))
      +        end do
      +
      +    end subroutine filter_link_arguments
      +
      +end module fpm_meta_mpi
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/fpm_meta_netcdf.f90.html b/sourcefile/fpm_meta_netcdf.f90.html new file mode 100644 index 0000000000..1e1cbb4cc0 --- /dev/null +++ b/sourcefile/fpm_meta_netcdf.f90.html @@ -0,0 +1,275 @@ + + + + + + + + + + + + + fpm_meta_netcdf.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      fpm_meta_netcdf.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      module fpm_meta_netcdf
      +    use fpm_compiler, only: compiler_t, get_include_flag
      +    use fpm_meta_base, only: metapackage_t, destroy
      +    use fpm_meta_util, only: add_pkg_config_compile_options
      +    use fpm_pkg_config, only: assert_pkg_config, pkgcfg_has_package
      +    use fpm_strings, only: string_t
      +    use fpm_error, only: error_t, fatal_error
      +    use fpm_manifest_metapackages, only: metapackage_request_t
      +
      +    implicit none
      +
      +    private
      +
      +    public :: init_netcdf
      +
      +contains
      +
      +    !> Initialize NetCDF metapackage for the current system
      +    subroutine init_netcdf(this, compiler, all_meta, error)
      +        class(metapackage_t), intent(inout) :: this
      +        type(compiler_t), intent(in) :: compiler
      +        type(metapackage_request_t), intent(in) :: all_meta(:)
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        logical :: s
      +        character(len=:), allocatable :: include_flag, libdir
      +
      +        include_flag = get_include_flag(compiler, "")
      +
      +        !> Cleanup
      +        call destroy(this)
      +        allocate (this % link_libs(0), this % incl_dirs(0), this % external_modules(0))
      +        this % link_flags = string_t("")
      +        this % flags = string_t("")
      +        
      +        !> Set name
      +        this%name = "netcdf"
      +
      +        !> Assert pkg-config is installed
      +        if (.not. assert_pkg_config()) then
      +            call fatal_error(error, 'netcdf metapackage requires pkg-config')
      +            return
      +        end if
      +
      +        if (.not. pkgcfg_has_package('netcdf')) then
      +            call fatal_error(error, 'pkg-config could not find a suitable netcdf package.')
      +            return
      +        end if
      +        call add_pkg_config_compile_options(this, 'netcdf', include_flag, libdir, error)
      +        if (allocated(error)) return
      +
      +        if (.not. pkgcfg_has_package('netcdf-fortran')) then
      +            call fatal_error(error, &
      +                             'pkg-config could not find a suitable netcdf-fortran package.')
      +            return
      +        end if
      +        call add_pkg_config_compile_options(this, 'netcdf-fortran', include_flag, libdir, error)
      +        if (allocated(error)) return
      +
      +        !> Add NetCDF modules as external
      +        this % has_external_modules = .true.
      +        this % external_modules = [string_t('netcdf'), &
      +                                   string_t('netcdf4_f03'), &
      +                                   string_t('netcdf4_nc_interfaces'), &
      +                                   string_t('netcdf4_nf_interfaces'), &
      +                                   string_t('netcdf_f03'), &
      +                                   string_t('netcdf_fortv2_c_interfaces'), &
      +                                   string_t('netcdf_nc_data'), &
      +                                   string_t('netcdf_nc_interfaces'), &
      +                                   string_t('netcdf_nf_data'), &
      +                                   string_t('netcdf_nf_interfaces')]
      +    end subroutine init_netcdf
      +end module fpm_meta_netcdf
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/fpm_meta_openmp.f90.html b/sourcefile/fpm_meta_openmp.f90.html new file mode 100644 index 0000000000..65dbb87209 --- /dev/null +++ b/sourcefile/fpm_meta_openmp.f90.html @@ -0,0 +1,283 @@ + + + + + + + + + + + + + fpm_meta_openmp.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      fpm_meta_openmp.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      module fpm_meta_openmp
      +    use fpm_compiler, only: compiler_t, id_gcc, id_f95, id_intel_classic_windows, &
      +       id_intel_llvm_windows, id_intel_classic_nix, id_intel_llvm_nix, &
      +       id_intel_classic_mac, id_pgi, id_nvhpc, id_ibmxl, id_nag, id_lfortran, &
      +       id_flang, id_flang_new, flag_gnu_openmp, flag_intel_openmp_win, &
      +       flag_intel_openmp, flag_pgi_openmp, flag_nag_openmp, &
      +       flag_lfortran_openmp, flag_flang_new_openmp
      +    use fpm_strings, only: string_t
      +    use fpm_meta_base, only: metapackage_t, destroy
      +    use fpm_error, only: error_t, fatal_error
      +    use fpm_manifest_metapackages, only: metapackage_request_t
      +
      +    implicit none
      +
      +    private
      +
      +    public :: init_openmp
      +
      +    contains
      +
      +    !> Initialize OpenMP metapackage for the current system
      +    subroutine init_openmp(this,compiler,all_meta,error)
      +        class(metapackage_t), intent(inout) :: this
      +        type(compiler_t), intent(in) :: compiler
      +        type(metapackage_request_t), intent(in) :: all_meta(:)
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        !> Cleanup
      +        call destroy(this)
      +        
      +        !> Set name
      +        this%name = "openmp"
      +
      +        !> OpenMP has compiler flags
      +        this%has_build_flags = .true.
      +        this%has_link_flags  = .true.
      +
      +        !> OpenMP flags should be added to
      +        which_compiler: select case (compiler%id)
      +           case (id_gcc,id_f95)
      +                this%flags      = string_t(flag_gnu_openmp)
      +                this%link_flags = string_t(flag_gnu_openmp)
      +
      +           case (id_intel_classic_windows,id_intel_llvm_windows)
      +                this%flags      = string_t(flag_intel_openmp_win)
      +                this%link_flags = string_t(flag_intel_openmp_win)
      +
      +           case (id_intel_classic_nix,id_intel_classic_mac,&
      +                 id_intel_llvm_nix)
      +                this%flags      = string_t(flag_intel_openmp)
      +                this%link_flags = string_t(flag_intel_openmp)
      +
      +           case (id_pgi,id_nvhpc)
      +                this%flags      = string_t(flag_pgi_openmp)
      +                this%link_flags = string_t(flag_pgi_openmp)
      +
      +           case (id_ibmxl)
      +                this%flags      = string_t(" -qsmp=omp")
      +                this%link_flags = string_t(" -qsmp=omp")
      +
      +           case (id_nag)
      +                this%flags      = string_t(flag_nag_openmp)
      +                this%link_flags = string_t(flag_nag_openmp)
      +
      +           case (id_lfortran)
      +                this%flags      = string_t(flag_lfortran_openmp)
      +                this%link_flags = string_t(flag_lfortran_openmp)
      +
      +           case (id_flang, id_flang_new)
      +                this%flags      = string_t(flag_flang_new_openmp)
      +                this%link_flags = string_t(flag_flang_new_openmp)
      +
      +           case default
      +
      +              call fatal_error(error,'openmp not supported on compiler '//compiler%name()//' yet')
      +
      +        end select which_compiler
      +
      +
      +    end subroutine init_openmp
      +end module fpm_meta_openmp
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/fpm_meta_stdlib.f90.html b/sourcefile/fpm_meta_stdlib.f90.html new file mode 100644 index 0000000000..e12ca1d6eb --- /dev/null +++ b/sourcefile/fpm_meta_stdlib.f90.html @@ -0,0 +1,286 @@ + + + + + + + + + + + + + fpm_meta_stdlib.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      fpm_meta_stdlib.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      module fpm_meta_stdlib
      +    use fpm_compiler, only: compiler_t
      +    use fpm_error, only: error_t, fatal_error
      +    use fpm_meta_base, only: metapackage_t, destroy
      +    use fpm_git, only: git_target_branch
      +    use fpm_manifest_metapackages, only: metapackage_request_t
      +    use fpm_strings, only: string_t
      +    use iso_fortran_env, only: stdout => output_unit
      +
      +    implicit none
      +
      +    private
      +
      +    public :: init_stdlib
      +
      +    contains
      +
      +    !> Initialize stdlib metapackage for the current system
      +    subroutine init_stdlib(this,compiler,all_meta,error)
      +        class(metapackage_t), intent(inout) :: this
      +        type(compiler_t), intent(in) :: compiler
      +        type(metapackage_request_t), intent(in) :: all_meta(:)
      +        type(error_t), allocatable, intent(out) :: error
      +        
      +        integer :: i
      +        logical :: with_blas
      +
      +        !> Cleanup
      +        call destroy(this)
      +        
      +        !> Set name
      +        this%name = "stdlib"
      +        
      +        !> Stdlib is queried as a dependency from the official repository
      +        this%has_dependencies = .true.
      +
      +        allocate(this%dependency(2))
      +
      +        !> 1) Test-drive
      +        this%dependency(1)%name = "test-drive"
      +        this%dependency(1)%git = git_target_branch("https://github.com/fortran-lang/test-drive","v0.4.0")
      +        if (.not.allocated(this%dependency(1)%git)) then
      +            call fatal_error(error,'cannot initialize test-drive git dependency for stdlib metapackage')
      +            return
      +        end if
      +
      +        !> 2) stdlib
      +        this%dependency(2)%name = "stdlib"
      +        this%dependency(2)%git = git_target_branch("https://github.com/fortran-lang/stdlib","stdlib-fpm")
      +        if (.not.allocated(this%dependency(2)%git)) then
      +            call fatal_error(error,'cannot initialize git repo dependency for stdlib metapackage')
      +            return
      +        end if
      +        
      +        !> If an external BLAS is available, deploy appropriate macros    
      +        with_blas = external_blas(all_meta)
      +        if (with_blas) then 
      +            allocate(this%preprocess)
      +            call this%preprocess%new([string_t('STDLIB_EXTERNAL_BLAS'),string_t('STDLIB_EXTERNAL_LAPACK')])
      +            call this%dependency(2)%add_preprocess(this%preprocess)
      +        end if
      +
      +        ! Stdlib is not 100% thread safe. print a warning to the user
      +        do i=1,size(all_meta)
      +            if (all_meta(i)%name=="openmp") then 
      +                write(stdout,'(a)')'<WARNING> both openmp and stdlib requested: some functions may not be thread-safe!'
      +            end if                
      +        end do
      +
      +    end subroutine init_stdlib
      +    
      +    logical function external_blas(all_meta)
      +        type(metapackage_request_t), intent(in) :: all_meta(:)
      +        integer :: i
      +        external_blas = .false.
      +        do i=1,size(all_meta)
      +            if (all_meta(i)%name=="blas") then
      +                external_blas = .true.
      +                exit 
      +            end if                
      +        end do            
      +    end function external_blas
      +    
      +end module fpm_meta_stdlib
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/fpm_meta_util.f90.html b/sourcefile/fpm_meta_util.f90.html new file mode 100644 index 0000000000..7396edff95 --- /dev/null +++ b/sourcefile/fpm_meta_util.f90.html @@ -0,0 +1,324 @@ + + + + + + + + + + + + + fpm_meta_util.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      fpm_meta_util.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      module fpm_meta_util
      +    use fpm_meta_base, only: metapackage_t, destroy
      +    use fpm_filesystem, only: join_path
      +    use fpm_strings, only: split, string_t, str_begins_with_str
      +    use fpm_error, only: error_t
      +    use fpm_versioning, only: new_version
      +    use fpm_pkg_config, only: pkgcfg_get_libs, pkgcfg_get_build_flags, pkgcfg_get_version
      +
      +    implicit none
      +
      +    private
      +
      +    public :: add_pkg_config_compile_options, lib_get_trailing
      +
      +    contains
      +
      +    !> Add pkgconfig compile options to a metapackage
      +    subroutine add_pkg_config_compile_options(this, name, include_flag, libdir, error)
      +        class(metapackage_t), intent(inout) :: this
      +        character(len=*), intent(in) :: name
      +        character(len=*), intent(in) :: include_flag
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        character(len=:), allocatable :: libdir
      +        type(string_t) :: log, current_include_dir, current_lib
      +        type(string_t), allocatable :: libs(:), flags(:)
      +        integer :: i
      +
      +        !> Get version
      +        if (.not. allocated(this%version)) then
      +            log = pkgcfg_get_version(name, error)
      +            if (allocated(error)) return
      +            allocate(this%version)
      +            call new_version(this%version, log%s, error)
      +            if (allocated(error)) return
      +        end if
      +
      +        !> Get libraries
      +        libs = pkgcfg_get_libs(name, error)
      +        if (allocated(error)) return
      +
      +        libdir = ""
      +        do i = 1, size(libs)
      +            if (str_begins_with_str(libs(i)%s, '-l')) then
      +                current_lib = string_t(libs(i)%s(3:))
      +                if (len_trim(current_lib%s) == 0) cycle
      +                this%has_link_libraries = .true.
      +                this%link_libs = [this%link_libs, current_lib]
      +            else ! -L and others: concatenate
      +                this%has_link_flags = .true.
      +                this%link_flags = string_t(trim(this%link_flags%s)//' '//libs(i)%s)
      +
      +                ! Also save library dir
      +                if (str_begins_with_str(libs(i)%s, '-L')) then
      +                    libdir = libs(i)%s(3:)
      +                elseif (str_begins_with_str(libs(i)%s, '/LIBPATH')) then
      +                    libdir = libs(i)%s(9:)
      +                end if
      +            end if
      +        end do
      +
      +        !> Get compiler flags
      +        flags = pkgcfg_get_build_flags(name, .true., error)
      +        if (allocated(error)) return
      +
      +        do i = 1, size(flags)
      +            if (str_begins_with_str(flags(i)%s, include_flag)) then
      +                current_include_dir = string_t(flags(i)%s(len(include_flag)+1:))
      +                if (len_trim(current_include_dir%s) == 0) cycle
      +                this%has_include_dirs = .true.
      +                this%incl_dirs = [this%incl_dirs, current_include_dir]
      +            else
      +                this%has_build_flags = .true.
      +                this%flags = string_t(trim(this%flags%s)//' '//flags(i)%s)
      +            end if
      +        end do
      +    end subroutine add_pkg_config_compile_options
      +
      +    !> Given a library name and folder, find extension and prefix
      +    subroutine lib_get_trailing(lib_name,lib_dir,prefix,suffix,found)
      +        character(*), intent(in) :: lib_name,lib_dir
      +        character(:), allocatable, intent(out) :: prefix,suffix
      +        logical, intent(out) :: found
      +
      +        character(*), parameter :: extensions(*) = [character(11) :: '.dll.a','.a','.dylib','.dll']
      +        logical :: is_file
      +        character(:), allocatable :: noext,tokens(:),path
      +        integer :: l,k
      +
      +        ! Extract name with no extension
      +        call split(lib_name,tokens,'.')
      +        noext = trim(tokens(1))
      +
      +        ! Get library extension: find file name: NAME.a, NAME.dll.a, NAME.dylib, libNAME.a, etc.
      +        found = .false.
      +        suffix = ""
      +        prefix = ""
      +        with_pref: do l=1,2
      +            if (l==2) then
      +               prefix = "lib"
      +            else
      +               prefix = ""
      +            end if
      +            find_ext: do k=1,size(extensions)
      +                path = join_path(lib_dir,prefix//noext//trim(extensions(k)))
      +                inquire(file=path,exist=is_file)
      +
      +                if (is_file) then
      +                   suffix = trim(extensions(k))
      +                   found = .true.
      +                   exit with_pref
      +                end if
      +            end do find_ext
      +        end do with_pref
      +
      +        if (.not.found) then
      +             prefix = ""
      +             suffix = ""
      +        end if
      +
      +    end subroutine lib_get_trailing
      +end module fpm_meta_util
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/fpm_model.f90.html b/sourcefile/fpm_model.f90.html new file mode 100644 index 0000000000..97308384a3 --- /dev/null +++ b/sourcefile/fpm_model.f90.html @@ -0,0 +1,1423 @@ + + + + + + + + + + + + + fpm_model.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      fpm_model.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      !># The fpm package model
      +!>
      +!> Defines the fpm model data types which encapsulate all information
      +!> required to correctly build a package and its dependencies.
      +!>
      +!> The process (see `[[build_model(subroutine)]]`) for generating a valid `[[fpm_model]]` involves
      +!>  source files discovery ([[fpm_sources]]) and parsing ([[fpm_source_parsing]]).
      +!>
      +!> Once a valid `[[fpm_model]]` has been constructed, it may be passed to `[[fpm_targets:targets_from_sources]]` to
      +!> generate a list of build targets for the backend.
      +!>
      +!>### Enumerations
      +!>
      +!> __Source type:__ `FPM_UNIT_*`
      +!> Describes the type of source file — determines build target generation
      +!>
      +!> The logical order of precedence for assigning `unit_type` is as follows:
      +!>
      +!>```
      +!> if source-file contains program then
      +!>   unit_type = FPM_UNIT_PROGRAM
      +!> else if source-file contains non-module subroutine/function then
      +!>   unit_type = FPM_UNIT_SUBPROGRAM
      +!> else if source-file contains submodule then
      +!>   unit_type = FPM_UNIT_SUBMODULE
      +!> else if source-file contains module then
      +!>   unit_type = FPM_UNIT_MODULE
      +!> end if
      +!>```
      +!>
      +!> @note A source file is only designated `FPM_UNIT_MODULE` if it **only** contains modules - no non-module subprograms.
      +!> (This allows tree-shaking/pruning of build targets based on unused module dependencies.)
      +!>
      +!> __Source scope:__ `FPM_SCOPE_*`
      +!> Describes the scoping rules for using modules — controls module dependency resolution
      +!>
      +module fpm_model
      +use iso_fortran_env, only: int64
      +use fpm_compiler, only: compiler_t, archiver_t, debug
      +use fpm_dependency, only: dependency_tree_t
      +use fpm_strings, only: string_t, str, len_trim, upper, operator(==)
      +use tomlf, only: toml_table, toml_stat
      +use fpm_toml, only: serializable_t, set_value, set_list, get_value, &
      +                    & get_list, add_table, toml_key, add_array, set_string
      +use fpm_error, only: error_t, fatal_error
      +use fpm_environment, only: OS_WINDOWS,OS_MACOS
      +use fpm_manifest_preprocess, only: preprocess_config_t
      +implicit none
      +
      +private
      +public :: fpm_model_t, srcfile_t, show_model, fortran_features_t, package_t
      +
      +public :: FPM_UNIT_UNKNOWN, FPM_UNIT_PROGRAM, FPM_UNIT_MODULE, &
      +          FPM_UNIT_SUBMODULE, FPM_UNIT_SUBPROGRAM, FPM_UNIT_CSOURCE, &
      +          FPM_UNIT_CHEADER, FPM_SCOPE_UNKNOWN, FPM_SCOPE_LIB, &
      +          FPM_SCOPE_DEP, FPM_SCOPE_APP, FPM_SCOPE_EXAMPLE, FPM_SCOPE_TEST, &
      +          FPM_UNIT_CPPSOURCE, FPM_SCOPE_NAME, FPM_UNIT_NAME
      +
      +!> Source type unknown
      +integer, parameter :: FPM_UNIT_UNKNOWN = -1
      +!> Source contains a fortran program
      +integer, parameter :: FPM_UNIT_PROGRAM = 1
      +!> Source **only** contains one or more fortran modules
      +integer, parameter :: FPM_UNIT_MODULE = 2
      +!> Source contains one or more fortran submodules
      +integer, parameter :: FPM_UNIT_SUBMODULE = 3
      +!> Source contains one or more fortran subprogram not within modules
      +integer, parameter :: FPM_UNIT_SUBPROGRAM = 4
      +!> Source type is c source file
      +integer, parameter :: FPM_UNIT_CSOURCE = 5
      +!> Source type is c header file
      +integer, parameter :: FPM_UNIT_CHEADER = 6
      +!> Souce type is c++ source file.
      +integer, parameter :: FPM_UNIT_CPPSOURCE = 7
      +
      +!> Source has no module-use scope
      +integer, parameter :: FPM_SCOPE_UNKNOWN = -1
      +!> Module-use scope is library/dependency modules only
      +integer, parameter :: FPM_SCOPE_LIB = 1
      +!> Module-use scope is library/dependency modules only
      +integer, parameter :: FPM_SCOPE_DEP = 2
      +!> Module-use scope is library/dependency and app modules
      +integer, parameter :: FPM_SCOPE_APP = 3
      +!> Module-use scope is library/dependency and test modules
      +integer, parameter :: FPM_SCOPE_TEST = 4
      +integer, parameter :: FPM_SCOPE_EXAMPLE = 5
      +
      +!> Enabled Fortran language features
      +type, extends(serializable_t) :: fortran_features_t
      +
      +    !> Use default implicit typing
      +    logical :: implicit_typing = .false.
      +
      +    !> Use implicit external interface
      +    logical :: implicit_external = .false.
      +
      +    !> Form to use for all Fortran sources
      +    character(:), allocatable :: source_form
      +
      +    contains
      +
      +        !> Serialization interface
      +        procedure :: serializable_is_same => fft_is_same
      +        procedure :: dump_to_toml   => fft_dump_to_toml
      +        procedure :: load_from_toml => fft_load_from_toml
      +
      +end type fortran_features_t
      +
      +!> Type for describing a source file
      +type, extends(serializable_t) :: srcfile_t
      +    !> File path relative to cwd
      +    character(:), allocatable :: file_name
      +
      +    !> Name of executable for FPM_UNIT_PROGRAM
      +    character(:), allocatable :: exe_name
      +
      +    !> Target module-use scope
      +    integer :: unit_scope = FPM_SCOPE_UNKNOWN
      +
      +    !> Modules provided by this source file (lowerstring)
      +    type(string_t), allocatable :: modules_provided(:)
      +
      +    !> Type of source unit
      +    integer :: unit_type = FPM_UNIT_UNKNOWN
      +
      +    !> Parent modules (submodules only)
      +    type(string_t), allocatable :: parent_modules(:)
      +
      +    !>  Modules USEd by this source file (lowerstring)
      +    type(string_t), allocatable :: modules_used(:)
      +
      +    !> Files INCLUDEd by this source file
      +    type(string_t), allocatable :: include_dependencies(:)
      +
      +    !> Native libraries to link against
      +    type(string_t), allocatable :: link_libraries(:)
      +
      +    !> Current hash
      +    integer(int64) :: digest
      +
      +    contains
      +
      +        !> Serialization interface
      +        procedure :: serializable_is_same => srcfile_is_same
      +        procedure :: dump_to_toml   => srcfile_dump_to_toml
      +        procedure :: load_from_toml => srcfile_load_from_toml
      +
      +end type srcfile_t
      +
      +
      +!> Type for describing a single package
      +type, extends(serializable_t) :: package_t
      +
      +    !> Name of package
      +    character(:), allocatable :: name
      +
      +    !> Array of sources
      +    type(srcfile_t), allocatable :: sources(:)
      +
      +    !> List of macros.
      +    type(preprocess_config_t) :: preprocess
      +
      +    !> Package version number.
      +    character(:), allocatable :: version
      +
      +    !> Module naming conventions
      +    logical :: enforce_module_names = .false.
      +
      +    !> Prefix for all module names
      +    type(string_t) :: module_prefix
      +
      +    !> Language features
      +    type(fortran_features_t) :: features
      +
      +    contains
      +    
      +        !> Check if a package will create a library
      +        procedure :: has_library => package_has_library
      +    
      +        !> Serialization interface
      +        procedure :: serializable_is_same => package_is_same
      +        procedure :: dump_to_toml   => package_dump_to_toml
      +        procedure :: load_from_toml => package_load_from_toml
      +
      +end type package_t
      +
      +
      +!> Type describing everything required to build
      +!>  the root package and its dependencies.
      +type, extends(serializable_t) :: fpm_model_t
      +
      +    !> Name of root package
      +    character(:), allocatable :: package_name
      +
      +    !> Array of packages (including the root package)
      +    type(package_t), allocatable :: packages(:)
      +
      +    !> Compiler object
      +    type(compiler_t) :: compiler
      +
      +    !> Archiver object
      +    type(archiver_t) :: archiver
      +
      +    !> Command line flags passed to fortran for compilation
      +    character(:), allocatable :: fortran_compile_flags
      +
      +    !> Command line flags passed to C for compilation
      +    character(:), allocatable :: c_compile_flags
      +
      +    !> Command line flags passed to C++ for compilation
      +    character(:), allocatable :: cxx_compile_flags
      +
      +    !> Command line flags passed to the linker
      +    character(:), allocatable :: link_flags
      +
      +    !> Base directory for build
      +    character(:), allocatable :: build_prefix
      +
      +    !> Include directories
      +    type(string_t), allocatable :: include_dirs(:)
      +
      +    !> Native libraries to link against
      +    type(string_t), allocatable :: link_libraries(:)
      +
      +    !> External modules used
      +    type(string_t), allocatable :: external_modules(:)
      +
      +    !> Project dependencies
      +    type(dependency_tree_t) :: deps
      +
      +    !> Whether tests should be added to the build list
      +    logical :: include_tests = .true.
      +
      +    !> Whether module names should be prefixed with the package name
      +    logical :: enforce_module_names = .false.
      +
      +    !> Prefix for all module names
      +    type(string_t) :: module_prefix
      +
      +    contains
      +    
      +        !> Get target link flags
      +        procedure :: get_package_libraries_link
      +    
      +        !> Serialization interface
      +        procedure :: serializable_is_same => model_is_same
      +        procedure :: dump_to_toml   => model_dump_to_toml
      +        procedure :: load_from_toml => model_load_from_toml
      +
      +end type fpm_model_t
      +
      +contains
      +
      +function info_package(p) result(s)
      +    ! Returns representation of package_t
      +    type(package_t), intent(in) :: p
      +    character(:), allocatable :: s
      +
      +    integer :: i
      +
      +    s = s // 'package_t('
      +    s = s // 'name="' // p%name //'"'
      +    s = s // ', sources=['
      +    do i = 1, size(p%sources)
      +        s = s // info_srcfile(p%sources(i))
      +        if (i < size(p%sources)) s = s // ", "
      +    end do
      +    s = s // "]"
      +
      +    ! Print module naming convention
      +    s = s // ', enforce_module_names="' // merge('T','F',p%enforce_module_names) // '"'
      +
      +    ! Print custom prefix
      +    if (p%enforce_module_names .and. len_trim(p%module_prefix)>0) &
      +    s = s // ', custom_prefix="' // p%module_prefix%s // '"'
      +
      +    s = s // ")"
      +
      +end function info_package
      +
      +function info_srcfile(source) result(s)
      +    type(srcfile_t), intent(in) :: source
      +    character(:), allocatable :: s
      +    integer :: i
      +    !type srcfile_t
      +    s = "srcfile_t("
      +    !    character(:), allocatable :: file_name
      +    s = s // 'file_name="' // source%file_name // '"'
      +    !    character(:), allocatable :: exe_name
      +    s = s // ', exe_name="' // source%exe_name // '"'
      +    !    integer :: unit_scope = FPM_SCOPE_UNKNOWN
      +    s = s // ', unit_scope="' // FPM_SCOPE_NAME(source%unit_scope) // '"'
      +    !    type(string_t), allocatable :: modules_provided(:)
      +    s = s // ", modules_provided=["
      +    do i = 1, size(source%modules_provided)
      +        s = s // '"' // source%modules_provided(i)%s // '"'
      +        if (i < size(source%modules_provided)) s = s // ", "
      +    end do
      +    s = s // "]"
      +    s = s // ", parent_modules=["
      +    do i = 1, size(source%parent_modules)
      +        s = s // '"' // source%parent_modules(i)%s // '"'
      +        if (i < size(source%parent_modules)) s = s // ", "
      +    end do
      +    s = s // "]"
      +    !    integer :: unit_type = FPM_UNIT_UNKNOWN
      +    s = s // ', unit_type="' // FPM_UNIT_NAME(source%unit_type) // '"'
      +    !    type(string_t), allocatable :: modules_used(:)
      +    s = s // ", modules_used=["
      +    do i = 1, size(source%modules_used)
      +        s = s // '"' // source%modules_used(i)%s // '"'
      +        if (i < size(source%modules_used)) s = s // ", "
      +    end do
      +    s = s // "]"
      +    !    type(string_t), allocatable :: include_dependencies(:)
      +    s = s // ", include_dependencies=["
      +    do i = 1, size(source%include_dependencies)
      +        s = s // '"' // source%include_dependencies(i)%s // '"'
      +        if (i < size(source%include_dependencies)) s = s // ", "
      +    end do
      +    s = s // "]"
      +    !    type(string_t), allocatable :: link_libraries(:)
      +    s = s // ", link_libraries=["
      +    do i = 1, size(source%link_libraries)
      +        s = s // '"' // source%link_libraries(i)%s // '"'
      +        if (i < size(source%link_libraries)) s = s // ", "
      +    end do
      +    s = s // "]"
      +    !    integer(int64) :: digest
      +    s = s // ", digest=" // str(source%digest)
      +    !end type srcfile_t
      +    s = s // ")"
      +end function info_srcfile
      +
      +function info_srcfile_short(source) result(s)
      +    ! Prints a shortened version of srcfile_t
      +    type(srcfile_t), intent(in) :: source
      +    character(:), allocatable :: s
      +    s = "srcfile_t("
      +    s = s // 'file_name="' // source%file_name // '"'
      +    s = s // ", ...)"
      +end function info_srcfile_short
      +
      +function info_model(model) result(s)
      +    type(fpm_model_t), intent(in) :: model
      +    character(:), allocatable :: s
      +    integer :: i
      +    !type :: fpm_model_t
      +    s = "fpm_model_t("
      +    !    character(:), allocatable :: package_name
      +    s = s // 'package_name="' // model%package_name // '"'
      +    !    type(srcfile_t), allocatable :: sources(:)
      +    s = s // ", packages=["
      +    do i = 1, size(model%packages)
      +        s = s // info_package(model%packages(i))
      +        if (i < size(model%packages)) s = s // ", "
      +    end do
      +    s = s // "]"
      +    s = s // ', compiler=(' // debug(model%compiler) // ')'
      +    s = s // ', archiver=(' // debug(model%archiver) // ')'
      +    !    character(:), allocatable :: fortran_compile_flags
      +    s = s // ', fortran_compile_flags="' // model%fortran_compile_flags // '"'
      +    s = s // ', c_compile_flags="' // model%c_compile_flags // '"'
      +    s = s // ', cxx_compile_flags="' // model%cxx_compile_flags // '"'
      +    s = s // ', link_flags="' // model%link_flags // '"'
      +    s = s // ', build_prefix="' // model%build_prefix // '"'
      +    !    type(string_t), allocatable :: link_libraries(:)
      +    s = s // ", link_libraries=["
      +    do i = 1, size(model%link_libraries)
      +        s = s // '"' // model%link_libraries(i)%s // '"'
      +        if (i < size(model%link_libraries)) s = s // ", "
      +    end do
      +    s = s // "]"
      +    !    type(string_t), allocatable :: external_modules(:)
      +    s = s // ", external_modules=["
      +    do i = 1, size(model%external_modules)
      +        s = s // '"' // model%external_modules(i)%s // '"'
      +        if (i < size(model%external_modules)) s = s // ", "
      +    end do
      +    s = s // "]"
      +    !    type(dependency_tree_t) :: deps
      +    ! TODO: print `dependency_tree_t` properly, which should become part of the
      +    !       model, not imported from another file
      +    s = s // ", deps=dependency_tree_t(...)"
      +
      +    ! Print module naming convention
      +    s = s // ', enforce_module_names="' // merge('T','F',model%enforce_module_names) // '"'
      +
      +    ! Print custom prefix
      +    if (model%enforce_module_names .and. len_trim(model%module_prefix)>0) &
      +    s = s // ', custom_prefix="' // model%module_prefix%s // '"'
      +
      +    !end type fpm_model_t
      +    s = s // ")"
      +end function info_model
      +
      +subroutine show_model(model)
      +    ! Prints a human readable representation of the Model
      +    type(fpm_model_t), intent(in) :: model
      +    print *, info_model(model)
      +end subroutine show_model
      +
      +!> Return the character name of a scope flag
      +function FPM_SCOPE_NAME(flag) result(name)
      +    integer, intent(in) :: flag
      +    character(len=:), allocatable :: name
      +
      +    select case (flag)
      +       case (FPM_SCOPE_UNKNOWN); name = "FPM_SCOPE_UNKNOWN"
      +       case (FPM_SCOPE_LIB);     name = "FPM_SCOPE_LIB"
      +       case (FPM_SCOPE_DEP);     name = "FPM_SCOPE_DEP"
      +       case (FPM_SCOPE_APP);     name = "FPM_SCOPE_APP"
      +       case (FPM_SCOPE_TEST);    name = "FPM_SCOPE_TEST"
      +       case (FPM_SCOPE_EXAMPLE); name = "FPM_SCOPE_EXAMPLE"
      +       case default;             name = "INVALID"
      +    end select
      +end function FPM_SCOPE_NAME
      +
      +!> Parse git FPM_SCOPE identifier from a string
      +integer function parse_scope(name) result(scope)
      +    character(len=*), intent(in) :: name
      +
      +    character(len=len(name)) :: uppercase
      +
      +    !> Make it Case insensitive
      +    uppercase = upper(name)
      +
      +    select case (trim(uppercase))
      +       case ("FPM_SCOPE_UNKNOWN"); scope = FPM_SCOPE_UNKNOWN
      +       case ("FPM_SCOPE_LIB");     scope = FPM_SCOPE_LIB
      +       case ("FPM_SCOPE_DEP");     scope = FPM_SCOPE_DEP
      +       case ("FPM_SCOPE_APP");     scope = FPM_SCOPE_APP
      +       case ("FPM_SCOPE_TEST");    scope = FPM_SCOPE_TEST
      +       case ("FPM_SCOPE_EXAMPLE"); scope = FPM_SCOPE_EXAMPLE
      +       case default;               scope = -9999
      +    end select
      +
      +end function parse_scope
      +
      +!> Return the character name of a unit flag
      +function FPM_UNIT_NAME(flag) result(name)
      +    integer, intent(in) :: flag
      +    character(len=:), allocatable :: name
      +
      +    select case (flag)
      +       case (FPM_UNIT_UNKNOWN);    name = "FPM_UNIT_UNKNOWN"
      +       case (FPM_UNIT_PROGRAM);    name = "FPM_UNIT_PROGRAM"
      +       case (FPM_UNIT_MODULE);     name = "FPM_UNIT_MODULE"
      +       case (FPM_UNIT_SUBMODULE);  name = "FPM_UNIT_SUBMODULE"
      +       case (FPM_UNIT_SUBPROGRAM); name = "FPM_UNIT_SUBPROGRAM"
      +       case (FPM_UNIT_CSOURCE);    name = "FPM_UNIT_CSOURCE"
      +       case (FPM_UNIT_CPPSOURCE);  name = "FPM_UNIT_CPPSOURCE"
      +       case (FPM_UNIT_CHEADER);    name = "FPM_UNIT_CHEADER"
      +       case default;               name = "INVALID"
      +    end select
      +end function FPM_UNIT_NAME
      +
      +!> Parse git FPM_UNIT identifier from a string
      +integer function parse_unit(name) result(unit)
      +    character(len=*), intent(in) :: name
      +
      +    character(len=len(name)) :: uppercase
      +
      +    !> Make it Case insensitive
      +    uppercase = upper(name)
      +
      +    select case (trim(uppercase))
      +       case ("FPM_UNIT_UNKNOWN");    unit = FPM_UNIT_UNKNOWN
      +       case ("FPM_UNIT_PROGRAM");    unit = FPM_UNIT_PROGRAM
      +       case ("FPM_UNIT_MODULE");     unit = FPM_UNIT_MODULE
      +       case ("FPM_UNIT_SUBMODULE");  unit = FPM_UNIT_SUBMODULE
      +       case ("FPM_UNIT_SUBPROGRAM"); unit = FPM_UNIT_SUBPROGRAM
      +       case ("FPM_UNIT_CSOURCE");    unit = FPM_UNIT_CSOURCE
      +       case ("FPM_UNIT_CPPSOURCE");  unit = FPM_UNIT_CPPSOURCE
      +       case ("FPM_UNIT_CHEADER");    unit = FPM_UNIT_CHEADER
      +       case default;                 unit = -9999
      +    end select
      +
      +end function parse_unit
      +
      +!> Check that two source files are equal
      +logical function srcfile_is_same(this,that)
      +    class(srcfile_t), intent(in) :: this
      +    class(serializable_t), intent(in) :: that
      +
      +    srcfile_is_same = .false.
      +
      +    select type (other=>that)
      +       type is (srcfile_t)
      +          if (allocated(this%file_name).neqv.allocated(other%file_name)) return
      +          if (allocated(this%file_name)) then
      +            if (.not.(this%file_name==other%file_name)) return
      +          end if
      +          if (allocated(this%exe_name).neqv.allocated(other%exe_name)) return
      +          if (allocated(this%exe_name)) then
      +            if (.not.(this%exe_name==other%exe_name)) return
      +          end if
      +          if (.not.(this%unit_scope==other%unit_scope)) return
      +          if (allocated(this%modules_provided).neqv.allocated(other%modules_provided)) return
      +          if (allocated(this%modules_provided)) then
      +            if (.not.(this%modules_provided==other%modules_provided)) return
      +          end if
      +          if (.not.(this%unit_type==other%unit_type)) return
      +          if (allocated(this%parent_modules).neqv.allocated(other%parent_modules)) return
      +          if (allocated(this%parent_modules)) then
      +            if (.not.(this%parent_modules==other%parent_modules)) return
      +          end if
      +          if (allocated(this%modules_used).neqv.allocated(other%modules_used)) return
      +          if (allocated(this%modules_used)) then
      +            if (.not.(this%modules_used==other%modules_used)) return
      +          end if
      +          if (allocated(this%include_dependencies).neqv.allocated(other%include_dependencies)) return
      +          if (allocated(this%include_dependencies)) then
      +            if (.not.(this%include_dependencies==other%include_dependencies)) return
      +          end if
      +          if (allocated(this%link_libraries).neqv.allocated(other%link_libraries)) return
      +          if (allocated(this%link_libraries)) then
      +            if (.not.(this%link_libraries==other%link_libraries)) return
      +          end if
      +          if (.not.(this%digest==other%digest)) return
      +
      +       class default
      +          ! Not the same type
      +          return
      +    end select
      +
      +    !> All checks passed!
      +    srcfile_is_same = .true.
      +
      +end function srcfile_is_same
      +
      +!> Dump dependency to toml table
      +subroutine srcfile_dump_to_toml(self, table, error)
      +
      +    !> Instance of the serializable object
      +    class(srcfile_t), intent(inout) :: self
      +
      +    !> Data structure
      +    type(toml_table), intent(inout) :: table
      +
      +    !> Error handling
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    integer :: ierr
      +
      +    call set_string(table, "file-name", self%file_name, error, 'srcfile_t')
      +    if (allocated(error)) return
      +    call set_string(table, "exe-name", self%exe_name, error, 'srcfile_t')
      +    if (allocated(error)) return
      +    call set_value(table, "digest", self%digest, error, 'srcfile_t')
      +    if (allocated(error)) return
      +
      +    ! unit_scope and unit_type are saved as strings so the output is independent
      +    ! of the internal representation
      +    call set_string(table,"unit-scope",FPM_SCOPE_NAME(self%unit_scope), error, 'srcfile_t')
      +    if (allocated(error)) return
      +    call set_string(table,"unit-type",FPM_UNIT_NAME(self%unit_type), error, 'srcfile_t')
      +    if (allocated(error)) return
      +    call set_list(table, "modules-provided",self%modules_provided, error)
      +    if (allocated(error)) return
      +    call set_list(table, "parent-modules",self%parent_modules, error)
      +    if (allocated(error)) return
      +    call set_list(table, "modules-used",self%modules_used, error)
      +    if (allocated(error)) return
      +    call set_list(table, "include-dependencies",self%include_dependencies, error)
      +    if (allocated(error)) return
      +    call set_list(table, "link-libraries",self%link_libraries, error)
      +    if (allocated(error)) return
      +
      +end subroutine srcfile_dump_to_toml
      +
      +!> Read dependency from toml table (no checks made at this stage)
      +subroutine srcfile_load_from_toml(self, table, error)
      +
      +    !> Instance of the serializable object
      +    class(srcfile_t), intent(inout) :: self
      +
      +    !> Data structure
      +    type(toml_table), intent(inout) :: table
      +
      +    !> Error handling
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    character(len=:), allocatable :: flag
      +    integer :: ierr
      +
      +    call get_value(table, "file-name", self%file_name)
      +    call get_value(table, "exe-name", self%exe_name)
      +    call get_value(table, "digest", self%digest, error, 'srcfile_t')
      +    if (allocated(error)) return
      +
      +    ! unit_scope and unit_type are saved as strings so the output is independent
      +    ! of the internal representation
      +    call get_value(table, "unit-scope", flag)
      +    if (allocated(flag)) self%unit_scope = parse_scope(flag)
      +    call get_value(table, "unit-type", flag)
      +    if (allocated(flag)) self%unit_type = parse_unit(flag)
      +
      +    call get_list(table,"modules-provided",self%modules_provided, error)
      +    if (allocated(error)) return
      +
      +    call get_list(table,"parent-modules",self%parent_modules, error)
      +    if (allocated(error)) return
      +
      +    call get_list(table,"modules-used",self%modules_used, error)
      +    if (allocated(error)) return
      +
      +    call get_list(table,"include-dependencies",self%include_dependencies, error)
      +    if (allocated(error)) return
      +
      +    call get_list(table,"link-libraries",self%link_libraries, error)
      +    if (allocated(error)) return
      +
      +end subroutine srcfile_load_from_toml
      +
      +!> Check that two fortran feature objects are equal
      +logical function fft_is_same(this,that)
      +    class(fortran_features_t), intent(in) :: this
      +    class(serializable_t), intent(in) :: that
      +
      +    fft_is_same = .false.
      +
      +    select type (other=>that)
      +       type is (fortran_features_t)
      +
      +           if (.not.(this%implicit_typing.eqv.other%implicit_typing)) return
      +           if (.not.(this%implicit_external.eqv.other%implicit_external)) return
      +           if (allocated(this%source_form).neqv.allocated(other%source_form)) return
      +           if (allocated(this%source_form)) then
      +             if (.not.(this%source_form==other%source_form)) return
      +           end if
      +
      +       class default
      +          ! Not the same type
      +          return
      +    end select
      +
      +    !> All checks passed!
      +    fft_is_same = .true.
      +
      +end function fft_is_same
      +
      +!> Dump fortran features to toml table
      +subroutine fft_dump_to_toml(self, table, error)
      +
      +    !> Instance of the serializable object
      +    class(fortran_features_t), intent(inout) :: self
      +
      +    !> Data structure
      +    type(toml_table), intent(inout) :: table
      +
      +    !> Error handling
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    call set_value(table, "implicit-typing", self%implicit_typing, error, 'fortran_features_t')
      +    if (allocated(error)) return
      +    call set_value(table, "implicit-external", self%implicit_external, error, 'fortran_features_t')
      +    if (allocated(error)) return
      +    call set_string(table, "source-form", self%source_form, error, 'fortran_features_t')
      +    if (allocated(error)) return
      +
      +end subroutine fft_dump_to_toml
      +
      +!> Read dependency from toml table (no checks made at this stage)
      +subroutine fft_load_from_toml(self, table, error)
      +
      +    !> Instance of the serializable object
      +    class(fortran_features_t), intent(inout) :: self
      +
      +    !> Data structure
      +    type(toml_table), intent(inout) :: table
      +
      +    !> Error handling
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    integer :: ierr
      +
      +    call get_value(table, "implicit-typing", self%implicit_typing, error, 'fortran_features_t')
      +    if (allocated(error)) return
      +    call get_value(table, "implicit-external", self%implicit_external, error, 'fortran_features_t')
      +    if (allocated(error)) return
      +    ! Return unallocated value if not present
      +    call get_value(table, "source-form", self%source_form)
      +
      +end subroutine fft_load_from_toml
      +
      +!> Check that two package objects are equal
      +logical function package_is_same(this,that)
      +    class(package_t), intent(in) :: this
      +    class(serializable_t), intent(in) :: that
      +
      +    integer :: ii
      +
      +    package_is_same = .false.
      +
      +    select type (other=>that)
      +       type is (package_t)
      +           if (allocated(this%name).neqv.allocated(other%name)) return
      +           if (allocated(this%name)) then
      +              if (.not.(this%name==other%name)) return
      +           end if
      +           if (allocated(this%sources).neqv.allocated(other%sources)) return
      +           if (allocated(this%sources)) then
      +              if (.not.(size(this%sources)==size(other%sources))) return
      +              do ii = 1, size(this%sources)
      +                  if (.not.(this%sources(ii)==other%sources(ii))) return
      +              end do
      +           end if
      +
      +           if (.not.(this%preprocess==other%preprocess)) return
      +           if (allocated(this%version).neqv.allocated(other%version)) return
      +           if (allocated(this%version)) then
      +             if (.not.(this%version==other%version)) return
      +           end if
      +
      +           !> Module naming
      +           if (.not.(this%enforce_module_names.eqv.other%enforce_module_names)) return
      +           if (.not.(this%module_prefix==other%module_prefix)) return
      +
      +           !> Fortran features
      +           if (.not.(this%features==other%features)) return
      +
      +       class default
      +          ! Not the same type
      +          return
      +    end select
      +
      +    !> All checks passed!
      +    package_is_same = .true.
      +
      +end function package_is_same
      +
      +!> Dump dependency to toml table
      +subroutine package_dump_to_toml(self, table, error)
      +
      +    !> Instance of the serializable object
      +    class(package_t), intent(inout) :: self
      +
      +    !> Data structure
      +    type(toml_table), intent(inout) :: table
      +
      +    !> Error handling
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    integer :: ierr, ii
      +    type(toml_table), pointer :: ptr,this_source
      +    character(16) :: src_name
      +
      +    call set_string(table, "name", self%name, error, 'package_t')
      +    if (allocated(error)) return
      +
      +    call set_string(table, "version", self%version, error, 'package_t')
      +    if (allocated(error)) return
      +
      +    call set_value(table, "module-naming", self%enforce_module_names, error, 'package_t')
      +    if (allocated(error)) return
      +
      +    call set_string(table, "module-prefix", self%module_prefix, error, 'package_t')
      +    if (allocated(error)) return
      +
      +    !> Create a preprocessor table
      +    call add_table(table, "preprocess", ptr, error, 'package_t')
      +    if (allocated(error)) return
      +    call self%preprocess%dump_to_toml(ptr, error)
      +    if (allocated(error)) return
      +
      +    !> Create a fortran table
      +    call add_table(table, "fortran", ptr, error, 'package_t')
      +    if (allocated(error)) return
      +    call self%features%dump_to_toml(ptr, error)
      +    if (allocated(error)) return
      +
      +    !> Create a sources table
      +    if (allocated(self%sources)) then
      +
      +        call add_table(table, "sources", ptr, error, 'package_t')
      +        if (allocated(error)) return
      +
      +        do ii = 1, size(self%sources)
      +
      +            write(src_name,1) ii
      +            call add_table(ptr, trim(src_name), this_source, error, 'package_t[source]')
      +            if (allocated(error)) return
      +            call self%sources(ii)%dump_to_toml(this_source,error)
      +            if (allocated(error)) return
      +
      +        end do
      +
      +    end if
      +
      +    1 format('src_',i0)
      +
      +end subroutine package_dump_to_toml
      +
      +!> Read dependency from toml table (no checks made at this stage)
      +subroutine package_load_from_toml(self, table, error)
      +
      +    !> Instance of the serializable object
      +    class(package_t), intent(inout) :: self
      +
      +    !> Data structure
      +    type(toml_table), intent(inout) :: table
      +
      +    !> Error handling
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    integer :: ierr,ii,jj
      +    type(toml_key), allocatable :: keys(:),src_keys(:)
      +    type(toml_table), pointer :: ptr_sources,ptr,ptr_fortran,ptr_preprocess
      +    type(error_t), allocatable :: new_error
      +
      +    call get_value(table, "name", self%name)
      +    call get_value(table, "version", self%version)
      +
      +    call get_value(table, "module-naming", self%enforce_module_names, error, 'package_t')
      +    if (allocated(error)) return
      +
      +    ! Return unallocated value if not present
      +    call get_value(table, "module-prefix", self%module_prefix%s)
      +
      +    ! Sources
      +    call table%get_keys(keys)
      +
      +    find_others: do ii = 1, size(keys)
      +        select case (keys(ii)%key)
      +           case ("fortran")
      +
      +               call get_value(table, keys(ii), ptr_fortran)
      +               if (.not.associated(ptr_fortran)) then
      +                  call fatal_error(error,'package_t: error retrieving fortran table from TOML table')
      +                  return
      +               end if
      +
      +               call self%features%load_from_toml(ptr_fortran,error)
      +               if (allocated(error)) return
      +
      +           case ("preprocess")
      +
      +               call get_value(table, keys(ii), ptr_preprocess)
      +               if (.not.associated(ptr_preprocess)) then
      +                  call fatal_error(error,'package_t: error retrieving preprocess table from TOML table')
      +                  return
      +               end if
      +
      +               call self%preprocess%load_from_toml(ptr_preprocess,error)
      +               if (allocated(error)) return
      +
      +           case ("sources")
      +
      +               call get_value(table, keys(ii), ptr_sources)
      +               if (.not.associated(ptr_sources)) then
      +                  call fatal_error(error,'package_t: error retrieving sources table from TOML table')
      +                  return
      +               end if
      +
      +               !> Read all dependencies
      +               call ptr_sources%get_keys(src_keys)
      +               allocate(self%sources(size(src_keys)))
      +
      +               do jj = 1, size(src_keys)
      +                   call get_value(ptr_sources, src_keys(jj), ptr)
      +                   call self%sources(jj)%load_from_toml(ptr, error)
      +                   if (allocated(error)) return
      +               end do
      +
      +           case default
      +              cycle find_others
      +        end select
      +    end do find_others
      +
      +end subroutine package_load_from_toml
      +
      +
      +!> Check that two model objects are equal
      +logical function model_is_same(this,that)
      +    class(fpm_model_t), intent(in) :: this
      +    class(serializable_t), intent(in) :: that
      +
      +    type(fpm_model_t), pointer :: other
      +
      +    integer :: ii
      +
      +    model_is_same = .false.
      +
      +    select type (other=>that)
      +       type is (fpm_model_t)
      +
      +           if ((allocated(this%package_name).neqv.allocated(other%package_name))) return
      +           if (allocated(this%package_name)) then
      +             if (.not.(this%package_name==other%package_name)) return
      +           end if
      +           if (.not.(allocated(this%packages).eqv.allocated(other%packages))) return
      +           if (allocated(this%packages)) then
      +               if (.not.(size(this%packages)==size(other%packages))) return
      +               do ii = 1, size(this%packages)
      +                   if (.not.(this%packages(ii)==other%packages(ii))) return
      +               end do
      +           end if
      +
      +           if (.not.(this%compiler==other%compiler)) return
      +           if (.not.(this%archiver==other%archiver)) return
      +           if (allocated(this%fortran_compile_flags).neqv.allocated(other%fortran_compile_flags)) return
      +           if (allocated(this%fortran_compile_flags)) then
      +             if (.not.(this%fortran_compile_flags==other%fortran_compile_flags)) return
      +           end if
      +           if (allocated(this%c_compile_flags).neqv.allocated(other%c_compile_flags)) return
      +           if (allocated(this%c_compile_flags)) then
      +             if (.not.(this%c_compile_flags==other%c_compile_flags)) return
      +           end if
      +           if (allocated(this%cxx_compile_flags).neqv.allocated(other%cxx_compile_flags)) return
      +           if (allocated(this%cxx_compile_flags)) then
      +             if (.not.(this%cxx_compile_flags==other%cxx_compile_flags)) return
      +           end if
      +           if (allocated(this%link_flags).neqv.allocated(other%link_flags)) return
      +           if (allocated(this%link_flags)) then
      +             if (.not.(this%link_flags==other%link_flags)) return
      +           end if
      +           if (allocated(this%build_prefix).neqv.allocated(other%build_prefix)) return
      +           if (allocated(this%build_prefix)) then
      +             if (.not.(this%build_prefix==other%build_prefix)) return
      +           end if
      +           if (allocated(this%include_dirs).neqv.allocated(other%include_dirs)) return
      +           if (allocated(this%include_dirs)) then
      +             if (.not.(this%include_dirs==other%include_dirs)) return
      +           end if
      +           if (allocated(this%link_libraries).neqv.allocated(other%link_libraries)) return
      +           if (allocated(this%link_libraries)) then
      +             if (.not.(this%link_libraries==other%link_libraries)) return
      +           end if
      +           if (allocated(this%external_modules).neqv.allocated(other%external_modules)) return
      +           if (allocated(this%external_modules)) then
      +             if (.not.(this%external_modules==other%external_modules)) return
      +           end if
      +           if (.not.(this%deps==other%deps)) return
      +           if (.not.(this%include_tests.eqv.other%include_tests)) return
      +           if (.not.(this%enforce_module_names.eqv.other%enforce_module_names)) return
      +           if (.not.(this%module_prefix==other%module_prefix)) return
      +
      +       class default
      +          ! Not the same type
      +          return
      +    end select
      +
      +    !> All checks passed!
      +    model_is_same = .true.
      +
      +end function model_is_same
      +
      +!> Dump dependency to toml table
      +subroutine model_dump_to_toml(self, table, error)
      +
      +    !> Instance of the serializable object
      +    class(fpm_model_t), intent(inout) :: self
      +
      +    !> Data structure
      +    type(toml_table), intent(inout) :: table
      +
      +    !> Error handling
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    integer :: ierr, ii
      +    type(toml_table), pointer :: ptr,ptr_pkg
      +    character(27) :: unnamed
      +
      +    call set_string(table, "package-name", self%package_name, error, 'fpm_model_t')
      +    if (allocated(error)) return
      +
      +    call add_table(table, "compiler", ptr, error, 'fpm_model_t')
      +    if (allocated(error)) return
      +    call self%compiler%dump_to_toml(ptr, error)
      +    if (allocated(error)) return
      +
      +    call add_table(table, "archiver", ptr, error, 'fpm_model_t')
      +    if (allocated(error)) return
      +    call self%archiver%dump_to_toml(ptr, error)
      +    if (allocated(error)) return
      +
      +    call set_string(table, "fortran-flags", self%fortran_compile_flags, error, 'fpm_model_t')
      +    if (allocated(error)) return
      +    call set_string(table, "c-flags", self%c_compile_flags, error, 'fpm_model_t')
      +    if (allocated(error)) return
      +    call set_string(table, "cxx-flags", self%cxx_compile_flags, error, 'fpm_model_t')
      +    if (allocated(error)) return
      +    call set_string(table, "link-flags", self%link_flags, error, 'fpm_model_t')
      +    if (allocated(error)) return
      +    call set_string(table, "build-prefix", self%build_prefix, error, 'fpm_model_t')
      +    if (allocated(error)) return
      +    call set_list(table, "include-dirs", self%include_dirs, error)
      +    if (allocated(error)) return
      +    call set_list(table, "link-libraries", self%link_libraries, error)
      +    if (allocated(error)) return
      +    call set_list(table, "external-modules", self%external_modules, error)
      +    if (allocated(error)) return
      +
      +    call set_value(table, "include-tests", self%include_tests, error, 'fpm_model_t')
      +    if (allocated(error)) return
      +    call set_value(table, "module-naming", self%enforce_module_names, error, 'fpm_model_t')
      +    if (allocated(error)) return
      +    call set_string(table, "module-prefix", self%module_prefix, error, 'fpm_model_t')
      +    if (allocated(error)) return
      +
      +    call add_table(table, "deps", ptr, error, 'fpm_model_t')
      +    if (allocated(error)) return
      +    call self%deps%dump_to_toml(ptr, error)
      +    if (allocated(error)) return
      +
      +    !> Array of packages (including the root package)
      +    if (allocated(self%packages)) then
      +
      +           ! Create packages table
      +           call add_table(table, "packages", ptr_pkg)
      +           if (.not. associated(ptr_pkg)) then
      +              call fatal_error(error, "fpm_model_t cannot create dependency table ")
      +              return
      +           end if
      +
      +           do ii = 1, size(self%packages)
      +
      +              associate (pkg => self%packages(ii))
      +
      +                 !> Because dependencies are named, fallback if this has no name
      +                 !> So, serialization will work regardless of size(self%dep) == self%ndep
      +                 if (len_trim(pkg%name)==0) then
      +                    write(unnamed,1) ii
      +                    call add_table(ptr_pkg, trim(unnamed), ptr, error, 'fpm_model_t[package]')
      +                 else
      +                    call add_table(ptr_pkg, pkg%name, ptr, error, 'fpm_model_t[package]')
      +                 end if
      +                 if (allocated(error)) return
      +                 call pkg%dump_to_toml(ptr, error)
      +                 if (allocated(error)) return
      +
      +              end associate
      +
      +           end do
      +    end if
      +
      +    1 format('UNNAMED_PACKAGE_',i0)
      +
      +end subroutine model_dump_to_toml
      +
      +!> Read dependency from toml table (no checks made at this stage)
      +subroutine model_load_from_toml(self, table, error)
      +
      +    !> Instance of the serializable object
      +    class(fpm_model_t), intent(inout) :: self
      +
      +    !> Data structure
      +    type(toml_table), intent(inout) :: table
      +
      +    !> Error handling
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    type(toml_key), allocatable :: keys(:),pkg_keys(:)
      +    integer :: ierr, ii, jj
      +    type(toml_table), pointer :: ptr,ptr_pkg
      +
      +    call table%get_keys(keys)
      +
      +    call get_value(table, "package-name", self%package_name)
      +    call get_value(table, "fortran-flags", self%fortran_compile_flags)
      +    call get_value(table, "c-flags", self%c_compile_flags)
      +    call get_value(table, "cxx-flags", self%cxx_compile_flags)
      +    call get_value(table, "link-flags", self%link_flags)
      +    call get_value(table, "build-prefix", self%build_prefix)
      +
      +    if (allocated(self%packages)) deallocate(self%packages)
      +    sub_deps: do ii = 1, size(keys)
      +
      +       select case (keys(ii)%key)
      +          case ("compiler")
      +
      +               call get_value(table, keys(ii), ptr)
      +               if (.not.associated(ptr)) then
      +                  call fatal_error(error,'fpm_model_t: error retrieving compiler table')
      +                  return
      +               end if
      +
      +               call self%compiler%load_from_toml(ptr, error)
      +               if (allocated(error)) return
      +
      +          case ("archiver")
      +
      +               call get_value(table, keys(ii), ptr)
      +               if (.not.associated(ptr)) then
      +                  call fatal_error(error,'fpm_model_t: error retrieving archiver table')
      +                  return
      +               end if
      +
      +               call self%archiver%load_from_toml(ptr, error)
      +               if (allocated(error)) return
      +
      +          case ("deps")
      +
      +               call get_value(table, keys(ii), ptr)
      +               if (.not.associated(ptr)) then
      +                  call fatal_error(error,'fpm_model_t: error retrieving dependency tree table')
      +                  return
      +               end if
      +
      +               call self%deps%load_from_toml(ptr, error)
      +               if (allocated(error)) return
      +
      +          case ("packages")
      +
      +               call get_value(table, keys(ii), ptr)
      +               if (.not.associated(ptr)) then
      +                  call fatal_error(error,'fpm_model_t: error retrieving packages table')
      +                  return
      +               end if
      +
      +               !> Read all packages
      +               call ptr%get_keys(pkg_keys)
      +               allocate(self%packages(size(pkg_keys)))
      +
      +               do jj = 1, size(pkg_keys)
      +
      +                   call get_value(ptr, pkg_keys(jj), ptr_pkg)
      +                   call self%packages(jj)%load_from_toml(ptr_pkg, error)
      +                   if (allocated(error)) return
      +
      +               end do
      +
      +
      +          case default
      +                cycle sub_deps
      +       end select
      +
      +    end do sub_deps
      +
      +    call get_list(table, "include-dirs", self%include_dirs, error)
      +    if (allocated(error)) return
      +    call get_list(table, "link-libraries", self%link_libraries, error)
      +    if (allocated(error)) return
      +    call get_list(table, "external-modules", self%external_modules, error)
      +    if (allocated(error)) return
      +    call get_value(table, "include-tests", self%include_tests, error, 'fpm_model_t')
      +    if (allocated(error)) return
      +    call get_value(table, "module-naming", self%enforce_module_names, error, 'fpm_model_t')
      +    if (allocated(error)) return
      +    call get_value(table, "module-prefix", self%module_prefix%s)
      +
      +end subroutine model_load_from_toml
      +
      +function get_package_libraries_link(model, package_name, prefix, exclude_self, dep_IDs, error) result(r)
      +    class(fpm_model_t), intent(in) :: model
      +    character(*), intent(in) :: package_name
      +    type(error_t), allocatable, intent(out) :: error
      +    character(*), intent(in) :: prefix
      +    !> Option to exclude linking to the given package (needed building it as a library)
      +    logical, optional, intent(in) :: exclude_self
      +    !> Optionally export the list of dependency IDs
      +    integer, allocatable, optional, intent(out) :: dep_IDs(:)
      +    character(len=:), allocatable :: r
      +    
      +    integer :: id,ndep,i
      +    logical :: no_root
      +    integer, allocatable :: sorted_package_IDs(:)
      +    logical, allocatable :: has_lib(:)
      +    type(string_t), allocatable :: package_deps(:)
      +    
      +    ! Get dependency ID of this target 
      +    id = model%deps%find(package_name)
      +    if (id<=0) then 
      +        call fatal_error(error, "Internal error: shared library "//package_name// &
      +                                " does not correspond to a package")
      +        return
      +    end if
      +    
      +    ! Get ordered IDs of the shared libraries that should be linked against
      +    call model%deps%local_link_order(id, sorted_package_IDs, error)
      +    if (allocated(error)) return
      +    
      +    ! Get names of the package dependencies
      +    ndep = size(sorted_package_IDs)
      +    
      +    if (ndep<=0) then 
      +       r = prefix
      +       if (present(dep_IDs)) allocate(dep_IDs(0))
      +       return 
      +    end if
      +    
      +    ! Optional exclusion of self (top-level) package
      +    no_root = .false.
      +    if (present(exclude_self)) no_root = exclude_self
      +    if (no_root) then 
      +        sorted_package_IDs = pack(sorted_package_IDs, sorted_package_IDs /= id)
      +        ndep = size(sorted_package_IDs)
      +    endif
      +    
      +    ! Exclusion of package IDs marked "empty" (i.e. they contain no sources)
      +    has_lib = model%packages%has_library()
      +    
      +    if (any(.not.has_lib)) then 
      +        sorted_package_IDs = pack(sorted_package_IDs, has_lib(sorted_package_IDs))
      +        ndep = size(sorted_package_IDs)
      +    end if
      +    
      +    package_deps = [(string_t(model%deps%dep(sorted_package_IDs(i))%name),i=1,ndep)]
      +    
      +    r = model%compiler%enumerate_libraries(prefix, package_deps)
      +    
      +    ! If requested, export the list of dependency IDs
      +    if (present(dep_IDs)) call move_alloc(from=sorted_package_IDs,to=dep_IDs)
      +    
      +end function get_package_libraries_link
      +
      +!> Check whether a package has an object library
      +elemental logical function package_has_library(self) result(has_library)
      +    class(package_t), intent(in) :: self
      +    
      +    if (allocated(self%sources)) then 
      +        has_library = any(self%sources%unit_scope==FPM_SCOPE_LIB)
      +    else
      +        has_library = .false.
      +    end if
      +    
      +end function package_has_library
      +
      +
      +end module fpm_model
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/fpm_os.f90.html b/sourcefile/fpm_os.f90.html new file mode 100644 index 0000000000..5674813b30 --- /dev/null +++ b/sourcefile/fpm_os.f90.html @@ -0,0 +1,460 @@ + + + + + + + + + + + + + fpm_os.F90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      fpm_os.F90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      module fpm_os
      +    use, intrinsic :: iso_c_binding, only: c_char, c_int, c_null_char, c_ptr, c_associated
      +    use fpm_filesystem, only: exists, join_path, get_home
      +    use fpm_environment, only: os_is_unix
      +    use fpm_error, only: error_t, fatal_error
      +
      +    implicit none
      +    private
      +    public :: change_directory, get_current_directory, get_absolute_path, convert_to_absolute_path, &
      +            & get_absolute_path_by_cd
      +
      +    integer(c_int), parameter :: buffersize = 1000_c_int
      +
      +#ifndef _WIN32
      +    character(len=*), parameter :: pwd_env = "PWD"
      +#else
      +    character(len=*), parameter :: pwd_env = "CD"
      +#endif
      +
      +    interface
      +        function chdir_(path) result(stat) &
      +#ifndef _WIN32
      +            bind(C, name="chdir")
      +#else
      +            bind(C, name="_chdir")
      +#endif
      +            import :: c_char, c_int
      +            character(kind=c_char, len=1), intent(in) :: path(*)
      +            integer(c_int) :: stat
      +        end function chdir_
      +
      +        function getcwd_(buf, bufsize) result(path) &
      +#ifndef _WIN32
      +            bind(C, name="getcwd")
      +#else
      +            bind(C, name="_getcwd")
      +#endif
      +            import :: c_char, c_int, c_ptr
      +            character(kind=c_char, len=1), intent(in) :: buf(*)
      +            integer(c_int), value, intent(in) :: bufsize
      +            type(c_ptr) :: path
      +        end function getcwd_
      +
      +        !> Determine the absolute, canonicalized path for a given path. Unix-only.
      +        function realpath(path, resolved_path) result(ptr) bind(C)
      +            import :: c_ptr, c_char, c_int
      +            character(kind=c_char, len=1), intent(in) :: path(*)
      +            character(kind=c_char, len=1), intent(out) :: resolved_path(*)
      +            type(c_ptr) :: ptr
      +        end function realpath
      +
      +        !> Determine the absolute, canonicalized path for a given path. Windows-only.
      +        function fullpath(resolved_path, path, maxLength) result(ptr) bind(C, name="_fullpath")
      +            import :: c_ptr, c_char, c_int
      +            character(kind=c_char, len=1), intent(in) :: path(*)
      +            character(kind=c_char, len=1), intent(out) :: resolved_path(*)
      +            integer(c_int), value, intent(in) :: maxLength
      +            type(c_ptr) :: ptr
      +        end function fullpath
      +
      +        !> Determine the absolute, canonicalized path for a given path.
      +        !> Calls custom C routine because the `_WIN32` macro is correctly exported
      +        !> in C using `gfortran`.
      +        function c_realpath(path, resolved_path, maxLength) result(ptr) &
      +            bind(C, name="c_realpath")
      +            import :: c_ptr, c_char, c_int
      +            character(kind=c_char, len=1), intent(in) :: path(*)
      +            character(kind=c_char, len=1), intent(out) :: resolved_path(*)
      +            integer(c_int), value, intent(in) :: maxLength
      +            type(c_ptr) :: ptr
      +        end function c_realpath
      +    end interface
      +
      +contains
      +
      +    subroutine change_directory(path, error)
      +        character(len=*), intent(in) :: path
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        character(kind=c_char, len=1), allocatable :: cpath(:)
      +        integer :: stat
      +
      +        allocate (cpath(len(path) + 1))
      +        call f_c_character(path, cpath, len(path) + 1)
      +
      +        stat = chdir_(cpath)
      +
      +        if (stat /= 0) then
      +            call fatal_error(error, "Failed to change directory to '"//path//"'")
      +        end if
      +    end subroutine change_directory
      +
      +    subroutine get_current_directory(path, error)
      +        character(len=:), allocatable, intent(out) :: path
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        character(kind=c_char, len=1), allocatable :: cpath(:)
      +        type(c_ptr) :: tmp
      +
      +        allocate (cpath(buffersize))
      +
      +        tmp = getcwd_(cpath, buffersize)
      +        if (c_associated(tmp)) then
      +            call c_f_character(cpath, path)
      +        else
      +            call fatal_error(error, "Failed to retrieve current directory")
      +        end if
      +
      +    end subroutine get_current_directory
      +
      +    subroutine f_c_character(rhs, lhs, len)
      +        character(kind=c_char), intent(out) :: lhs(*)
      +        character(len=*), intent(in) :: rhs
      +        integer, intent(in) :: len
      +        integer :: length
      +        length = min(len - 1, len_trim(rhs))
      +
      +        lhs(1:length) = transfer(rhs(1:length), lhs(1:length))
      +        lhs(length + 1:length + 1) = c_null_char
      +
      +    end subroutine f_c_character
      +
      +    subroutine c_f_character(rhs, lhs)
      +        character(kind=c_char), intent(in) :: rhs(*)
      +        character(len=:), allocatable, intent(out) :: lhs
      +
      +        integer :: ii
      +
      +        do ii = 1, huge(ii) - 1
      +            if (rhs(ii) == c_null_char) then
      +                exit
      +            end if
      +        end do
      +
      +        allocate (character(len=ii - 1) :: lhs)
      +        lhs = transfer(rhs(1:ii - 1), lhs)
      +
      +    end subroutine c_f_character
      +
      +    !> Determine the canonical, absolute path for the given path.
      +    !>
      +    !> Calls a C routine that uses the `_WIN32` macro to determine the correct function.
      +    !>
      +    !> Cannot be used in bootstrap mode.
      +    subroutine get_realpath(path, real_path, error)
      +        character(len=*), intent(in) :: path
      +        character(len=:), allocatable, intent(out) :: real_path
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        character(kind=c_char, len=1), allocatable :: appended_path(:)
      +        character(kind=c_char, len=1), allocatable :: cpath(:)
      +        type(c_ptr) :: ptr
      +
      +        if (.not. exists(path)) then
      +            call fatal_error(error, "Cannot determine absolute path. Path '"//path//"' does not exist.")
      +            return
      +        end if
      +
      +        allocate (appended_path(len(path) + 1))
      +        call f_c_character(path, appended_path, len(path) + 1)
      +
      +        allocate (cpath(buffersize))
      +
      +#ifndef FPM_BOOTSTRAP
      +        ptr = c_realpath(appended_path, cpath, buffersize)
      +#endif
      +
      +        if (c_associated(ptr)) then
      +            call c_f_character(cpath, real_path)
      +        else
      +            call fatal_error(error, "Failed to retrieve absolute path for '"//path//"'.")
      +        end if
      +
      +    end subroutine
      +
      +    !> Determine the canonical, absolute path for the given path.
      +    !> Expands home folder (~) on both Unix and Windows.
      +    subroutine get_absolute_path(path, absolute_path, error)
      +        character(len=*), intent(in) :: path
      +        character(len=:), allocatable, intent(out) :: absolute_path
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        character(len=:), allocatable :: home
      +
      +#ifdef FPM_BOOTSTRAP
      +        call get_absolute_path_by_cd(path, absolute_path, error); return
      +#endif
      +
      +        if (len_trim(path) < 1) then
      +            call fatal_error(error, 'Path cannot be empty'); return
      +        else if (path(1:1) == '~') then
      +            call get_home(home, error)
      +            if (allocated(error)) return
      +
      +            if (len_trim(path) == 1) then
      +                absolute_path = home; return
      +            end if
      +
      +            if (os_is_unix()) then
      +                if (path(2:2) /= '/') then
      +                    call fatal_error(error, "Wrong separator in path: '"//path//"'"); return
      +                end if
      +            else
      +                if (path(2:2) /= '\') then
      +                    call fatal_error(error, "Wrong separator in path: '"//path//"'"); return
      +                end if
      +            end if
      +
      +            if (len_trim(path) == 2) then
      +                absolute_path = home; return
      +            end if
      +
      +            absolute_path = join_path(home, path(3:len_trim(path)))
      +
      +            if (.not. exists(absolute_path)) then
      +                call fatal_error(error, "Path not found: '"//absolute_path//"'"); return
      +            end if
      +        else
      +            ! Get canonicalized absolute path from either the absolute or the relative path.
      +            call get_realpath(path, absolute_path, error)
      +        end if
      +    end subroutine
      +
      +    !> Alternative to `get_absolute_path` that uses `chdir`/`_chdir` to determine the absolute path.
      +    !>
      +    !> `get_absolute_path` is preferred but `get_absolute_path_by_cd` can be used in bootstrap mode.
      +    subroutine get_absolute_path_by_cd(path, absolute_path, error)
      +        character(len=*), intent(in) :: path
      +        character(len=:), allocatable, intent(out) :: absolute_path
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        character(len=:), allocatable :: current_path
      +
      +        call get_current_directory(current_path, error)
      +        if (allocated(error)) return
      +
      +        call change_directory(path, error)
      +        if (allocated(error)) return
      +
      +        call get_current_directory(absolute_path, error)
      +        if (allocated(error)) return
      +
      +        call change_directory(current_path, error)
      +        if (allocated(error)) return
      +    end subroutine
      +
      +    !> Converts a path to an absolute, canonical path.
      +    subroutine convert_to_absolute_path(path, error)
      +        character(len=:), allocatable, intent(inout) :: path
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        character(len=:), allocatable :: absolute_path
      +
      +        call get_absolute_path(path, absolute_path, error)
      +        path = absolute_path
      +    end subroutine
      +
      +end module fpm_os
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/fpm_pkg_config.f90.html b/sourcefile/fpm_pkg_config.f90.html new file mode 100644 index 0000000000..fe87615b3d --- /dev/null +++ b/sourcefile/fpm_pkg_config.f90.html @@ -0,0 +1,550 @@ + + + + + + + + + + + + + fpm_pkg_config.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      fpm_pkg_config.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      !># The fpm interface to pkg-config
      +!>
      +!> This module contains wrapper functions to interface with a pkg-config installation.
      +!>
      +module fpm_pkg_config
      +
      +use fpm_strings, only: string_t,str_begins_with_str,len_trim,remove_newline_characters, &
      +    split
      +use fpm_error, only: error_t, fatal_error, fpm_stop
      +use fpm_filesystem, only: get_temp_filename,getline
      +use fpm_environment, only: get_env,os_is_unix,set_env,delete_env
      +use shlex_module, only: shlex_split => split
      +implicit none
      +private
      +
      +public :: assert_pkg_config
      +public :: pkgcfg_get_version
      +public :: pkgcfg_get_libs
      +public :: pkgcfg_get_build_flags
      +public :: pkgcfg_has_package
      +public :: pkgcfg_list_all
      +public :: run_wrapper
      +
      +contains
      +    
      +!> Check whether pkg-config is available on the local system
      +logical function assert_pkg_config()
      +
      +   integer :: exitcode
      +   logical :: success
      +   type(string_t) :: log
      +
      +   call run_wrapper(wrapper=string_t('pkg-config'),args=[string_t('-h')], &
      +                    exitcode=exitcode,cmd_success=success,screen_output=log)
      +   
      +   assert_pkg_config = exitcode==0 .and. success 
      +    
      +end function assert_pkg_config
      +    
      +!> Get package version from pkg-config
      +type(string_t) function pkgcfg_get_version(package,error) result(screen)
      +
      +    !> Package name
      +    character(*), intent(in) :: package
      +    
      +    !> Error handler
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    integer :: exitcode
      +    logical :: success
      +    type(string_t) :: log    
      +        
      +    call run_wrapper(wrapper=string_t('pkg-config'), &
      +                     args=[string_t(package),string_t('--modversion')], &
      +                     exitcode=exitcode,cmd_success=success,screen_output=log)    
      +    
      +    if (success .and. exitcode==0) then 
      +        call remove_newline_characters(log)
      +        screen = log
      +    else
      +        screen = string_t("")
      +    end if      
      +
      +end function pkgcfg_get_version
      +
      +!> Check if pkgcfg has package
      +logical function pkgcfg_has_package(name) result(success)
      +
      +    !> Package name
      +    character(*), intent(in) :: name
      +    
      +    integer :: exitcode
      +    logical :: cmdok
      +    type(string_t) :: log    
      +        
      +    call run_wrapper(wrapper=string_t('pkg-config'), &
      +                     args=[string_t(name),string_t('--exists')], &
      +                     exitcode=exitcode,cmd_success=cmdok,screen_output=log)    
      +    
      +    !> pkg-config --exists returns 0 only if the package exists
      +    success = cmdok .and. exitcode==0
      +            
      +end function pkgcfg_has_package
      +    
      +
      +!> Get package libraries from pkg-config
      +function pkgcfg_get_libs(package,error) result(libraries)
      +
      +    !> Package name
      +    character(*), intent(in) :: package
      +    
      +    !> Error handler
      +    type(error_t), allocatable, intent(out) :: error
      +    
      +    !> A list of libraries
      +    type(string_t), allocatable :: libraries(:)
      +
      +    integer :: exitcode,nlib,i
      +    logical :: success
      +    character(len=:), allocatable :: tokens(:)
      +    type(string_t) :: log    
      +        
      +    call run_wrapper(wrapper=string_t('pkg-config'), &
      +                     args=[string_t(package),string_t('--libs')], &
      +                     exitcode=exitcode,cmd_success=success,screen_output=log)         
      +
      +    if (success .and. exitcode==0) then 
      +        
      +        call remove_newline_characters(log)
      +        
      +        ! Split all arguments
      +        tokens = shlex_split(log%s)
      +        
      +        nlib = size(tokens)
      +        allocate(libraries(nlib))
      +        do i=1,nlib
      +            libraries(i) = string_t(trim(adjustl(tokens(i))))
      +        end do
      +        
      +    else
      +        
      +        allocate(libraries(0))
      +        call fatal_error(error,'cannot get <'//package//'> libraries from pkg-config')
      +        
      +    end if   
      +
      +end function pkgcfg_get_libs
      +
      +!> Return whole list of available pkg-cfg packages
      +function pkgcfg_list_all(error,descriptions) result(modules)
      +    
      +    !> Error handler
      +    type(error_t), allocatable, intent(out) :: error
      +    
      +    !> A list of all available packages 
      +    type(string_t), allocatable :: modules(:)    
      +    
      +    !> An optional list of package descriptions
      +    type(string_t), optional, allocatable, intent(out) :: descriptions(:)
      +    
      +    integer :: exitcode,i,spc
      +    logical :: success
      +    character(len=:), allocatable :: lines(:)
      +    type(string_t) :: log    
      +    type(string_t), allocatable :: mods(:),descr(:)
      +    character(*), parameter :: CRLF = achar(13)//new_line('a')
      +        
      +    call run_wrapper(wrapper=string_t('pkg-config'), &
      +                     args=[string_t('--list-all')], &
      +                     exitcode=exitcode,cmd_success=success,screen_output=log) 
      +                     
      +    if (.not.(success .and. exitcode==0)) then 
      +        call fatal_error(error,'cannot get pkg-config modules')
      +        allocate(modules(0))
      +        return
      +    end if
      +                    
      +    !> Extract list 
      +    call split(log%s,lines,CRLF)
      +    allocate(mods(size(lines)),descr(size(lines)))
      +    
      +    do i=1,size(lines)
      +        
      +        ! Module names have no spaces
      +        spc = index(lines(i),' ')
      +        
      +        if (spc>0) then 
      +            
      +            mods(i)  = string_t(trim(adjustl(lines(i)(1:spc))))
      +            descr(i) = string_t(trim(adjustl(lines(i)(spc+1:))))
      +            
      +        else
      +            
      +            mods(i)  = string_t(trim(adjustl(lines(i))))
      +            descr(i) = string_t("")
      +            
      +        end if
      +        
      +    end do
      +    
      +    call move_alloc(from=mods,to=modules)
      +    if (present(descriptions)) call move_alloc(from=descr,to=descriptions)
      +    
      +end function pkgcfg_list_all
      +    
      +!> Get build flags (option to include flags from system directories, that 
      +!> gfortran does not look into by default)
      +function pkgcfg_get_build_flags(name,allow_system,error) result(flags)
      +    
      +    !> Package name
      +    character(*), intent(in) :: name
      +    
      +    !> Should pkg-config look in system paths? This is necessary for gfortran 
      +    !> that doesn't otherwise look into them
      +    logical, intent(in) :: allow_system 
      +    
      +    !> Error flag 
      +    type(error_t), allocatable, intent(out) :: error
      +    
      +    !> List of compile flags
      +    type(string_t), allocatable :: flags(:)
      +    
      +    integer :: exitcode,i,nlib
      +    logical :: old_had,success,old_allow
      +    character(:), allocatable :: old,tokens(:)
      +    type(string_t) :: log    
      +    
      +    ! Check if the current environment includes system flags
      +    old = get_env('PKG_CONFIG_ALLOW_SYSTEM_CFLAGS',default='ERROR')
      +    old_had = old/='ERROR'
      +    old_allow = merge(old=='1',.false.,old_had)
      +    
      +    ! Set system flags
      +    success = set_env('PKG_CONFIG_ALLOW_SYSTEM_CFLAGS',value=merge('1','0',allow_system))
      +    if (.not.success) then 
      +        call fatal_error(error,'Cannot get pkg-config build flags: environment variable error.')
      +        return
      +    end if
      +    
      +    ! Now run wrapper
      +    call run_wrapper(wrapper=string_t('pkg-config'), &
      +                     args=[string_t(name),string_t('--cflags')], &
      +                     exitcode=exitcode,cmd_success=success,screen_output=log) 
      +                     
      +    if (success .and. exitcode==0) then 
      +        
      +        call remove_newline_characters(log)
      +        
      +        ! Split all arguments
      +        tokens = shlex_split(log%s)
      +        
      +        nlib = size(tokens)
      +        allocate(flags(nlib))
      +        do i=1,nlib
      +            flags(i) = string_t(trim(adjustl(tokens(i))))
      +        end do
      +        
      +    else
      +        
      +        allocate(flags(0))
      +        call fatal_error(error,'cannot get <'//name//'> build flags from pkg-config')
      +        
      +    end if   
      +
      +    ! Restore environment variable
      +    if (old_had) then 
      +        success = set_env('PKG_CONFIG_ALLOW_SYSTEM_CFLAGS',value=old)
      +    else
      +        success = delete_env('PKG_CONFIG_ALLOW_SYSTEM_CFLAGS')
      +    end if
      +    if (.not.success) then 
      +        call fatal_error(error,'Cannot get pkg-config build flags: environment variable error.')
      +        return
      +    end if    
      +    
      +    
      +end function pkgcfg_get_build_flags
      +    
      +!> Simple call to execute_command_line involving one mpi* wrapper
      +subroutine run_wrapper(wrapper,args,verbose,exitcode,cmd_success,screen_output)
      +    type(string_t), intent(in) :: wrapper
      +    type(string_t), intent(in), optional :: args(:)
      +    logical, intent(in), optional :: verbose
      +    integer, intent(out), optional :: exitcode
      +    logical, intent(out), optional :: cmd_success
      +    type(string_t), intent(out), optional :: screen_output
      +
      +    logical :: echo_local
      +    character(:), allocatable :: redirect_str,command,redirect,line
      +    integer :: iunit,iarg,stat,cmdstat
      +
      +
      +    if(present(verbose))then
      +       echo_local=verbose
      +    else
      +       echo_local=.false.
      +    end if
      +
      +    ! No redirection and non-verbose output
      +    if (present(screen_output)) then
      +        redirect = get_temp_filename()
      +        redirect_str =  ">"//redirect//" 2>&1"
      +    else
      +        if (os_is_unix()) then
      +            redirect_str = " >/dev/null 2>&1"
      +        else
      +            redirect_str = " >NUL 2>&1"
      +        end if
      +    end if
      +
      +    ! Empty command
      +    if (len_trim(wrapper)<=0) then
      +        if (echo_local) print *, '+ <EMPTY COMMAND>'
      +        if (present(exitcode)) exitcode = 0
      +        if (present(cmd_success)) cmd_success = .true.
      +        if (present(screen_output)) screen_output = string_t("")
      +        return
      +    end if
      +
      +    ! Init command
      +    command = trim(wrapper%s)
      +
      +    add_arguments: if (present(args)) then
      +        do iarg=1,size(args)
      +            if (len_trim(args(iarg))<=0) cycle
      +            command = trim(command)//' '//args(iarg)%s
      +        end do
      +    endif add_arguments
      +
      +    if (echo_local) print *, '+ ', command
      +
      +    ! Test command
      +    call execute_command_line(command//redirect_str,exitstat=stat,cmdstat=cmdstat)
      +
      +    ! Command successful?
      +    if (present(cmd_success)) cmd_success = cmdstat==0
      +
      +    ! Program exit code?
      +    if (present(exitcode)) exitcode = stat
      +
      +    ! Want screen output?
      +    if (present(screen_output) .and. cmdstat==0) then
      +
      +        allocate(character(len=0) :: screen_output%s)
      +
      +        open(newunit=iunit,file=redirect,status='old',iostat=stat)
      +        if (stat == 0)then
      +           do
      +               call getline(iunit, line, stat)
      +               if (stat /= 0) exit
      +
      +               screen_output%s = screen_output%s//new_line('a')//line
      +
      +               if (echo_local) write(*,'(A)') trim(line)
      +           end do
      +
      +           ! Close and delete file
      +           close(iunit,status='delete')
      +
      +        else
      +           call fpm_stop(1,'cannot read temporary file from successful MPI wrapper')
      +        endif
      +
      +    end if
      +
      +end subroutine run_wrapper
      +    
      +end module fpm_pkg_config
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/fpm_release.f90.html b/sourcefile/fpm_release.f90.html new file mode 100644 index 0000000000..0c0bc61112 --- /dev/null +++ b/sourcefile/fpm_release.f90.html @@ -0,0 +1,248 @@ + + + + + + + + + + + + + fpm_release.F90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      fpm_release.F90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      !># Release parameters
      +!> Module fpm_release contains public constants storing this build's unique version IDs
      +module fpm_release
      +    use fpm_versioning, only: version_t,new_version
      +    use fpm_error, only: error_t, fpm_stop
      +    implicit none
      +    private
      +
      +    public :: fpm_version
      +    public :: version_t
      +
      +    contains
      +
      +    !> Return the current fpm version from fpm_version_ID as a version type
      +    type(version_t) function fpm_version()
      +
      +        type(error_t), allocatable :: error
      +
      +! Fallback to last known version in case of undefined macro
      +#ifndef FPM_RELEASE_VERSION
      +#  define FPM_RELEASE_VERSION 0.12.0
      +#endif
      +
      +! Accept solution from https://stackoverflow.com/questions/31649691/stringify-macro-with-gnu-gfortran
      +! which provides the "easiest" way to pass a macro to a string in Fortran complying with both
      +! gfortran's "traditional" cpp and the standard cpp syntaxes
      +#ifdef __GFORTRAN__ /* traditional-cpp stringification */
      +#  define STRINGIFY_START(X) "&
      +#  define STRINGIFY_END(X) &X"
      +#else               /* default stringification */
      +#  define STRINGIFY_(X) #X
      +#  define STRINGIFY_START(X) &
      +#  define STRINGIFY_END(X) STRINGIFY_(X)
      +#endif
      +
      +        character (len=:), allocatable :: ver_string
      +        ver_string = STRINGIFY_START(FPM_RELEASE_VERSION)
      +        STRINGIFY_END(FPM_RELEASE_VERSION)
      +
      +        call new_version(fpm_version,ver_string,error)
      +
      +        if (allocated(error)) call fpm_stop(1,'*fpm*:internal error: cannot get version - '//error%message)
      +
      +    end function fpm_version
      +
      +end module fpm_release
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/fpm_settings.f90.html b/sourcefile/fpm_settings.f90.html new file mode 100644 index 0000000000..e18e8da819 --- /dev/null +++ b/sourcefile/fpm_settings.f90.html @@ -0,0 +1,447 @@ + + + + + + + + + + + + + fpm_settings.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      fpm_settings.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      !> Manages global settings which are defined in the global config file.
      +module fpm_settings
      +  use fpm_filesystem, only: exists, join_path, get_local_prefix, is_absolute_path, mkdir
      +  use fpm_environment, only: os_is_unix
      +  use fpm_error, only: error_t, fatal_error
      +  use tomlf, only: toml_table, toml_error, toml_stat, toml_load
      +  use fpm_toml, only: get_value, check_keys
      +  use fpm_os, only: get_current_directory, change_directory, get_absolute_path, convert_to_absolute_path
      +
      +  implicit none
      +  private
      +  public :: fpm_global_settings, get_global_settings, get_registry_settings, official_registry_base_url
      +
      +  character(*), parameter :: official_registry_base_url = 'https://fpm-registry.vercel.app'
      +  character(*), parameter :: default_config_file_name = 'config.toml'
      +
      +  type :: fpm_global_settings
      +    !> Path to the global config file excluding the file name.
      +    character(len=:), allocatable :: path_to_config_folder
      +    !> Name of the global config file. The default is `config.toml`.
      +    character(len=:), allocatable :: config_file_name
      +    !> Registry configs.
      +    type(fpm_registry_settings), allocatable :: registry_settings
      +  contains
      +    procedure :: has_custom_location, full_path, path_to_config_folder_or_empty
      +  end type
      +
      +  type :: fpm_registry_settings
      +    !> The path to the local registry. If allocated, the local registry
      +    !> will be used instead of the remote registry and replaces the
      +    !> local cache.
      +    character(len=:), allocatable :: path
      +    !> The URL to the remote registry. Can be used to get packages
      +    !> from the official or a custom registry.
      +    character(len=:), allocatable :: url
      +    !> The path to the cache folder. If not specified, the default cache
      +    !> folders are `~/.local/share/fpm/dependencies` on Unix and
      +    !> `%APPDATA%\local\fpm\dependencies` on Windows.
      +    !> Cannot be used together with `path`.
      +    character(len=:), allocatable :: cache_path
      +  end type
      +
      +contains
      +  !> Obtain global settings from the global config file.
      +  subroutine get_global_settings(global_settings, error)
      +    !> Global settings to be obtained.
      +    type(fpm_global_settings), intent(inout) :: global_settings
      +    !> Error reading config file.
      +    type(error_t), allocatable, intent(out) :: error
      +    !> TOML table to be filled with global config settings.
      +    type(toml_table), allocatable :: table
      +    !> Error parsing to TOML table.
      +    type(toml_error), allocatable :: parse_error
      +
      +    type(toml_table), pointer :: registry_table
      +    integer :: stat
      +
      +    ! Use custom path to the config file if it was specified.
      +    if (global_settings%has_custom_location()) then
      +      ! Throw error if folder doesn't exist.
      +      if (.not. exists(global_settings%path_to_config_folder)) then
      +        call fatal_error(error, "Folder not found: '"//global_settings%path_to_config_folder//"'."); return
      +      end if
      +
      +      ! Throw error if the file doesn't exist.
      +      if (.not. exists(global_settings%full_path())) then
      +        call fatal_error(error, "File not found: '"//global_settings%full_path()//"'."); return
      +      end if
      +
      +      ! Make sure that the path to the global config file is absolute.
      +      call convert_to_absolute_path(global_settings%path_to_config_folder, error)
      +      if (allocated(error)) return
      +    else
      +      ! Use default path if it wasn't specified.
      +      if (os_is_unix()) then
      +        global_settings%path_to_config_folder = join_path(get_local_prefix(), 'share', 'fpm')
      +      else
      +        global_settings%path_to_config_folder = join_path(get_local_prefix(), 'fpm')
      +      end if
      +
      +      ! Use default file name.
      +      global_settings%config_file_name = default_config_file_name
      +
      +      ! Apply default registry settings and return if config file doesn't exist.
      +      if (.not. exists(global_settings%full_path())) then
      +        call use_default_registry_settings(global_settings); return
      +      end if
      +    end if
      +
      +    ! Load into TOML table.
      +    call toml_load(table, global_settings%full_path(), error=parse_error)
      +
      +    if (allocated(parse_error)) then
      +      allocate (error); call move_alloc(parse_error%message, error%message); return
      +    end if
      +
      +    call get_value(table, 'registry', registry_table, requested=.false., stat=stat)
      +
      +    if (stat /= toml_stat%success) then
      +      call fatal_error(error, "Error reading registry from config file '"// &
      +      & global_settings%full_path()//"'."); return
      +    end if
      +
      +    ! A registry table was found.
      +    if (associated(registry_table)) then
      +      call get_registry_settings(registry_table, global_settings, error)
      +    else
      +      call use_default_registry_settings(global_settings)
      +    end if
      +  end
      +
      +  !> Default registry settings are typically applied if the config file doesn't exist or no registry table was found in
      +  !> the global config file.
      +  subroutine use_default_registry_settings(global_settings)
      +    type(fpm_global_settings), intent(inout) :: global_settings
      +
      +    if (.not. allocated(global_settings%registry_settings)) allocate (global_settings%registry_settings)
      +    global_settings%registry_settings%url = official_registry_base_url
      +    global_settings%registry_settings%cache_path = join_path(global_settings%path_to_config_folder_or_empty(), &
      +    & 'dependencies')
      +  end
      +
      +  !> Read registry settings from the global config file.
      +  subroutine get_registry_settings(table, global_settings, error)
      +    !> The [registry] subtable from the global config file.
      +    type(toml_table), target, intent(inout) :: table
      +    !> The global settings which can be filled with the registry settings.
      +    type(fpm_global_settings), intent(inout) :: global_settings
      +    !> Error handling.
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    character(:), allocatable :: path, url, cache_path
      +    integer :: stat
      +
      +    !> List of valid keys for the dependency table.
      +    character(*), dimension(*), parameter :: valid_keys = [character(10) :: &
      +        & 'path', &
      +        & 'url', &
      +        & 'cache_path' &
      +        & ]
      +
      +    call check_keys(table, valid_keys, error)
      +    if (allocated(error)) return
      +
      +    allocate (global_settings%registry_settings)
      +
      +    if (table%has_key('path')) then
      +      call get_value(table, 'path', path, stat=stat)
      +      if (stat /= toml_stat%success) then
      +        call fatal_error(error, "Error reading registry path: '"//path//"'."); return
      +      end if
      +    end if
      +
      +    if (allocated(path)) then
      +      if (is_absolute_path(path)) then
      +        global_settings%registry_settings%path = path
      +      else
      +        ! Get canonical, absolute path on both Unix and Windows.
      +        call get_absolute_path(join_path(global_settings%path_to_config_folder_or_empty(), path), &
      +        & global_settings%registry_settings%path, error)
      +        if (allocated(error)) return
      +
      +        ! Check if the path to the registry exists.
      +        if (.not. exists(global_settings%registry_settings%path)) then
      +          call fatal_error(error, "Directory '"//global_settings%registry_settings%path// &
      +          & "' doesn't exist."); return
      +        end if
      +      end if
      +    end if
      +
      +    if (table%has_key('url')) then
      +      call get_value(table, 'url', url, stat=stat)
      +      if (stat /= toml_stat%success) then
      +        call fatal_error(error, "Error reading registry url: '"//url//"'."); return
      +      end if
      +    end if
      +
      +    if (allocated(url)) then
      +      ! Throw error when both path and url were provided.
      +      if (allocated(path)) then
      +        call fatal_error(error, 'Do not provide both path and url to the registry.'); return
      +      end if
      +      global_settings%registry_settings%url = url
      +    else if (.not. allocated(path)) then
      +      global_settings%registry_settings%url = official_registry_base_url
      +    end if
      +
      +    if (table%has_key('cache_path')) then
      +      call get_value(table, 'cache_path', cache_path, stat=stat)
      +      if (stat /= toml_stat%success) then
      +        call fatal_error(error, "Error reading path to registry cache: '"//cache_path//"'."); return
      +      end if
      +    end if
      +
      +    if (allocated(cache_path)) then
      +      ! Throw error when both path and cache_path were provided.
      +      if (allocated(path)) then
      +        call fatal_error(error, "Do not provide both 'path' and 'cache_path'."); return
      +      end if
      +
      +      if (is_absolute_path(cache_path)) then
      +        if (.not. exists(cache_path)) call mkdir(cache_path)
      +        global_settings%registry_settings%cache_path = cache_path
      +      else
      +        cache_path = join_path(global_settings%path_to_config_folder_or_empty(), cache_path)
      +        if (.not. exists(cache_path)) call mkdir(cache_path)
      +        ! Get canonical, absolute path on both Unix and Windows.
      +        call get_absolute_path(cache_path, global_settings%registry_settings%cache_path, error)
      +        if (allocated(error)) return
      +      end if
      +    else if (.not. allocated(path)) then
      +      global_settings%registry_settings%cache_path = &
      +        join_path(global_settings%path_to_config_folder_or_empty(), 'dependencies')
      +    end if
      +  end
      +
      +  !> True if the global config file is not at the default location.
      +  elemental logical function has_custom_location(self)
      +    class(fpm_global_settings), intent(in) :: self
      +
      +    has_custom_location = allocated(self%path_to_config_folder) .and. allocated(self%config_file_name)
      +    if (.not. has_custom_location) return
      +    has_custom_location = len_trim(self%path_to_config_folder) > 0 .and. len_trim(self%config_file_name) > 0
      +  end
      +
      +  !> The full path to the global config file.
      +  function full_path(self) result(result)
      +    class(fpm_global_settings), intent(in) :: self
      +    character(len=:), allocatable :: result
      +
      +    result = join_path(self%path_to_config_folder_or_empty(), self%config_file_name)
      +  end
      +
      +  !> The path to the global config directory.
      +  pure function path_to_config_folder_or_empty(self)
      +    class(fpm_global_settings), intent(in) :: self
      +    character(len=:), allocatable :: path_to_config_folder_or_empty
      +
      +    if (allocated(self%path_to_config_folder)) then
      +      path_to_config_folder_or_empty = self%path_to_config_folder
      +    else
      +      path_to_config_folder_or_empty = ""
      +    end if
      +  end
      +end
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/fpm_source_parsing.f90.html b/sourcefile/fpm_source_parsing.f90.html new file mode 100644 index 0000000000..52d0d7c592 --- /dev/null +++ b/sourcefile/fpm_source_parsing.f90.html @@ -0,0 +1,928 @@ + + + + + + + + + + + + + fpm_source_parsing.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      fpm_source_parsing.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      !># Parsing of package source files
      +!>
      +!> This module exposes two functions, `[[parse_f_source]]` and `[[parse_c_source]]`,
      +!> which perform a rudimentary parsing of fortran and c source files
      +!> in order to extract information required for module dependency tracking.
      +!>
      +!> Both functions additionally calculate and store a file digest (hash) which
      +!> is used by the backend ([[fpm_backend]]) to skip compilation of unmodified sources.
      +!>
      +!> Both functions return an instance of the [[srcfile_t]] type.
      +!>
      +!> For more information, please read the documentation for each function:
      +!>
      +!> - `[[parse_f_source]]`
      +!> - `[[parse_c_source]]`
      +!>
      +module fpm_source_parsing
      +use fpm_error, only: error_t, file_parse_error, fatal_error, file_not_found_error
      +use fpm_strings, only: string_t, string_cat, len_trim, split, lower, str_ends_with, fnv_1a, is_fortran_name
      +use fpm_model, only: srcfile_t, &
      +                    FPM_UNIT_UNKNOWN, FPM_UNIT_PROGRAM, FPM_UNIT_MODULE, &
      +                    FPM_UNIT_SUBMODULE, FPM_UNIT_SUBPROGRAM, &
      +                    FPM_UNIT_CSOURCE, FPM_UNIT_CHEADER, FPM_SCOPE_UNKNOWN, &
      +                    FPM_SCOPE_DEP, FPM_SCOPE_APP, FPM_SCOPE_TEST, FPM_UNIT_CPPSOURCE
      +use fpm_filesystem, only: read_lines, read_lines_expanded, exists
      +implicit none
      +
      +private
      +public :: parse_f_source, parse_c_source, parse_use_statement
      +
      +contains
      +
      +!> Parsing of free-form fortran source files
      +!>
      +!> The following statements are recognised and parsed:
      +!>
      +!> - `Module`/`submodule`/`program` declaration
      +!> - Module `use` statement
      +!> - `include` statement
      +!>
      +!> @note Intrinsic modules used by sources are not listed in
      +!> the `modules_used` field of source objects.
      +!>
      +!> @note Submodules are treated as normal modules which `use` their
      +!> corresponding parent modules.
      +!>
      +!>### Parsing limitations
      +!>
      +!> __Statements must not continued onto another line
      +!>  except for an `only:` list in the `use` statement.__
      +!>
      +!> This is supported:
      +!>
      +!>```fortran
      +!> use my_module, only: &
      +!>      my_var, my_function, my_subroutine
      +!>```
      +!>
      +!> This is __NOT supported:__
      +!>
      +!>```fortran
      +!> use &
      +!>    my_module
      +!>```
      +!>
      +function parse_f_source(f_filename,error) result(f_source)
      +    character(*), intent(in) :: f_filename
      +    type(srcfile_t) :: f_source
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    logical :: inside_module, inside_interface, using, intrinsic_module
      +    integer :: stat
      +    integer :: fh, n_use, n_include, n_mod, n_parent, i, j, ic, pass
      +    type(string_t), allocatable :: file_lines(:), file_lines_lower(:)
      +    character(:), allocatable :: temp_string, mod_name, string_parts(:)
      +
      +    if (.not. exists(f_filename)) then
      +        call file_not_found_error(error, f_filename)
      +        return
      +    end if
      +
      +    f_source%file_name = f_filename
      +
      +    file_lines = read_lines_expanded(f_filename)
      +
      +    ! for efficiency in parsing make a lowercase left-adjusted copy of the file
      +    ! Need a copy because INCLUDE (and #include) file arguments are case-sensitive
      +    file_lines_lower=file_lines
      +    do i=1,size(file_lines_lower)
      +       file_lines_lower(i)%s=adjustl(lower(file_lines_lower(i)%s))
      +    enddo
      +
      +    ! fnv_1a can only be applied to non-zero-length arrays
      +    if (len_trim(file_lines_lower) > 0) f_source%digest = fnv_1a(file_lines)
      +
      +    do pass = 1,2
      +        n_use = 0
      +        n_include = 0
      +        n_mod = 0
      +        n_parent = 0
      +        inside_module = .false.
      +        inside_interface = .false.
      +        file_loop: do i=1,size(file_lines_lower)
      +
      +            ! Skip comment lines and preprocessor directives
      +            if (index(file_lines_lower(i)%s,'!') == 1 .or. &
      +                index(file_lines_lower(i)%s,'#') == 1 .or. &
      +                len_trim(file_lines_lower(i)%s) < 1) then
      +                cycle
      +            end if
      +
      +            ! Detect exported C-API via bind(C)
      +            if (.not.inside_interface .and. &
      +                parse_subsequence(file_lines_lower(i)%s,'bind','(','c')) then
      +
      +                do j=i,1,-1
      +
      +                    if (index(file_lines_lower(j)%s,'function') > 0 .or. &
      +                        index(file_lines_lower(j)%s,'subroutine') > 0) then
      +                        f_source%unit_type = FPM_UNIT_SUBPROGRAM
      +                        exit
      +                    end if
      +
      +                    if (j>1) then
      +
      +                        ic = index(file_lines_lower(j-1)%s,'!')
      +                        if (ic < 1) then
      +                            ic = len(file_lines_lower(j-1)%s)
      +                        end if
      +
      +                        temp_string = trim(file_lines_lower(j-1)%s(1:ic))
      +                        if (index(temp_string,'&') /= len(temp_string)) then
      +                            exit
      +                        end if
      +
      +                    end if
      +
      +                end do
      +
      +            end if
      +
      +            ! Skip lines that are continued: not statements
      +            if (i > 1) then
      +                ic = index(file_lines_lower(i-1)%s,'!')
      +                if (ic < 1) then
      +                    ic = len(file_lines_lower(i-1)%s)
      +                end if
      +                temp_string = trim(file_lines_lower(i-1)%s(1:ic))
      +                if (len(temp_string) > 0 .and. index(temp_string,'&') == len(temp_string)) then
      +                    cycle
      +                end if
      +            end if
      +
      +            ! Detect beginning of interface block
      +            if (index(file_lines_lower(i)%s,'interface') == 1 &
      +                .or. parse_sequence(file_lines_lower(i)%s,'abstract','interface')) then
      +
      +                inside_interface = .true.
      +                cycle
      +
      +            end if
      +
      +            ! Detect end of interface block
      +            if (parse_sequence(file_lines_lower(i)%s,'end','interface')) then
      +
      +                inside_interface = .false.
      +                cycle
      +
      +            end if
      +
      +            ! Process 'USE' statements
      +            call parse_use_statement(f_filename,i,file_lines_lower(i)%s,using,intrinsic_module,mod_name,error)
      +            if (allocated(error)) return
      +
      +            if (using) then
      +
      +                ! Not a valid module name?
      +                if (.not.is_fortran_name(mod_name)) cycle
      +
      +                ! Valid intrinsic module: not a dependency
      +                if (intrinsic_module) cycle
      +
      +                n_use = n_use + 1
      +
      +                if (pass == 2) f_source%modules_used(n_use)%s = mod_name
      +
      +                cycle
      +
      +            endif
      +
      +            ! Process 'INCLUDE' statements
      +            ic = index(file_lines_lower(i)%s,'include')
      +            if ( ic == 1 ) then
      +                ic = index(lower(file_lines(i)%s),'include')
      +                if (index(adjustl(file_lines(i)%s(ic+7:)),'"') == 1 .or. &
      +                    index(adjustl(file_lines(i)%s(ic+7:)),"'") == 1 ) then
      +
      +                    n_include = n_include + 1
      +
      +                    if (pass == 2) then
      +                        f_source%include_dependencies(n_include)%s = &
      +                         & split_n(file_lines(i)%s,n=2,delims="'"//'"',stat=stat)
      +                        if (stat /= 0) then
      +                            call file_parse_error(error,f_filename, &
      +                                  'unable to find include file name',i, &
      +                                  file_lines(i)%s)
      +                            return
      +                        end if
      +                    end if
      +
      +                    cycle
      +
      +                end if
      +            end if
      +
      +            ! Extract name of module if is module
      +            if (index(file_lines_lower(i)%s,'module ') == 1) then
      +
      +                ! Remove any trailing comments
      +                ic = index(file_lines_lower(i)%s,'!')-1
      +                if (ic < 1) then
      +                    ic = len(file_lines_lower(i)%s)
      +                end if
      +                temp_string = trim(file_lines_lower(i)%s(1:ic))
      +
      +                ! R1405 module-stmt := "MODULE" module-name
      +                ! module-stmt has two space-delimited parts only
      +                ! (no line continuations)
      +                call split(temp_string,string_parts,' ')
      +                if (size(string_parts) /= 2) then
      +                    cycle
      +                end if
      +
      +                mod_name = trim(adjustl(string_parts(2)))
      +                if (scan(mod_name,'=(&')>0 ) then
      +                    ! Ignore these cases:
      +                    ! module <something>&
      +                    ! module =*
      +                    ! module (i)
      +                    cycle
      +                end if
      +
      +                if (.not.is_fortran_name(mod_name)) then
      +                    call file_parse_error(error,f_filename, &
      +                          'empty or invalid name for module',i, &
      +                          file_lines_lower(i)%s, index(file_lines_lower(i)%s,mod_name))
      +                    return
      +                end if
      +
      +                n_mod = n_mod + 1
      +
      +                if (pass == 2) then
      +                    f_source%modules_provided(n_mod) = string_t(mod_name)
      +                end if
      +
      +                if (f_source%unit_type == FPM_UNIT_UNKNOWN) then
      +                    f_source%unit_type = FPM_UNIT_MODULE
      +                end if
      +
      +                if (.not.inside_module) then
      +                    inside_module = .true.
      +                else
      +                    ! Must have missed an end module statement (can't assume a pure module)
      +                    if (f_source%unit_type /= FPM_UNIT_PROGRAM) then
      +                        f_source%unit_type = FPM_UNIT_SUBPROGRAM
      +                    end if
      +                end if
      +
      +                cycle
      +
      +            end if
      +
      +            ! Extract name of submodule if is submodule
      +            if (index(file_lines_lower(i)%s,'submodule') == 1) then
      +
      +                mod_name = split_n(file_lines_lower(i)%s,n=3,delims='()',stat=stat)
      +                if (stat /= 0) then
      +                    call file_parse_error(error,f_filename, &
      +                          'unable to get submodule name',i, &
      +                          file_lines_lower(i)%s)
      +                    return
      +                end if
      +                if (.not.is_fortran_name(mod_name)) then
      +                    call file_parse_error(error,f_filename, &
      +                          'empty or invalid name for submodule',i, &
      +                          file_lines_lower(i)%s, index(file_lines_lower(i)%s,mod_name))
      +                    return
      +                end if
      +
      +                n_mod = n_mod + 1
      +
      +                temp_string = split_n(file_lines_lower(i)%s,n=2,delims='()',stat=stat)
      +                if (stat /= 0) then
      +                    call file_parse_error(error,f_filename, &
      +                          'unable to get submodule ancestry',i, &
      +                          file_lines_lower(i)%s)
      +                    return
      +                end if
      +
      +                if (f_source%unit_type /= FPM_UNIT_PROGRAM) then
      +                    f_source%unit_type = FPM_UNIT_SUBMODULE
      +                end if
      +
      +                n_use = n_use + 1
      +
      +                inside_module = .true.
      +
      +                n_parent = n_parent + 1
      +
      +                if (pass == 2) then
      +
      +                    if (index(temp_string,':') > 0) then
      +
      +                        temp_string = temp_string(index(temp_string,':')+1:)
      +
      +                    end if
      +
      +                    if (.not.is_fortran_name(temp_string)) then
      +                        call file_parse_error(error,f_filename, &
      +                          'empty or invalid name for submodule parent',i, &
      +                          file_lines_lower(i)%s, index(file_lines_lower(i)%s,temp_string))
      +                        return
      +                    end if
      +
      +                    f_source%modules_used(n_use)%s = temp_string
      +                    f_source%parent_modules(n_parent)%s = temp_string
      +                    f_source%modules_provided(n_mod)%s = mod_name
      +
      +                end if
      +
      +                cycle
      +
      +            end if
      +
      +            ! Detect if contains a program
      +            ! - no modules allowed after program def
      +            ! - program header may be missing (only "end program" statement present)
      +            if (index(file_lines_lower(i)%s,'program ')==1 .or. &
      +                parse_sequence(file_lines_lower(i)%s,'end','program')) then
      +
      +                temp_string = split_n(file_lines_lower(i)%s,n=2,delims=' ',stat=stat)
      +                if (stat == 0) then
      +
      +                    if (scan(temp_string,'=(')>0 ) then
      +                        ! Ignore:
      +                        ! program =*
      +                        ! program (i) =*
      +                        cycle
      +                    end if
      +
      +                end if
      +
      +                f_source%unit_type = FPM_UNIT_PROGRAM
      +
      +                cycle
      +                
      +
      +            end if
      +
      +            ! Parse end module statement
      +            !  (to check for code outside of modules)
      +            if (parse_sequence(file_lines_lower(i)%s,'end','module') .or. &
      +                parse_sequence(file_lines_lower(i)%s,'end','submodule')) then
      +
      +                inside_module = .false.
      +                cycle
      +
      +            end if
      +
      +            ! Any statements not yet parsed are assumed to be other code statements
      +            if (.not.inside_module .and. f_source%unit_type /= FPM_UNIT_PROGRAM) then
      +
      +                f_source%unit_type = FPM_UNIT_SUBPROGRAM
      +
      +            end if
      +
      +        end do file_loop
      +
      +        ! If unable to parse end of module statement, then can't assume pure module
      +        !  (there could be non-module subprograms present)
      +        if (inside_module .and. f_source%unit_type == FPM_UNIT_MODULE) then
      +            f_source%unit_type = FPM_UNIT_SUBPROGRAM
      +        end if
      +
      +        if (pass == 1) then
      +            allocate(f_source%modules_used(n_use))
      +            allocate(f_source%include_dependencies(n_include))
      +            allocate(f_source%modules_provided(n_mod))
      +            allocate(f_source%parent_modules(n_parent))
      +        end if
      +
      +    end do
      +
      +end function parse_f_source
      +
      +
      +!> Parsing of c, cpp source files
      +!>
      +!> The following statements are recognised and parsed:
      +!>
      +!> - `#include` preprocessor statement
      +!>
      +function parse_c_source(c_filename,error) result(c_source)
      +    character(*), intent(in) :: c_filename
      +    type(srcfile_t) :: c_source
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    integer :: fh, n_include, i, pass, stat
      +    type(string_t), allocatable :: file_lines(:)
      +
      +    c_source%file_name = c_filename
      +
      +    if (str_ends_with(lower(c_filename), ".c")) then
      +
      +        c_source%unit_type = FPM_UNIT_CSOURCE
      +
      +    else if (str_ends_with(lower(c_filename), ".h")) then
      +
      +        c_source%unit_type = FPM_UNIT_CHEADER
      +
      +    else if (str_ends_with(lower(c_filename), ".cpp")) then
      +
      +        c_source%unit_type = FPM_UNIT_CPPSOURCE
      +
      +    end if
      +
      +    allocate(c_source%modules_used(0))
      +    allocate(c_source%modules_provided(0))
      +    allocate(c_source%parent_modules(0))
      +
      +    file_lines = read_lines(c_filename)
      +
      +    ! Ignore empty files, returned as FPM_UNIT_UNKNOWN
      +    if (len_trim(file_lines) < 1) then
      +        c_source%unit_type = FPM_UNIT_UNKNOWN
      +        return
      +    end if
      +
      +    c_source%digest = fnv_1a(file_lines)
      +
      +    do pass = 1,2
      +        n_include = 0
      +        file_loop: do i=1,size(file_lines)
      +
      +            ! Process 'INCLUDE' statements
      +            if (index(adjustl(lower(file_lines(i)%s)),'#include') == 1 .and. &
      +                index(file_lines(i)%s,'"') > 0) then
      +
      +                n_include = n_include + 1
      +
      +                if (pass == 2) then
      +
      +                    c_source%include_dependencies(n_include)%s = &
      +                     &   split_n(file_lines(i)%s,n=2,delims='"',stat=stat)
      +                    if (stat /= 0) then
      +                        call file_parse_error(error,c_filename, &
      +                            'unable to get c include file',i, &
      +                            file_lines(i)%s,index(file_lines(i)%s,'"'))
      +                        return
      +                    end if
      +
      +                end if
      +
      +            end if
      +
      +        end do file_loop
      +
      +        if (pass == 1) then
      +            allocate(c_source%include_dependencies(n_include))
      +        end if
      +
      +    end do
      +
      +end function parse_c_source
      +
      +!> Split a string on one or more delimeters
      +!>  and return the nth substring if it exists
      +!>
      +!> n=0  will return the last item
      +!> n=-1 will return the penultimate item etc.
      +!>
      +!> stat = 1 on return if the index
      +!>  is not found
      +!>
      +function split_n(string,delims,n,stat) result(substring)
      +
      +    character(*), intent(in) :: string
      +    character(*), intent(in) :: delims
      +    integer, intent(in) :: n
      +    integer, intent(out) :: stat
      +    character(:), allocatable :: substring
      +
      +    integer :: i
      +    character(:), allocatable :: string_parts(:)
      +
      +    call split(string,string_parts,delims)
      +
      +    if (n<1) then
      +        i = size(string_parts) + n
      +        if (i < 1) then
      +            allocate(character(len=0) :: substring) ! ifort bus error otherwise
      +            stat = 1
      +            return
      +        end if
      +    else
      +        i = n
      +    end if
      +
      +    if (i>size(string_parts)) then
      +        allocate(character(len=0) :: substring) ! ifort bus error otherwise
      +        stat = 1
      +        return
      +    end if
      +
      +    substring = trim(adjustl(string_parts(i)))
      +    stat = 0
      +
      +end function split_n
      +
      +
      +!> Parse a subsequence of blank-separated tokens within a string
      +!>  (see parse_sequence)
      +function parse_subsequence(string,t1,t2,t3,t4) result(found)
      +    character(*), intent(in) :: string
      +    character(*), intent(in) :: t1
      +    character(*), intent(in), optional :: t2, t3, t4
      +    logical :: found
      +
      +    integer :: offset, i
      +
      +    found = .false.
      +    offset = 1
      +
      +    do
      +
      +        i = index(string(offset:),t1)
      +
      +        if (i == 0) return
      +
      +        offset = offset + i - 1
      +
      +        found = parse_sequence(string(offset:),t1,t2,t3,t4)
      +
      +        if (found) return
      +
      +        offset = offset + len(t1)
      +
      +        if (offset > len(string)) return
      +
      +    end do
      +
      +end function parse_subsequence
      +
      +!> Helper utility to parse sequences of tokens
      +!> that may be optionally separated by zero or more spaces
      +function parse_sequence(string,t1,t2,t3,t4) result(found)
      +    character(*), intent(in) :: string
      +    character(*), intent(in) :: t1
      +    character(*), intent(in), optional :: t2, t3, t4
      +    logical :: found
      +
      +    integer :: post, n, incr, pos, token_n
      +    logical :: match
      +
      +    n = len(string)
      +    found = .false.
      +    pos = 1
      +
      +    do token_n=1,4
      +
      +        do while (pos <= n)
      +            if (string(pos:pos) /= ' ') then
      +                exit
      +            end if
      +            pos = pos + 1
      +        end do
      +
      +        select case(token_n)
      +        case(1)
      +            incr = len(t1)
      +            if (pos+incr-1>n) return
      +            match = string(pos:pos+incr-1) == t1
      +        case(2)
      +            if (.not.present(t2)) exit
      +            incr = len(t2)
      +            if (pos+incr-1>n) return
      +            match = string(pos:pos+incr-1) == t2
      +        case(3)
      +            if (.not.present(t3)) exit
      +            incr = len(t3)
      +            if (pos+incr-1>n) return
      +            match = string(pos:pos+incr-1) == t3
      +        case(4)
      +            if (.not.present(t4)) exit
      +            incr = len(t4)
      +            if (pos+incr-1>n) return
      +            match = string(pos:pos+incr-1) == t4
      +        case default
      +            exit
      +        end select
      +
      +        if (.not.match) then
      +            return
      +        end if
      +
      +        pos = pos + incr
      +
      +    end do
      +
      +    found = .true.
      +
      +end function parse_sequence
      +
      +! USE [, intrinsic] :: module_name [, only: only_list]
      +! USE [, non_intrinsic] :: module_name [, only: only_list]
      +subroutine parse_use_statement(f_filename,i,line,use_stmt,is_intrinsic,module_name,error)
      +
      +    !> Current file name and line number (for error messaging)
      +    character(*), intent(in) :: f_filename
      +    integer, intent(in) :: i
      +
      +    !> The line being parsed. MUST BE preprocessed with trim(adjustl()
      +    character(*), intent(in) :: line
      +
      +    !> Does this line contain a `use` statement?
      +    logical, intent(out) :: use_stmt
      +
      +    !> Is the module in this statement intrinsic?
      +    logical, intent(out) :: is_intrinsic
      +
      +    !> used module name
      +    character(:), allocatable, intent(out) :: module_name
      +
      +    !> Error handling
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    character(15), parameter :: INTRINSIC_NAMES(*) =  &
      +                                 ['iso_c_binding  ', &
      +                                  'iso_fortran_env', &
      +                                  'ieee_arithmetic', &
      +                                  'ieee_exceptions', &
      +                                  'ieee_features  ', &
      +                                  'omp_lib        ']
      +
      +    character(len=:), allocatable :: temp_string
      +    integer :: colons,intr,nonintr,j,stat
      +    logical :: has_intrinsic_name
      +
      +    use_stmt      = .false.
      +    is_intrinsic  = .false.
      +    if (len_trim(line)<=0) return
      +
      +    ! Quick check that the line is preprocessed
      +    if (line(1:1)==' ') then
      +        call fatal_error(error,'internal_error: source file line is not trim(adjustl()) on input to parse_use_statement')
      +        return
      +    end if
      +
      +    ! 'use' should be the first string in the adjustl line
      +    use_stmt = index(line,'use ')==1 .or. index(line,'use::')==1 .or. index(line,'use,')==1
      +    if (.not.use_stmt) return
      +    colons   = index(line,'::')
      +    nonintr  = 0
      +    intr     = 0
      +
      +    have_colons: if (colons>3) then
      +
      +        ! there may be an intrinsic/non-intrinsic spec
      +        nonintr = index(line(1:colons-1),'non_intrinsic')
      +        if (nonintr==0) intr = index(line(1:colons-1),'intrinsic')
      +
      +
      +        temp_string = split_n(line,delims=':',n=2,stat=stat)
      +        if (stat /= 0) then
      +            call file_parse_error(error,f_filename, &
      +                    'unable to find used module name',i, &
      +                    line,colons)
      +            return
      +        end if
      +
      +        module_name = split_n(temp_string,delims=' ,',n=1,stat=stat)
      +        if (stat /= 0) then
      +            call file_parse_error(error,f_filename, &
      +                     'unable to find used module name',i, &
      +                     line)
      +            return
      +        end if
      +
      +    else
      +
      +        module_name = split_n(line,n=2,delims=' ,',stat=stat)
      +        if (stat /= 0) then
      +            call file_parse_error(error,f_filename, &
      +                    'unable to find used module name',i, &
      +                    line)
      +            return
      +        end if
      +
      +    end if have_colons
      +
      +    ! If declared intrinsic, check that it is true
      +    has_intrinsic_name = any([(index(module_name,trim(INTRINSIC_NAMES(j)))>0, &
      +                             j=1,size(INTRINSIC_NAMES))])
      +    if (intr>0 .and. .not.has_intrinsic_name) then
      +
      +        ! An intrinsic module was not found. Its name could be in the next line,
      +        ! in which case, we just skip this check. The compiler will do the job if the name is invalid.
      +
      +        ! Module name was not read: it's in the next line
      +        if (index(module_name,'&')<=0) then
      +            call file_parse_error(error,f_filename, &
      +                                  'module '//module_name//' is declared intrinsic but it is not ',i, &
      +                                  line)
      +            return
      +        endif
      +    endif
      +
      +    ! Should we treat this as an intrinsic module
      +    is_intrinsic = nonintr==0 .and. & ! not declared non-intrinsic
      +                   (intr>0 .or. has_intrinsic_name)
      +
      +end subroutine parse_use_statement
      +
      +
      +
      +end module fpm_source_parsing
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/fpm_sources.f90.html b/sourcefile/fpm_sources.f90.html new file mode 100644 index 0000000000..908bf8bef8 --- /dev/null +++ b/sourcefile/fpm_sources.f90.html @@ -0,0 +1,493 @@ + + + + + + + + + + + + + fpm_sources.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      fpm_sources.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      !># Discovery of sources
      +!>
      +!> This module implements subroutines for building a list of
      +!> `[[srcfile_t]]` objects by looking for source files in the filesystem.
      +!>
      +module fpm_sources
      +use fpm_error, only: error_t
      +use fpm_model, only: srcfile_t, FPM_UNIT_PROGRAM
      +use fpm_filesystem, only: basename, canon_path, dirname, join_path, list_files, is_hidden_file
      +use fpm_environment, only: get_os_type,OS_WINDOWS
      +use fpm_strings, only: lower, str_ends_with, string_t, operator(.in.)
      +use fpm_source_parsing, only: parse_f_source, parse_c_source
      +use fpm_manifest_executable, only: executable_config_t
      +implicit none
      +
      +private
      +public :: add_sources_from_dir, add_executable_sources
      +public :: get_exe_name_with_suffix
      +
      +character(4), parameter :: fortran_suffixes(2) = [".f90", &
      +                                                  ".f  "]
      +character(4), parameter :: c_suffixes(4) = [".c  ", ".h  ", ".cpp", ".hpp"]
      +
      +contains
      +
      +!> Wrapper to source parsing routines.
      +!> Selects parsing routine based on source file name extension
      +function parse_source(source_file_path,custom_f_ext,error) result(source)
      +    character(*), intent(in) :: source_file_path
      +    type(string_t), optional, intent(in) :: custom_f_ext(:)
      +    type(error_t), allocatable, intent(out) :: error
      +    type(srcfile_t)  :: source
      +    type(string_t), allocatable :: f_ext(:)
      +
      +    call list_fortran_suffixes(f_ext,custom_f_ext)
      +
      +    if (str_ends_with(lower(source_file_path), f_ext)) then
      +
      +        source = parse_f_source(source_file_path, error)
      +
      +        if (source%unit_type == FPM_UNIT_PROGRAM) then
      +            source%exe_name = basename(source_file_path,suffix=.false.)
      +        end if
      +
      +    else if (str_ends_with(lower(source_file_path), c_suffixes)) then
      +
      +        source = parse_c_source(source_file_path,error)
      +
      +    endif
      +
      +    if (allocated(error)) then
      +        return
      +    end if
      +
      +end function parse_source
      +
      +!> List fortran suffixes, including optional ones
      +subroutine list_fortran_suffixes(suffixes,with_f_ext)
      +    type(string_t), allocatable, intent(out) :: suffixes(:)
      +    !> Additional user-defined (preprocessor) extensions that should be treated as Fortran sources
      +    type(string_t), intent(in), optional :: with_f_ext(:)
      +
      +    integer :: ndefault,nuser,i
      +
      +    ndefault = size(fortran_suffixes)
      +    nuser    = 0; if (present(with_f_ext)) nuser = size(with_f_ext)
      +
      +    allocate(suffixes(ndefault + nuser))
      +    do i=1,ndefault
      +        suffixes(i) = string_t(fortran_suffixes(i))
      +    end do
      +    if (present(with_f_ext)) then
      +        do i=1,nuser
      +            suffixes(ndefault+i) = string_t(with_f_ext(i)%s)
      +        end do
      +    endif
      +
      +end subroutine list_fortran_suffixes
      +
      +!> Add to `sources` by looking for source files in `directory`
      +subroutine add_sources_from_dir(sources,directory,scope,with_executables,with_f_ext,recurse,error)
      +    !> List of `[[srcfile_t]]` objects to append to. Allocated if not allocated
      +    type(srcfile_t), allocatable, intent(inout), target :: sources(:)
      +    !> Directory in which to search for source files
      +    character(*), intent(in) :: directory
      +    !> Scope to apply to the discovered sources, see [[fpm_model]] for enumeration
      +    integer, intent(in) :: scope
      +    !> Executable sources (fortran `program`s) are ignored unless `with_executables=.true.`
      +    logical, intent(in), optional :: with_executables
      +    !> Additional user-defined (preprocessor) extensions that should be treated as Fortran sources
      +    type(string_t), intent(in), optional :: with_f_ext(:)
      +    !> Whether to recursively search subdirectories, default is `.true.`
      +    logical, intent(in), optional :: recurse
      +    !> Error handling
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    integer :: i
      +    logical, allocatable :: is_source(:), exclude_source(:)
      +    logical :: recurse_
      +    type(string_t), allocatable :: file_names(:)
      +    type(string_t), allocatable :: src_file_names(:),f_ext(:)
      +    type(string_t), allocatable :: existing_src_files(:)
      +    type(srcfile_t), allocatable :: dir_sources(:)
      +
      +    recurse_ = .true.
      +    if (present(recurse)) recurse_ = recurse
      +    ! Scan directory for sources
      +    call list_files(directory, file_names,recurse=recurse_)
      +
      +    if (allocated(sources)) then
      +        allocate(existing_src_files(size(sources)))
      +        do i=1,size(sources)
      +            existing_src_files(i)%s = canon_path(sources(i)%file_name)
      +        end do
      +    else
      +        allocate(existing_src_files(0))
      +    end if
      +
      +    ! Get legal fortran suffixes
      +    call list_fortran_suffixes(f_ext,with_f_ext)
      +
      +    is_source = [(.not.(is_hidden_file(basename(file_names(i)%s))) .and. &
      +                 .not.(canon_path(file_names(i)%s) .in. existing_src_files) .and. &
      +                 (str_ends_with(lower(file_names(i)%s), f_ext) .or. &
      +                 str_ends_with(lower(file_names(i)%s), c_suffixes) ),i=1,size(file_names))]
      +
      +
      +    src_file_names = pack(file_names,is_source)
      +
      +    allocate(dir_sources(size(src_file_names)))
      +    allocate(exclude_source(size(src_file_names)))
      +
      +    do i = 1, size(src_file_names)
      +
      +        dir_sources(i) = parse_source(src_file_names(i)%s,with_f_ext,error)
      +        if (allocated(error)) return
      +
      +        dir_sources(i)%unit_scope = scope
      +        allocate(dir_sources(i)%link_libraries(0))
      +
      +        ! Exclude executables unless specified otherwise
      +        exclude_source(i) = (dir_sources(i)%unit_type == FPM_UNIT_PROGRAM)
      +        if (dir_sources(i)%unit_type == FPM_UNIT_PROGRAM .and. &
      +            & present(with_executables)) then
      +            if (with_executables) then
      +
      +                exclude_source(i) = .false.
      +
      +            end if
      +        end if
      +
      +    end do
      +
      +    if (.not.allocated(sources)) then
      +        sources = pack(dir_sources,.not.exclude_source)
      +    else
      +        sources = [sources, pack(dir_sources,.not.exclude_source)]
      +    end if
      +
      +end subroutine add_sources_from_dir
      +
      +
      +!> Add to `sources` using the executable and test entries in the manifest and
      +!> applies any executable-specific overrides such as `executable%name`.
      +!> Adds all sources (including modules) from each `executable%source_dir`
      +subroutine add_executable_sources(sources,executables,scope,auto_discover,with_f_ext,error)
      +    !> List of `[[srcfile_t]]` objects to append to. Allocated if not allocated
      +    type(srcfile_t), allocatable, intent(inout), target :: sources(:)
      +    !> List of `[[executable_config_t]]` entries from manifest
      +    class(executable_config_t), intent(in) :: executables(:)
      +    !> Scope to apply to the discovered sources: either `FPM_SCOPE_APP` or `FPM_SCOPE_TEST`, see [[fpm_model]]
      +    integer, intent(in) :: scope
      +    !> If `.false.` only executables and tests specified in the manifest are added to `sources`
      +    logical, intent(in) :: auto_discover
      +    !> Additional user-defined (preprocessor) extensions that should be treated as Fortran sources
      +    type(string_t), intent(in), optional :: with_f_ext(:)
      +    !> Error handling
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    integer :: i, j
      +
      +    type(string_t), allocatable :: exe_dirs(:)
      +    type(srcfile_t) :: exe_source
      +
      +    call get_executable_source_dirs(exe_dirs,executables)
      +
      +    do i=1,size(exe_dirs)
      +        call add_sources_from_dir(sources,exe_dirs(i)%s, scope, &
      +                     with_executables=auto_discover, with_f_ext=with_f_ext,recurse=.false., error=error)
      +
      +        if (allocated(error)) then
      +            return
      +        end if
      +    end do
      +
      +    exe_loop: do i=1,size(executables)
      +
      +        ! Check if executable already discovered automatically
      +        !  and apply any overrides
      +        do j=1,size(sources)
      +
      +            !> Compare lowercase strings to allow auto-discovery of pre-processed extensions
      +            if (lower(basename(sources(j)%file_name,suffix=.true.)) == lower(executables(i)%main) .and.&
      +                 canon_path(dirname(sources(j)%file_name)) == &
      +                 canon_path(executables(i)%source_dir) ) then
      +
      +                sources(j)%exe_name = executables(i)%name
      +                if (allocated(executables(i)%link)) then
      +                    sources(j)%link_libraries = executables(i)%link
      +                end if
      +                sources(j)%unit_type = FPM_UNIT_PROGRAM
      +                cycle exe_loop
      +
      +            end if
      +
      +        end do
      +
      +        ! Add if not already discovered (auto_discovery off)
      +        associate(exe => executables(i))
      +            exe_source = parse_source(join_path(exe%source_dir,exe%main),with_f_ext,error)
      +            exe_source%exe_name = exe%name
      +            if (allocated(exe%link)) then
      +                exe_source%link_libraries = exe%link
      +            end if
      +            exe_source%unit_type = FPM_UNIT_PROGRAM
      +            exe_source%unit_scope = scope
      +        end associate
      +
      +        if (allocated(error)) return
      +
      +        if (.not.allocated(sources)) then
      +            sources = [exe_source]
      +        else
      +            sources = [sources, exe_source]
      +        end if
      +
      +    end do exe_loop
      +
      +end subroutine add_executable_sources
      +
      +!> Build a list of unique source directories
      +!>  from executables specified in manifest
      +subroutine get_executable_source_dirs(exe_dirs,executables)
      +    type(string_t), allocatable, intent(inout) :: exe_dirs(:)
      +    class(executable_config_t), intent(in) :: executables(:)
      +
      +    type(string_t) :: dirs_temp(size(executables))
      +
      +    integer :: i, n
      +
      +    n = 0
      +
      +    do i=1,size(executables)
      +       dirs_temp(i)%s=' '
      +    enddo
      +
      +    do i=1,size(executables)
      +        if (.not.(executables(i)%source_dir .in. dirs_temp)) then
      +
      +            n = n + 1
      +            dirs_temp(n)%s = executables(i)%source_dir
      +
      +        end if
      +    end do
      +
      +    if (.not.allocated(exe_dirs)) then
      +        exe_dirs = dirs_temp(1:n)
      +    else
      +        exe_dirs = [exe_dirs,dirs_temp(1:n)]
      +    end if
      +
      +end subroutine get_executable_source_dirs
      +
      +!> Build an executable name with suffix. Safe routine that always returns an allocated string
      +function get_exe_name_with_suffix(source) result(suffixed)
      +    type(srcfile_t), intent(in) :: source
      +    character(len=:), allocatable :: suffixed
      +
      +    if (allocated(source%exe_name)) then
      +       if (get_os_type() == OS_WINDOWS) then
      +           suffixed = source%exe_name//'.exe'
      +       else
      +           suffixed = source%exe_name
      +       end if
      +    else
      +       suffixed = ""
      +    endif
      +
      +end function get_exe_name_with_suffix
      +
      +end module fpm_sources
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/fpm_strings.f90.html b/sourcefile/fpm_strings.f90.html new file mode 100644 index 0000000000..d77d21f1a4 --- /dev/null +++ b/sourcefile/fpm_strings.f90.html @@ -0,0 +1,1864 @@ + + + + + + + + + + + + + fpm_strings.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      fpm_strings.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      !> This module defines general procedures for **string operations** for both CHARACTER and
      +!! TYPE(STRING_T) variables
      +!
      +!>## general routines for performing __string operations__
      +!!
      +!!### Types
      +!! - **TYPE(STRING_T)** define a type to contain strings of variable length
      +!!### Type Conversions
      +!! - [[F_STRING]]  return Fortran **CHARACTER** variable when given a C-like array of
      +!!                 single characters terminated with a C_NULL_CHAR **CHARACTER**
      +!! - [[STR]]  Converts **INTEGER** or** LOGICAL** to **CHARACTER** string
      +!!### Case
      +!! - [[LOWER]]  Changes a string to lowercase over optional specified column range
      +!!### Parsing and joining
      +!! - [[SPLIT]]  parse string on delimiter characters and store tokens into an allocatable array
      +!! - [[SPLIT_FIRST_LAST]]  Computes the first and last indices of tokens in input string, delimited by the characters in set,
      +!!                         and stores them into first and last output arrays.
      +!! - [[STRING_CAT]]  Concatenate an array of **type(string_t)** into a single **CHARACTER** variable
      +!! - [[JOIN]]  append an array of **CHARACTER** variables into a single **CHARACTER** variable
      +!!### Testing
      +!! - [[STR_ENDS_WITH]]  test if a **CHARACTER** string or array ends with a specified suffix
      +!! - [[STRING_ARRAY_CONTAINS]]  Check if array of **TYPE(STRING_T)** matches a particular **CHARACTER** string
      +!! - **OPERATOR(.IN.)**  Check if array of **TYPE(STRING_T)** matches a particular **CHARACTER** string
      +!! - [[GLOB]]  function compares text strings, one of which can have wildcards ('*' or '?').
      +!! - [[IS_FORTRAN_NAME]]  determine whether a string is an acceptable Fortran entity name
      +!! - [[TO_FORTRAN_NAME]]  replace allowed special but unusuable characters in names with underscore
      +!!### Whitespace
      +!! - [[NOTABS]]  subroutine to expand tab characters assuming a tab space every eight characters
      +!! - [[DILATE]]  function to expand tab characters assuming a tab space every eight characters
      +!! - [[LEN_TRIM]]  Determine total trimmed length of **STRING_T** array
      +!!### Miscellaneous
      +!! - [[FNV_1A]]  Hash a **CHARACTER(*)** string of default kind or a **TYPE(STRING_T)** array
      +!! - [[REPLACE]]  Returns string with characters in charset replaced with target_char.
      +!! - [[RESIZE]]  increase the size of a **TYPE(STRING_T)** array by N elements
      +!!
      +module fpm_strings
      +use iso_fortran_env, only: int64
      +use,intrinsic :: iso_fortran_env, only : stdin=>input_unit,   &
      +                                       & stdout=>output_unit, &
      +                                       & stderr=>error_unit
      +use iso_c_binding, only: c_char, c_ptr, c_int, c_null_char, c_associated, c_f_pointer, c_size_t
      +implicit none
      +
      +private
      +public :: f_string, lower, upper, split, split_first_last, split_lines_first_last, str_ends_with, string_t, str_begins_with_str
      +public :: to_fortran_name, is_fortran_name
      +public :: string_array_contains, string_cat, len_trim, operator(.in.), fnv_1a
      +public :: replace, resize, str, join, glob
      +public :: notabs, dilate, remove_newline_characters, remove_characters_in_set
      +public :: operator(==)
      +
      +!> Module naming
      +public :: is_valid_module_name, is_valid_module_prefix, &
      +          has_valid_custom_prefix, has_valid_standard_prefix, &
      +          module_prefix_template, module_prefix_type
      +
      +type string_t
      +    character(len=:), allocatable :: s
      +end type
      +
      +interface len_trim
      +    module procedure :: string_len_trim
      +    module procedure :: strings_len_trim
      +end interface len_trim
      +
      +interface resize
      +  module procedure :: resize_string
      +end interface
      +
      +interface operator(.in.)
      +    module procedure string_array_contains
      +end interface
      +
      +interface fnv_1a
      +    procedure :: fnv_1a_char
      +    procedure :: fnv_1a_string_t
      +end interface fnv_1a
      +
      +interface str_ends_with
      +    procedure :: str_ends_with_str
      +    procedure :: str_ends_with_any
      +    procedure :: str_ends_with_any_string
      +end interface str_ends_with
      +
      +interface str
      +    module procedure str_int, str_int64, str_logical
      +end interface
      +
      +interface string_t
      +    module procedure new_string_t
      +end interface string_t
      +
      +interface f_string
      +    module procedure f_string, f_string_cptr, f_string_cptr_n
      +end interface f_string
      +
      +interface operator(==)
      +    module procedure string_is_same
      +    module procedure string_arrays_same
      +end interface
      +
      +contains
      +
      +!> test if a CHARACTER string ends with a specified suffix
      +pure logical function str_ends_with_str(s, e) result(r)
      +    character(*), intent(in) :: s, e
      +    integer :: n1, n2
      +    n1 = len(s)-len(e)+1
      +    n2 = len(s)
      +    if (n1 < 1) then
      +        r = .false.
      +    else
      +        r = (s(n1:n2) == e)
      +    end if
      +end function str_ends_with_str
      +
      +!> test if a CHARACTER string ends with any of an array of suffixs
      +pure logical function str_ends_with_any(s, e) result(r)
      +    character(*), intent(in) :: s
      +    character(*), intent(in) :: e(:)
      +
      +    integer :: i
      +
      +    r = .true.
      +    do i=1,size(e)
      +
      +        if (str_ends_with(s,trim(e(i)))) return
      +
      +    end do
      +    r = .false.
      +
      +end function str_ends_with_any
      +
      +!> Test if a CHARACTER string ends with any of an array of string suffixs
      +pure logical function str_ends_with_any_string(s, e) result(r)
      +    character(*), intent(in) :: s
      +    type(string_t), intent(in) :: e(:)
      +
      +    integer :: i
      +
      +    r = .true.
      +    do i=1,size(e)
      +
      +        if (str_ends_with(s,trim(e(i)%s))) return
      +
      +    end do
      +    r = .false.
      +
      +end function str_ends_with_any_string
      +
      +!> test if a CHARACTER string begins with a specified prefix
      +pure logical function str_begins_with_str(s, e, case_sensitive) result(r)
      +    character(*), intent(in) :: s, e
      +    logical, optional, intent(in) :: case_sensitive ! Default option: case sensitive
      +    integer :: n1, n2
      +    logical :: lower_case
      +
      +    ! Check if case sensitive
      +    if (present(case_sensitive)) then
      +        lower_case = .not.case_sensitive
      +    else
      +        lower_case = .false.
      +    end if
      +
      +    n1 = 1
      +    n2 = 1 + len(e)-1
      +    if (n2 > len(s)) then
      +        r = .false.
      +    elseif (lower_case) then
      +        r = lower(s(n1:n2)) == lower(e)
      +    else
      +        r = (s(n1:n2) == e)
      +    end if
      +end function str_begins_with_str
      +
      +!> return Fortran character variable when given a C-like array of
      +!! single characters terminated with a C_NULL_CHAR character
      +function f_string(c_string)
      +    use iso_c_binding
      +    character(len=1), intent(in) :: c_string(:)
      +    character(:), allocatable :: f_string
      +
      +    integer :: i, n
      +
      +    i = 0
      +    do while(c_string(i+1) /= C_NULL_CHAR)
      +      i = i + 1
      +    end do
      +    n = i
      +
      +    allocate(character(n) :: f_string)
      +    do i=1,n
      +      f_string(i:i) = c_string(i)
      +    end do
      +
      +end function f_string
      +
      +
      +!> return Fortran character variable when given a null-terminated c_ptr
      +function f_string_cptr(cptr) result(s)
      +    type(c_ptr), intent(in), value :: cptr
      +    character(len=:,kind=c_char), allocatable :: s
      +
      +    interface
      +        function c_strlen(s) result(r) bind(c, name="strlen")
      +            import c_size_t, c_ptr
      +            type(c_ptr), intent(in), value :: s
      +            integer(kind=c_size_t) :: r
      +        end function
      +    end interface
      +
      +    s = f_string_cptr_n(cptr, c_strlen(cptr))
      +end function
      +
      +!> return Fortran character variable when given a null-terminated c_ptr and its length
      +function f_string_cptr_n(cptr, n) result(s)
      +    type(c_ptr), intent(in), value :: cptr
      +    integer(kind=c_size_t), intent(in) :: n
      +    character(len=n,kind=c_char) :: s
      +    character(len=n,kind=c_char), pointer :: sptr
      +
      +    call c_f_pointer(cptr, sptr)
      +    s = sptr
      +end function
      +
      +!> Hash a character(*) string of default kind
      +pure function fnv_1a_char(input, seed) result(hash)
      +    character(*), intent(in) :: input
      +    integer(int64), intent(in), optional :: seed
      +    integer(int64) :: hash
      +
      +    integer :: i
      +    integer(int64), parameter :: FNV_OFFSET_32 = 2166136261_int64
      +    integer(int64), parameter :: FNV_PRIME_32 = 16777619_int64
      +
      +    if (present(seed)) then
      +        hash = seed
      +    else
      +        hash = FNV_OFFSET_32
      +    end if
      +
      +    do i=1,len(input)
      +        hash = ieor(hash,iachar(input(i:i),int64)) * FNV_PRIME_32
      +    end do
      +
      +end function fnv_1a_char
      +
      +
      +!> Hash a string_t array of default kind
      +pure function fnv_1a_string_t(input, seed) result(hash)
      +    type(string_t), intent(in) :: input(:)
      +    integer(int64), intent(in), optional :: seed
      +    integer(int64) :: hash
      +
      +    integer :: i
      +
      +    hash = fnv_1a(input(1)%s,seed)
      +
      +    do i=2,size(input)
      +        hash = fnv_1a(input(i)%s,hash)
      +    end do
      +
      +end function fnv_1a_string_t
      +
      +
      +!>Author: John S. Urban
      +!!License: Public Domain
      +!! Changes a string to lowercase over optional specified column range
      +elemental pure function lower(str,begin,end) result (string)
      +
      +    character(*), intent(In)     :: str
      +    character(len(str))          :: string
      +    integer,intent(in),optional  :: begin, end
      +    integer                      :: i
      +    integer                      :: ibegin, iend
      +    string = str
      +
      +    ibegin = 1
      +    if (present(begin))then
      +        ibegin = max(ibegin,begin)
      +    endif
      +
      +    iend = len_trim(str)
      +    if (present(end))then
      +        iend= min(iend,end)
      +    endif
      +
      +    do i = ibegin, iend                               ! step thru each letter in the string in specified range
      +        select case (str(i:i))
      +        case ('A':'Z')
      +            string(i:i) = char(iachar(str(i:i))+32)     ! change letter to miniscule
      +        case default
      +        end select
      +    end do
      +
      +end function lower
      +
      +  !!License: Public Domain
      + !! Changes a string to upprtcase over optional specified column range
      +elemental pure function upper(str,begin,end) result (string)
      +
      +    character(*), intent(In)     :: str
      +    character(len(str))          :: string
      +    integer,intent(in),optional  :: begin, end
      +    integer                      :: i
      +    integer                      :: ibegin, iend
      +    string = str
      +
      +    ibegin = 1
      +    if (present(begin))then
      +        ibegin = max(ibegin,begin)
      +    endif
      +
      +    iend = len_trim(str)
      +    if (present(end))then
      +        iend= min(iend,end)
      +    endif
      +
      +    do i = ibegin, iend                               ! step thru each letter in the string in specified range
      +        select case (str(i:i))
      +        case ('a':'z')
      +            string(i:i) = char(iachar(str(i:i))-32)   ! change letter to capitalized
      +        case default
      +        end select
      +    end do
      +
      +end function upper
      +
      +!> Helper function to generate a new string_t instance
      +!>  (Required due to the allocatable component)
      +function new_string_t(s) result(string)
      +    character(*), intent(in) :: s
      +    type(string_t) :: string
      +
      +    string%s = s
      +
      +end function new_string_t
      +
      +!> Check if array of TYPE(STRING_T) matches a particular CHARACTER string
      +!!
      +logical function string_array_contains(search_string,array)
      +    character(*), intent(in) :: search_string
      +    type(string_t), intent(in) :: array(:)
      +
      +    integer :: i
      +
      +    string_array_contains = any([(array(i)%s==search_string, &
      +                                   i=1,size(array))])
      +
      +end function string_array_contains
      +
      +!> Concatenate an array of type(string_t) into
      +!>  a single CHARACTER variable
      +function string_cat(strings,delim) result(cat)
      +    type(string_t), intent(in) :: strings(:)
      +    character(*), intent(in), optional :: delim
      +    character(:), allocatable :: cat
      +
      +    integer :: i
      +    character(:), allocatable :: delim_str
      +
      +    if (size(strings) < 1) then
      +        cat = ''
      +        return
      +    end if
      +
      +    if (present(delim)) then
      +        delim_str = delim
      +    else
      +        delim_str = ''
      +    end if
      +
      +    cat = strings(1)%s
      +    do i=2,size(strings)
      +
      +        cat = cat//delim_str//strings(i)%s
      +
      +    end do
      +
      +end function string_cat
      +
      +!> Determine total trimmed length of `string_t` array
      +pure function strings_len_trim(strings) result(n)
      +    type(string_t), intent(in) :: strings(:)
      +    integer :: i, n
      +
      +    n = 0
      +    do i=1,size(strings)
      +        n = n + len_trim(strings(i)%s)
      +    end do
      +
      +end function strings_len_trim
      +
      +!> Determine total trimmed length of `string_t` array
      +elemental integer function string_len_trim(string) result(n)
      +    type(string_t), intent(in) :: string
      +
      +    if (allocated(string%s)) then
      +        n = len_trim(string%s)
      +    else
      +        n = 0
      +    end if
      +
      +end function string_len_trim
      +
      +!>Author: John S. Urban
      +!!License: Public Domain
      +!! parse string on delimiter characters and store tokens into an allocatable array
      +subroutine split(input_line,array,delimiters,order,nulls)
      +    !! given a line of structure " par1 par2 par3 ... parn " store each par(n) into a separate variable in array.
      +    !!
      +    !! * by default adjacent delimiters in the input string do not create an empty string in the output array
      +    !! * no quoting of delimiters is supported
      +    character(len=*),intent(in)              :: input_line  !! input string to tokenize
      +    character(len=*),optional,intent(in)     :: delimiters  !! list of delimiter characters
      +    character(len=*),optional,intent(in)     :: order       !! order of output array sequential|[reverse|right]
      +    character(len=*),optional,intent(in)     :: nulls       !! return strings composed of delimiters or not ignore|return|ignoreend
      +    character(len=:),allocatable,intent(out) :: array(:)    !! output array of tokens
      +
      +    integer                       :: n                      ! max number of strings INPUT_LINE could split into if all delimiter
      +    integer,allocatable           :: ibegin(:)              ! positions in input string where tokens start
      +    integer,allocatable           :: iterm(:)               ! positions in input string where tokens end
      +    character(len=:),allocatable  :: dlim                   ! string containing delimiter characters
      +    character(len=:),allocatable  :: ordr                   ! string containing order keyword
      +    character(len=:),allocatable  :: nlls                   ! string containing nulls keyword
      +    integer                       :: ii,iiii                ! loop parameters used to control print order
      +    integer                       :: icount                 ! number of tokens found
      +    integer                       :: ilen                   ! length of input string with trailing spaces trimmed
      +    integer                       :: i10,i20,i30            ! loop counters
      +    integer                       :: icol                   ! pointer into input string as it is being parsed
      +    integer                       :: idlim                  ! number of delimiter characters
      +    integer                       :: ifound                 ! where next delimiter character is found in remaining input string data
      +    integer                       :: inotnull               ! count strings not composed of delimiters
      +    integer                       :: ireturn                ! number of tokens returned
      +    integer                       :: imax                   ! length of longest token
      +
      +    ! decide on value for optional DELIMITERS parameter
      +    if (present(delimiters)) then                                     ! optional delimiter list was present
      +        if(delimiters/='')then                                       ! if DELIMITERS was specified and not null use it
      +            dlim=delimiters
      +        else                                                           ! DELIMITERS was specified on call as empty string
      +            dlim=' '//char(9)//char(10)//char(11)//char(12)//char(13)//char(0) ! use default delimiter when not specified
      +        endif
      +    else                                                              ! no delimiter value was specified
      +        dlim=' '//char(9)//char(10)//char(11)//char(12)//char(13)//char(0)    ! use default delimiter when not specified
      +    endif
      +    idlim=len(dlim)                                                   ! dlim a lot of blanks on some machines if dlim is a big string
      +
      +    if(present(order))then; ordr=lower(adjustl(order)); else; ordr='sequential'; endif ! decide on value for optional ORDER parameter
      +    if(present(nulls))then; nlls=lower(adjustl(nulls)); else; nlls='ignore'    ; endif ! optional parameter
      +
      +    n=len(input_line)+1                        ! max number of strings INPUT_LINE could split into if all delimiter
      +    allocate(ibegin(n))                        ! allocate enough space to hold starting location of tokens if string all tokens
      +    allocate(iterm(n))                         ! allocate enough space to hold ending location of tokens if string all tokens
      +    ibegin(:)=1
      +    iterm(:)=1
      +
      +    ilen=len(input_line)                                           ! ILEN is the column position of the last non-blank character
      +    icount=0                                                       ! how many tokens found
      +    inotnull=0                                                     ! how many tokens found not composed of delimiters
      +    imax=0                                                         ! length of longest token found
      +
      +    select case (ilen)
      +
      +    case (0)                                                      ! command was totally blank
      +
      +    case default                                                   ! there is at least one non-delimiter in INPUT_LINE if get here
      +        icol=1                                                      ! initialize pointer into input line
      +        INFINITE: do i30=1,ilen,1                                   ! store into each array element
      +            ibegin(i30)=icol                                         ! assume start new token on the character
      +            if(index(dlim(1:idlim),input_line(icol:icol))==0)then  ! if current character is not a delimiter
      +            iterm(i30)=ilen                                       ! initially assume no more tokens
      +            do i10=1,idlim                                        ! search for next delimiter
      +                ifound=index(input_line(ibegin(i30):ilen),dlim(i10:i10))
      +                IF(ifound>0)then
      +                    iterm(i30)=min(iterm(i30),ifound+ibegin(i30)-2)
      +                endif
      +            enddo
      +            icol=iterm(i30)+2                                     ! next place to look as found end of this token
      +            inotnull=inotnull+1                                   ! increment count of number of tokens not composed of delimiters
      +            else                                                     ! character is a delimiter for a null string
      +            iterm(i30)=icol-1                                     ! record assumed end of string. Will be less than beginning
      +            icol=icol+1                                           ! advance pointer into input string
      +            endif
      +            imax=max(imax,iterm(i30)-ibegin(i30)+1)
      +            icount=i30                                               ! increment count of number of tokens found
      +            if(icol>ilen)then                                     ! no text left
      +            exit INFINITE
      +            endif
      +        enddo INFINITE
      +
      +    end select
      +
      +    select case (trim(adjustl(nlls)))
      +    case ('ignore','','ignoreend')
      +        ireturn=inotnull
      +    case default
      +        ireturn=icount
      +    end select
      +    allocate(character(len=imax) :: array(ireturn))                ! allocate the array to return
      +    !allocate(array(ireturn))                                       ! allocate the array to turn
      +
      +    select case (trim(adjustl(ordr)))                              ! decide which order to store tokens
      +    case ('reverse','right') ; ii=ireturn ; iiii=-1                ! last to first
      +    case default             ; ii=1       ; iiii=1                 ! first to last
      +    end select
      +
      +    do i20=1,icount                                                ! fill the array with the tokens that were found
      +        if(iterm(i20)<ibegin(i20))then
      +            select case (trim(adjustl(nlls)))
      +            case ('ignore','','ignoreend')
      +            case default
      +            array(ii)=' '
      +            ii=ii+iiii
      +            end select
      +        else
      +            array(ii)=input_line(ibegin(i20):iterm(i20))
      +            ii=ii+iiii
      +        endif
      +    enddo
      +end subroutine split
      +
      +!! Author: Milan Curcic
      +!! Computes the first and last indices of tokens in input string, delimited
      +!! by the characters in set, and stores them into first and last output
      +!! arrays.
      +pure subroutine split_first_last(string, set, first, last)
      +    character(*), intent(in) :: string
      +    character(*), intent(in) :: set
      +    integer, allocatable, intent(out) :: first(:)
      +    integer, allocatable, intent(out) :: last(:)
      +
      +    integer, dimension(len(string) + 1) :: istart, iend
      +    integer :: p, n, slen
      +
      +    slen = len(string)
      +
      +    n = 0
      +    if (slen > 0) then
      +        p = 0
      +        do while (p < slen)
      +            n = n + 1
      +            istart(n) = min(p + 1, slen)
      +            call split_pos(string, set, p)
      +            iend(n) = p - 1
      +        end do
      +    end if
      +
      +    first = istart(:n)
      +    last = iend(:n)
      +
      +end subroutine split_first_last
      +
      +!! Author: Federico Perini
      +!! Computes the first and last indices of lines in input string, delimited
      +!! by either CR, LF, or CRLF, and stores them into first and last output
      +!! arrays.
      +pure subroutine split_lines_first_last(string, first, last)
      +    character(*), intent(in) :: string
      +    integer, allocatable, intent(out) :: first(:)
      +    integer, allocatable, intent(out) :: last(:)
      +
      +    integer, dimension(len(string) + 1) :: istart, iend
      +    integer :: p, n, slen
      +    character, parameter :: CR = achar(13)
      +    character, parameter :: LF = new_line('A')
      +
      +    slen = len(string)
      +
      +    n = 0
      +    if (slen > 0) then
      +        p = 1
      +        do while (p <= slen)
      +            
      +            if (index(CR//LF, string(p:p)) == 0) then
      +                n = n + 1
      +                istart(n) = p
      +                do while (p <= slen)
      +                    if (index(CR//LF, string(p:p)) /= 0) exit
      +                    p = p + 1
      +                end do
      +                iend(n) = p - 1
      +            end if
      +            
      +            ! Handle Windows CRLF by skipping LF after CR
      +            if (p < slen) then 
      +               if (string(p:p) == CR .and. string(p+1:p+1) == LF) p = p + 1
      +            endif
      +            
      +            p = p + 1
      +        end do
      +    end if
      +
      +    first = istart(:n)
      +    last = iend(:n)
      +
      +end subroutine split_lines_first_last
      +
      +!! Author: Milan Curcic
      +!! If back is absent, computes the leftmost token delimiter in string whose
      +!! position is > pos. If back is present and true, computes the rightmost
      +!! token delimiter in string whose position is < pos. The result is stored
      +!! in pos.
      +pure subroutine split_pos(string, set, pos, back)
      +    character(*), intent(in) :: string
      +    character(*), intent(in) :: set
      +    integer, intent(in out) :: pos
      +    logical, intent(in), optional :: back
      +
      +    logical :: backward
      +    integer :: result_pos, bound
      +
      +    if (len(string) == 0) then
      +        pos = 1
      +        return
      +    end if
      +
      +    !TODO use optval when implemented in stdlib
      +    !backward = optval(back, .false.)
      +    backward = .false.
      +    if (present(back)) backward = back
      +
      +    if (backward) then
      +        bound = min(len(string), max(pos - 1, 0))
      +        result_pos = scan(string(:bound), set, back=.true.)
      +    else
      +        result_pos = scan(string(min(pos + 1, len(string)):), set) + pos
      +        if (result_pos < pos + 1) result_pos = len(string) + 1
      +    end if
      +
      +    pos = result_pos
      +
      +end subroutine split_pos
      +
      +!> Returns string with characters in charset replaced with target_char.
      +pure function replace(string, charset, target_char) result(res)
      +    character(*), intent(in) :: string
      +    character, intent(in) :: charset(:), target_char
      +    character(len(string)) :: res
      +    integer :: n
      +    res = string
      +    do n = 1, len(string)
      +        if (any(string(n:n) == charset)) then
      +            res(n:n) = target_char
      +        end if
      +    end do
      +end function replace
      +
      +!> increase the size of a TYPE(STRING_T) array by N elements
      +subroutine resize_string(list, n)
      +  !> Instance of the array to be resized
      +  type(string_t), allocatable, intent(inout) :: list(:)
      +  !> Dimension of the final array size
      +  integer, intent(in), optional :: n
      +
      +  type(string_t), allocatable :: tmp(:)
      +  integer :: this_size, new_size, i
      +  integer, parameter :: initial_size = 16
      +
      +  if (allocated(list)) then
      +    this_size = size(list, 1)
      +    call move_alloc(list, tmp)
      +  else
      +    this_size = initial_size
      +  end if
      +
      +  if (present(n)) then
      +    new_size = n
      +  else
      +    new_size = this_size + this_size/2 + 1
      +  end if
      +
      +  allocate(list(new_size))
      +
      +  if (allocated(tmp)) then
      +    this_size = min(size(tmp, 1), size(list, 1))
      +    do i = 1, this_size
      +      call move_alloc(tmp(i)%s, list(i)%s)
      +    end do
      +    deallocate(tmp)
      +  end if
      +
      +end subroutine resize_string
      +
      +!>AUTHOR: John S. Urban
      +!!LICENSE: Public Domain
      +!>
      +!!##NAME
      +!!    join(3f) - [M_strings:EDITING] append CHARACTER variable array into
      +!!    a single CHARACTER variable with specified separator
      +!!    (LICENSE:PD)
      +!!
      +!!##SYNOPSIS
      +!!
      +!!    pure function join(str,sep,trm,left,right,start,end) result (string)
      +!!
      +!!     character(len=*),intent(in)          :: str(:)
      +!!     character(len=*),intent(in),optional :: sep
      +!!     logical,intent(in),optional          :: trm
      +!!     character(len=*),intent(in),optional :: right
      +!!     character(len=*),intent(in),optional :: left
      +!!     character(len=*),intent(in),optional :: start
      +!!     character(len=*),intent(in),optional :: end
      +!!     character(len=:),allocatable         :: string
      +!!
      +!!##DESCRIPTION
      +!!   JOIN(3f) appends the elements of a CHARACTER array into a single
      +!!   CHARACTER variable, with elements 1 to N joined from left to right.
      +!!   By default each element is trimmed of trailing spaces and the
      +!!   default separator is a null string.
      +!!
      +!!##OPTIONS
      +!!      STR(:)  array of CHARACTER variables to be joined
      +!!      SEP     separator string to place between each variable. defaults
      +!!              to a null string.
      +!!      LEFT    string to place at left of each element
      +!!      RIGHT   string to place at right of each element
      +!!      START   prefix string
      +!!      END     suffix string
      +!!      TRM     option to trim each element of STR of trailing
      +!!              spaces. Defaults to .TRUE.
      +!!
      +!!##RESULT
      +!!      STRING  CHARACTER variable composed of all of the elements of STR()
      +!!              appended together with the optional separator SEP placed
      +!!              between the elements.
      +!!
      +!!##EXAMPLE
      +!!
      +!!  Sample program:
      +!!
      +!!   program demo_join
      +!!   use M_strings, only: join
      +!!   implicit none
      +!!   character(len=:),allocatable  :: s(:)
      +!!   character(len=:),allocatable  :: out
      +!!   integer                       :: i
      +!!     s=[character(len=10) :: 'United',' we',' stand,', &
      +!!     & ' divided',' we fall.']
      +!!     out=join(s)
      +!!     write(*,'(a)') out
      +!!     write(*,'(a)') join(s,trm=.false.)
      +!!     write(*,'(a)') (join(s,trm=.false.,sep='|'),i=1,3)
      +!!     write(*,'(a)') join(s,sep='<>')
      +!!     write(*,'(a)') join(s,sep=';',left='[',right=']')
      +!!     write(*,'(a)') join(s,left='[',right=']')
      +!!     write(*,'(a)') join(s,left='>>')
      +!!   end program demo_join
      +!!
      +!!  Expected output:
      +!!
      +!!   United we stand, divided we fall.
      +!!   United     we        stand,    divided   we fall.
      +!!   United    | we       | stand,   | divided  | we fall.
      +!!   United    | we       | stand,   | divided  | we fall.
      +!!   United    | we       | stand,   | divided  | we fall.
      +!!   United<> we<> stand,<> divided<> we fall.
      +!!   [United];[ we];[ stand,];[ divided];[ we fall.]
      +!!   [United][ we][ stand,][ divided][ we fall.]
      +!!   >>United>> we>> stand,>> divided>> we fall.
      +pure function join(str,sep,trm,left,right,start,end) result (string)
      +
      +! @(#)M_strings::join(3f): merge string array into a single CHARACTER value adding specified separators, caps, prefix and suffix
      +
      +character(len=*),intent(in)          :: str(:)
      +character(len=*),intent(in),optional :: sep, right, left, start, end
      +logical,intent(in),optional          :: trm
      +character(len=:),allocatable         :: sep_local, left_local, right_local
      +character(len=:),allocatable         :: string
      +logical                              :: trm_local
      +integer                              :: i
      +   if(present(sep))then   ; sep_local=sep     ; else ; sep_local=''     ; endif
      +   if(present(trm))then   ; trm_local=trm     ; else ; trm_local=.true. ; endif
      +   if(present(left))then  ; left_local=left   ; else ; left_local=''    ; endif
      +   if(present(right))then ; right_local=right ; else ; right_local=''   ; endif
      +   string=''
      +   if(size(str)==0)then
      +      string=string//left_local//right_local
      +   else
      +      do i = 1,size(str)-1
      +         if(trm_local)then
      +            string=string//left_local//trim(str(i))//right_local//sep_local
      +         else
      +            string=string//left_local//str(i)//right_local//sep_local
      +         endif
      +      enddo
      +      if(trm_local)then
      +         string=string//left_local//trim(str(i))//right_local
      +      else
      +         string=string//left_local//str(i)//right_local
      +      endif
      +   endif
      +   if(present(start))string=start//string
      +   if(present(end))string=string//end
      +end function join
      +
      +!>AUTHOR: John S. Urban
      +!!LICENSE: Public Domain
      +!>
      +!!## NAME
      +!!    glob(3f) - [fpm_strings:COMPARE] compare given string for match to
      +!!    pattern which may contain wildcard characters
      +!!    (LICENSE:PD)
      +!!
      +!!## SYNOPSIS
      +!!
      +!!    logical function glob(string, pattern )
      +!!
      +!!     character(len=*),intent(in) :: string
      +!!     character(len=*),intent(in) :: pattern
      +!!
      +!!## DESCRIPTION
      +!!   glob(3f) compares given STRING for match to PATTERN which may
      +!!   contain wildcard characters.
      +!!
      +!!   In this version to get a match the entire string must be described
      +!!   by PATTERN. Trailing whitespace is significant, so trim the input
      +!!   string to have trailing whitespace ignored.
      +!!
      +!!## OPTIONS
      +!!    string   the input string to test to see if it contains the pattern.
      +!!    pattern  the following simple globbing options are available
      +!!
      +!!             o "?" matching any one character
      +!!             o "*" matching zero or more characters.
      +!!               Do NOT use adjacent asterisks.
      +!!             o Both strings may have trailing spaces which
      +!!               are ignored.
      +!!             o There is no escape character, so matching strings with
      +!!               literal question mark and asterisk is problematic.
      +!!
      +!!## EXAMPLES
      +!!
      +!!   Example program
      +!!
      +!!    program demo_glob
      +!!    implicit none
      +!!    ! This main() routine passes a bunch of test strings
      +!!    ! into the above code.  In performance comparison mode,
      +!!    ! it does that over and over. Otherwise, it does it just
      +!!    ! once. Either way, it outputs a passed/failed result.
      +!!    !
      +!!    integer :: nReps
      +!!    logical :: allpassed
      +!!    integer :: i
      +!!     allpassed = .true.
      +!!
      +!!     nReps = 10000
      +!!     ! Can choose as many repetitions as you're expecting
      +!!     ! in the real world.
      +!!     nReps = 1
      +!!
      +!!     do i=1,nReps
      +!!      ! Cases with repeating character sequences.
      +!!      allpassed=allpassed .and. test("a*abab", "a*b", .true.)
      +!!      !!cycle
      +!!      allpassed=allpassed .and. test("ab", "*?", .true.)
      +!!      allpassed=allpassed .and. test("abc", "*?", .true.)
      +!!      allpassed=allpassed .and. test("abcccd", "*ccd", .true.)
      +!!      allpassed=allpassed .and. test("bLah", "bLaH", .false.)
      +!!      allpassed=allpassed .and. test("mississippi", "*sip*", .true.)
      +!!      allpassed=allpassed .and. &
      +!!       & test("xxxx*zzzzzzzzy*f", "xxx*zzy*f", .true.)
      +!!      allpassed=allpassed .and. &
      +!!       & test("xxxx*zzzzzzzzy*f", "xxxx*zzy*fffff", .false.)
      +!!      allpassed=allpassed .and. &
      +!!       & test("mississipissippi", "*issip*ss*", .true.)
      +!!      allpassed=allpassed .and. &
      +!!       & test("xxxxzzzzzzzzyf", "xxxx*zzy*fffff", .false.)
      +!!      allpassed=allpassed .and. &
      +!!       & test("xxxxzzzzzzzzyf", "xxxx*zzy*f", .true.)
      +!!      allpassed=allpassed .and. test("xyxyxyzyxyz", "xy*z*xyz", .true.)
      +!!      allpassed=allpassed .and. test("xyxyxyxyz", "xy*xyz", .true.)
      +!!      allpassed=allpassed .and. test("mississippi", "mi*sip*", .true.)
      +!!      allpassed=allpassed .and. test("ababac", "*abac*", .true.)
      +!!      allpassed=allpassed .and. test("aaazz", "a*zz*", .true.)
      +!!      allpassed=allpassed .and. test("a12b12", "*12*23", .false.)
      +!!      allpassed=allpassed .and. test("a12b12", "a12b", .false.)
      +!!      allpassed=allpassed .and. test("a12b12", "*12*12*", .true.)
      +!!
      +!!      ! Additional cases where the '*' char appears in the tame string.
      +!!      allpassed=allpassed .and. test("*", "*", .true.)
      +!!      allpassed=allpassed .and. test("a*r", "a*", .true.)
      +!!      allpassed=allpassed .and. test("a*ar", "a*aar", .false.)
      +!!
      +!!      ! More double wildcard scenarios.
      +!!      allpassed=allpassed .and. test("XYXYXYZYXYz", "XY*Z*XYz", .true.)
      +!!      allpassed=allpassed .and. test("missisSIPpi", "*SIP*", .true.)
      +!!      allpassed=allpassed .and. test("mississipPI", "*issip*PI", .true.)
      +!!      allpassed=allpassed .and. test("xyxyxyxyz", "xy*xyz", .true.)
      +!!      allpassed=allpassed .and. test("miSsissippi", "mi*sip*", .true.)
      +!!      allpassed=allpassed .and. test("miSsissippi", "mi*Sip*", .false.)
      +!!      allpassed=allpassed .and. test("abAbac", "*Abac*", .true.)
      +!!      allpassed=allpassed .and. test("aAazz", "a*zz*", .true.)
      +!!      allpassed=allpassed .and. test("A12b12", "*12*23", .false.)
      +!!      allpassed=allpassed .and. test("a12B12", "*12*12*", .true.)
      +!!      allpassed=allpassed .and. test("oWn", "*oWn*", .true.)
      +!!
      +!!      ! Completely tame (no wildcards) cases.
      +!!      allpassed=allpassed .and. test("bLah", "bLah", .true.)
      +!!
      +!!      ! Simple mixed wildcard tests suggested by IBMer Marlin Deckert.
      +!!      allpassed=allpassed .and. test("a", "*?", .true.)
      +!!
      +!!      ! More mixed wildcard tests including coverage for false positives.
      +!!      allpassed=allpassed .and. test("a", "??", .false.)
      +!!      allpassed=allpassed .and. test("ab", "?*?", .true.)
      +!!      allpassed=allpassed .and. test("ab", "*?*?*", .true.)
      +!!      allpassed=allpassed .and. test("abc", "?**?*?", .true.)
      +!!      allpassed=allpassed .and. test("abc", "?**?*&?", .false.)
      +!!      allpassed=allpassed .and. test("abcd", "?b*??", .true.)
      +!!      allpassed=allpassed .and. test("abcd", "?a*??", .false.)
      +!!      allpassed=allpassed .and. test("abcd", "?**?c?", .true.)
      +!!      allpassed=allpassed .and. test("abcd", "?**?d?", .false.)
      +!!      allpassed=allpassed .and. test("abcde", "?*b*?*d*?", .true.)
      +!!
      +!!      ! Single-character-match cases.
      +!!      allpassed=allpassed .and. test("bLah", "bL?h", .true.)
      +!!      allpassed=allpassed .and. test("bLaaa", "bLa?", .false.)
      +!!      allpassed=allpassed .and. test("bLah", "bLa?", .true.)
      +!!      allpassed=allpassed .and. test("bLaH", "?Lah", .false.)
      +!!      allpassed=allpassed .and. test("bLaH", "?LaH", .true.)
      +!!
      +!!      ! Many-wildcard scenarios.
      +!!      allpassed=allpassed .and. test(&
      +!!      &"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa&
      +!!      &aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaab",&
      +!!      &"a*a*a*a*a*a*aa*aaa*a*a*b",&
      +!!      &.true.)
      +!!      allpassed=allpassed .and. test(&
      +!!      &"abababababababababababababababababababaacacacacacacac&
      +!!      &adaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab",&
      +!!      &"*a*b*ba*ca*a*aa*aaa*fa*ga*b*",&
      +!!      &.true.)
      +!!      allpassed=allpassed .and. test(&
      +!!      &"abababababababababababababababababababaacacacacacaca&
      +!!      &cadaeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab",&
      +!!      &"*a*b*ba*ca*a*x*aaa*fa*ga*b*",&
      +!!      &.false.)
      +!!      allpassed=allpassed .and. test(&
      +!!      &"abababababababababababababababababababaacacacacacacacad&
      +!!      &aeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab",&
      +!!      &"*a*b*ba*ca*aaaa*fa*ga*gggg*b*",&
      +!!      &.false.)
      +!!      allpassed=allpassed .and. test(&
      +!!      &"abababababababababababababababababababaacacacacacacacad&
      +!!      &aeafagahaiajakalaaaaaaaaaaaaaaaaaffafagaagggagaaaaaaaab",&
      +!!      &"*a*b*ba*ca*aaaa*fa*ga*ggg*b*",&
      +!!      &.true.)
      +!!      allpassed=allpassed .and. test("aaabbaabbaab", "*aabbaa*a*", .true.)
      +!!      allpassed=allpassed .and. &
      +!!      test("a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*",&
      +!!      &"a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*", .true.)
      +!!      allpassed=allpassed .and. test("aaaaaaaaaaaaaaaaa",&
      +!!      &"*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*", .true.)
      +!!      allpassed=allpassed .and. test("aaaaaaaaaaaaaaaa",&
      +!!      &"*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*a*", .false.)
      +!!      allpassed=allpassed .and. test(&
      +!!      &"abc*abcd*abcde*abcdef*abcdefg*abcdefgh*abcdefghi*abcdefghij&
      +!!      &*abcdefghijk*abcdefghijkl*abcdefghijklm*abcdefghijklmn",&
      +!!      & "abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc&
      +!!      &*abc*abc*abc*",&
      +!!      &.false.)
      +!!      allpassed=allpassed .and. test(&
      +!!      &"abc*abcd*abcde*abcdef*abcdefg*abcdefgh*abcdefghi*abcdefghij&
      +!!      &*abcdefghijk*abcdefghijkl*abcdefghijklm*abcdefghijklmn",&
      +!!      &"abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*",&
      +!!      &.true.)
      +!!      allpassed=allpassed .and. test("abc*abcd*abcd*abc*abcd",&
      +!!      &"abc*abc*abc*abc*abc", .false.)
      +!!      allpassed=allpassed .and. test( "abc*abcd*abcd*abc*abcd*abcd&
      +!!      &*abc*abcd*abc*abc*abcd", &
      +!!      &"abc*abc*abc*abc*abc*abc*abc*abc*abc*abc*abcd",&
      +!!      &.true.)
      +!!      allpassed=allpassed .and. test("abc",&
      +!!      &"********a********b********c********", .true.)
      +!!      allpassed=allpassed .and.&
      +!!      &test("********a********b********c********", "abc", .false.)
      +!!      allpassed=allpassed .and. &
      +!!      &test("abc", "********a********b********b********", .false.)
      +!!      allpassed=allpassed .and. test("*abc*", "***a*b*c***", .true.)
      +!!
      +!!      ! A case-insensitive algorithm test.
      +!!      ! allpassed=allpassed .and. test("mississippi", "*issip*PI", .true.)
      +!!     enddo
      +!!
      +!!     if (allpassed)then
      +!!        write(*,'(a)')"Passed",nReps
      +!!     else
      +!!        write(*,'(a)')"Failed"
      +!!     endif
      +!!    contains
      +!!    ! This is a test program for wildcard matching routines.
      +!!    ! It can be used either to test a single routine for correctness,
      +!!    ! or to compare the timings of two (or more) different wildcard
      +!!    ! matching routines.
      +!!    !
      +!!    function test(tame, wild, bExpectedResult) result(bpassed)
      +!!    use fpm_strings, only : glob
      +!!       character(len=*) :: tame
      +!!       character(len=*) :: wild
      +!!       logical          :: bExpectedResult
      +!!       logical          :: bResult
      +!!       logical          :: bPassed
      +!!       bResult = .true.    ! We'll do "&=" cumulative checking.
      +!!       bPassed = .false.   ! Assume the worst.
      +!!       write(*,*)repeat('=',79)
      +!!       bResult = glob(tame, wild) ! Call a wildcard matching routine.
      +!!
      +!!       ! To assist correctness checking, output the two strings in any
      +!!       ! failing scenarios.
      +!!       if (bExpectedResult .eqv. bResult) then
      +!!          bPassed = .true.
      +!!          if(nReps == 1) write(*,*)"Passed match on ",tame," vs. ", wild
      +!!       else
      +!!          if(nReps == 1) write(*,*)"Failed match on ",tame," vs. ", wild
      +!!       endif
      +!!
      +!!    end function test
      +!!    end program demo_glob
      +!!
      +!!   Expected output
      +!!
      +!!
      +!!## REFERENCE
      +!!   The article "Matching Wildcards: An Empirical Way to Tame an Algorithm"
      +!!   in Dr Dobb's Journal, By Kirk J. Krauss, October 07, 2014
      +!!
      +function glob(tame,wild)
      +
      +! @(#)fpm_strings::glob(3f): function compares text strings, one of which can have wildcards ('*' or '?').
      +
      +logical                    :: glob       !! result of test
      +character(len=*)           :: tame       !! A string without wildcards to compare to the globbing expression
      +character(len=*)           :: wild       !! A (potentially) corresponding string with wildcards
      +character(len=len(tame)+1) :: tametext
      +character(len=len(wild)+1) :: wildtext
      +character(len=1),parameter :: NULL=char(0)
      +integer                    :: wlen
      +integer                    :: ti, wi
      +integer                    :: i
      +character(len=:),allocatable :: tbookmark, wbookmark
      +! These two values are set when we observe a wildcard character. They
      +! represent the locations, in the two strings, from which we start once we've observed it.
      +   tametext=tame//NULL
      +   wildtext=wild//NULL
      +   tbookmark = NULL
      +   wbookmark = NULL
      +   wlen=len(wild)
      +   wi=1
      +   ti=1
      +   do                                            ! Walk the text strings one character at a time.
      +      if(wildtext(wi:wi) == '*')then             ! How do you match a unique text string?
      +         do i=wi,wlen                            ! Easy: unique up on it!
      +            if(wildtext(wi:wi)=='*')then
      +               wi=wi+1
      +            else
      +               exit
      +            endif
      +         enddo
      +         if(wildtext(wi:wi)==NULL) then        ! "x" matches "*"
      +            glob=.true.
      +            return
      +         endif
      +         if(wildtext(wi:wi) /= '?') then
      +            ! Fast-forward to next possible match.
      +            do while (tametext(ti:ti) /= wildtext(wi:wi))
      +               ti=ti+1
      +               if (tametext(ti:ti)==NULL)then
      +                  glob=.false.
      +                  return                         ! "x" doesn't match "*y*"
      +               endif
      +            enddo
      +         endif
      +         wbookmark = wildtext(wi:)
      +         tbookmark = tametext(ti:)
      +      elseif(tametext(ti:ti) /= wildtext(wi:wi) .and. wildtext(wi:wi) /= '?') then
      +         ! Got a non-match. If we've set our bookmarks, back up to one or both of them and retry.
      +         if(wbookmark/=NULL) then
      +            if(wildtext(wi:)/= wbookmark) then
      +               wildtext = wbookmark;
      +               wlen=len_trim(wbookmark)
      +               wi=1
      +               ! Don't go this far back again.
      +               if (tametext(ti:ti) /= wildtext(wi:wi)) then
      +                  tbookmark=tbookmark(2:)
      +                  tametext = tbookmark
      +                  ti=1
      +                  cycle                          ! "xy" matches "*y"
      +               else
      +                  wi=wi+1
      +               endif
      +            endif
      +            if (tametext(ti:ti)/=NULL) then
      +               ti=ti+1
      +               cycle                             ! "mississippi" matches "*sip*"
      +            endif
      +         endif
      +         glob=.false.
      +         return                                  ! "xy" doesn't match "x"
      +      endif
      +      ti=ti+1
      +      wi=wi+1
      +      if (tametext(ti:ti)==NULL) then          ! How do you match a tame text string?
      +         if(wildtext(wi:wi)/=NULL)then
      +            do while (wildtext(wi:wi) == '*')    ! The tame way: unique up on it!
      +               wi=wi+1                           ! "x" matches "x*"
      +               if(wildtext(wi:wi)==NULL)exit
      +            enddo
      +         endif
      +         if (wildtext(wi:wi)==NULL)then
      +            glob=.true.
      +            return                               ! "x" matches "x"
      +         endif
      +         glob=.false.
      +         return                                  ! "x" doesn't match "xy"
      +      endif
      +   enddo
      +end function glob
      +
      +!> Returns the length of the string representation of 'i'
      +pure integer function str_int_len(i) result(sz)
      +integer, intent(in) :: i
      +integer, parameter :: MAX_STR = 100
      +character(MAX_STR) :: s
      +! If 's' is too short (MAX_STR too small), Fortran will abort with:
      +! "Fortran runtime error: End of record"
      +write(s, '(i0)') i
      +sz = len_trim(s)
      +end function
      +
      +!> Converts integer "i" to string
      +pure function str_int(i) result(s)
      +integer, intent(in) :: i
      +character(len=str_int_len(i)) :: s
      +write(s, '(i0)') i
      +end function
      +
      +!> Returns the length of the string representation of 'i'
      +pure integer function str_int64_len(i) result(sz)
      +integer(int64), intent(in) :: i
      +integer, parameter :: MAX_STR = 100
      +character(MAX_STR) :: s
      +! If 's' is too short (MAX_STR too small), Fortran will abort with:
      +! "Fortran runtime error: End of record"
      +write(s, '(i0)') i
      +sz = len_trim(s)
      +end function
      +
      +!> Converts integer "i" to string
      +pure function str_int64(i) result(s)
      +integer(int64), intent(in) :: i
      +character(len=str_int64_len(i)) :: s
      +write(s, '(i0)') i
      +end function
      +
      +!> Returns the length of the string representation of 'l'
      +pure integer function str_logical_len(l) result(sz)
      +logical, intent(in) :: l
      +if (l) then
      +    sz = 6
      +else
      +    sz = 7
      +end if
      +end function
      +
      +!> Converts logical "l" to string
      +pure function str_logical(l) result(s)
      +logical, intent(in) :: l
      +character(len=str_logical_len(l)) :: s
      +if (l) then
      +    s = ".true."
      +else
      +    s = ".false."
      +end if
      +end function
      +
      +!> Returns string with special characters replaced with an underscore.
      +!! For now, only a hyphen is treated as a special character, but this can be
      +!! expanded to other characters if needed.
      +pure function to_fortran_name(string) result(res)
      +    character(*), intent(in) :: string
      +    character(len(string)) :: res
      +    character, parameter :: SPECIAL_CHARACTERS(*) = ['-']
      +    res = replace(string, SPECIAL_CHARACTERS, '_')
      +end function to_fortran_name
      +
      +elemental function is_fortran_name(line) result (lout)
      +! determine if a string is a valid Fortran name ignoring trailing spaces
      +! (but not leading spaces)
      +    character(len=*),parameter   :: int='0123456789'
      +    character(len=*),parameter   :: lower='abcdefghijklmnopqrstuvwxyz'
      +    character(len=*),parameter   :: upper='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
      +    character(len=*),parameter   :: allowed=upper//lower//int//'_'
      +    character(len=*),intent(in)  :: line
      +    character(len=:),allocatable :: name
      +    logical                      :: lout
      +        name=trim(line)
      +        if(len(name)/=0)then
      +            lout = .true.                                  &
      +             & .and. verify(name(1:1), lower//upper) == 0  &
      +             & .and. verify(name,allowed) == 0             &
      +             & .and. len(name) <= 63
      +        else
      +            lout = .false.
      +        endif
      +end function is_fortran_name
      +
      +!> Check that a module name fits the current naming rules:
      +!> 1) It must be a valid FORTRAN name (<=63 chars, begin with letter, "_" is only allowed non-alphanumeric)
      +!> 2) It must begin with the package name
      +!> 3) If longer, package name must be followed by default separator plus at least one char
      +logical function is_valid_module_name(module_name,package_name,custom_prefix,enforce_module_names) result(valid)
      +
      +    type(string_t), intent(in) :: module_name
      +    type(string_t), intent(in) :: package_name
      +    type(string_t), intent(in) :: custom_prefix
      +    logical       , intent(in) :: enforce_module_names
      +
      +
      +    !> Basic check: check the name is Fortran-compliant
      +    valid = is_fortran_name(module_name%s); if (.not.valid) return
      +
      +    !> FPM package enforcing: check that the module name begins with the package name
      +    if (enforce_module_names) then
      +
      +        ! Default prefixing is always valid
      +        valid = has_valid_standard_prefix(module_name,package_name)
      +
      +        ! If a custom prefix was validated, it provides additional naming options
      +        ! Because they never overlap with the default prefix, the former is always an option
      +        if (len_trim(custom_prefix)>0 .and. .not.valid) &
      +            valid = has_valid_custom_prefix(module_name,custom_prefix)
      +
      +    end if
      +
      +end function is_valid_module_name
      +
      +!> Check that a custom module prefix fits the current naming rules:
      +!> 1) Only alphanumeric characters (no spaces, dashes, underscores or other characters)
      +!> 2) Does not begin with a number (Fortran-compatible syntax)
      +logical function is_valid_module_prefix(module_prefix) result(valid)
      +
      +    type(string_t), intent(in) :: module_prefix
      +
      +    character(len=*),parameter :: num='0123456789'
      +    character(len=*),parameter :: lower='abcdefghijklmnopqrstuvwxyz'
      +    character(len=*),parameter :: upper='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
      +    character(len=*),parameter :: alpha  =upper//lower
      +    character(len=*),parameter :: allowed=alpha//num
      +
      +    character(len=:),allocatable :: name
      +
      +    name = trim(module_prefix%s)
      +
      +    if (len(name)>0 .and. len(name)<=63) then
      +        valid = verify(name(1:1), alpha) == 0 .and. &
      +                verify(name,allowed)     == 0
      +    else
      +        valid = .false.
      +    endif
      +
      +end function is_valid_module_prefix
      +
      +
      +type(string_t) function module_prefix_template(project_name,custom_prefix) result(prefix)
      +    type(string_t), intent(in) :: project_name
      +    type(string_t), intent(in) :: custom_prefix
      +
      +    if (is_valid_module_prefix(custom_prefix)) then
      +
      +        prefix = string_t(trim(custom_prefix%s)//"_")
      +
      +    else
      +
      +        prefix = string_t(to_fortran_name(project_name%s)//"__")
      +
      +    end if
      +
      +end function module_prefix_template
      +
      +type(string_t) function module_prefix_type(project_name,custom_prefix) result(ptype)
      +    type(string_t), intent(in) :: project_name
      +    type(string_t), intent(in) :: custom_prefix
      +
      +    if (is_valid_module_prefix(custom_prefix)) then
      +        ptype = string_t("custom")
      +    else
      +        ptype = string_t("default")
      +    end if
      +
      +end function module_prefix_type
      +
      +!> Check that a module name is prefixed with a custom prefix:
      +!> 1) It must be a valid FORTRAN name subset (<=63 chars, begin with letter, only alphanumeric allowed)
      +!> 2) It must begin with the prefix
      +!> 3) If longer, package name must be followed by default separator ("_") plus at least one char
      +logical function has_valid_custom_prefix(module_name,custom_prefix) result(valid)
      +
      +    type(string_t), intent(in) :: module_name
      +    type(string_t), intent(in) :: custom_prefix
      +
      +    !> custom_module separator: single underscore
      +    character(*), parameter :: SEP = "_"
      +
      +    logical :: is_same,has_separator,same_beginning
      +    integer :: lpkg,lmod,lsep
      +
      +    !> Basic check: check that both names are individually valid
      +    valid = is_fortran_name(module_name%s) .and. &
      +            is_valid_module_prefix(custom_prefix)
      +
      +    !> FPM package enforcing: check that the module name begins with the custom prefix
      +    if (valid) then
      +
      +        !> Query string lengths
      +        lpkg  = len_trim(custom_prefix)
      +        lmod  = len_trim(module_name)
      +        lsep  = len_trim(SEP)
      +
      +        same_beginning = str_begins_with_str(module_name%s,custom_prefix%s,case_sensitive=.false.)
      +
      +        is_same = lpkg==lmod .and. same_beginning
      +
      +        if (lmod>=lpkg+lsep) then
      +           has_separator = str_begins_with_str(module_name%s(lpkg+1:lpkg+lsep),SEP)
      +        else
      +           has_separator = .false.
      +        endif
      +
      +        !> 2) It must begin with the package name.
      +        !> 3) It can be equal to the package name, or, if longer, must be followed by the
      +        !     default separator plus at least one character
      +        !> 4) Package name must not end with an underscore
      +        valid = same_beginning .and. (is_same .or. (lmod>lpkg+lsep .and. has_separator))
      +
      +    end if
      +
      +end function has_valid_custom_prefix
      +
      +
      +!> Check that a module name is prefixed with the default package prefix:
      +!> 1) It must be a valid FORTRAN name (<=63 chars, begin with letter, "_" is only allowed non-alphanumeric)
      +!> 2) It must begin with the package name
      +!> 3) If longer, package name must be followed by default separator plus at least one char
      +logical function has_valid_standard_prefix(module_name,package_name) result(valid)
      +
      +    type(string_t), intent(in) :: module_name
      +    type(string_t), intent(in) :: package_name
      +
      +    !> Default package__module separator: two underscores
      +    character(*), parameter :: SEP = "__"
      +
      +    character(len=:), allocatable :: fortranized_pkg
      +    logical :: is_same,has_separator,same_beginning
      +    integer :: lpkg,lmod,lsep
      +
      +    !> Basic check: check the name is Fortran-compliant
      +    valid = is_fortran_name(module_name%s)
      +
      +    !> FPM package enforcing: check that the module name begins with the package name
      +    if (valid) then
      +
      +        fortranized_pkg = to_fortran_name(package_name%s)
      +
      +        !> Query string lengths
      +        lpkg  = len_trim(fortranized_pkg)
      +        lmod  = len_trim(module_name)
      +        lsep  = len_trim(SEP)
      +
      +        same_beginning = str_begins_with_str(module_name%s,fortranized_pkg,case_sensitive=.false.)
      +
      +        is_same = lpkg==lmod .and. same_beginning
      +
      +        if (lmod>=lpkg+lsep) then
      +           has_separator = str_begins_with_str(module_name%s(lpkg+1:lpkg+lsep),SEP)
      +        else
      +           has_separator = .false.
      +        endif
      +
      +        !> 2) It must begin with the package name.
      +        !> 3) It can be equal to the package name, or, if longer, must be followed by the
      +        !     default separator plus at least one character
      +        !> 4) Package name must not end with an underscore
      +        valid = is_fortran_name(fortranized_pkg) .and. &
      +                fortranized_pkg(lpkg:lpkg)/='_' .and. &
      +                (same_beginning .and. (is_same .or. (lmod>lpkg+lsep .and. has_separator)))
      +
      +    end if
      +
      +end function has_valid_standard_prefix
      +
      +!> Check that two string _objects_ are exactly identical
      +pure logical function string_is_same(this,that)
      +   !> two strings to be compared
      +   type(string_t), intent(in) :: this, that
      +
      +   integer :: i
      +
      +   string_is_same = .false.
      +
      +   if (allocated(this%s).neqv.allocated(that%s)) return
      +   if (allocated(this%s)) then
      +      if (.not.len(this%s)==len(that%s)) return
      +      if (.not.len_trim(this%s)==len_trim(that%s)) return
      +      do i=1,len_trim(this%s)
      +         if (.not.(this%s(i:i)==that%s(i:i))) return
      +      end do
      +   end if
      +
      +   ! All checks passed
      +   string_is_same = .true.
      +
      +end function string_is_same
      +
      +!> Check that two allocatable string _object_ arrays are exactly identical
      +pure logical function string_arrays_same(this,that)
      +   !> two string arrays to be compared
      +   type(string_t), allocatable, intent(in) :: this(:), that(:)
      +
      +   integer :: i
      +
      +   string_arrays_same = .false.
      +
      +   if (allocated(this).neqv.allocated(that)) return
      +   if (allocated(this)) then
      +      if (.not.(size(this)==size(that))) return
      +      if (.not.(ubound(this,1)==ubound(that,1))) return
      +      if (.not.(lbound(this,1)==lbound(that,1))) return
      +      do i=lbound(this,1),ubound(this,1)
      +         if (.not.string_is_same(this(i),that(i))) return
      +      end do
      +   end if
      +
      +   ! All checks passed
      +   string_arrays_same = .true.
      +
      +end function string_arrays_same
      +
      +! Remove all characters from a set from a string
      +subroutine remove_characters_in_set(string,set,replace_with)
      +    character(len=:), allocatable, intent(inout) :: string
      +    character(*), intent(in) :: set
      +    character, optional, intent(in) :: replace_with ! Replace with this character instead of removing
      +
      +    integer :: feed,length
      +
      +    if (.not.allocated(string)) return
      +    if (len(set)<=0) return
      +
      +    length = len(string)
      +    feed   = scan(string,set)
      +
      +    do while (length>0 .and. feed>0)
      +
      +        ! Remove heading
      +        if (length==1) then
      +            string = ""
      +
      +        elseif (feed==1) then
      +            string = string(2:length)
      +
      +        ! Remove trailing
      +        elseif (feed==length) then
      +            string = string(1:length-1)
      +
      +        ! In between: replace with given character
      +        elseif (present(replace_with)) then
      +            string(feed:feed) = replace_with
      +        ! Or just remove
      +        else
      +            string = string(1:feed-1)//string(feed+1:length)
      +        end if
      +
      +        length = len(string)
      +        feed   = scan(string,set)
      +
      +    end do
      +
      +end subroutine remove_characters_in_set
      +
      +! Remove all new line characters from the current string, replace them with spaces
      +subroutine remove_newline_characters(string)
      +    type(string_t), intent(inout) :: string
      +
      +    integer :: feed,length
      +
      +    character(*), parameter :: CRLF  = achar(13)//new_line('a')
      +    character(*), parameter :: SPACE = ' '
      +
      +    call remove_characters_in_set(string%s,set=CRLF,replace_with=SPACE)
      +
      +end subroutine remove_newline_characters
      +
      +!>AUTHOR: John S. Urban
      +!!LICENSE: Public Domain
      +!>
      +!!### NAME
      +!!   notabs(3f) - [fpm_strings:NONALPHA] expand tab characters
      +!!   (LICENSE:PD)
      +!!
      +!!### SYNOPSIS
      +!!
      +!!    subroutine notabs(INSTR,OUTSTR,ILEN)
      +!!
      +!!     character(len=*),intent=(in)  :: INSTR
      +!!     character(len=*),intent=(out) :: OUTSTR
      +!!     integer,intent=(out)          :: ILEN
      +!!
      +!!### DESCRIPTION
      +!!   NOTABS() converts tabs in INSTR to spaces in OUTSTR while maintaining
      +!!   columns. It assumes a tab is set every 8 characters. Trailing spaces
      +!!   are removed.
      +!!
      +!!   In addition, trailing carriage returns and line feeds are removed
      +!!   (they are usually a problem created by going to and from MSWindows).
      +!!
      +!!   What are some reasons for removing tab characters from an input line?
      +!!   Some Fortran compilers have problems with tabs, as tabs are not
      +!!   part of the Fortran character set. Some editors and printers will
      +!!   have problems with tabs. It is often useful to expand tabs in input
      +!!   files to simplify further processing such as tokenizing an input line.
      +!!
      +!!### OPTIONS
      +!!     instr     Input line to remove tabs from
      +!!
      +!!### RESULTS
      +!!     outstr    Output string with tabs expanded. Assumed to be of sufficient
      +!!               length
      +!!     ilen      Significant length of returned string
      +!!
      +!!### EXAMPLES
      +!!
      +!!   Sample program:
      +!!
      +!!    program demo_notabs
      +!!
      +!!    !  test filter to remove tabs and trailing white space from input
      +!!    !  on files up to 1024 characters wide
      +!!    use fpm_strings, only : notabs
      +!!    character(len=1024) :: in,out
      +!!    integer             :: ios,iout
      +!!       do
      +!!          read(*,'(A)',iostat=ios)in
      +!!          if(ios /= 0) exit
      +!!          call notabs(in,out,iout)
      +!!          write(*,'(a)')out(:iout)
      +!!       enddo
      +!!    end program demo_notabs
      +!!
      +!!### SEE ALSO
      +!!   GNU/Unix commands expand(1) and unexpand(1)
      +!!
      +elemental impure subroutine notabs(instr,outstr,ilen)
      +
      +! ident_31="@(#)fpm_strings::notabs(3f): convert tabs to spaces while maintaining columns, remove CRLF chars"
      +
      +character(len=*),intent(in)   :: instr        ! input line to scan for tab characters
      +character(len=*),intent(out)  :: outstr       ! tab-expanded version of INSTR produced
      +integer,intent(out)           :: ilen         ! column position of last character put into output string
      +                                              ! that is, ILEN holds the position of the last non-blank character in OUTSTR
      +
      +integer,parameter             :: tabsize=8    ! assume a tab stop is set every 8th column
      +integer                       :: ipos         ! position in OUTSTR to put next character of INSTR
      +integer                       :: lenin        ! length of input string trimmed of trailing spaces
      +integer                       :: lenout       ! number of characters output string can hold
      +integer                       :: istep        ! counter that advances thru input string INSTR one character at a time
      +character(len=1)              :: c            ! character in input line being processed
      +integer                       :: iade         ! ADE (ASCII Decimal Equivalent) of character being tested
      +
      +   ipos=1                                     ! where to put next character in output string OUTSTR
      +   lenin=len_trim(instr( 1:len(instr) ))      ! length of INSTR trimmed of trailing spaces
      +   lenout=len(outstr)                         ! number of characters output string OUTSTR can hold
      +   outstr=" "                                 ! this SHOULD blank-fill string, a buggy machine required a loop to set all characters
      +
      +      SCAN_LINE: do istep=1,lenin             ! look through input string one character at a time
      +         c=instr(istep:istep)                 ! get next character
      +         iade=ichar(c)                        ! get ADE of the character
      +         EXPAND_TABS : select case (iade)     ! take different actions depending on which character was found
      +         case(9)                              ! test if character is a tab and move pointer out to appropriate column
      +            ipos = ipos + (tabsize - (mod(ipos-1,tabsize)))
      +         case(10,13)                          ! convert carriage-return and new-line to space ,typically to handle DOS-format files
      +            ipos=ipos+1
      +         case default                         ! c is anything else other than a tab,newline,or return  insert it in output string
      +            if(ipos > lenout)then
      +               write(stderr,*)"*notabs* output string overflow"
      +               exit
      +            else
      +               outstr(ipos:ipos)=c
      +               ipos=ipos+1
      +            endif
      +         end select EXPAND_TABS
      +      enddo SCAN_LINE
      +
      +      ipos=min(ipos,lenout)                   ! tabs or newline or return characters or last character might have gone too far
      +      ilen=len_trim(outstr(:ipos))            ! trim trailing spaces
      +
      +end subroutine notabs
      +
      +!>AUTHOR: John S. Urban
      +!!LICENSE: Public Domain
      +!>
      +!!##NAME
      +!!    dilate(3f) - [M_strings:NONALPHA] expand tab characters
      +!!    (LICENSE:PD)
      +!!
      +!!##SYNOPSIS
      +!!
      +!!    function dilate(INSTR) result(OUTSTR)
      +!!
      +!!     character(len=*),intent=(in)  :: INSTR
      +!!     character(len=:),allocatable  :: OUTSTR
      +!!
      +!!##DESCRIPTION
      +!!     dilate() converts tabs in INSTR to spaces in OUTSTR.  It assumes a
      +!!     tab is set every 8 characters. Trailing spaces are removed.
      +!!
      +!!     In addition, trailing carriage returns and line feeds are removed
      +!!     (they are usually a problem created by going to and from MSWindows).
      +!!
      +!!##OPTIONS
      +!!     instr     Input line to remove tabs from
      +!!
      +!!##RESULTS
      +!!     outstr    Output string with tabs expanded.
      +!!
      +!!##EXAMPLES
      +!!
      +!!   Sample program:
      +!!
      +!!    program demo_dilate
      +!!
      +!!    use M_strings, only : dilate
      +!!    implicit none
      +!!    character(len=:),allocatable :: in
      +!!    integer                      :: i
      +!!       in='  this is my string  '
      +!!       ! change spaces to tabs to make a sample input
      +!!       do i=1,len(in)
      +!!          if(in(i:i) == ' ')in(i:i)=char(9)
      +!!       enddo
      +!!       write(*,'(a)')in,dilate(in)
      +!!    end program demo_dilate
      +!!
      +function dilate(instr) result(outstr)
      +
      +   character(len=*), intent(in)  :: instr        ! input line to scan for tab characters
      +   character(len=:), allocatable :: outstr       ! tab-expanded version of INSTR produced
      +   integer                       :: i
      +   integer                       :: icount
      +   integer                       :: lgth
      +   icount = 0
      +   do i = 1, len(instr)
      +      if (instr(i:i) == char(9)) icount = icount + 1
      +   end do
      +   allocate (character(len=(len(instr) + 8*icount)) :: outstr)
      +   call notabs(instr, outstr, lgth)
      +   outstr = outstr(:lgth)
      +
      +end function dilate
      +
      +end module fpm_strings
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/fpm_targets.f90.html b/sourcefile/fpm_targets.f90.html new file mode 100644 index 0000000000..1dcf175438 --- /dev/null +++ b/sourcefile/fpm_targets.f90.html @@ -0,0 +1,1685 @@ + + + + + + + + + + + + + fpm_targets.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      fpm_targets.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      !># Build target handling
      +!>
      +!> This module handles the construction of the build target list
      +!> from the sources list (`[[targets_from_sources]]`), the
      +!> resolution of module-dependencies between build targets
      +!> (`[[resolve_module_dependencies]]`), and the enumeration of
      +!> objects required for link targets (`[[resolve_target_linking]]`).
      +!>
      +!> A build target (`[[build_target_t]]`) is a file to be generated
      +!> by the backend (compilation and linking).
      +!>
      +!> @note The current implementation is ignorant to the existence of
      +!> module files (`.mod`,`.smod`). Dependencies arising from modules
      +!> are based on the corresponding object files (`.o`) only.
      +!>
      +!> For more information, please read the documentation for the procedures:
      +!>
      +!> - `[[build_target_list]]`
      +!> - `[[resolve_module_dependencies]]`
      +!>
      +!>### Enumerations
      +!>
      +!> __Target type:__ `FPM_TARGET_*`
      +!> Describes the type of build target — determines backend build rules
      +!>
      +module fpm_targets
      +use iso_fortran_env, only: int64, stdout=>output_unit
      +use fpm_error, only: error_t, fatal_error, fpm_stop
      +use fpm_model
      +use fpm_compiler, only : compiler_t
      +use fpm_environment, only: get_os_type, OS_WINDOWS, OS_MACOS, library_filename
      +use fpm_filesystem, only: dirname, join_path, canon_path
      +use fpm_strings, only: string_t, operator(.in.), string_cat, fnv_1a, resize, lower, str_ends_with
      +use fpm_compiler, only: get_macros
      +use fpm_sources, only: get_exe_name_with_suffix
      +use fpm_manifest_library, only: library_config_t
      +use fpm_manifest_preprocess, only: preprocess_config_t
      +implicit none
      +
      +private
      +
      +public FPM_TARGET_UNKNOWN,  FPM_TARGET_EXECUTABLE, &
      +       FPM_TARGET_ARCHIVE,  FPM_TARGET_OBJECT, &
      +       FPM_TARGET_C_OBJECT, FPM_TARGET_CPP_OBJECT, &
      +       FPM_TARGET_SHARED,   FPM_TARGET_NAME
      +public build_target_t, build_target_ptr
      +public targets_from_sources, resolve_module_dependencies
      +public add_target, new_target, add_dependency, get_library_dirs
      +public filter_library_targets, filter_executable_targets, filter_modules
      +
      +
      +
      +!> Target type is unknown (ignored)
      +integer, parameter :: FPM_TARGET_UNKNOWN = -1
      +!> Target type is executable
      +integer, parameter :: FPM_TARGET_EXECUTABLE = 1
      +!> Target type is library archive
      +integer, parameter :: FPM_TARGET_ARCHIVE = 2
      +!> Target type is compiled object
      +integer, parameter :: FPM_TARGET_OBJECT = 3
      +!> Target type is c compiled object
      +integer, parameter :: FPM_TARGET_C_OBJECT = 4
      +!> Target type is cpp compiled object
      +integer, parameter :: FPM_TARGET_CPP_OBJECT = 5
      +!> Target type is a shared library
      +integer, parameter :: FPM_TARGET_SHARED = 6
      +
      +!> Wrapper type for constructing arrays of `[[build_target_t]]` pointers
      +type build_target_ptr
      +
      +    type(build_target_t), pointer :: ptr => null()
      +
      +end type build_target_ptr
      +
      +
      +!> Type describing a generated build target
      +type build_target_t
      +
      +    !> File path of build target object relative to cwd
      +    character(:), allocatable :: output_file
      +
      +    !> File path of build target object relative to output_dir
      +    character(:), allocatable :: output_name
      +
      +    !> File path of output directory
      +    character(:), allocatable :: output_dir
      +
      +    !> File path of build log file relative to cwd
      +    character(:), allocatable :: output_log_file
      +
      +    !> Name of parent package
      +    character(:), allocatable :: package_name
      +
      +    !> Primary source for this build target
      +    type(srcfile_t), allocatable :: source
      +
      +    !> Resolved build dependencies
      +    type(build_target_ptr), allocatable :: dependencies(:)
      +
      +    !> Target type
      +    integer :: target_type = FPM_TARGET_UNKNOWN
      +
      +    !> Native libraries to link against
      +    type(string_t), allocatable :: link_libraries(:)
      +
      +    !> Objects needed to link this target
      +    type(string_t), allocatable :: link_objects(:)
      +
      +    !> Link flags for this build target
      +    character(:), allocatable :: link_flags
      +
      +    !> Compile flags for this build target
      +    character(:), allocatable :: compile_flags
      +
      +    !> Flag set when first visited to check for circular dependencies
      +    logical :: touched = .false.
      +
      +    !> Flag set if build target is sorted for building
      +    logical :: sorted = .false.
      +
      +    !> Flag set if build target will be skipped (not built)
      +    logical :: skip = .false.
      +
      +    !> Language features
      +    type(fortran_features_t) :: features
      +
      +    !> Targets in the same schedule group are guaranteed to be independent
      +    integer :: schedule = -1
      +
      +    !> Previous source file hash
      +    integer(int64), allocatable :: digest_cached
      +
      +    !> List of macros
      +    type(string_t), allocatable :: macros(:)
      +
      +    !> Version number
      +    character(:), allocatable :: version
      +    
      +    contains
      +    
      +        !> Print information on this instance
      +        procedure :: info    
      +        
      +        !> Set output directory
      +        procedure :: set_output_dir
      +         
      +        procedure :: is_executable_target
      +
      +end type build_target_t
      +
      +interface add_target
      +    module procedure add_new_target
      +    module procedure add_old_target
      +    module procedure add_old_targets
      +end interface
      +
      +contains
      +
      +!> Target type name
      +pure function FPM_TARGET_NAME(type) result(msg)
      +   integer, intent(in) :: type
      +   character(:), allocatable :: msg
      +
      +   select case (type)
      +      case (FPM_TARGET_ARCHIVE);    msg = 'Archive'
      +      case (FPM_TARGET_SHARED);     msg = 'Shared library'
      +      case (FPM_TARGET_CPP_OBJECT); msg = 'C++ object'
      +      case (FPM_TARGET_C_OBJECT);   msg = 'C Object'
      +      case (FPM_TARGET_EXECUTABLE); msg = 'Executable'
      +      case (FPM_TARGET_OBJECT);     msg = 'Object'      
      +      case default;                 msg = 'Unknown'
      +   end select
      +
      +end function FPM_TARGET_NAME
      +
      +!> Write information on a build target
      +subroutine info(self, unit, verbosity)
      +    class(build_target_t), intent(in) :: self
      +    integer, intent(in) :: unit
      +    integer, intent(in), optional :: verbosity
      +
      +    integer :: pr
      +    character(len=*), parameter :: fmt = '("#", 1x, a, t30, a)'
      +    character(len=*), parameter :: fmt_list = '("#", 1x, a, t30, a, " (", i0, " items)")'
      +
      +    if (present(verbosity)) then
      +        pr = verbosity
      +    else
      +        pr = 1
      +    end if
      +    if (pr < 1) return
      +
      +    write(unit, fmt) "Build target"
      +    write(unit, fmt) "- output file",        self%output_file
      +    write(unit, fmt) "- output name",        self%output_name
      +    write(unit, fmt) "- output directory",   self%output_dir
      +    write(unit, fmt) "- log file",           self%output_log_file
      +    write(unit, fmt) "- package",            self%package_name
      +    write(unit, fmt) "- type",               FPM_TARGET_NAME(self%target_type)
      +
      +    if (allocated(self%source)) then
      +        write(unit, fmt) "- source file", self%source%file_name
      +    end if
      +
      +    if (allocated(self%dependencies)) then
      +        write(unit, fmt_list) "- dependencies", "", size(self%dependencies)
      +    end if
      +
      +    if (allocated(self%link_objects)) then
      +        write(unit, fmt_list) "- link objects", "", size(self%link_objects)
      +    end if
      +
      +    if (allocated(self%link_libraries)) then
      +        write(unit, fmt_list) "- link libraries", "", size(self%link_libraries)
      +    end if
      +
      +    if (allocated(self%compile_flags)) then
      +        write(unit, fmt) "- compile flags", self%compile_flags
      +    end if
      +
      +    if (allocated(self%link_flags)) then
      +        write(unit, fmt) "- link flags", self%link_flags
      +    end if
      +
      +    if (allocated(self%version)) then
      +        write(unit, fmt) "- version", self%version
      +    end if
      +
      +    if (allocated(self%macros)) then
      +        write(unit, fmt_list) "- macros", "", size(self%macros)
      +    end if
      +
      +    write(unit, fmt) "- skip", merge("yes", "no ", self%skip)
      +    write(unit, fmt) "- schedule", trim(adjustl(to_string(self%schedule)))
      +
      +contains
      +
      +    pure function to_string(i) result(s)
      +        integer, intent(in) :: i
      +        character(len=32) :: s
      +        write(s, '(i0)') i
      +    end function to_string
      +
      +end subroutine info
      +
      +!> High-level wrapper to generate build target information
      +subroutine targets_from_sources(targets,model,prune,library,error)
      +
      +    !> The generated list of build targets
      +    type(build_target_ptr), intent(out), allocatable :: targets(:)
      +
      +    !> The package model from which to construct the target list
      +    type(fpm_model_t), intent(inout), target :: model
      +    
      +    !> Library build configuration
      +    type(library_config_t), intent(in), optional :: library
      +
      +    !> Enable tree-shaking/pruning of module dependencies
      +    logical, intent(in) :: prune
      +
      +    !> Error structure
      +    type(error_t), intent(out), allocatable :: error
      +    
      +    logical :: should_prune
      +
      +    call build_target_list(targets,model,library)
      +
      +    call collect_exe_link_dependencies(targets)
      +
      +    call resolve_module_dependencies(targets,model%external_modules,error)
      +    if (allocated(error)) return
      +
      +    ! Prune unused source files, unless we're building shared libraries that need 
      +    ! all sources to be distributable
      +    should_prune = prune
      +    if (present(library)) should_prune = should_prune .and. library%monolithic()
      +        
      +    call prune_build_targets(targets,model%packages(1),should_prune)
      +
      +    call resolve_target_linking(targets,model,library,error)
      +    if (allocated(error)) return
      +
      +end subroutine targets_from_sources
      +
      +
      +!> Constructs a list of build targets from a list of source files
      +!>
      +!>### Source-target mapping
      +!>
      +!> One compiled object target (`FPM_TARGET_OBJECT`) is generated for each
      +!> non-executable source file (`FPM_UNIT_MODULE`,`FPM_UNIT_SUBMODULE`,
      +!>  `FPM_UNIT_SUBPROGRAM`,`FPM_UNIT_CSOURCE`).
      +!>
      +!> If any source file has scope `FPM_SCOPE_LIB` (*i.e.* there are library sources)
      +!> then the first target in the target list will be a library archive target
      +!> (`FPM_TARGET_ARCHIVE`). The archive target will have a dependency on every
      +!> compiled object target corresponding to a library source file.
      +!>
      +!> One compiled object target (`FPM_TARGET_OBJECT`) and one executable target (`FPM_TARGET_EXECUTABLE`) is
      +!> generated for each exectuable source file (`FPM_UNIT_PROGRAM`). The exectuble target
      +!> always has a dependency on the corresponding compiled object target. If there
      +!> is a library, then the executable target has an additional dependency on the library
      +!> archive target.
      +!>
      +subroutine build_target_list(targets,model,library)
      +
      +    !> The generated list of build targets
      +    type(build_target_ptr), intent(out), allocatable :: targets(:)
      +
      +    !> The package model from which to construct the target list
      +    type(fpm_model_t), intent(inout), target :: model
      +    
      +    !> The optional model library configuration
      +    type(library_config_t), optional, intent(in) :: library
      +
      +    integer :: i, j, k, n_source, exe_type
      +    character(:), allocatable :: exe_dir, compile_flags, lib_name
      +    logical :: with_lib, monolithic, shared_lib, static_lib
      +
      +    ! Initialize targets
      +    allocate(targets(0))
      +
      +    ! Check for empty build (e.g. header-only lib)
      +    n_source = sum([(size(model%packages(j)%sources), &
      +                      j=1,size(model%packages))])
      +
      +    if (n_source < 1) return
      +
      +    with_lib = any(model%packages%has_library())
      +    
      +    if (with_lib .and. present(library)) then 
      +        shared_lib = library%shared()
      +        static_lib = library%static()
      +        monolithic = library%monolithic()
      +    else
      +        monolithic = with_lib
      +        shared_lib = .false.
      +        static_lib = .false.            
      +    end if
      +
      +    ! For a static object archive, everything from this package or all its dependencies is 
      +    ! put into the same file. For a shared library configuration, each package has its own 
      +    ! dynamic library file to avoid dependency collisions
      +    if (monolithic) then 
      +        
      +        lib_name = join_path(model%package_name, &
      +                             library_filename(model%packages(1)%name,.false.,.false.,get_os_type()))
      +        
      +        call add_target(targets,package=model%package_name, &
      +                        type = FPM_TARGET_ARCHIVE,output_name = lib_name)
      +                            
      +    elseif (shared_lib .or. static_lib) then 
      +        
      +        ! Individual package libraries are built. 
      +        ! Create as many targets as the packages in the dependency tree
      +        do j=1,size(model%packages)
      +                        
      +            lib_name = library_filename(model%packages(j)%name,shared_lib,.false.,get_os_type())
      +            
      +            call add_target(targets,package=model%packages(j)%name, &
      +                            type=merge(FPM_TARGET_SHARED,FPM_TARGET_ARCHIVE,shared_lib), &
      +                            output_name=lib_name)
      +        end do
      +        
      +    endif
      +    
      +    do j=1,size(model%packages)
      +
      +        associate(sources=>model%packages(j)%sources)
      +
      +            do i=1,size(sources)
      +
      +                if (.not. model%include_tests) then
      +                    if (sources(i)%unit_scope == FPM_SCOPE_TEST) cycle
      +                end if
      +
      +                select case (sources(i)%unit_type)
      +                case (FPM_UNIT_MODULE,FPM_UNIT_SUBMODULE,FPM_UNIT_SUBPROGRAM,FPM_UNIT_CSOURCE)
      +                    
      +                    call add_target(targets,package=model%packages(j)%name,source = sources(i), &
      +                                type = merge(FPM_TARGET_C_OBJECT,FPM_TARGET_OBJECT,&
      +                                               sources(i)%unit_type==FPM_UNIT_CSOURCE), &
      +                                output_name = get_object_name(sources(i)), &
      +                                features    = model%packages(j)%features, &
      +                                preprocess  = model%packages(j)%preprocess, &
      +                                version = model%packages(j)%version)
      +
      +
      +                    if (with_lib .and. sources(i)%unit_scope == FPM_SCOPE_LIB) then
      +                        ! Archive depends on object
      +                        call add_dependency(targets(merge(1,j,monolithic))%ptr, targets(size(targets))%ptr)
      +                    end if
      +
      +                case (FPM_UNIT_CPPSOURCE)
      +
      +                    call add_target(targets,package=model%packages(j)%name,source = sources(i), &
      +                                type = FPM_TARGET_CPP_OBJECT, &
      +                                output_name = get_object_name(sources(i)), &
      +                                preprocess = model%packages(j)%preprocess, &
      +                                version = model%packages(j)%version)
      +
      +                    if (with_lib .and. sources(i)%unit_scope == FPM_SCOPE_LIB) then
      +                        ! Archive depends on object
      +                        call add_dependency(targets(merge(1,j,monolithic))%ptr, targets(size(targets))%ptr)
      +                    end if
      +
      +                    !> Add stdc++ as a linker flag. If not already there.
      +                    if (.not. ("stdc++" .in. model%link_libraries)) then
      +
      +                        if (get_os_type() == OS_MACOS) then
      +                            model%link_libraries = [model%link_libraries, string_t("c++")]
      +                        else
      +                            model%link_libraries = [model%link_libraries, string_t("stdc++")]
      +                        end if
      +
      +                    end if
      +
      +                case (FPM_UNIT_PROGRAM)
      +
      +                    if (str_ends_with(lower(sources(i)%file_name), [".c"])) then
      +                        exe_type = FPM_TARGET_C_OBJECT
      +                    else if (str_ends_with(lower(sources(i)%file_name), [".cpp", ".cc "])) then
      +                        exe_type = FPM_TARGET_CPP_OBJECT
      +                    else    ! Default to a Fortran object
      +                        exe_type = FPM_TARGET_OBJECT
      +                    end if
      +
      +                    call add_target(targets,package=model%packages(j)%name,type = exe_type,&
      +                                output_name = get_object_name(sources(i)), &
      +                                source = sources(i), &
      +                                features = model%packages(j)%features, &
      +                                preprocess = model%packages(j)%preprocess &
      +                                )
      +
      +                    if (sources(i)%unit_scope == FPM_SCOPE_APP) then
      +
      +                        exe_dir = 'app'
      +
      +                    else if (sources(i)%unit_scope == FPM_SCOPE_EXAMPLE) then
      +
      +                        exe_dir = 'example'
      +
      +                    else
      +
      +                        exe_dir = 'test'
      +
      +                    end if
      +
      +                    call add_target(targets,package=model%packages(j)%name,type = FPM_TARGET_EXECUTABLE,&
      +                                    link_libraries = sources(i)%link_libraries, &
      +                                    output_name = join_path(exe_dir,get_exe_name_with_suffix(sources(i))))
      +
      +                    associate(target => targets(size(targets))%ptr)
      +
      +                    ! Linker-only flags are necessary on some compilers for codes with non-Fortran main
      +                    select case (exe_type)
      +                       case (FPM_TARGET_C_OBJECT)
      +                            call model%compiler%get_main_flags("c",compile_flags)
      +                       case (FPM_TARGET_CPP_OBJECT)
      +                            call model%compiler%get_main_flags("c++",compile_flags)
      +                       case default
      +                            compile_flags = ""
      +                    end select
      +                    target%compile_flags = target%compile_flags//' '//compile_flags
      +
      +                    ! Executable depends on object
      +                    call add_dependency(target, targets(size(targets)-1)%ptr)
      +
      +                    if (with_lib) then
      +                        ! Executable depends on library file(s)
      +                        do k=1,merge(1,size(model%packages),monolithic)
      +                           call add_dependency(target, targets(k)%ptr)
      +                        end do
      +                    end if
      +
      +                    endassociate
      +
      +                end select
      +
      +            end do
      +
      +        end associate
      +
      +    end do
      +
      +    contains
      +
      +    function get_object_name(source) result(object_file)
      +        ! Generate object target path from source name and model params
      +        !
      +        !
      +        type(srcfile_t), intent(in) :: source
      +        character(:), allocatable :: object_file
      +
      +        integer :: i
      +        character(1), parameter :: filesep = '/'
      +
      +        object_file = canon_path(source%file_name)
      +
      +        ! Convert any remaining directory separators to underscores
      +        i = index(object_file,filesep)
      +        do while(i > 0)
      +            object_file(i:i) = '_'
      +            i = index(object_file,filesep)
      +        end do
      +
      +        object_file = join_path(model%package_name,object_file)//'.o'
      +
      +    end function get_object_name
      +
      +end subroutine build_target_list
      +
      +
      +!> Add non-library non-module dependencies for executable targets
      +!>
      +!>  Executable targets will link to any non-program non-module source files that
      +!>   are in the same directory or in a subdirectory.
      +!>
      +!>  (Note: Fortran module dependencies are handled separately in
      +!>    `resolve_module_dependencies` and `resolve_target_linking`.)
      +!>
      +subroutine collect_exe_link_dependencies(targets)
      +    type(build_target_ptr), intent(inout) :: targets(:)
      +
      +    integer :: i, j
      +    character(:), allocatable :: exe_source_dir
      +
      +    ! Add non-module dependencies for executables
      +    do j=1,size(targets)
      +
      +        if (targets(j)%ptr%target_type == FPM_TARGET_EXECUTABLE) then
      +
      +            do i=1,size(targets)
      +
      +                if (i == j) cycle
      +
      +                associate(exe => targets(j)%ptr, dep => targets(i)%ptr)
      +
      +                    exe_source_dir = dirname(exe%dependencies(1)%ptr%source%file_name)
      +
      +                    if (allocated(dep%source)) then
      +
      +                        if (dep%source%unit_scope /= FPM_SCOPE_LIB .and. &
      +                            dep%source%unit_type /= FPM_UNIT_PROGRAM .and. &
      +                            dep%source%unit_type /= FPM_UNIT_MODULE .and. &
      +                            index(dirname(dep%source%file_name), exe_source_dir) == 1) then
      +
      +                            call add_dependency(exe, dep)
      +
      +                        end if
      +
      +                    end if
      +
      +                end associate
      +
      +            end do
      +
      +        end if
      +
      +    end do
      +
      +end subroutine collect_exe_link_dependencies
      +
      +!> Allocate a new target 
      +type(build_target_ptr) function new_target(package, type, output_name, source, link_libraries, &
      +        & features, preprocess, version, output_dir)
      +    character(*), intent(in) :: package
      +    integer, intent(in) :: type
      +    character(*), intent(in) :: output_name
      +    type(srcfile_t), intent(in), optional :: source
      +    type(string_t), intent(in), optional :: link_libraries(:)
      +    type(fortran_features_t), intent(in), optional :: features
      +    type(preprocess_config_t), intent(in), optional :: preprocess
      +    character(*), intent(in), optional :: version
      +    character(*), intent(in), optional :: output_dir
      +
      +    allocate(new_target%ptr)
      +    
      +    associate(target=>new_target%ptr)
      +    
      +        target%target_type = type
      +        target%output_name = output_name
      +        target%package_name = package
      +        if (present(source)) target%source = source
      +        if (present(link_libraries)) target%link_libraries = link_libraries
      +        if (present(features)) target%features = features
      +        if (present(preprocess)) then
      +            if (allocated(preprocess%macros)) target%macros = preprocess%macros
      +        endif
      +        if (present(version)) target%version = version
      +        allocate(target%dependencies(0))
      +        
      +        call target%set_output_dir(output_dir)
      +    
      +    endassociate
      +    
      +end function new_target
      +
      +!> Allocate a new target and append to target list
      +subroutine add_new_target(targets, package, type, output_name, source, link_libraries, &
      +        & features, preprocess, version, output_dir)
      +    type(build_target_ptr), allocatable, intent(inout) :: targets(:)
      +    character(*), intent(in) :: package
      +    integer, intent(in) :: type
      +    character(*), intent(in) :: output_name
      +    type(srcfile_t), intent(in), optional :: source
      +    type(string_t), intent(in), optional :: link_libraries(:)
      +    type(fortran_features_t), intent(in), optional :: features
      +    type(preprocess_config_t), intent(in), optional :: preprocess
      +    character(*), intent(in), optional :: version
      +    character(*), intent(in), optional :: output_dir
      +
      +    type(build_target_ptr) :: added
      +
      +    if (.not.allocated(targets)) allocate(targets(0))
      +    
      +    ! Create new target 
      +    added = new_target(package,type,output_name,source,link_libraries,features,preprocess,&
      +                     version,output_dir)
      +
      +    call add_old_target(targets, added)
      +
      +end subroutine add_new_target
      +
      +subroutine add_old_targets(targets, add_targets)
      +    type(build_target_ptr), allocatable, intent(inout) :: targets(:)
      +    type(build_target_ptr), intent(in) :: add_targets(:)
      +
      +    integer :: i,j
      +
      +    if (.not.allocated(targets)) allocate(targets(0))
      +    
      +    ! Check for duplicate outputs
      +    do j=1,size(add_targets)
      +        associate(added=>add_targets(j)%ptr)
      +
      +        do i=1,size(targets)
      +
      +            if (targets(i)%ptr%output_name == added%output_name) then
      +
      +                write(*,*) 'Error while building target list: duplicate output object "',&
      +                            added%output_name,'"'
      +                if (allocated(added%source)) write(*,*) ' Source file: "',added%source%file_name,'"'
      +                call fpm_stop(1,' ')
      +
      +            end if
      +
      +        end do
      +        
      +        endassociate
      +    end do
      +    
      +    targets = [targets, add_targets ]
      +
      +end subroutine add_old_targets
      +
      +subroutine add_old_target(targets, add_target)
      +    type(build_target_ptr), allocatable, intent(inout) :: targets(:)
      +    type(build_target_ptr), intent(in) :: add_target
      +    call add_old_targets(targets, [add_target])
      +end subroutine add_old_target
      +
      +!> Add pointer to dependeny in target%dependencies
      +subroutine add_dependency(target, dependency)
      +    type(build_target_t), intent(inout) :: target
      +    type(build_target_t) , intent(in), target :: dependency
      +
      +    target%dependencies = [target%dependencies, build_target_ptr(dependency)]
      +
      +end subroutine add_dependency
      +
      +
      +!> Add dependencies to source-based targets (`FPM_TARGET_OBJECT`)
      +!> based on any modules used by the corresponding source file.
      +!>
      +!>### Source file scoping
      +!>
      +!> Source files are assigned a scope of either `FPM_SCOPE_LIB`,
      +!> `FPM_SCOPE_APP` or `FPM_SCOPE_TEST`. The scope controls which
      +!> modules may be used by the source file:
      +!>
      +!> - Library sources (`FPM_SCOPE_LIB`) may only use modules
      +!>   also with library scope. This includes library modules
      +!>   from dependencies.
      +!>
      +!> - Executable sources (`FPM_SCOPE_APP`,`FPM_SCOPE_TEST`) may use
      +!>   library modules (including dependencies) as well as any modules
      +!>   corresponding to source files in the same directory or a
      +!>   subdirectory of the executable source file.
      +!>
      +!> @warning If a module used by a source file cannot be resolved to
      +!> a source file in the package of the correct scope, then a __fatal error__
      +!> is returned by the procedure and model construction fails.
      +!>
      +subroutine resolve_module_dependencies(targets,external_modules,error)
      +    type(build_target_ptr), intent(inout), target :: targets(:)
      +    type(string_t), intent(in) :: external_modules(:)
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    type(build_target_ptr) :: dep
      +
      +    integer :: i, j
      +
      +    do i=1,size(targets)
      +
      +        if (.not.allocated(targets(i)%ptr%source)) cycle
      +
      +            do j=1,size(targets(i)%ptr%source%modules_used)
      +
      +                if (targets(i)%ptr%source%modules_used(j)%s .in. targets(i)%ptr%source%modules_provided) then
      +                    ! Dependency satisfied in same file, skip
      +                    cycle
      +                end if
      +
      +                if (targets(i)%ptr%source%modules_used(j)%s .in. external_modules) then
      +                    ! Dependency satisfied in system-installed module
      +                    cycle
      +                end if
      +
      +                if (any(targets(i)%ptr%source%unit_scope == &
      +                    [FPM_SCOPE_APP, FPM_SCOPE_EXAMPLE, FPM_SCOPE_TEST])) then
      +                    dep%ptr => &
      +                        find_module_dependency(targets,targets(i)%ptr%source%modules_used(j)%s, &
      +                                            include_dir = dirname(targets(i)%ptr%source%file_name))
      +                else
      +                    dep%ptr => &
      +                        find_module_dependency(targets,targets(i)%ptr%source%modules_used(j)%s)
      +                end if
      +
      +                if (.not.associated(dep%ptr)) then
      +                    call fatal_error(error, &
      +                            'Unable to find source for module dependency: "' // &
      +                            targets(i)%ptr%source%modules_used(j)%s // &
      +                            '" used by "'//targets(i)%ptr%source%file_name//'"')
      +                    return
      +                end if
      +
      +                call add_dependency(targets(i)%ptr, dep%ptr)
      +
      +            end do
      +
      +    end do
      +
      +end subroutine resolve_module_dependencies
      +
      +function find_module_dependency(targets,module_name,include_dir) result(target_ptr)
      +    ! Find a module dependency in the library or a dependency library
      +    !
      +    ! 'include_dir' specifies an allowable non-library search directory
      +    !   (Used for executable dependencies)
      +    !
      +    type(build_target_ptr), intent(in), target :: targets(:)
      +    character(*), intent(in) :: module_name
      +    character(*), intent(in), optional :: include_dir
      +    type(build_target_t), pointer :: target_ptr
      +
      +    integer :: k, l
      +
      +    target_ptr => NULL()
      +
      +    do k=1,size(targets)
      +
      +        if (.not.allocated(targets(k)%ptr%source)) cycle
      +
      +        do l=1,size(targets(k)%ptr%source%modules_provided)
      +
      +            if (module_name == targets(k)%ptr%source%modules_provided(l)%s) then
      +                select case(targets(k)%ptr%source%unit_scope)
      +                case (FPM_SCOPE_LIB, FPM_SCOPE_DEP)
      +                    target_ptr => targets(k)%ptr
      +                    exit
      +                case default
      +                    if (present(include_dir)) then
      +                        if (index(dirname(targets(k)%ptr%source%file_name), include_dir) == 1) then ! source file is within the include_dir or a subdirectory
      +                            target_ptr => targets(k)%ptr
      +                            exit
      +                        end if
      +                    end if
      +                end select
      +            end if
      +
      +        end do
      +
      +    end do
      +
      +end function find_module_dependency
      +
      +
      +!> Perform tree-shaking to remove unused module targets
      +subroutine prune_build_targets(targets, root_package, prune_unused_objects)
      +
      +    !> Build target list to prune
      +    type(build_target_ptr), intent(inout), allocatable :: targets(:)
      +
      +    !> Root package
      +    type(package_t), intent(in) :: root_package
      +    
      +    !> Whether unused objects should be pruned
      +    logical, intent(in) :: prune_unused_objects
      +
      +    integer :: i, j, nexec
      +    type(string_t), allocatable :: modules_used(:)
      +    logical :: exclude_target(size(targets))
      +    logical, allocatable :: exclude_from_archive(:)
      +
      +    if (size(targets) < 1) then
      +        return
      +    end if
      +
      +    nexec = 0
      +    allocate(modules_used(0))
      +
      +    ! Enumerate modules used by executables, non-module subprograms and their dependencies
      +    do i=1,size(targets)
      +
      +        if (targets(i)%ptr%target_type == FPM_TARGET_EXECUTABLE) then
      +
      +            nexec = nexec + 1
      +            call collect_used_modules(targets(i)%ptr)
      +
      +        elseif (allocated(targets(i)%ptr%source)) then
      +
      +            if (targets(i)%ptr%source%unit_type == FPM_UNIT_SUBPROGRAM) then
      +
      +                call collect_used_modules(targets(i)%ptr)
      +
      +            end if
      +
      +        end if
      +
      +    end do
      +
      +    ! If there aren't any executables, then prune
      +    !  based on modules used in root package
      +    if (nexec < 1) then
      +
      +        do i=1,size(targets)
      +
      +            if (targets(i)%ptr%package_name == root_package%name .and. &
      +                 all(targets(i)%ptr%target_type /= [FPM_TARGET_ARCHIVE,FPM_TARGET_SHARED])) then
      +
      +                call collect_used_modules(targets(i)%ptr)
      +
      +            end if
      +
      +        end do
      +
      +    end if
      +
      +    call reset_target_flags(targets)
      +    
      +    exclude_target = .false.
      +
      +    ! Exclude purely module targets if they are not used anywhere
      +    do i=1,size(targets)
      +        associate(target=>targets(i)%ptr)
      +
      +            if (allocated(target%source)) then
      +                if (target%source%unit_type == FPM_UNIT_MODULE) then
      +
      +                    exclude_target(i) = prune_unused_objects
      +                    target%skip = prune_unused_objects
      +
      +                    do j=1,size(target%source%modules_provided)
      +
      +                        if (target%source%modules_provided(j)%s .in. modules_used) then
      +
      +                            exclude_target(i) = .false.
      +                            target%skip = .false.
      +
      +                        end if
      +
      +                    end do
      +
      +                elseif (target%source%unit_type == FPM_UNIT_SUBMODULE) then
      +                    ! Remove submodules if their parents are not used
      +
      +                    exclude_target(i) = prune_unused_objects
      +                    target%skip = prune_unused_objects
      +                    do j=1,size(target%source%parent_modules)
      +
      +                        if (target%source%parent_modules(j)%s .in. modules_used) then
      +
      +                            exclude_target(i) = .false.
      +                            target%skip = .false.
      +
      +                        end if
      +
      +                    end do
      +
      +                end if
      +                
      +            elseif (any(target%target_type == [FPM_TARGET_ARCHIVE,FPM_TARGET_SHARED])) then 
      +                
      +                ! Remove empty library files
      +                if (size(target%dependencies)==0) then 
      +                    exclude_target(i) = .true.
      +                    target%skip = .true.
      +                endif
      +                
      +            end if
      +
      +            ! (If there aren't any executables then we only prune modules from dependencies, 
      +            ! unless the root package is also empty)
      +            if (nexec < 1 .and. target%package_name == root_package%name) then
      +                exclude_target(i) = .not.root_package%has_library()
      +                target%skip = exclude_target(i)
      +            end if
      +            
      +        end associate
      +    end do
      +
      +    targets = pack(targets,.not.exclude_target)
      +
      +    ! Remove unused targets from library dependency list
      +    do j=1,size(targets)
      +        associate(archive=>targets(j)%ptr)
      +            
      +            if (any(archive%target_type==[FPM_TARGET_ARCHIVE,FPM_TARGET_OBJECT])) then 
      +
      +                allocate(exclude_from_archive(size(archive%dependencies)),source=.false.)
      +
      +                    do i=1,size(archive%dependencies)
      +
      +                        if (archive%dependencies(i)%ptr%skip) then
      +
      +                            exclude_from_archive(i) = .true.
      +
      +                        end if
      +
      +                    end do
      +
      +                archive%dependencies = pack(archive%dependencies,.not.exclude_from_archive)
      +                
      +                deallocate(exclude_from_archive)
      +            
      +            endif
      +
      +        end associate
      +    end do
      +
      +    contains
      +
      +    !> Recursively collect which modules are actually used
      +    recursive subroutine collect_used_modules(target)
      +        type(build_target_t), intent(inout) :: target
      +
      +        integer :: j, k
      +
      +        if (target%touched) then
      +            return
      +        else
      +            target%touched = .true.
      +        end if
      +
      +        if (allocated(target%source)) then
      +
      +            ! Add modules from this target and from any of it's children submodules
      +            do j=1,size(target%source%modules_provided)
      +
      +                if (.not.(target%source%modules_provided(j)%s .in. modules_used)) then
      +
      +                    modules_used = [modules_used, target%source%modules_provided(j)]
      +
      +                end if
      +
      +                ! Recurse into child submodules
      +                do k=1,size(targets)
      +                    if (allocated(targets(k)%ptr%source)) then
      +                        if (targets(k)%ptr%source%unit_type == FPM_UNIT_SUBMODULE) then
      +                            if (target%source%modules_provided(j)%s .in. targets(k)%ptr%source%parent_modules) then
      +                                call collect_used_modules(targets(k)%ptr)
      +                            end if
      +                        end if
      +                    end if
      +                end do
      +
      +            end do
      +        end if
      +
      +        ! Recurse into dependencies
      +        do j=1,size(target%dependencies)
      +
      +            if (target%dependencies(j)%ptr%target_type /= FPM_TARGET_ARCHIVE) then
      +                call collect_used_modules(target%dependencies(j)%ptr)
      +            end if
      +
      +        end do
      +
      +    end subroutine collect_used_modules
      +
      +    !> Reset target flags after recursive search
      +    subroutine reset_target_flags(targets)
      +        type(build_target_ptr), intent(inout) :: targets(:)
      +
      +        integer :: i
      +
      +        do i=1,size(targets)
      +
      +            targets(i)%ptr%touched = .false.
      +
      +        end do
      +
      +    end subroutine reset_target_flags
      +
      +end subroutine prune_build_targets
      +
      +
      +!> Construct the linker flags string for each target
      +!>  `target%link_flags` includes non-library objects and library flags
      +!>
      +subroutine resolve_target_linking(targets, model, library, error)
      +    type(build_target_ptr), intent(inout), target :: targets(:)
      +    type(fpm_model_t), intent(in) :: model
      +    type(library_config_t), intent(in), optional :: library    
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    integer :: i,j
      +    logical :: shared,static,monolithic,has_self_lib
      +    integer, allocatable :: package_deps(:),dep_target_ID(:)
      +    character(:), allocatable :: global_link_flags, local_link_flags
      +    character(:), allocatable :: global_include_flags, shared_lib_paths
      +
      +    if (size(targets) == 0) return
      +
      +    global_link_flags = ""
      +    if (allocated(model%link_libraries)) then
      +        if (size(model%link_libraries) > 0) then
      +            global_link_flags = model%compiler%enumerate_libraries(global_link_flags, model%link_libraries)
      +        end if
      +    end if
      +    
      +    allocate(character(0) :: global_include_flags)
      +    if (allocated(model%include_dirs)) then
      +        if (size(model%include_dirs) > 0) then
      +            global_include_flags = global_include_flags // &
      +            & " -I" // string_cat(model%include_dirs," -I")
      +        end if
      +        end if
      +        
      +    if (present(library)) then 
      +        shared     = library%shared()
      +        static     = library%static()
      +        monolithic = library%monolithic()
      +    else
      +        shared     = .false.
      +        static     = .false.
      +        monolithic = .true.
      +    end if
      +    
      +    do i=1,size(targets)
      +
      +        associate(target => targets(i)%ptr)
      +
      +            ! If the main program is a C/C++ one, some compilers require additional linking flags, see
      +            ! https://stackoverflow.com/questions/36221612/p3dfft-compilation-ifort-compiler-error-multiple-definiton-of-main
      +            ! In this case, compile_flags were already allocated
      +            if (.not.allocated(target%compile_flags)) allocate(character(len=0) :: target%compile_flags)
      +
      +            target%compile_flags = target%compile_flags//' '
      +
      +            select case (target%target_type)
      +               case (FPM_TARGET_C_OBJECT)
      +                   target%compile_flags = target%compile_flags//model%c_compile_flags
      +               case (FPM_TARGET_CPP_OBJECT)
      +                   target%compile_flags = target%compile_flags//model%cxx_compile_flags
      +               case default
      +                   target%compile_flags = target%compile_flags//model%fortran_compile_flags &
      +                                        & // get_feature_flags(model%compiler, target%features)
      +            end select
      +
      +            !> Get macros as flags.
      +            target%compile_flags = target%compile_flags // get_macros(model%compiler%id, &
      +                                                            target%macros, &
      +                                                            target%version)
      +
      +            if (len(global_include_flags) > 0) then
      +                target%compile_flags = target%compile_flags//global_include_flags
      +            end if
      +            
      +            call target%set_output_dir(get_output_dir(model%build_prefix, target%compile_flags))
      +            
      +        end associate
      +
      +    end do
      +    
      +    call add_include_build_dirs(model, targets)
      +    call add_library_link_dirs(model, targets, shared_lib_paths)
      +    call library_targets_to_deps(model, targets, dep_target_ID)
      +    
      +    do i=1,size(targets)
      +
      +        associate(target => targets(i)%ptr)
      +            allocate(target%link_objects(0))
      +
      +            select case (target%target_type)
      +                case (FPM_TARGET_ARCHIVE) 
      +                    
      +                    ! This adds the monolithic archive to the link flags
      +                    if (monolithic) global_link_flags = " " // target%output_file // global_link_flags
      +
      +                    call get_link_objects(target%link_objects,target,is_exe=.false.)
      +
      +                    allocate(character(0) :: target%link_flags)
      +                    
      +                case (FPM_TARGET_SHARED)
      +                
      +                    ! Gather object files from this package only
      +                    call get_link_objects(target%link_objects, target, is_exe=.false.)
      +
      +                    ! Build link flags
      +                    target%link_flags = string_cat(target%link_objects, " ")
      +                    
      +                    target%link_flags = target%link_flags // shared_lib_paths
      +
      +                    ! Add dependencies' shared libraries (excluding self)
      +                    target%link_flags = model%get_package_libraries_link(target%package_name, &
      +                                                                        target%link_flags, &
      +                                                                        exclude_self=.true., &
      +                                                                        dep_IDs=package_deps, &
      +                                                                        error=error)
      +                                                                        
      +                    if (allocated(error)) return
      +                    
      +                    ! Now that they're available, add these dependencies to the targets
      +                    if (size(package_deps)>0) then 
      +                        do j=1,size(package_deps)
      +                            if (dep_target_ID(package_deps(j))<=0) cycle
      +                            call add_dependency(target, targets(dep_target_ID(package_deps(j)))%ptr)
      +                        end do
      +                    end if                    
      +                                                        
      +                    ! Add any per-target libraries (e.g., `target%link_libraries`)
      +                    if (allocated(target%link_libraries)) then
      +                        if (size(target%link_libraries) > 0) then
      +                            target%link_flags = model%compiler%enumerate_libraries(target%link_flags, &
      +                                                                                   target%link_libraries)
      +                        end if
      +                    end if
      +
      +                    ! Add shared library exports (import library + .def)
      +                    target%link_flags = target%link_flags // " " // &
      +                                        model%compiler%get_export_flags(target%output_dir,target%package_name)
      +                    
      +                    ! Add install_name flag (macOS only)
      +                    target%link_flags = target%link_flags // " " // &
      +                                        model%compiler%get_install_name_flags(target%output_dir, target%package_name)                    
      +                    
      +                    ! Add global link flags (e.g., system-wide libraries)
      +                    target%link_flags = target%link_flags // " " // global_link_flags     
      +                            
      +
      +                case (FPM_TARGET_EXECUTABLE)
      +
      +                    local_link_flags = ""
      +                    if (allocated(model%link_flags)) local_link_flags = model%link_flags
      +
      +                    call get_link_objects(target%link_objects,target,is_exe=.true.)
      +
      +                    target%link_flags = model%link_flags//" "//string_cat(target%link_objects," ")
      +                    
      +                    ! Add shared libs
      +                    if (.not.monolithic) then 
      +
      +                        target%link_flags = target%link_flags // shared_lib_paths
      +                        
      +                        ! Check if there's a library with this name (maybe not, if it is a 
      +                        ! single-file app with only external dependencies)
      +                        has_self_lib = .false.
      +                        find_self: do j=1,size(targets)
      +                            associate(target_loop=>targets(j)%ptr)
      +                                if (any(target_loop%target_type==[FPM_TARGET_SHARED,FPM_TARGET_ARCHIVE]) &
      +                                    .and. target_loop%package_name==target%package_name) then 
      +                                    has_self_lib = .true.
      +                                    exit find_self
      +                                end if
      +                            end associate
      +                        end do find_self
      +                        
      +                        ! Add dependencies' shared libraries (including self if there is a library)
      +                        target%link_flags = model%get_package_libraries_link(target%package_name, &
      +                                                                            target%link_flags, &
      +                                                                            error=error, &
      +                                                                            exclude_self=.not.has_self_lib)   
      +                                                                            
      +                        
      +                        ! On macOS, add room for 2 install_name_tool paths
      +                        target%link_flags = target%link_flags // model%compiler%get_headerpad_flags()
      +                        
      +                    end if
      +
      +                    if (allocated(target%link_libraries)) then
      +                        if (size(target%link_libraries) > 0) then
      +                            target%link_flags = model%compiler%enumerate_libraries(target%link_flags, target%link_libraries)
      +                            local_link_flags = model%compiler%enumerate_libraries(local_link_flags, target%link_libraries)
      +                        end if
      +                    end if
      +
      +                    target%link_flags = target%link_flags//" "//global_link_flags
      +                    
      +                end select
      +
      +        end associate
      +
      +    end do
      +    
      +contains
      +
      +    !> Wrapper to build link object list
      +    !>
      +    !>  For libraries: just list dependency objects of lib target
      +    !>
      +    !>  For executables: need to recursively discover non-library
      +    !>   dependency objects. (i.e. modules in same dir as program)
      +    !>
      +    recursive subroutine get_link_objects(link_objects,target,is_exe)
      +        type(string_t), intent(inout), allocatable :: link_objects(:)
      +        type(build_target_t), intent(in) :: target
      +        logical, intent(in) :: is_exe
      +
      +        integer :: i
      +        type(string_t) :: temp_str
      +        
      +        if (.not.allocated(target%dependencies)) return
      +
      +        do i=1,size(target%dependencies)
      +
      +            associate(dep => target%dependencies(i)%ptr)
      +                
      +                if (.not.allocated(dep%source)) cycle
      +
      +                ! Skip library dependencies for executable targets
      +                !  since the library archive will always be linked
      +                if (is_exe.and.(dep%source%unit_scope == FPM_SCOPE_LIB)) cycle
      +
      +                ! Skip if dependency object already listed
      +                if (dep%output_file .in. link_objects) cycle
      +
      +                ! Add dependency object file to link object list
      +                temp_str%s = dep%output_file
      +                link_objects = [link_objects, temp_str]
      +                
      +                ! For executable objects, also need to include non-library
      +                !  dependencies from dependencies (recurse)
      +                if (is_exe) call get_link_objects(link_objects,dep,is_exe=.true.)
      +
      +            end associate
      +
      +        end do
      +
      +    end subroutine get_link_objects
      +
      +end subroutine resolve_target_linking
      +
      +
      +subroutine add_include_build_dirs(model, targets)
      +    type(fpm_model_t), intent(in) :: model
      +    type(build_target_ptr), intent(inout), target :: targets(:)
      +
      +    integer :: i
      +    type(string_t), allocatable :: build_dirs(:)
      +    type(string_t) :: temp
      +
      +    allocate(build_dirs(0))
      +    do i = 1, size(targets)
      +        associate(target => targets(i)%ptr)
      +            if (target%target_type /= FPM_TARGET_OBJECT) cycle
      +            if (target%output_dir .in. build_dirs) cycle
      +            temp%s = target%output_dir
      +            build_dirs = [build_dirs, temp]
      +        end associate
      +    end do
      +
      +    do i = 1, size(targets)
      +        associate(target => targets(i)%ptr)
      +            if (target%target_type /= FPM_TARGET_OBJECT) cycle
      +
      +            target%compile_flags = target%compile_flags // &
      +                " " // model%compiler%get_module_flag(target%output_dir) // &
      +                " -I" // string_cat(build_dirs, " -I")
      +        end associate
      +    end do
      +
      +end subroutine add_include_build_dirs
      +
      +!> Add link directories for all shared libraries in the dependency graph
      +subroutine get_library_dirs(model, targets, shared_lib_dirs)
      +    type(fpm_model_t), intent(in) :: model
      +    type(build_target_ptr), intent(inout), target :: targets(:)
      +    type(string_t), allocatable, intent(out) :: shared_lib_dirs(:)
      +
      +    integer :: i
      +    type(string_t) :: temp
      +    
      +    allocate(shared_lib_dirs(0))
      +
      +    do i = 1, size(targets)
      +        associate(target => targets(i)%ptr)
      +            if (all(target%target_type /= [FPM_TARGET_SHARED,FPM_TARGET_ARCHIVE])) cycle
      +            if (target%output_dir .in. shared_lib_dirs) cycle
      +            temp = string_t(target%output_dir)
      +            shared_lib_dirs = [shared_lib_dirs, temp]
      +        end associate
      +    end do
      +    
      +end subroutine get_library_dirs
      +
      +!> Add link directories for all shared libraries in the dependency graph
      +subroutine add_library_link_dirs(model, targets, shared_lib_path)
      +    type(fpm_model_t), intent(in) :: model
      +    type(build_target_ptr), intent(inout), target :: targets(:)
      +    character(:), allocatable, intent(out) :: shared_lib_path
      +
      +    type(string_t), allocatable :: shared_lib_dirs(:)
      +
      +    call get_library_dirs(model, targets, shared_lib_dirs)    
      +    shared_lib_path = " -L" // string_cat(shared_lib_dirs, " -L")
      +
      +end subroutine add_library_link_dirs
      +
      +function get_output_dir(build_prefix, args) result(path)
      +    character(len=*), intent(in) :: build_prefix
      +    character(len=*), intent(in) :: args
      +    character(len=:), allocatable :: path
      +
      +    character(len=16) :: build_hash
      +
      +    write(build_hash, '(z16.16)') fnv_1a(args)
      +    path = build_prefix//"_"//build_hash
      +end function get_output_dir
      +
      +!> Returns pointers to all library targets
      +subroutine filter_library_targets(targets, list)
      +    type(build_target_ptr), intent(in) :: targets(:)
      +    type(build_target_ptr), allocatable, intent(out) :: list(:)
      +
      +    integer :: i, n
      +    
      +    n = 0
      +    do i = 1, size(targets)
      +        if (any(targets(i)%ptr%target_type == [FPM_TARGET_ARCHIVE,FPM_TARGET_SHARED])) then
      +            n = n + 1
      +        end if
      +    end do    
      +    
      +    allocate(list(n))
      +
      +    n = 0
      +    do i = 1, size(targets)
      +        if (any(targets(i)%ptr%target_type == [FPM_TARGET_ARCHIVE,FPM_TARGET_SHARED])) then
      +            n = n + 1
      +            list(n)%ptr => targets(i)%ptr
      +        end if
      +    end do
      +end subroutine filter_library_targets
      +
      +subroutine filter_executable_targets(targets, scope, list)
      +    type(build_target_ptr), intent(in) :: targets(:)
      +    integer, intent(in) :: scope
      +    type(string_t), allocatable, intent(out) :: list(:)
      +
      +    integer :: i, n
      +
      +    n = 0
      +    call resize(list)
      +    do i = 1, size(targets)
      +        if (is_executable_target(targets(i)%ptr, scope)) then
      +            if (n >= size(list)) call resize(list)
      +            n = n + 1
      +            list(n)%s = targets(i)%ptr%output_file
      +        end if
      +    end do
      +    call resize(list, n)
      +end subroutine filter_executable_targets
      +
      +
      +elemental function is_executable_target(target_ptr, scope) result(is_exe)
      +    class(build_target_t), intent(in) :: target_ptr
      +    integer, intent(in) :: scope
      +    logical :: is_exe
      +    is_exe = target_ptr%target_type == FPM_TARGET_EXECUTABLE .and. &
      +        allocated(target_ptr%dependencies)
      +    if (is_exe) then
      +        is_exe = target_ptr%dependencies(1)%ptr%source%unit_scope == scope
      +    end if
      +end function is_executable_target
      +
      +
      +subroutine filter_modules(targets, list)
      +    type(build_target_ptr), intent(in) :: targets(:)
      +    type(string_t), allocatable, intent(out) :: list(:)
      +
      +    integer :: i, j, n
      +
      +    n = 0
      +    call resize(list)
      +    do i = 1, size(targets)
      +        associate(target => targets(i)%ptr)
      +            if (.not.allocated(target%source)) cycle
      +            if (target%source%unit_type == FPM_UNIT_SUBMODULE) cycle
      +            if (n + size(target%source%modules_provided) >= size(list)) call resize(list)
      +            do j = 1, size(target%source%modules_provided)
      +                n = n + 1
      +                list(n)%s = join_path(target%output_dir, &
      +                    target%source%modules_provided(j)%s)
      +            end do
      +        end associate
      +    end do
      +    call resize(list, n)
      +end subroutine filter_modules
      +
      +
      +function get_feature_flags(compiler, features) result(flags)
      +    type(compiler_t), intent(in) :: compiler
      +    type(fortran_features_t), intent(in) :: features
      +    character(:), allocatable :: flags
      +
      +    flags = ""
      +    if (features%implicit_typing) then
      +        flags = flags // compiler%get_feature_flag("implicit-typing")
      +    else
      +        flags = flags // compiler%get_feature_flag("no-implicit-typing")
      +    end if
      +
      +    if (features%implicit_external) then
      +        flags = flags // compiler%get_feature_flag("implicit-external")
      +    else
      +        flags = flags // compiler%get_feature_flag("no-implicit-external")
      +    end if
      +
      +    if (allocated(features%source_form)) then
      +        flags = flags // compiler%get_feature_flag(features%source_form//"-form")
      +    end if
      +end function get_feature_flags
      +
      +!> Helper function: update output directory of a target
      +subroutine set_output_dir(self, output_dir)
      +    class(build_target_t), intent(inout) :: self
      +    character(*), optional, intent(in) :: output_dir
      +
      +    character(:), allocatable :: outdir
      +
      +    ! Normalize: if output_dir is empty, use no path
      +    outdir = ""
      +    if (present(output_dir)) outdir = trim(output_dir)
      +        
      +    self%output_dir = outdir
      +    self%output_file = join_path(outdir, self%output_name)
      +    self%output_log_file = self%output_file // ".log"
      +
      +end subroutine set_output_dir
      +
      +!> Build a lookup table mapping each package dependency to its corresponding
      +!> shared or archive build target in the targets list.
      +!>
      +!> This mapping is essential when model%deps%dep(i) indices do not match
      +!> the pruned or reordered targets(:) array.
      +subroutine library_targets_to_deps(model, targets, target_ID)
      +    class(fpm_model_t), intent(in)           :: model
      +    type(build_target_ptr), intent(in)       :: targets(:)
      +
      +    !> For each package (by dependency index), gives the index of the corresponding target
      +    integer, allocatable, intent(out)        :: target_ID(:)
      +
      +    integer :: it, ip, n
      +
      +    n = size(model%deps%dep)
      +    allocate(target_ID(n), source=0)
      +
      +    do it = 1, size(targets)
      +        associate(target => targets(it)%ptr)
      +            ! Only shared libraries and archives are mapped
      +            if (all(target%target_type /= [FPM_TARGET_ARCHIVE, FPM_TARGET_SHARED])) cycle
      +
      +            ! Get the dependency graph index of this package
      +            ip = model%deps%find(target%package_name)
      +            if (ip > 0) target_ID(ip) = it
      +        end associate
      +    end do
      +
      +end subroutine library_targets_to_deps
      +
      +end module fpm_targets
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/git.f90.html b/sourcefile/git.f90.html new file mode 100644 index 0000000000..1a2d513c35 --- /dev/null +++ b/sourcefile/git.f90.html @@ -0,0 +1,662 @@ + + + + + + + + + + + + + git.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      git.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      !> Implementation for interacting with git repositories.
      +module fpm_git
      +    use fpm_error, only: error_t, fatal_error
      +    use fpm_filesystem, only : get_temp_filename, getline, join_path, execute_and_read_output, run
      +    use tomlf, only: toml_table, toml_stat
      +    use fpm_toml, only: serializable_t, get_value, set_value, set_string
      +    implicit none
      +
      +    public :: git_target_t, git_target_default, git_target_branch, git_target_tag, git_target_revision, git_revision, &
      +            & git_archive, git_matches_manifest, compressed_package_name
      +
      +    !> Name of the compressed package that is generated temporarily.
      +    character(len=*), parameter :: compressed_package_name = 'compressed_package'
      +
      +    !> Possible git target
      +    type :: enum_descriptor
      +
      +        !> Default target
      +        integer :: default = 200
      +
      +        !> Branch in git repository
      +        integer :: branch = 201
      +
      +        !> Tag in git repository
      +        integer :: tag = 202
      +
      +        !> Commit hash
      +        integer :: revision = 203
      +
      +        !> Invalid descriptor
      +        integer :: error = -999
      +
      +    end type enum_descriptor
      +
      +    !> Actual enumerator for descriptors
      +    type(enum_descriptor), parameter :: git_descriptor = enum_descriptor()
      +
      +
      +    !> Description of an git target
      +    type, extends(serializable_t) :: git_target_t
      +
      +        !> Kind of the git target
      +        integer :: descriptor = git_descriptor%default
      +
      +        !> Target URL of the git repository
      +        character(len=:), allocatable :: url
      +
      +        !> Additional descriptor of the git object
      +        character(len=:), allocatable :: object
      +
      +    contains
      +
      +        !> Fetch and checkout in local directory
      +        procedure :: checkout
      +
      +        !> Show information on instance
      +        procedure :: info
      +
      +        !> Serialization interface
      +        procedure :: serializable_is_same => git_is_same
      +        procedure :: dump_to_toml
      +        procedure :: load_from_toml
      +
      +    end type git_target_t
      +
      +    !> Common output format for writing to the command line
      +    character(len=*), parameter :: out_fmt = '("#", *(1x, g0))'
      +
      +contains
      +
      +
      +    !> Default target
      +    function git_target_default(url) result(self)
      +
      +        !> Target URL of the git repository
      +        character(len=*), intent(in) :: url
      +
      +        !> New git target
      +        type(git_target_t) :: self
      +
      +        self%descriptor = git_descriptor%default
      +        self%url = url
      +
      +    end function git_target_default
      +
      +
      +    !> Target a branch in the git repository
      +    function git_target_branch(url, branch) result(self)
      +
      +        !> Target URL of the git repository
      +        character(len=*), intent(in) :: url
      +
      +        !> Name of the branch of interest
      +        character(len=*), intent(in) :: branch
      +
      +        !> New git target
      +        type(git_target_t) :: self
      +
      +        self%descriptor = git_descriptor%branch
      +        self%url = url
      +        self%object = branch
      +
      +    end function git_target_branch
      +
      +
      +    !> Target a specific git revision
      +    function git_target_revision(url, sha1) result(self)
      +
      +        !> Target URL of the git repository
      +        character(len=*), intent(in) :: url
      +
      +        !> Commit hash of interest
      +        character(len=*), intent(in) :: sha1
      +
      +        !> New git target
      +        type(git_target_t) :: self
      +
      +        self%descriptor = git_descriptor%revision
      +        self%url = url
      +        self%object = sha1
      +
      +    end function git_target_revision
      +
      +
      +    !> Target a git tag
      +    function git_target_tag(url, tag) result(self)
      +
      +        !> Target URL of the git repository
      +        character(len=*), intent(in) :: url
      +
      +        !> Tag name of interest
      +        character(len=*), intent(in) :: tag
      +
      +        !> New git target
      +        type(git_target_t) :: self
      +
      +        self%descriptor = git_descriptor%tag
      +        self%url = url
      +        self%object = tag
      +
      +    end function git_target_tag
      +
      +    !> Check that two git targets are equal
      +    logical function git_is_same(this,that)
      +        class(git_target_t), intent(in) :: this
      +        class(serializable_t), intent(in) :: that
      +
      +        git_is_same = .false.
      +
      +        select type (other=>that)
      +           type is (git_target_t)
      +              if (.not.(this%descriptor==other%descriptor)) return
      +              if (allocated(this%url) .neqv. allocated(other%url)) return
      +              if (allocated(this%url)) then
      +                if (.not.(this%url==other%url)) return
      +              end if
      +              if (allocated(this%object) .neqv. allocated(other%object)) return
      +              if (allocated(this%object)) then
      +                if (.not.(this%object==other%object)) return
      +              end if
      +           class default
      +              ! Not the same type
      +              return
      +        end select
      +
      +        !> All checks passed!
      +        git_is_same = .true.
      +
      +    end function git_is_same
      +
      +    !> Check that a cached dependency matches a manifest request
      +    logical function git_matches_manifest(cached,manifest,verbosity,iunit)
      +
      +        !> Two input git targets
      +        type(git_target_t), intent(in) :: cached,manifest
      +
      +        integer, intent(in) :: verbosity,iunit
      +
      +        git_matches_manifest = cached%url == manifest%url
      +        if (.not.git_matches_manifest) then
      +            if (verbosity>1) write(iunit,out_fmt) "GIT URL has changed: ",cached%url," vs. ", manifest%url
      +            return
      +        endif
      +
      +        !> The manifest dependency only contains partial information (what's requested),
      +        !> while the cached dependency always stores a commit hash because it's built
      +        !> after the repo is available (saved as git_descriptor%revision==revision).
      +        !> So, comparing against the descriptor is not reliable
      +        git_matches_manifest = allocated(cached%object) .eqv. allocated(manifest%object)
      +        if (git_matches_manifest .and. allocated(cached%object)) &
      +        git_matches_manifest = cached%object == manifest%object
      +        if (.not.git_matches_manifest) then
      +            if (verbosity>1) write(iunit,out_fmt) "GIT OBJECT has changed: ",cached%object," vs. ", manifest%object
      +        end if
      +
      +    end function git_matches_manifest
      +
      +
      +    subroutine checkout(self, local_path, error)
      +
      +        !> Instance of the git target
      +        class(git_target_t), intent(in) :: self
      +
      +        !> Local path to checkout in
      +        character(*), intent(in) :: local_path
      +
      +        !> Error
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        integer :: stat
      +        character(len=:), allocatable :: object, workdir
      +
      +        if (allocated(self%object)) then
      +            object = self%object
      +        else
      +            object = 'HEAD'
      +        end if
      +        workdir = "--work-tree="//local_path//" --git-dir="//join_path(local_path, ".git")
      +
      +        call execute_command_line("git init "//local_path, exitstat=stat)
      +
      +        if (stat /= 0) then
      +            call fatal_error(error,'Error while initiating git repository for remote dependency')
      +            return
      +        end if
      +
      +        call execute_command_line("git "//workdir//" fetch --depth=1 "// &
      +                                  self%url//" "//object, exitstat=stat)
      +
      +        if (stat /= 0) then
      +            call fatal_error(error,'Error while fetching git repository for remote dependency')
      +            return
      +        end if
      +
      +        call execute_command_line("git "//workdir//" checkout -qf FETCH_HEAD", exitstat=stat)
      +
      +        if (stat /= 0) then
      +            call fatal_error(error,'Error while checking out git repository for remote dependency')
      +            return
      +        end if
      +
      +    end subroutine checkout
      +
      +
      +    subroutine git_revision(local_path, object, error)
      +
      +        !> Local path to checkout in
      +        character(*), intent(in) :: local_path
      +
      +        !> Git object reference
      +        character(len=:), allocatable, intent(out) :: object
      +
      +        !> Error
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        integer :: stat, unit, istart, iend
      +        character(len=:), allocatable :: temp_file, line, iomsg, workdir
      +        character(len=*), parameter :: hexdigits = '0123456789abcdef'
      +
      +        workdir = "--work-tree="//local_path//" --git-dir="//join_path(local_path, ".git")
      +        allocate(temp_file, source=get_temp_filename())
      +        line = "git "//workdir//" log -n 1 > "//temp_file
      +        call execute_command_line(line, exitstat=stat)
      +
      +        if (stat /= 0) then
      +            call fatal_error(error, "Error while retrieving commit information")
      +            return
      +        end if
      +
      +        open(file=temp_file, newunit=unit)
      +        call getline(unit, line, stat, iomsg)
      +
      +        if (stat /= 0) then
      +            call fatal_error(error, iomsg)
      +            return
      +        end if
      +        close(unit, status="delete")
      +
      +        ! Tokenize:
      +        ! commit 0123456789abcdef (HEAD, ...)
      +        istart = scan(line, ' ') + 1
      +        iend = verify(line(istart:), hexdigits) + istart - 1
      +        if (iend < istart) iend = len(line)
      +        object = line(istart:iend)
      +
      +    end subroutine git_revision
      +
      +
      +    !> Show information on git target
      +    subroutine info(self, unit, verbosity)
      +
      +        !> Instance of the git target
      +        class(git_target_t), intent(in) :: self
      +
      +        !> Unit for IO
      +        integer, intent(in) :: unit
      +
      +        !> Verbosity of the printout
      +        integer, intent(in), optional :: verbosity
      +
      +        integer :: pr
      +        character(len=*), parameter :: fmt = '("#", 1x, a, t30, a)'
      +
      +        if (present(verbosity)) then
      +            pr = verbosity
      +        else
      +            pr = 1
      +        end if
      +
      +        if (pr < 1) return
      +
      +        write(unit, fmt) "Git target"
      +        if (allocated(self%url)) then
      +            write(unit, fmt) "- URL", self%url
      +        end if
      +        if (allocated(self%object)) then
      +            select case(self%descriptor)
      +            case default
      +                write(unit, fmt) "- object", self%object
      +            case(git_descriptor%tag)
      +                write(unit, fmt) "- tag", self%object
      +            case(git_descriptor%branch)
      +                write(unit, fmt) "- branch", self%object
      +            case(git_descriptor%revision)
      +                write(unit, fmt) "- sha1", self%object
      +            end select
      +        end if
      +
      +    end subroutine info
      +
      +    !> Dump dependency to toml table
      +    subroutine dump_to_toml(self, table, error)
      +
      +        !> Instance of the serializable object
      +        class(git_target_t), intent(inout) :: self
      +
      +        !> Data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        integer :: ierr
      +
      +        call set_string(table, "descriptor", descriptor_name(self%descriptor), error, 'git_target_t')
      +        if (allocated(error)) return
      +        call set_string(table, "url", self%url, error, 'git_target_t')
      +        if (allocated(error)) return
      +        call set_string(table, "object", self%object, error, 'git_target_t')
      +        if (allocated(error)) return
      +
      +    end subroutine dump_to_toml
      +
      +    !> Read dependency from toml table (no checks made at this stage)
      +    subroutine load_from_toml(self, table, error)
      +
      +        !> Instance of the serializable object
      +        class(git_target_t), intent(inout) :: self
      +
      +        !> Data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        !> Local variables
      +        character(len=:), allocatable :: descriptor_name
      +
      +        call get_value(table, "descriptor", descriptor_name)
      +        self%descriptor = parse_descriptor(descriptor_name)
      +
      +        if (self%descriptor==git_descriptor%error) then
      +            call fatal_error(error,"invalid descriptor ID <"//descriptor_name//"> in TOML entry")
      +            return
      +        end if
      +
      +        !> Target URL of the git repository
      +        call get_value(table, "url", self%url)
      +
      +        !> Additional descriptor of the git object
      +        call get_value(table,"object", self%object)
      +
      +    end subroutine load_from_toml
      +
      +    !> Parse git descriptor identifier from a string
      +    pure integer function parse_descriptor(name)
      +        character(len=*), intent(in) :: name
      +
      +        select case (name)
      +           case ("default");  parse_descriptor = git_descriptor%default
      +           case ("branch");   parse_descriptor = git_descriptor%branch
      +           case ("tag");      parse_descriptor = git_descriptor%tag
      +           case ("revision"); parse_descriptor = git_descriptor%revision
      +           case default;      parse_descriptor = git_descriptor%error
      +        end select
      +
      +    end function parse_descriptor
      +
      +    !> Code git descriptor to a string
      +    pure function descriptor_name(descriptor) result(name)
      +       integer, intent(in) :: descriptor
      +       character(len=:), allocatable :: name
      +
      +       select case (descriptor)
      +          case (git_descriptor%default);   name = "default"
      +          case (git_descriptor%branch);    name = "branch"
      +          case (git_descriptor%tag);       name = "tag"
      +          case (git_descriptor%revision);  name = "revision"
      +          case default;                    name = "ERROR"
      +       end select
      +
      +    end function descriptor_name
      +
      +  !> Archive a folder using `git archive`.
      +  subroutine git_archive(source, destination, ref, additional_files, verbose, error)
      +    !> Directory to archive.
      +    character(*), intent(in) :: source
      +    !> Destination of the archive.
      +    character(*), intent(in) :: destination
      +    !> (Symbolic) Reference to be archived.
      +    character(*), intent(in) :: ref
      +    !> (Optional) list of additional untracked files to be added to the archive.
      +    character(*), optional, intent(in) :: additional_files(:)
      +    !> Print additional information if true.
      +    logical, intent(in) :: verbose
      +    !> Error handling.
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    integer :: stat,i
      +    character(len=:), allocatable :: cmd_output, archive_format, add_files
      +
      +    call execute_and_read_output('git archive -l', cmd_output, error, verbose)
      +    if (allocated(error)) return
      +
      +    if (index(cmd_output, 'tar.gz') /= 0) then
      +      archive_format = 'tar.gz'
      +    else
      +      call fatal_error(error, "Cannot find a suitable archive format for 'git archive'."); return
      +    end if
      +
      +    allocate(character(len=0) :: add_files)
      +    if (present(additional_files)) then
      +       do i=1,size(additional_files)
      +          add_files = trim(add_files)//' --add-file='//adjustl(additional_files(i))
      +       end do
      +    endif
      +
      +    call run('git archive '//ref//' &
      +        & --format='//archive_format// &
      +        & add_files//' &
      +        & -o '//destination, &
      +        & echo=verbose, &
      +        & exitstat=stat)
      +
      +    if (stat /= 0) then
      +      call fatal_error(error, "Error packing '"//source//"'."); return
      +    end if
      +  end
      +
      +end module fpm_git
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/install.f90.html b/sourcefile/install.f90.html new file mode 100644 index 0000000000..fd6befc382 --- /dev/null +++ b/sourcefile/install.f90.html @@ -0,0 +1,383 @@ + + + + + + + + + + + + + install.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      install.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      !> Implementation of the installation configuration.
      +!>
      +!> An install table can currently have the following fields
      +!>
      +!>```toml
      +!>library = bool
      +!>```
      +module fpm_manifest_install
      +  use fpm_error, only : error_t, fatal_error, syntax_error
      +  use tomlf, only : toml_table, toml_key, toml_stat
      +  use fpm_toml, only : get_value, set_value, serializable_t
      +  implicit none
      +  private
      +
      +  public :: install_config_t, new_install_config
      +
      +  !> Configuration data for installation
      +  type, extends(serializable_t) :: install_config_t
      +
      +    !> Install library with this project
      +    logical :: library = .false.
      +
      +    !> Install tests with this project
      +    logical :: test = .false.
      +
      +  contains
      +
      +    !> Print information on this instance
      +    procedure :: info
      +
      +    !> Serialization interface
      +    procedure :: serializable_is_same => install_conf_same
      +    procedure :: dump_to_toml
      +    procedure :: load_from_toml
      +
      +  end type install_config_t
      +
      +  character(*), parameter, private :: class_name = 'install_config_t'
      +
      +contains
      +
      +  !> Create a new installation configuration from a TOML data structure
      +  subroutine new_install_config(self, table, error)
      +
      +    !> Instance of the install configuration
      +    type(install_config_t), intent(out) :: self
      +
      +    !> Instance of the TOML data structure
      +    type(toml_table), intent(inout) :: table
      +
      +    !> Error handling
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    call check(table, error)
      +    if (allocated(error)) return
      +
      +    call get_value(table, "library", self%library, .false.)
      +    call get_value(table, "test", self%test, .false.)
      +
      +  end subroutine new_install_config
      +
      +
      +  !> Check local schema for allowed entries
      +  subroutine check(table, error)
      +
      +    !> Instance of the TOML data structure
      +    type(toml_table), intent(inout) :: table
      +
      +    !> Error handling
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    type(toml_key), allocatable :: list(:)
      +    integer :: ikey
      +
      +    call table%get_keys(list)
      +    if (size(list) < 1) return
      +
      +    do ikey = 1, size(list)
      +      select case(list(ikey)%key)
      +      case default
      +        call syntax_error(error, "Key "//list(ikey)%key//" is not allowed in install table")
      +        exit
      +      case("library","test")
      +        continue
      +      end select
      +    end do
      +    if (allocated(error)) return
      +
      +  end subroutine check
      +
      +  !> Write information on install configuration instance
      +  subroutine info(self, unit, verbosity)
      +
      +    !> Instance of the build configuration
      +    class(install_config_t), intent(in) :: self
      +
      +    !> Unit for IO
      +    integer, intent(in) :: unit
      +
      +    !> Verbosity of the printout
      +    integer, intent(in), optional :: verbosity
      +
      +    integer :: pr
      +    character(len=*), parameter :: fmt = '("#", 1x, a, t30, a)'
      +
      +    if (present(verbosity)) then
      +      pr = verbosity
      +    else
      +      pr = 1
      +    end if
      +
      +    if (pr < 1) return
      +
      +    write(unit, fmt) "Install configuration"
      +    write(unit, fmt) " - library install", trim(merge("enabled ", "disabled", self%library))
      +    write(unit, fmt) " - test    install", trim(merge("enabled ", "disabled", self%test))
      +
      +  end subroutine info
      +
      +  logical function install_conf_same(this,that)
      +    class(install_config_t), intent(in) :: this
      +    class(serializable_t), intent(in) :: that
      +
      +    install_conf_same = .false.
      +
      +    select type (other=>that)
      +       type is (install_config_t)
      +          if (this%library.neqv.other%library) return
      +          if (this%test.neqv.other%test) return
      +       class default
      +          ! Not the same type
      +          return
      +    end select
      +
      +    !> All checks passed!
      +    install_conf_same = .true.
      +
      +  end function install_conf_same
      +
      +  !> Dump install config to toml table
      +  subroutine dump_to_toml(self, table, error)
      +
      +    !> Instance of the serializable object
      +    class(install_config_t), intent(inout) :: self
      +
      +    !> Data structure
      +    type(toml_table), intent(inout) :: table
      +
      +    !> Error handling
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    call set_value(table, "library", self%library, error, class_name)
      +    if (allocated(error)) return
      +
      +    call set_value(table, "test", self%test, error, class_name)
      +    if (allocated(error)) return
      +
      +  end subroutine dump_to_toml
      +
      +  !> Read install config from toml table (no checks made at this stage)
      +  subroutine load_from_toml(self, table, error)
      +
      +    !> Instance of the serializable object
      +    class(install_config_t), intent(inout) :: self
      +
      +    !> Data structure
      +    type(toml_table), intent(inout) :: table
      +
      +    !> Error handling
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    integer :: stat
      +
      +    call get_value(table, "library", self%library, error, class_name)
      +    if (allocated(error)) return
      +    call get_value(table, "test", self%test, error, class_name)
      +    if (allocated(error)) return
      +
      +  end subroutine load_from_toml
      +
      +end module fpm_manifest_install
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/install.f90~2.html b/sourcefile/install.f90~2.html new file mode 100644 index 0000000000..14ab645e92 --- /dev/null +++ b/sourcefile/install.f90~2.html @@ -0,0 +1,390 @@ + + + + + + + + + + + + + install.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      install.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      module fpm_cmd_install
      +  use, intrinsic :: iso_fortran_env, only : output_unit
      +  use fpm, only : build_model
      +  use fpm_backend, only : build_package
      +  use fpm_command_line, only : fpm_install_settings
      +  use fpm_error, only : error_t, fatal_error, fpm_stop
      +  use fpm_filesystem, only : join_path, list_files
      +  use fpm_installer, only : installer_t, new_installer
      +  use fpm_manifest, only : package_config_t, get_package_data
      +  use fpm_model, only : fpm_model_t, FPM_SCOPE_APP, FPM_SCOPE_TEST
      +  use fpm_targets, only: targets_from_sources, build_target_t, &
      +                         build_target_ptr, FPM_TARGET_EXECUTABLE, &
      +                         filter_library_targets, filter_executable_targets, filter_modules
      +  use fpm_strings, only : string_t, resize
      +  implicit none
      +  private
      +
      +  public :: cmd_install
      +
      +contains
      +
      +  !> Entry point for the fpm-install subcommand
      +  subroutine cmd_install(settings)
      +    !> Representation of the command line settings
      +    type(fpm_install_settings), intent(inout) :: settings
      +    type(package_config_t) :: package
      +    type(error_t), allocatable :: error
      +    type(fpm_model_t) :: model
      +    type(build_target_ptr), allocatable :: targets(:), libraries(:)
      +    type(installer_t) :: installer
      +    type(string_t), allocatable :: list(:)
      +    logical :: installable
      +    integer :: ntargets,i
      +
      +    call get_package_data(package, "fpm.toml", error, apply_defaults=.true.)
      +    call handle_error(error)
      +    
      +    call build_model(model, settings, package, error)
      +    call handle_error(error)
      +
      +    ! ifx bug: does not resolve allocatable -> optional
      +    if (allocated(package%library)) then 
      +       call targets_from_sources(targets, model, settings%prune, package%library, error)
      +    else
      +       call targets_from_sources(targets, model, settings%prune, error=error) 
      +    endif
      +    call handle_error(error)
      +
      +    call install_info(output_unit, settings%list, targets, ntargets)
      +    if (settings%list) return
      +
      +    installable = (allocated(package%library) .and. package%install%library) &
      +                   .or. allocated(package%executable) .or. ntargets>0
      +    
      +    if (.not.installable) then
      +      call fatal_error(error, "Project does not contain any installable targets")
      +      call handle_error(error)
      +    end if
      +
      +    if (.not.settings%no_rebuild) then
      +      call build_package(targets,model,verbose=settings%verbose,dry_run=settings%list)
      +    end if
      +
      +    call new_installer(installer, prefix=settings%prefix, &
      +      bindir=settings%bindir, libdir=settings%libdir, testdir=settings%testdir, &
      +      includedir=settings%includedir, &
      +      verbosity=merge(2, 1, settings%verbose))
      +
      +    if (allocated(package%library) .and. package%install%library) then
      +      call filter_library_targets(targets, libraries)
      +
      +      if (size(libraries) > 0) then
      +        do i=1,size(libraries)
      +           call installer%install_library(libraries(i)%ptr, error)
      +           call handle_error(error)
      +        end do
      +
      +        call install_module_files(installer, targets, error)
      +        call handle_error(error)
      +      end if
      +    end if
      +    
      +    if (allocated(package%executable) .or. ntargets>0) then
      +      call install_executables(installer, targets, error)
      +      call handle_error(error)
      +    end if
      +
      +    if (allocated(package%test) .and. (package%install%test .or. model%include_tests)) then 
      +        
      +        call install_tests(installer, targets, error)
      +        call handle_error(error)
      +        
      +    end if
      +
      +  end subroutine cmd_install
      +
      +  subroutine install_info(unit, verbose, targets, ntargets)
      +    integer, intent(in) :: unit
      +    logical, intent(in) :: verbose
      +    type(build_target_ptr), intent(in) :: targets(:)
      +    integer, intent(out) :: ntargets
      +
      +    integer :: ii
      +    type(string_t), allocatable :: install_target(:), temp(:)
      +    type(build_target_ptr), allocatable :: libs(:)
      +
      +    allocate(install_target(0))
      +
      +    call filter_library_targets(targets, libs)
      +    install_target = [install_target, (string_t(libs(ii)%ptr%output_file),ii=1,size(libs))]
      +
      +    call filter_executable_targets(targets, FPM_SCOPE_APP, temp)
      +    install_target = [install_target, temp]
      +
      +    call filter_executable_targets(targets, FPM_SCOPE_TEST, temp)
      +    install_target = [install_target, temp]
      +
      +    ntargets = size(install_target)
      +    
      +    if (verbose) then 
      +
      +        write(unit, '("#", *(1x, g0))') &
      +          "total number of installable targets:", ntargets
      +        do ii = 1, ntargets
      +          write(unit, '("-", *(1x, g0))') install_target(ii)%s
      +        end do
      +    
      +    endif
      +
      +  end subroutine install_info
      +
      +  subroutine install_module_files(installer, targets, error)
      +    type(installer_t), intent(inout) :: installer
      +    type(build_target_ptr), intent(in) :: targets(:)
      +    type(error_t), allocatable, intent(out) :: error
      +    type(string_t), allocatable :: modules(:)
      +    integer :: ii
      +
      +    call filter_modules(targets, modules)
      +
      +    do ii = 1, size(modules)
      +      call installer%install_header(modules(ii)%s//".mod", error)
      +      if (allocated(error)) exit
      +    end do
      +    if (allocated(error)) return
      +
      +  end subroutine install_module_files
      +
      +  subroutine install_executables(installer, targets, error)
      +    type(installer_t), intent(inout) :: installer
      +    type(build_target_ptr), intent(in) :: targets(:)
      +    type(error_t), allocatable, intent(out) :: error
      +    integer :: ii
      +
      +    do ii = 1, size(targets)
      +      if (targets(ii)%ptr%is_executable_target(FPM_SCOPE_APP)) then
      +        call installer%install_executable(targets(ii)%ptr%output_file, error)
      +        if (allocated(error)) exit
      +      end if
      +    end do
      +    if (allocated(error)) return
      +
      +  end subroutine install_executables
      +
      +  subroutine install_tests(installer, targets, error)
      +    type(installer_t), intent(inout) :: installer
      +    type(build_target_ptr), intent(in) :: targets(:)
      +    type(error_t), allocatable, intent(out) :: error
      +    integer :: ii
      +    
      +    do ii = 1, size(targets)
      +      if (targets(ii)%ptr%is_executable_target(FPM_SCOPE_TEST)) then
      +        call installer%install_test(targets(ii)%ptr%output_file, error)
      +        if (allocated(error)) exit
      +      end if
      +    end do
      +    if (allocated(error)) return
      +
      +  end subroutine install_tests
      +
      +  subroutine handle_error(error)
      +    type(error_t), intent(in), optional :: error
      +    if (present(error)) then
      +      call fpm_stop(1,'*cmd_install* error: '//error%message)
      +    end if
      +  end subroutine handle_error
      +
      +end module fpm_cmd_install
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/installer.f90.html b/sourcefile/installer.f90.html new file mode 100644 index 0000000000..d97b139807 --- /dev/null +++ b/sourcefile/installer.f90.html @@ -0,0 +1,583 @@ + + + + + + + + + + + + + installer.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      installer.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      !> Implementation of an installer object.
      +!>
      +!> The installer provides a way to install objects to their respective directories
      +!> in the installation prefix, a generic install command allows to install
      +!> to any directory within the prefix.
      +module fpm_installer
      +  use, intrinsic :: iso_fortran_env, only : output_unit
      +  use fpm_environment, only : get_os_type, os_is_unix, OS_WINDOWS, OS_MACOS
      +  use fpm_error, only : error_t, fatal_error
      +  use fpm_targets, only: build_target_t, FPM_TARGET_ARCHIVE, FPM_TARGET_SHARED, FPM_TARGET_NAME
      +  use fpm_filesystem, only : join_path, mkdir, exists, unix_path, windows_path, get_local_prefix, &
      +      basename
      +
      +  implicit none
      +  private
      +  public :: installer_t, new_installer
      +
      +  !> Declaration of the installer type
      +  type :: installer_t
      +    !> Path to installation directory
      +    character(len=:), allocatable :: prefix
      +    !> Binary dir relative to the installation prefix
      +    character(len=:), allocatable :: bindir
      +    !> Library directory relative to the installation prefix
      +    character(len=:), allocatable :: libdir
      +    !> Test program directory relative to the installation prefix
      +    character(len=:), allocatable :: testdir
      +    !> Include directory relative to the installation prefix
      +    character(len=:), allocatable :: includedir
      +    !> Output unit for informative printout
      +    integer :: unit = output_unit
      +    !> Verbosity of the installer
      +    integer :: verbosity = 1
      +    !> Command to copy objects into the installation prefix
      +    character(len=:), allocatable :: copy
      +    !> Command to move objects into the installation prefix
      +    character(len=:), allocatable :: move
      +    !> Cached operating system
      +    integer :: os
      +  contains
      +    !> Evaluate the installation path
      +    procedure :: install_destination  
      +    !> Install an executable in its correct subdirectory
      +    procedure :: install_executable
      +    !> Install a library in its correct subdirectory
      +    procedure :: install_library
      +    !> Install a header/module in its correct subdirectory
      +    procedure :: install_header
      +    !> Install a test program in its correct subdirectory
      +    procedure :: install_test
      +    !> Install a generic file into a subdirectory in the installation prefix
      +    procedure :: install
      +    !> Run an installation command, type-bound for unit testing purposes
      +    procedure :: run
      +    !> Create a new directory in the prefix, type-bound for unit testing purposes
      +    procedure :: make_dir
      +
      +  end type installer_t
      +
      +  !> Default name of the binary subdirectory
      +  character(len=*), parameter :: default_bindir = "bin"
      +
      +  !> Default name of the library subdirectory
      +  character(len=*), parameter :: default_libdir = "lib"
      +  
      +  !> Default name of the test subdirectory
      +  character(len=*), parameter :: default_testdir = "test"
      +
      +  !> Default name of the include subdirectory
      +  character(len=*), parameter :: default_includedir = "include"
      +
      +  !> Copy command on Unix platforms
      +  character(len=*), parameter :: default_copy_unix = "cp"
      +
      +  !> Copy command on Windows platforms
      +  character(len=*), parameter :: default_copy_win = "copy"
      +
      +  !> Copy command on Unix platforms
      +  character(len=*), parameter :: default_force_copy_unix = "cp -f"
      +
      +  !> Copy command on Windows platforms
      +  character(len=*), parameter :: default_force_copy_win = "copy /Y"
      +
      +  !> Move command on Unix platforms
      +  character(len=*), parameter :: default_move_unix = "mv"
      +
      +  !> Move command on Windows platforms
      +  character(len=*), parameter :: default_move_win = "move"
      +
      +contains
      +
      +  !> Create a new instance of an installer
      +  subroutine new_installer(self, prefix, bindir, libdir, includedir, testdir, verbosity, &
      +          copy, move)
      +    !> Instance of the installer
      +    type(installer_t), intent(out) :: self
      +    !> Path to installation directory
      +    character(len=*), intent(in), optional :: prefix
      +    !> Binary dir relative to the installation prefix
      +    character(len=*), intent(in), optional :: bindir
      +    !> Library directory relative to the installation prefix
      +    character(len=*), intent(in), optional :: libdir
      +    !> Include directory relative to the installation prefix
      +    character(len=*), intent(in), optional :: includedir
      +    !> Test directory relative to the installation prefix
      +    character(len=*), intent(in), optional :: testdir    
      +    !> Verbosity of the installer
      +    integer, intent(in), optional :: verbosity
      +    !> Copy command
      +    character(len=*), intent(in), optional :: copy
      +    !> Move command
      +    character(len=*), intent(in), optional :: move
      +
      +    self%os = get_os_type()
      +
      +    ! By default, never prompt the user for overwrites
      +    if (present(copy)) then
      +      self%copy = copy
      +    else
      +      if (os_is_unix(self%os)) then
      +        self%copy = default_force_copy_unix
      +      else
      +        self%copy = default_force_copy_win
      +      end if
      +    end if
      +
      +    if (present(move)) then
      +      self%move = move
      +    else
      +      if (os_is_unix(self%os)) then
      +        self%move = default_move_unix
      +      else
      +        self%move = default_move_win
      +      end if
      +    end if
      +
      +    if (present(includedir)) then
      +      self%includedir = includedir
      +    else
      +      self%includedir = default_includedir
      +    end if
      +    
      +    if (present(testdir)) then 
      +      self%testdir = testdir
      +    else
      +      self%testdir = default_testdir  
      +    end if
      +
      +    if (present(prefix)) then
      +      self%prefix = prefix
      +    else
      +      self%prefix = get_local_prefix(self%os)
      +    end if
      +
      +    if (present(bindir)) then
      +      self%bindir = bindir
      +    else
      +      self%bindir = default_bindir
      +    end if
      +
      +    if (present(libdir)) then
      +      self%libdir = libdir
      +    else
      +      self%libdir = default_libdir
      +    end if
      +
      +    if (present(verbosity)) then
      +      self%verbosity = verbosity
      +    else
      +      self%verbosity = 1
      +    end if
      +
      +  end subroutine new_installer
      +
      +  !> Install an executable in its correct subdirectory
      +  subroutine install_executable(self, executable, error)
      +    !> Instance of the installer
      +    class(installer_t), intent(inout) :: self
      +    !> Path to the executable
      +    character(len=*), intent(in) :: executable
      +    !> Error handling
      +    type(error_t), allocatable, intent(out) :: error
      +    integer :: ll
      +    
      +    character(len=:), allocatable :: exe_path, cmd
      +
      +    if (.not.os_is_unix(self%os)) then
      +        ll = len(executable)
      +        if (executable(max(1, ll-3):ll) /= ".exe") then
      +            call self%install(executable//".exe", self%bindir, error)
      +            return
      +        end if
      +    end if
      +    
      +    call self%install(executable, self%bindir, error)
      +
      +    ! on MacOS, add two relative paths for search of dynamic library dependencies: 
      +    add_rpath: if (self%os==OS_MACOS) then  
      +        
      +        exe_path = join_path(self%install_destination(self%bindir) , basename(executable))
      +        
      +        ! First path: for bin/lib/include structure
      +        cmd = "install_name_tool -add_rpath @executable_path/../lib " // exe_path
      +        call self%run(cmd, error)
      +        if (allocated(error)) return
      +
      +        ! Second path: same as executable folder
      +        cmd = "install_name_tool -add_rpath @executable_path " // exe_path
      +        call self%run(cmd, error)
      +        if (allocated(error)) return
      +        
      +    end if add_rpath
      +
      +  end subroutine install_executable
      +
      +  !> Install a library in its correct subdirectory
      +  subroutine install_library(self, library, error)
      +    !> Instance of the installer
      +    class(installer_t), intent(inout) :: self
      +    !> Library target    
      +    type(build_target_t), intent(in) :: library
      +    !> Error handling
      +    type(error_t), allocatable, intent(out) :: error
      +    
      +    character(:), allocatable :: def_file, implib_file
      +    
      +    select case (library%target_type)
      +       case (FPM_TARGET_ARCHIVE)
      +          call self%install(library%output_file, self%libdir, error)
      +       case (FPM_TARGET_SHARED)
      +          call self%install(library%output_file, self%libdir, error)
      +          
      +          ! Handle shared library side-files only on Windows
      +          if (self%os==OS_WINDOWS) then 
      +            
      +            ! Try both compiler-dependent import library names
      +            implib_file = join_path(library%output_dir, library%package_name // ".dll.a")           
      +            if (exists(implib_file)) then 
      +                call self%install(implib_file, self%libdir, error)            
      +                if (allocated(error)) return
      +            else
      +                implib_file = join_path(library%output_dir, library%package_name // ".lib")
      +                if (exists(implib_file)) call self%install(implib_file, self%libdir, error)            
      +                if (allocated(error)) return
      +            endif
      +
      +          end if
      +          
      +       case default 
      +          call fatal_error(error,"Installer error: "//library%package_name//" is a "// &
      +                                 FPM_TARGET_NAME(library%target_type)//", not a library")
      +          return        
      +    end select
      +    
      +  end subroutine install_library
      +
      +  !> Install a test program in its correct subdirectory
      +  subroutine install_test(self, test, error)
      +    !> Instance of the installer
      +    class(installer_t), intent(inout) :: self
      +    !> Path to the test executable
      +    character(len=*), intent(in) :: test
      +    !> Error handling
      +    type(error_t), allocatable, intent(out) :: error
      +    integer :: ll
      +
      +    if (.not.os_is_unix(self%os)) then
      +        ll = len(test)
      +        if (test(max(1, ll-3):ll) /= ".exe") then
      +            call self%install(test//".exe", self%testdir, error)
      +            return
      +        end if
      +    end if
      +
      +    call self%install(test, self%testdir, error)
      +
      +  end subroutine install_test
      +
      +  !> Install a header/module in its correct subdirectory
      +  subroutine install_header(self, header, error)
      +    !> Instance of the installer
      +    class(installer_t), intent(inout) :: self
      +    !> Path to the header
      +    character(len=*), intent(in) :: header
      +    !> Error handling
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    call self%install(header, self%includedir, error)
      +  end subroutine install_header
      +
      +  !> Install a generic file into a subdirectory in the installation prefix
      +  subroutine install(self, source, destination, error)
      +    !> Instance of the installer
      +    class(installer_t), intent(inout) :: self
      +    !> Path to the original file
      +    character(len=*), intent(in) :: source
      +    !> Path to the destination inside the prefix
      +    character(len=*), intent(in) :: destination
      +    !> Error handling
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    character(len=:), allocatable :: install_dest
      +
      +    install_dest = self%install_destination(destination)
      +    call self%make_dir(install_dest, error)
      +    if (allocated(error)) return
      +
      +    if (self%verbosity > 0) then
      +      if (exists(install_dest)) then
      +        write(self%unit, '("# Update:", 1x, a, 1x, "->", 1x, a)') &
      +          source, install_dest
      +      else
      +        write(self%unit, '("# Install:", 1x, a, 1x, "->", 1x, a)') &
      +          source, install_dest
      +      end if
      +    end if
      +
      +    ! Use force-copy to never prompt the user for overwrite if a package was already installed
      +    call self%run(self%copy//' "'//source//'" "'//install_dest//'"', error)
      +
      +    if (allocated(error)) return
      +
      +  end subroutine install
      +  
      +  !> Evaluate the installation path
      +  function install_destination(self, destination) result(install_dest)
      +    !> Instance of the installer
      +    class(installer_t), intent(inout) :: self
      +    !> Path to the destination inside the prefix
      +    character(len=*), intent(in) :: destination    
      +    
      +    character(len=:), allocatable :: install_dest
      +
      +    install_dest = join_path(self%prefix, destination)
      +    if (os_is_unix(self%os)) then
      +      install_dest = unix_path(install_dest)
      +    else
      +      install_dest = windows_path(install_dest)
      +    end if    
      +    
      +  end function install_destination
      +
      +  !> Create a new directory in the prefix
      +  subroutine make_dir(self, dir, error)
      +    !> Instance of the installer
      +    class(installer_t), intent(inout) :: self
      +    !> Directory to be created
      +    character(len=*), intent(in) :: dir
      +    !> Error handling
      +    type(error_t), allocatable, intent(out) :: error
      +
      +    if (.not.exists(dir)) then
      +       if (self%verbosity > 1) then
      +          write(self%unit, '("# Dir:", 1x, a)') dir
      +       end if
      +       call mkdir(dir)
      +    end if
      +  end subroutine make_dir
      +
      +  !> Run an installation command
      +  subroutine run(self, command, error)
      +    !> Instance of the installer
      +    class(installer_t), intent(inout) :: self
      +    !> Command to be launched
      +    character(len=*), intent(in) :: command
      +    !> Error handling
      +    type(error_t), allocatable, intent(out) :: error
      +    integer :: stat
      +
      +    if (self%verbosity > 1) then
      +      write(self%unit, '("# Run:", 1x, a)') command
      +    end if
      +    call execute_command_line(command, exitstat=stat)
      +
      +    if (stat /= 0) then
      +      call fatal_error(error, "Failed in command: '"//command//"'")
      +      return
      +    end if
      +  end subroutine run
      +
      +end module fpm_installer
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/library.f90.html b/sourcefile/library.f90.html new file mode 100644 index 0000000000..af0a908a9f --- /dev/null +++ b/sourcefile/library.f90.html @@ -0,0 +1,506 @@ + + + + + + + + + + + + + library.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      library.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      !> Implementation of the meta data for libraries.
      +!>
      +!> A library table can currently have the following fields
      +!>
      +!>```toml
      +!>[library]
      +!>source-dir = "path"
      +!>include-dir = ["path1","path2"]
      +!>build-script = "file"
      +!>```
      +module fpm_manifest_library
      +    use fpm_error, only : error_t, syntax_error, fatal_error
      +    use fpm_strings, only: string_t, string_cat, operator(==)
      +    use tomlf, only : toml_table, toml_key, toml_stat
      +    use fpm_toml, only : get_value, get_list, serializable_t, set_value, &
      +                          set_list, set_string, get_value, has_list
      +    implicit none
      +    private
      +
      +    public :: library_config_t, new_library
      +
      +
      +    !> Configuration meta data for a library
      +    type, extends(serializable_t) :: library_config_t
      +
      +        !> Source path prefix
      +        character(len=:), allocatable :: source_dir
      +
      +        !> Include path prefix
      +        type(string_t), allocatable :: include_dir(:)
      +
      +        !> Alternative build script to be invoked
      +        character(len=:), allocatable :: build_script
      +        
      +        !> Shared / Static / Monolithic library 
      +        character(:), allocatable :: lib_type
      +
      +    contains
      +
      +        !> Print information on this instance
      +        procedure :: info
      +
      +        !> Serialization interface
      +        procedure :: serializable_is_same => library_is_same
      +        procedure :: dump_to_toml
      +        procedure :: load_from_toml
      +        
      +        !> Check library types
      +        procedure, non_overridable :: monolithic
      +        procedure, non_overridable :: shared
      +        procedure, non_overridable :: static
      +
      +    end type library_config_t
      +
      +    character(*), parameter, private :: class_name = 'library_config_t'
      +
      +
      +contains
      +
      +    !> Check if this is a shared library config 
      +    !> (full packages built as shared libs)
      +    elemental logical function shared(self)
      +        !> Instance of the library configuration
      +        class(library_config_t), intent(in) :: self
      +        
      +        if (allocated(self%lib_type)) then 
      +           shared = self%lib_type == "shared"
      +        else
      +           shared = .false.
      +        endif
      +        
      +    end function shared
      +
      +
      +    !> Check if this is a static library config
      +    !> (full packages built as static libs)
      +    elemental logical function static(self)
      +        !> Instance of the library configuration
      +        class(library_config_t), intent(in) :: self
      +        
      +        if (allocated(self%lib_type)) then 
      +           static = self%lib_type == "static"
      +        else
      +           static = .false.
      +        endif
      +    end function static
      +
      +
      +    !> Check if this is a monolithic library config
      +    !> (single monolithic archive with all objects used by this project)
      +    elemental logical function monolithic(self)
      +        !> Instance of the library configuration
      +        class(library_config_t), intent(in) :: self
      +        
      +        monolithic = .not.(static(self) .or. shared(self))
      +    end function monolithic
      +
      +
      +    !> Construct a new library configuration from a TOML data structure
      +    subroutine new_library(self, table, error)
      +
      +        !> Instance of the library configuration
      +        type(library_config_t), intent(out) :: self
      +
      +        !> Instance of the TOML data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +        
      +        integer :: stat
      +
      +        call check(table, error)
      +        if (allocated(error)) return
      +
      +        if (has_list(table, "source-dir")) then
      +            call syntax_error(error, "Manifest key [library.source-dir] does not allow list input")
      +            return
      +        end if
      +
      +        if (has_list(table, "type")) then
      +            call syntax_error(error, "Manifest key [library.type] does not allow list input")
      +            return
      +        end if
      +
      +        call get_value(table, "source-dir", self%source_dir, "src")
      +        call get_value(table, "build-script", self%build_script)
      +
      +        call get_list(table, "include-dir", self%include_dir, error)
      +        if (allocated(error)) return
      +        
      +        call get_value(table, "type", self%lib_type, "monolithic")
      +        
      +        select case(self%lib_type)
      +        case("shared","static","monolithic")
      +            ! OK
      +        case default
      +            call fatal_error(error,"Value of library.type cannot be '"//self%lib_type &
      +                                 //"', choose shared/static/monolithic (default)")
      +            return
      +        end select        
      +        
      +        ! Set default value of include-dir if not found in manifest
      +        if (.not.allocated(self%include_dir)) then
      +            self%include_dir = [string_t("include")]
      +        end if
      +        
      +        if (.not.allocated(self%lib_type)) then 
      +            self%lib_type = "monolithic"
      +        end if
      +
      +    end subroutine new_library
      +
      +
      +    !> Check local schema for allowed entries
      +    subroutine check(table, error)
      +
      +        !> Instance of the TOML data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        type(toml_key), allocatable :: list(:)
      +        integer :: ikey
      +
      +        call table%get_keys(list)
      +
      +        ! table can be empty
      +        if (size(list) < 1) return
      +
      +        do ikey = 1, size(list)
      +            select case(list(ikey)%key)
      +            case default
      +                call syntax_error(error, "Key "//list(ikey)%key//" is not allowed in library")
      +                exit
      +
      +            case("source-dir", "include-dir", "build-script", "type")
      +                continue
      +
      +            end select
      +        end do
      +
      +    end subroutine check
      +
      +
      +    !> Write information on instance
      +    subroutine info(self, unit, verbosity)
      +
      +        !> Instance of the library configuration
      +        class(library_config_t), intent(in) :: self
      +
      +        !> Unit for IO
      +        integer, intent(in) :: unit
      +
      +        !> Verbosity of the printout
      +        integer, intent(in), optional :: verbosity
      +
      +        integer :: pr
      +        character(len=*), parameter :: fmt = '("#", 1x, a, t30, a)'
      +
      +        if (present(verbosity)) then
      +            pr = verbosity
      +        else
      +            pr = 1
      +        end if
      +
      +        if (pr < 1) return
      +
      +        write(unit, fmt) "Library target"
      +        if (allocated(self%source_dir)) then
      +            write(unit, fmt) "- source directory", self%source_dir
      +        end if
      +        if (allocated(self%include_dir)) then
      +            write(unit, fmt) "- include directory", string_cat(self%include_dir,",")
      +        end if
      +        
      +        write(unit, fmt) "- library type", self%lib_type
      +        
      +        if (allocated(self%build_script)) then
      +            write(unit, fmt) "- custom build", self%build_script
      +        end if
      +
      +    end subroutine info
      +
      +    logical function library_is_same(this,that)
      +       class(library_config_t), intent(in) :: this
      +       class(serializable_t), intent(in) :: that
      +
      +        library_is_same = .false.
      +
      +        select type (other=>that)
      +           type is (library_config_t)
      +              if (.not.this%include_dir==other%include_dir) return
      +              if (allocated(this%source_dir).neqv.allocated(other%source_dir)) return
      +              if (allocated(this%source_dir)) then
      +                if (.not.this%source_dir==other%source_dir) return
      +              end if
      +              if (allocated(this%build_script).neqv.allocated(other%build_script)) return
      +              if (allocated(this%build_script)) then
      +                if (.not.this%build_script==other%build_script) return
      +              end if
      +              if (allocated(this%lib_type).neqv.allocated(other%lib_type)) return
      +              if (allocated(this%lib_type)) then
      +                if (.not.this%lib_type==other%lib_type) return
      +              end if
      +           class default
      +              ! Not the same type
      +              return
      +        end select
      +
      +        !> All checks passed!
      +        library_is_same = .true.
      +
      +    end function library_is_same
      +
      +    !> Dump install config to toml table
      +    subroutine dump_to_toml(self, table, error)
      +
      +        !> Instance of the serializable object
      +        class(library_config_t), intent(inout) :: self
      +
      +        !> Data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        call set_string(table, "source-dir", self%source_dir, error, class_name)
      +        if (allocated(error)) return
      +        call set_string(table, "build-script", self%build_script, error, class_name)
      +        if (allocated(error)) return
      +        call set_list(table, "include-dir", self%include_dir, error)
      +        if (allocated(error)) return
      +        call set_string(table, "type", self%lib_type, error, class_name)
      +        if (allocated(error)) return
      +
      +    end subroutine dump_to_toml
      +
      +    !> Read install config from toml table (no checks made at this stage)
      +    subroutine load_from_toml(self, table, error)
      +
      +        !> Instance of the serializable object
      +        class(library_config_t), intent(inout) :: self
      +
      +        !> Data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        call get_value(table, "source-dir", self%source_dir)
      +        if (allocated(error)) return
      +        call get_value(table, "build-script", self%build_script)
      +        if (allocated(error)) return
      +        call get_list(table, "include-dir", self%include_dir, error)
      +        if (allocated(error)) return
      +        call get_value(table, "type", self%lib_type)
      +        if (allocated(error)) return
      +
      +    end subroutine load_from_toml
      +
      +
      +end module fpm_manifest_library
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/main.f90.html b/sourcefile/main.f90.html new file mode 100644 index 0000000000..9ed4d59534 --- /dev/null +++ b/sourcefile/main.f90.html @@ -0,0 +1,329 @@ + + + + + + + + + + + + + main.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      main.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      program main
      +use, intrinsic :: iso_fortran_env, only : error_unit, output_unit
      +use fpm_command_line, only: &
      +        fpm_cmd_settings, &
      +        fpm_new_settings, &
      +        fpm_build_settings, &
      +        fpm_export_settings, &
      +        fpm_run_settings, &
      +        fpm_test_settings, &
      +        fpm_install_settings, &
      +        fpm_update_settings, &
      +        fpm_clean_settings, &
      +        fpm_publish_settings, &
      +        get_command_line_settings
      +use fpm_error, only: error_t
      +use fpm_filesystem, only: exists, parent_dir, join_path
      +use fpm, only: cmd_build, cmd_run, cmd_clean
      +use fpm_cmd_install, only: cmd_install
      +use fpm_cmd_export, only: cmd_export
      +use fpm_cmd_new, only: cmd_new
      +use fpm_cmd_update, only : cmd_update
      +use fpm_cmd_publish, only: cmd_publish
      +use fpm_os,  only: change_directory, get_current_directory
      +
      +implicit none
      +
      +class(fpm_cmd_settings), allocatable :: cmd_settings
      +type(error_t), allocatable :: error
      +character(len=:), allocatable :: pwd_start, pwd_working, working_dir, project_root
      +
      +call get_command_line_settings(cmd_settings)
      +
      +call get_current_directory(pwd_start, error)
      +call handle_error(error)
      +
      +call get_working_dir(cmd_settings, working_dir)
      +if (allocated(working_dir)) then
      +    ! Change working directory if requested
      +    if (len_trim(working_dir) > 0) then
      +        call change_directory(working_dir, error)
      +        call handle_error(error)
      +
      +        call get_current_directory(pwd_working, error)
      +        call handle_error(error)
      +        write(output_unit, '(*(a))') "fpm: Entering directory '"//pwd_working//"'"
      +    else
      +        pwd_working = pwd_start
      +    end if
      +else
      +    pwd_working = pwd_start
      +end if
      +
      +select type (settings => cmd_settings)
      +type is (fpm_new_settings)
      +class default
      +    if (.not.has_manifest(pwd_working)) then
      +        project_root = pwd_working
      +        do while(.not.has_manifest(project_root))
      +            working_dir = parent_dir(project_root)
      +            if (len(working_dir) == 0) exit
      +            project_root = working_dir
      +        end do
      +
      +        if (has_manifest(project_root)) then
      +            call change_directory(project_root, error)
      +            call handle_error(error)
      +            write(output_unit, '(*(a))') "fpm: Entering directory '"//project_root//"'"
      +        end if
      +    end if
      +end select
      +
      +select type(settings=>cmd_settings)
      +type is (fpm_new_settings)
      +    call cmd_new(settings)
      +type is (fpm_build_settings)
      +    call cmd_build(settings)
      +type is (fpm_run_settings)
      +    call cmd_run(settings,test=.false.)
      +type is (fpm_test_settings)
      +    call cmd_run(settings,test=.true.)
      +type is (fpm_export_settings)
      +    call cmd_export(settings)
      +type is (fpm_install_settings)
      +    call cmd_install(settings)
      +type is (fpm_update_settings)
      +    call cmd_update(settings)
      +type is (fpm_clean_settings)
      +    call cmd_clean(settings)
      +type is (fpm_publish_settings)
      +    call cmd_publish(settings)
      +end select
      +
      +if (allocated(project_root)) then
      +    write(output_unit, '(*(a))') "fpm: Leaving directory '"//project_root//"'"
      +end if
      +
      +if (pwd_start /= pwd_working) then
      +    write(output_unit, '(*(a))') "fpm: Leaving directory '"//pwd_working//"'"
      +end if
      +
      +contains
      +
      +    function has_manifest(dir)
      +        character(len=*), intent(in) :: dir
      +        logical :: has_manifest
      +
      +        has_manifest = exists(join_path(dir, "fpm.toml"))
      +    end function has_manifest
      +
      +    subroutine handle_error(error_)
      +        type(error_t), optional, intent(in) :: error_
      +        if (present(error_)) then
      +            write (error_unit, '("[Error]", 1x, a)') error_%message
      +            stop 1
      +        end if
      +    end subroutine handle_error
      +
      +    !> Save access to working directory in settings, in case setting have not been allocated
      +    subroutine get_working_dir(settings, working_dir_)
      +        class(fpm_cmd_settings), optional, intent(in) :: settings
      +        character(len=:), allocatable, intent(out) :: working_dir_
      +        if (present(settings)) then
      +            working_dir_ = settings%working_dir
      +        end if
      +    end subroutine get_working_dir
      +
      +end program main
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/manifest.f90.html b/sourcefile/manifest.f90.html new file mode 100644 index 0000000000..a9853ac826 --- /dev/null +++ b/sourcefile/manifest.f90.html @@ -0,0 +1,489 @@ + + + + + + + + + + + + + manifest.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      manifest.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      !> Package configuration data.
      +!>
      +!> This module provides the necessary procedure to translate a TOML document
      +!> to the corresponding Fortran type, while verifying it with respect to
      +!> its schema.
      +!>
      +!> Additionally, the required data types for users of this module are reexported
      +!> to hide the actual implementation details.
      +module fpm_manifest
      +    use fpm_manifest_example, only : example_config_t
      +    use fpm_manifest_executable, only : executable_config_t
      +    use fpm_manifest_dependency, only : dependency_config_t
      +    use fpm_manifest_library, only : library_config_t
      +    use fpm_manifest_preprocess, only : preprocess_config_t
      +    use fpm_manifest_package, only : package_config_t, new_package
      +    use fpm_error, only : error_t, fatal_error
      +    use tomlf, only : toml_table
      +    use fpm_toml, only : read_package_file
      +    use fpm_manifest_test, only : test_config_t
      +    use fpm_filesystem, only: join_path, exists, dirname, is_dir
      +    use fpm_environment, only: os_is_unix
      +    use fpm_strings, only: string_t
      +    implicit none
      +    private
      +
      +    public :: get_package_data, default_executable, default_library, default_test
      +    public :: get_package_dependencies
      +    public :: default_example
      +    public :: package_config_t, dependency_config_t, preprocess_config_t
      +
      +
      +contains
      +
      +
      +    !> Populate library in case we find the default src directory
      +    subroutine default_library(self)
      +
      +        !> Instance of the library meta data
      +        type(library_config_t), intent(out) :: self
      +
      +        self%source_dir = "src"
      +        self%include_dir = [string_t("include")]
      +
      +    end subroutine default_library
      +
      +
      +    !> Populate executable in case we find the default app directory
      +    subroutine default_executable(self, name)
      +
      +        !> Instance of the executable meta data
      +        type(executable_config_t), intent(out) :: self
      +
      +        !> Name of the package
      +        character(len=*), intent(in) :: name
      +
      +        self%name = name
      +        self%source_dir = "app"
      +        self%main = "main.f90"
      +
      +    end subroutine default_executable
      +
      +    !> Populate test in case we find the default example/ directory
      +    subroutine default_example(self, name)
      +
      +        !> Instance of the executable meta data
      +        type(example_config_t), intent(out) :: self
      +
      +        !> Name of the package
      +        character(len=*), intent(in) :: name
      +
      +        self%name = name // "-demo"
      +        self%source_dir = "example"
      +        self%main = "main.f90"
      +
      +    end subroutine default_example
      +
      +    !> Populate test in case we find the default test/ directory
      +    subroutine default_test(self, name)
      +
      +        !> Instance of the executable meta data
      +        type(test_config_t), intent(out) :: self
      +
      +        !> Name of the package
      +        character(len=*), intent(in) :: name
      +
      +        self%name = name // "-test"
      +        self%source_dir = "test"
      +        self%main = "main.f90"
      +
      +    end subroutine default_test
      +
      +
      +    !> Obtain package meta data from a configuation file
      +    subroutine get_package_data(package, file, error, apply_defaults)
      +
      +        !> Parsed package meta data
      +        type(package_config_t), intent(out) :: package
      +
      +        !> Name of the package configuration file
      +        character(len=*), intent(in) :: file
      +
      +        !> Error status of the operation
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        !> Apply package defaults (uses file system operations)
      +        logical, intent(in), optional :: apply_defaults
      +
      +        type(toml_table), allocatable :: table
      +        character(len=:), allocatable :: root
      +
      +        call read_package_file(table, file, error)
      +        if (allocated(error)) return
      +
      +        if (.not. allocated(table)) then
      +            call fatal_error(error, "Unclassified error while reading: '"//file//"'")
      +            return
      +        end if
      +
      +        call new_package(package, table, dirname(file), error)
      +        if (allocated(error)) return
      +
      +        if (present(apply_defaults)) then
      +            if (apply_defaults) then
      +                root = dirname(file)
      +                if (len_trim(root) == 0) root = "."
      +                call package_defaults(package, root, error)
      +                if (allocated(error)) return
      +            end if
      +        end if
      +
      +    end subroutine get_package_data
      +
      +
      +    !> Apply package defaults
      +    subroutine package_defaults(package, root, error)
      +
      +        !> Parsed package meta data
      +        type(package_config_t), intent(inout) :: package
      +
      +        !> Current working directory
      +        character(len=*), intent(in) :: root
      +
      +        !> Error status of the operation
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        ! Populate library in case we find the default src directory
      +        if (.not.allocated(package%library) .and. &
      +            & (is_dir(join_path(root, "src")) .or. &
      +            &  is_dir(join_path(root, "include")))) then
      +
      +            allocate(package%library)
      +            call default_library(package%library)
      +        end if
      +
      +        ! Populate executable in case we find the default app
      +        if (.not.allocated(package%executable) .and. &
      +            & exists(join_path(root, "app", "main.f90"))) then
      +            allocate(package%executable(1))
      +            call default_executable(package%executable(1), package%name)
      +        end if
      +
      +        ! Populate example in case we find the default example directory
      +        if (.not.allocated(package%example) .and. &
      +            & exists(join_path(root, "example", "main.f90"))) then
      +            allocate(package%example(1))
      +            call default_example(package%example(1), package%name)
      +        endif
      +
      +        ! Populate test in case we find the default test directory
      +        if (.not.allocated(package%test) .and. &
      +            & exists(join_path(root, "test", "main.f90"))) then
      +            allocate(package%test(1))
      +            call default_test(package%test(1), package%name)
      +        endif
      +
      +        if (.not.(allocated(package%library) &
      +            & .or. allocated(package%executable) &
      +            & .or. allocated(package%example) &
      +            & .or. allocated(package%test))) then
      +            call fatal_error(error, "Neither library nor executable found, there is nothing to do")
      +            return
      +        end if
      +
      +    end subroutine package_defaults
      +    
      +    ! Return an array of all dependencies in the manifest
      +    subroutine get_package_dependencies(package, main, deps)
      +
      +        !> Parsed package meta data
      +        type(package_config_t), intent(in) :: package
      +        
      +        !> Is the main project
      +        logical, intent(in) :: main        
      +        
      +        !> Unprocessed list of all dependencies listed in this manifest
      +        type(dependency_config_t), allocatable, intent(out) :: deps(:)
      +        
      +        integer :: ndeps,k
      +        
      +        ndeps = 0
      +        if (allocated(package%dependency)) &
      +        ndeps = ndeps + size(package%dependency)
      +        
      +        if (main) then 
      +        
      +            if (allocated(package%dev_dependency)) &
      +            ndeps = ndeps + size(package%dev_dependency)
      +                    
      +            if (allocated(package%example)) then
      +               do k = 1, size(package%example)
      +                  if (allocated(package%example(k)%dependency)) &
      +                  ndeps = ndeps + size(package%example(k)%dependency)
      +               end do
      +            end if
      +
      +            if (allocated(package%executable)) then
      +               do k = 1, size(package%executable)
      +                  if (allocated(package%executable(k)%dependency)) &
      +                  ndeps = ndeps + size(package%executable(k)%dependency)
      +               end do
      +            end if
      +            
      +            if (allocated(package%test)) then
      +               do k = 1, size(package%test)
      +                  if (allocated(package%test(k)%dependency)) &
      +                  ndeps = ndeps + size(package%test(k)%dependency)
      +               end do
      +            end if     
      +        
      +        endif   
      +        
      +        allocate(deps(ndeps))
      +        
      +        if (ndeps > 0) then
      +           
      +           ndeps = 0
      +           
      +           if (allocated(package%dependency)) &
      +           call collect(deps,ndeps,package%dependency)
      +           
      +           if (main) then 
      +           
      +               if (allocated(package%dev_dependency)) &
      +               call collect(deps,ndeps,package%dev_dependency)
      +               
      +               if (allocated(package%example)) then
      +                  do k = 1, size(package%example)
      +                     if (allocated(package%example(k)%dependency)) &
      +                     call collect(deps,ndeps,package%example(k)%dependency)
      +                  end do
      +               end if
      +               if (allocated(package%executable)) then
      +                  do k = 1, size(package%executable)
      +                     if (allocated(package%executable(k)%dependency)) &
      +                     call collect(deps,ndeps,package%executable(k)%dependency)
      +                  end do
      +               end if
      +               if (allocated(package%test)) then
      +                  do k = 1, size(package%test)
      +                     if (allocated(package%test(k)%dependency)) &
      +                     call collect(deps,ndeps,package%test(k)%dependency)
      +                  end do
      +               end if    
      +           
      +           endif
      +         
      +         endif
      +
      +      contains
      +      
      +         ! Add dependencies to the list      
      +         pure subroutine collect(list, nreq, new_deps)
      +            type(dependency_config_t), intent(inout) :: list(:)
      +            integer,                   intent(inout) :: nreq
      +            type(dependency_config_t), intent(in)    :: new_deps(:)
      +            
      +            integer :: i
      +            do i = 1, size(new_deps)
      +               nreq = nreq + 1
      +               list(nreq) = new_deps(i)
      +            end do
      +         end subroutine collect
      +        
      +    end subroutine get_package_dependencies
      +
      +
      +end module fpm_manifest
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/meta.f90.html b/sourcefile/meta.f90.html new file mode 100644 index 0000000000..f94599fa1f --- /dev/null +++ b/sourcefile/meta.f90.html @@ -0,0 +1,503 @@ + + + + + + + + + + + + + meta.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      meta.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      !> Implementation of the metapackage configuration data.
      +!>
      +!> A metapackage table can currently have the following fields
      +!>
      +!>```toml
      +!>[metapackages]
      +!>fpm = "0.1.0"
      +!>openmp = bool
      +!>stdlib = bool
      +!>```
      +module fpm_manifest_metapackages
      +    use fpm_error, only: error_t, fatal_error, syntax_error
      +    use tomlf, only : toml_table, toml_key, toml_stat
      +    use fpm_toml, only : get_value
      +    use fpm_environment
      +    implicit none
      +    private
      +
      +    public :: metapackage_config_t, new_meta_config, is_meta_package
      +    public :: metapackage_request_t, new_meta_request
      +
      +
      +    !> Configuration data for a single metapackage request
      +    type :: metapackage_request_t
      +
      +        !> Request flag
      +        logical :: on = .false.
      +
      +        !> Metapackage name
      +        character(len=:), allocatable :: name
      +
      +        !> Version Specification string
      +        character(len=:), allocatable :: version
      +
      +    end type metapackage_request_t
      +
      +
      +    !> Configuration data for metapackages
      +    type :: metapackage_config_t
      +
      +        !> Request MPI support
      +        type(metapackage_request_t) :: mpi
      +
      +        !> Request OpenMP support
      +        type(metapackage_request_t) :: openmp
      +
      +        !> Request stdlib support
      +        type(metapackage_request_t) :: stdlib
      +
      +        !> fortran-lang minpack
      +        type(metapackage_request_t) :: minpack
      +
      +        !> HDF5
      +        type(metapackage_request_t) :: hdf5
      +
      +        !> NetCDF
      +        type(metapackage_request_t) :: netcdf
      +
      +        !> BLAS
      +        type(metapackage_request_t) :: blas
      +        
      +        contains
      +        
      +           procedure :: get_requests
      +
      +    end type metapackage_config_t
      +
      +
      +contains
      +
      +    !> Destroy a metapackage request
      +    elemental subroutine request_destroy(self)
      +
      +        !> Instance of the request
      +        class(metapackage_request_t), intent(inout) :: self
      +
      +        self%on = .false.
      +        if (allocated(self%version)) deallocate(self%version)
      +        if (allocated(self%name)) deallocate(self%name)
      +
      +    end subroutine request_destroy
      +
      +    !> Parse version string of a metapackage request
      +    subroutine request_parse(self, version_request, error)
      +
      +        ! Instance of this metapackage
      +        type(metapackage_request_t), intent(inout) :: self
      +
      +        ! Parse version request
      +        character(len=*), intent(in) :: version_request
      +
      +        ! Error message
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        ! wildcard = use any versions
      +        if (version_request=="*") then
      +
      +            ! Any version is OK
      +            self%on = .true.
      +            self%version = version_request
      +
      +        else
      +
      +            call fatal_error(error,'Value <'//version_request//'> for metapackage '//self%name//&
      +                                   'is not currently supported. Try "*" instead. ')
      +            return
      +
      +        end if
      +
      +    end subroutine request_parse
      +
      +    !> Construct a new metapackage request from the dependencies table
      +    subroutine new_meta_request(self, key, table, meta_allowed, error)
      +
      +        type(metapackage_request_t), intent(out) :: self
      +
      +        !> The package name
      +        character(len=*), intent(in) :: key
      +
      +        !> Instance of the TOML data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> List of keys allowed to be metapackages
      +        logical, intent(in), optional :: meta_allowed(:)
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +
      +        integer :: stat,i
      +        character(len=:), allocatable :: value
      +        logical, allocatable :: allow_meta(:)
      +        type(toml_key), allocatable :: keys(:)
      +
      +        call request_destroy(self)
      +
      +        !> Set name
      +        self%name = key
      +        if (.not.is_meta_package(key)) then
      +            call fatal_error(error,"Error reading fpm.toml: <"//key//"> is not a valid metapackage name")
      +            return
      +        end if
      +
      +        !> The toml table is not checked here because it already passed
      +        !> the "new_dependencies" check
      +
      +        call table%get_keys(keys)
      +
      +        !> Set list of entries that are allowed to be metapackages
      +        if (present(meta_allowed)) then
      +            if (size(meta_allowed)/=size(keys)) then
      +                 call fatal_error(error,"Internal error: list of metapackage-enable entries does not match table size")
      +                 return
      +            end if
      +            allow_meta = meta_allowed
      +        else
      +            allocate(allow_meta(size(keys)),source=.true.)
      +        endif
      +
      +
      +        do i=1,size(keys)
      +
      +            ! Skip standard dependencies
      +            if (.not.allow_meta(i)) cycle
      +
      +            if (keys(i)%key==key) then
      +                call get_value(table, key, value)
      +                if (.not. allocated(value)) then
      +                    call syntax_error(error, "Could not retrieve version string for metapackage key <"//key//">. Check syntax")
      +                    return
      +                else
      +                    call request_parse(self, value, error)
      +                    return
      +                endif
      +            end if
      +        end do
      +
      +        ! Key is not present, metapackage not requested
      +        return
      +
      +    end subroutine new_meta_request
      +
      +    !> Construct a new build configuration from a TOML data structure
      +    subroutine new_meta_config(self, table, meta_allowed, error)
      +
      +        !> Instance of the build configuration
      +        type(metapackage_config_t), intent(out) :: self
      +
      +        !> Instance of the TOML data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> List of keys allowed to be metapackages
      +        logical, intent(in) :: meta_allowed(:)
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        integer :: stat
      +
      +        !> The toml table is not checked here because it already passed
      +        !> the "new_dependencies" check
      +        call new_meta_request(self%openmp, "openmp", table, meta_allowed, error)
      +        if (allocated(error)) return
      +
      +        call new_meta_request(self%stdlib, "stdlib", table, meta_allowed, error)
      +        if (allocated(error)) return
      +
      +        call new_meta_request(self%minpack, "minpack", table, meta_allowed, error)
      +        if (allocated(error)) return
      +
      +        call new_meta_request(self%mpi, "mpi", table, meta_allowed, error)
      +        if (allocated(error)) return
      +
      +        call new_meta_request(self%hdf5, "hdf5", table, meta_allowed, error)
      +        if (allocated(error)) return
      +
      +        call new_meta_request(self%netcdf, "netcdf", table, meta_allowed, error)
      +        if (allocated(error)) return
      +
      +        call new_meta_request(self%blas, "blas", table, meta_allowed, error)
      +        if (allocated(error)) return
      +
      +    end subroutine new_meta_config
      +    
      +    !> Check local schema for allowed entries
      +    logical function is_meta_package(key)
      +
      +        !> Instance of the TOML data structure
      +        character(*), intent(in) :: key
      +
      +        select case (key)
      +
      +            !> Supported metapackages
      +            case ("openmp","stdlib","mpi","minpack","hdf5","netcdf","blas")
      +                is_meta_package = .true.
      +
      +            case default
      +                is_meta_package = .false.
      +
      +        end select
      +
      +    end function is_meta_package
      +    
      +    !> Return a list of metapackages requested for the current build
      +    function get_requests(meta) result(requests)
      +
      +        !> Instance of the build configuration
      +        class(metapackage_config_t), intent(in) :: meta
      +
      +        !> The list of requested metapackages (always allocated)
      +        type(metapackage_request_t), allocatable :: requests(:)
      +
      +        integer :: nreq
      +
      +        !> Count requests
      +        nreq = 0
      +        if (meta%mpi%on)     nreq = nreq + 1
      +        if (meta%openmp%on)  nreq = nreq + 1
      +        if (meta%stdlib%on)  nreq = nreq + 1
      +        if (meta%minpack%on) nreq = nreq + 1
      +        if (meta%hdf5%on)    nreq = nreq + 1
      +        if (meta%netcdf%on)  nreq = nreq + 1
      +        if (meta%blas%on)    nreq = nreq + 1
      +
      +        !> Prepare requests
      +        allocate(requests(nreq)); if (nreq <= 0) return
      +
      +        nreq = 0
      +        if (meta%mpi%on) then
      +            nreq = nreq + 1
      +            requests(nreq) = meta%mpi
      +        end if
      +        if (meta%openmp%on) then
      +            nreq = nreq + 1
      +            requests(nreq) = meta%openmp
      +        end if
      +        if (meta%stdlib%on) then
      +            nreq = nreq + 1
      +            requests(nreq) = meta%stdlib
      +        end if
      +        if (meta%minpack%on) then
      +            nreq = nreq + 1
      +            requests(nreq) = meta%minpack
      +        end if
      +        if (meta%hdf5%on) then
      +            nreq = nreq + 1
      +            requests(nreq) = meta%hdf5
      +        end if
      +        if (meta%netcdf%on) then
      +            nreq = nreq + 1
      +            requests(nreq) = meta%netcdf
      +        end if
      +        if (meta%blas%on) then
      +            nreq = nreq + 1
      +            requests(nreq) = meta%blas
      +        end if
      +
      +    end function get_requests
      +
      +
      +end module fpm_manifest_metapackages
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/new.f90.html b/sourcefile/new.f90.html new file mode 100644 index 0000000000..3b6d50d10c --- /dev/null +++ b/sourcefile/new.f90.html @@ -0,0 +1,936 @@ + + + + + + + + + + + + + new.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      new.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      module fpm_cmd_new
      +!># Definition of the "new" subcommand
      +!>
      +!> A type of the general command base class [[fpm_cmd_settings]]
      +!> was created for the "new" subcommand ==> type [[fpm_new_settings]].
      +!> This procedure read the values that were set on the command line
      +!> from this type to decide what actions to take.
      +!>
      +!> It is virtually self-contained and so independant of the rest of the
      +!> application that it could function as a separate program.
      +!>
      +!> The "new" subcommand options currently consist of a SINGLE top
      +!> directory name to create that must have a name that is an
      +!> allowable Fortran variable name. That should have been ensured
      +!> by the command line processing before this procedure is called.
      +!> So basically this routine has already had the options vetted and
      +!> just needs to conditionally create a few files.
      +!>
      +!> As described in the documentation it will selectively
      +!> create the subdirectories app/, test/, src/, and example/
      +!> and populate them with sample files.
      +!>
      +!> It also needs to create an initial manifest file "fpm.toml".
      +!>
      +!> It then calls the system command "git init".
      +!>
      +!> It should test for file existence and not overwrite existing
      +!> files and inform the user if there were conflicts.
      +!>
      +!> Any changes should be reflected in the documentation in
      +!> [[fpm_command_line.f90]]
      +!>
      +!> FUTURE
      +!> A filename like "." would need system commands or a standard routine
      +!> like realpath(3c) to process properly.
      +!>
      +!> Perhaps allow more than one name on a single command. It is an arbitrary
      +!> restriction based on a concensus preference, not a required limitation.
      +!>
      +!> Initially the name of the directory is used as the module name in the
      +!> src file so it must be an allowable Fortran variable name. If there are
      +!> complaints about it it might be changed. Handling unicode at this point
      +!> might be problematic as not all current compilers handle it. Other
      +!> utilities like content trackers (ie. git) or repositories like github
      +!> might also have issues with alternative names or names with spaces, etc.
      +!> So for the time being it seems prudent to encourage simple ASCII top directory
      +!> names (similiar to the primary programming language Fortran itself).
      +!>
      +!> Should be able to create or pull more complicated initial examples
      +!> based on various templates. It should place or mention other relevant
      +!> documents such as a description of the manifest file format in user hands;
      +!> or how to access registered packages and local packages,
      +!> although some other command might provide that (and the help command should
      +!> be the first go-to for a CLI utility).
      +
      +use fpm_command_line, only : fpm_new_settings
      +use fpm_environment, only : OS_LINUX, OS_MACOS, OS_WINDOWS
      +use fpm_filesystem, only : join_path, exists, basename, mkdir, is_dir
      +use fpm_filesystem, only : fileopen, fileclose, warnwrite, which, run
      +use fpm_strings, only : join, to_fortran_name
      +use fpm_error, only : fpm_stop
      +
      +use,intrinsic :: iso_fortran_env, only : stderr=>error_unit
      +implicit none
      +private
      +public :: cmd_new
      +
      +contains
      +
      +subroutine cmd_new(settings)
      +type(fpm_new_settings), intent(in) :: settings
      +integer,parameter            :: tfc = selected_char_kind('DEFAULT')
      +character(len=:,kind=tfc),allocatable :: bname          ! baeename of NAME
      +character(len=:,kind=tfc),allocatable :: tomlfile(:)
      +character(len=:,kind=tfc),allocatable :: littlefile(:)
      +
      +    !> TOP DIRECTORY NAME PROCESSING
      +    !> see if requested new directory already exists and process appropriately
      +    if(exists(settings%name) .and. .not.settings%backfill )then
      +        write(stderr,'(*(g0,1x))')&
      +        & '<ERROR>',settings%name,'already exists.'
      +        write(stderr,'(*(g0,1x))')&
      +        & '        perhaps you wanted to add --backfill ?'
      +        return
      +    elseif(is_dir(settings%name) .and. settings%backfill )then
      +        write(*,'(*(g0))')'backfilling ',settings%name
      +    elseif(exists(settings%name) )then
      +        write(stderr,'(*(g0,1x))')&
      +        & '<ERROR>',settings%name,'already exists and is not a directory.'
      +        return
      +    else
      +        ! make new directory
      +        call mkdir(settings%name)
      +    endif
      +
      +    !> temporarily change to new directory as a test. NB: System dependent
      +    call run('cd '//settings%name)
      +    ! NOTE: need some system routines to handle filenames like "."
      +    ! like realpath() or getcwd().
      +    bname=basename(settings%name)
      +
      +    littlefile=[character(len=80) :: '# '//bname, 'My cool new project!']
      +
      +    ! create NAME/README.md
      +    call warnwrite(join_path(settings%name, 'README.md'), littlefile)
      +
      +    ! start building NAME/fpm.toml
      +    if(settings%with_full)then
      +        tomlfile=[character(len=80) :: &
      +        &'  # This is your fpm(Fortran Package Manager) manifest file                     ',&
      +        &'  # ("fpm.toml"). It is heavily annotated to help guide you though              ',&
      +        &'  # customizing a package build, although the defaults are sufficient           ',&
      +        &'  # for many basic packages.                                                    ',&
      +        &'  #                                                                             ',&
      +        &'  # The manifest file is not only used to provide metadata identifying          ',&
      +        &'  # your project (so it can be used by others as a dependency). It can          ',&
      +        &'  # specify where your library and program sources live, what the name          ',&
      +        &'  # of the executable(s) will be, what files to build, dependencies on          ',&
      +        &'  # other fpm packages, and what external libraries are required.               ',&
      +        &'  #                                                                             ',&
      +        &'  # The manifest format must conform to the TOML configuration file             ',&
      +        &'  # standard.                                                                   ',&
      +        &'  #                                                                             ',&
      +        &'  # TOML files support flexible use of white-space and commenting of the        ',&
      +        &'  # configuration data, but for clarity in this sample active directives        ',&
      +        &'  # begin in column one. Inactive example directives are commented              ',&
      +        &'  # out with a pound character ("#") but begin in column one as well.           ',&
      +        &'  # Commentary begins with a pound character in column three.                   ',&
      +        &'  #                                                                             ',&
      +        &'  # This file draws heavily upon the following references:                      ',&
      +        &'  #                                                                             ',&
      +        &'  # The fpm home page at                                                        ',&
      +        &'  #     https://github.com/fortran-lang/fpm                                     ',&
      +        &'  # A complete list of keys and their attributes at                             ',&
      +        &'  #     https://github.com/fortran-lang/fpm/blob/main/manifest-reference.md     ',&
      +        &'  # examples of fpm project packaging at                                        ',&
      +        &'  #     https://github.com/fortran-lang/fpm/blob/main/PACKAGING.md              ',&
      +        &'  # The Fortran TOML file interface and it''s references at                     ',&
      +        &'  #     https://github.com/toml-f/toml-f                                        ',&
      +        &'  #                                                                             ',&
      +        &'  #-----------------------                                                      ',&
      +        &'  # project Identification                                                      ',&
      +        &'  #-----------------------                                                      ',&
      +        &'  # We begin with project metadata at the manifest root. This data is designed  ',&
      +        &'  # to aid others when searching for the project in a repository and to         ',&
      +        &'  # identify how and when to contact the package supporters.                    ',&
      +        &'                                                                                ',&
      +        &'name = "'//bname//'"',&
      +        &'  # The project name (required) is how the project will be referred to.         ',&
      +        &'  # The name is used by other packages using it as a dependency. It also        ',&
      +        &'  # is used as the default name of any library built and the optional           ',&
      +        &'  # default executable built from app/main.f90. It must conform to the rules    ',&
      +        &'  # for a Fortran variable name.                                                ',&
      +        &'                                                                                ',&
      +        &'version = "0.1.0"                                                               ',&
      +        &'  # The project version number is a string. A recommended scheme for            ',&
      +        &'  # specifying versions is the Semantic Versioning scheme.                      ',&
      +        &'                                                                                ',&
      +        &'license = "license"                                                             ',&
      +        &'  # Licensing information specified using SPDX identifiers is preferred         ',&
      +        &'  # (eg. "Apache-2.0 OR MIT" or "LGPL-3.0-or-later").                           ',&
      +        &'                                                                                ',&
      +        &'maintainer = "jane.doe@example.com"                                             ',&
      +        &'  # Information on the project maintainer and means to reach out to them.       ',&
      +        &'                                                                                ',&
      +        &'author = "Jane Doe"                                                             ',&
      +        &'  # Information on the project author.                                          ',&
      +        &'                                                                                ',&
      +        &'copyright = "Copyright 2020 Jane Doe"                                           ',&
      +        &'  # A statement clarifying the Copyright status of the project.                 ',&
      +        &'                                                                                ',&
      +        &'#description = "A short project summary in plain text"                          ',&
      +        &'  # The description provides a short summary on the project. It should be       ',&
      +        &'  # plain text and not use any markup formatting.                               ',&
      +        &'                                                                                ',&
      +        &'#categories = ["fortran", "graphics"]                                           ',&
      +        &'  # Categories associated with the project. Listing only one is preferred.      ',&
      +        &'                                                                                ',&
      +        &'#keywords = ["hdf5", "mpi"]                                                     ',&
      +        &'  # The keywords field is an array of strings describing the project.           ',&
      +        &'                                                                                ',&
      +        &'#homepage = "https://stdlib.fortran-lang.org"                                   ',&
      +        &'  # URL to the webpage of the project.                                          ',&
      +        &'                                                                                ',&
      +        &'  # -----------------------------------------                                   ',&
      +        &'  # We are done with identifying the project.                                   ',&
      +        &'  # -----------------------------------------                                   ',&
      +        &'  #                                                                             ',&
      +        &'  # Now lets start describing how the project should be built.                  ',&
      +        &'  #                                                                             ',&
      +        &'  # Note tables would go here but we will not be talking about them (much)!!'    ,&
      +        &'  #                                                                             ',&
      +        &'  # Tables are a way to explicitly specify large numbers of programs in         ',&
      +        &'  # a compact format instead of individual per-program entries in the           ',&
      +        &'  # [[executable]], [[test]], and [[example]] sections to follow but            ',&
      +        &'  # will not be discussed further except for the following notes:               ',&
      +        &'  #                                                                             ',&
      +        &'  # + Tables must appear (here) before any sections are declared. Once a        ',&
      +        &'  #   section is specified in a TOML file everything afterwards must be         ',&
      +        &'  #   values for that section or the beginning of a new section. A simple       ',&
      +        &'  #   example looks like:                                                       ',&
      +        &'                                                                                ',&
      +        &'#executable = [                                                                 ',&
      +        &'#  { name = "a-prog" },                                                         ',&
      +        &'#  { name = "app-tool", source-dir = "tool" },                                  ',&
      +        &'#  { name = "fpm-man", source-dir = "tool", main="fman.f90" }                   ',&
      +        &'#]                                                                              ',&
      +        &'                                                                                ',&
      +        &'  # This would be in lieue of the [[executable]] section found later in this    ',&
      +        &'  # configuration file.                                                         ',&
      +        &'  # + See the reference documents (at the beginning of this document)           ',&
      +        &'  #   for more information on tables if you have long lists of programs         ',&
      +        &'  #   to build and are not simply depending on auto-detection.                  ',&
      +        &'  #                                                                             ',&
      +        &'  # Now lets begin the TOML sections (lines beginning with "[") ...             ',&
      +        &'  #                                                                             ',&
      +        &'                                                                                ',&
      +        &'[install] # Options for the "install" subcommand                                ',&
      +        &'                                                                                ',&
      +        &'  # When you run the "install" subcommand only executables are installed by     ',&
      +        &'  # default on the local system. Library projects that will be used outside of  ',&
      +        &'  # "fpm" can set the "library" boolean to also allow installing the module     ',&
      +        &'  # files and library archive. Without this being set to "true" an "install"    ',&
      +        &'  # subcommand ignores parameters that specify library installation.            ',&
      +        &'                                                                                ',&
      +        &'  # If your project sets `[library] type = "shared"`, enabling this option      ',&
      +        &'  # will install the compiled `.so`, `.dylib`, or `.dll` files into the         ',&
      +        &'  # appropriate `lib/` folder. This applies equally to static archives.         ',&
      +        &'  #                                                                             ',&
      +        &'  # For shared libraries, installing is typically required for runtime usage.   ',&
      +        &'                                                                                ',&
      +        &'library = false                                                                 ',&
      +        &'                                                                                ',&
      +        &'[build] # General Build Options                                                 ',&
      +        &'                                                                                ',&
      +        &'  ###  Automatic target discovery                                               ',&
      +        &'  #                                                                             ',&
      +        &'  # Normally fpm recursively searches the app/, example/, and test/ directories ',&
      +        &'  # for program sources and builds them. To disable this automatic discovery of ',&
      +        &'  # program targets set the following to "false":                               ',&
      +        &'                                                                                ',&
      +        &'#auto-executables = true                                                        ',&
      +        &'#auto-examples = true                                                           ',&
      +        &'#auto-tests = true                                                              ',&
      +        &'                                                                                ',&
      +        &'  ### Package-level External Library Links                                      ',&
      +        &'  #                                                                             ',&
      +        &'  # To declare link-time dependencies on external libraries a list of           ',&
      +        &'  # native libraries can be specified with the "link" entry. You may            ',&
      +        &'  # have one library name or a list of strings in case several                  ',&
      +        &'  # libraries should be linked. This list of library dependencies is            ',&
      +        &'  # exported to dependent packages. You may have to alter your library          ',&
      +        &'  # search-path to ensure the libraries can be accessed. Typically,             ',&
      +        &'  # this is done with the LD_LIBRARY_PATH environment variable on ULS           ',&
      +        &'  # (Unix-Like Systems). You only specify the core name of the library          ',&
      +        &'  # (as is typical with most programming environments, where you                ',&
      +        &'  # would specify "-lz" on your load command to link against the zlib           ',&
      +        &'  # compression library even though the library file would typically be         ',&
      +        &'  # a file called "libz.a" "or libz.so"). So to link against that library       ',&
      +        &'  # you would specify:                                                          ',&
      +        &'                                                                                ',&
      +        &'#link = "z"                                                                     ',&
      +        &'                                                                                ',&
      +        &'  # Note that in some cases the order of the libraries matters:                 ',&
      +        &'                                                                                ',&
      +        &'#link = ["blas", "lapack"]                                                      ',&
      +        &'']
      +    endif
      +
      +    if(settings%with_bare)then
      +    elseif(settings%with_lib)then
      +        call mkdir(join_path(settings%name,'src') )
      +        ! create next section of fpm.toml
      +        if(settings%with_full)then
      +            tomlfile=[character(len=80) ::  tomlfile, &
      +            &'[library]                                                                       ',&
      +            &'                                                                                ',&
      +            &'  # You can change the name of the directory to search for your library         ',&
      +            &'  # source from the default of "src/". Library targets are exported             ',&
      +            &'  # and usable by other projects.                                               ',&
      +            &'                                                                                ',&
      +            &'source-dir="src"                                                                ',&
      +            &'                                                                                ',&
      +            &'  # this can be a list:                                                         ',&
      +            &'                                                                                ',&
      +            &'#source-dir=["src", "src2"]                                                     ',&
      +            &'                                                                                ',&
      +            &'  # More complex libraries may organize their modules in subdirectories.        ',&
      +            &'  # For modules in a top-level directory fpm requires (but does not             ',&
      +            &'  # enforce) that:                                                              ',&
      +            &'  #                                                                             ',&
      +            &'  #  + The module has the same name as the source file. This is important.      ',&
      +            &'  #  + There should be only one module per file.                                ',&
      +            &'  #                                                                             ',&
      +            &'  # These two requirements simplify the build process for fpm. As Fortran       ',&
      +            &'  # compilers emit module files (.mod) with the same name as the module         ',&
      +            &'  # itself (but not the source file, .f90), naming the module the same          ',&
      +            &'  # as the source file allows fpm to:                                           ',&
      +            &'  #                                                                             ',&
      +            &'  #  + Uniquely and exactly map a source file (.f90) to its object (.o)         ',&
      +            &'  #    and module (.mod) files.                                                 ',&
      +            &'  #  + Avoid conflicts with modules of the same name that could appear          ',&
      +            &'  #    in dependency packages.                                                  ',&
      +            &'  #                                                                             ',&
      +            &'  ### Multi-level library source                                                ',&
      +            &'  # You can place your module source files in any number of levels of           ',&
      +            &'  # subdirectories inside your source directory, but there are certain naming   ',&
      +            &'  # conventions to be followed -- module names must contain the path components ',&
      +            &'  # of the directory that its source file is in.                                ',&
      +            &'  #                                                                             ',&
      +            &'  # This rule applies generally to any number of nested directories and         ',&
      +            &'  # modules. For example, src/a/b/c/d.f90 must define a module called a_b_c_d.  ',&
      +            &'  # Again, this is not enforced but may be required in future releases.         ',&
      +            &'                                                                                ',&
      +            &'  ### Library type                                                              ',&
      +            &'  # Set `type = "shared"` to build dynamic libraries (.so/.dylib/.dll)          ',&
      +            &'  # instead of a static archive. You can also set `type = "static"` to          ',&
      +            &'  # generate per-package archives, or use `type = "monolithic"` (default)       ',&
      +            &'  # to bundle all sources and dependencies into a single archive.               ',&
      +            &'  #                                                                             ',&
      +            &'  # Supported types:                                                            ',&
      +            &'  #                                                                             ',&
      +            &'  #  + "monolithic": Single archive with used sources and dependencies.         ',&
      +            &'  #  + "static":    One full archive per package (for external integration).    ',&
      +            &'  #  + "shared":    One shared library per package, for dynamic linking.        ',&
      +            &'  #                                                                             ',&
      +            &'  # Shared libraries are useful for plugin systems, dynamic linking, or         ',&
      +            &'  # language bindings. Static per-package archives may aid external reuse.      ',&
      +            &'  #                                                                             ',&
      +            &'  # When running with `fpm run`, shared library paths are automatically         ',&
      +            &'  # added to the environment (e.g. `LD_LIBRARY_PATH`, `PATH`) at runtime.       ',&
      +            &'  #                                                                             ',&            
      +            &'  # Note: library files are not installed unless `[install] library=true`       ',&
      +            &'  # is also enabled.                                                            ',&
      +            &'  #                                                                             ',&
      +            &'  # Example:                                                                    ',&
      +            &'                                                                                ',&            
      +            &'type = "shared"                                                                 ',&
      +            &'                                                                                ',&
      +            &'']
      +        endif
      +        ! create placeholder module src/bname.f90
      +        littlefile=[character(len=80) ::          &
      +        &'module '//to_fortran_name(bname),       &
      +        &'  implicit none',                       &
      +        &'  private',                             &
      +        &'',                                      &
      +        &'  public :: say_hello',                 &
      +        &'contains',                              &
      +        &'  subroutine say_hello',                &
      +        &'    print *, "Hello, '//bname//'!"',    &
      +        &'  end subroutine say_hello',            &
      +        &'end module '//to_fortran_name(bname)]
      +        ! create NAME/src/NAME.f90
      +        call warnwrite(join_path(settings%name, 'src', bname//'.f90'),&
      +         & littlefile)
      +    endif
      +
      +    if(settings%with_full)then
      +        tomlfile=[character(len=80) ::  tomlfile ,&
      +        &'[dependencies]                                                                  ',&
      +        &'                                                                                ',&
      +        &'  # Inevitably, you will want to be able to include other packages in           ',&
      +        &'  # a project. Fpm makes this incredibly simple, by taking care of              ',&
      +        &'  # fetching and compiling your dependencies for you. You just tell it          ',&
      +        &'  # what your dependencies names are, and where to find them.                   ',&
      +        &'  #                                                                             ',&
      +        &'  # If you are going to distribute your package only place dependencies         ',&
      +        &'  # here someone using your package as a remote dependency needs built.         ',&
      +        &'  # You can define dependencies just for developer executables in the           ',&
      +        &'  # next section, or even for specific executables as we will see below         ',&
      +        &'  # (Then fpm will still fetch and compile it when building your                ',&
      +        &'  # developer executables, but users of your library will not have to).         ',&
      +        &'  #                                                                             ',&
      +        &'  ## GLOBAL DEPENDENCIES (exported with your project)                           ',&
      +        &'  #                                                                             ',&
      +        &'  # Typically, dependencies are defined by specifying the project''s            ',&
      +        &'  # git repository.                                                             ',&
      +        &'  #                                                                             ',&
      +        &'  # You can be specific about which version of a dependency you would           ',&
      +        &'  # like. By default the latest default branch is used. You can           ',&
      +        &'  # optionally specify a branch, a tag or a commit value.                       ',&
      +        &'  #                                                                             ',&
      +        &'  # So here are several alternates for specifying a remote dependency (you      ',&
      +        &'  # can have at most one of "branch", "rev" or "tag" present):                  ',&
      +        &'                                                                                ',&
      +        &'#stdlib = { git = "https://github.com/LKedward/stdlib-fpm.git" }                ',&
      +        &'#stdlib = {git="https://github.com/LKedward/stdlib-fpm.git",branch = "master" },',&
      +        &'#stdlib = {git="https://github.com/LKedward/stdlib-fpm.git", tag = "v0.1.0" },  ',&
      +        &'#stdlib = {git="https://github.com/LKedward/stdlib-fpm.git", rev = "5a9b7a8" }. ',&
      +        &'                                                                                ',&
      +        &'  # There may be multiple packages listed:                                      ',&
      +        &'                                                                                ',&
      +        &'#M_strings = { git = "https://github.com/urbanjost/M_strings.git" }             ',&
      +        &'#M_time    = { git = "https://github.com/urbanjost/M_time.git" }                ',&
      +        &'                                                                                ',&
      +        &'  #                                                                             ',&
      +        &'  # You can even specify the local path to another project if it is in          ',&
      +        &'  # a sub-folder (If for example you have got another fpm package **in          ',&
      +        &'  # the same repository**) like this:                                           ',&
      +        &'                                                                                ',&
      +        &'#M_strings = { path = "M_strings" }                                             ',&
      +        &'                                                                                ',&
      +        &'  # This tells fpm that we depend on a crate called M_strings which is found    ',&
      +        &'  # in the M_strings folder (relative to the fpm.toml it’s written in).         ',&
      +        &'  #                                                                             ',&
      +        &'  # For a more verbose layout use normal tables rather than inline tables       ',&
      +        &'  # to specify dependencies:                                                    ',&
      +        &'                                                                                ',&
      +        &'#[dependencies.toml-f]                                                          ',&
      +        &'#git = "https://github.com/toml-f/toml-f"                                       ',&
      +        &'#rev = "2f5eaba864ff630ba0c3791126a3f811b6e437f3"                               ',&
      +        &'                                                                                ',&
      +        &'  # Now you can use any modules from these libraries anywhere in your           ',&
      +        &'  # code -- whether is in your library source or a program source.              ',&
      +        &'                                                                                ',&
      +        &'[dev-dependencies]                                                              ',&
      +        &'                                                                                ',&
      +        &'  ## Dependencies Only for Development                                          ',&
      +        &'  #                                                                             ',&
      +        &'  # You can specify dependencies your library or application does not           ',&
      +        &'  # depend on in a similar way. The difference is that these will not           ',&
      +        &'  # be exported as part of your project to those using it as a remote           ',&
      +        &'  # dependency.                                                                 ',&
      +        &'  #                                                                             ',&
      +        &'  # Currently, like a global dependency it will still be available for          ',&
      +        &'  # all codes. It is up to the developer to ensure that nothing except          ',&
      +        &'  # developer test programs rely upon it.                                       ',&
      +        &'                                                                                ',&
      +        &'#M_msg    = { git = "https://github.com/urbanjost/M_msg.git" }                  ',&
      +        &'#M_verify = { git = "https://github.com/urbanjost/M_verify.git" }               ',&
      +        &'']
      +    endif
      +    if(settings%with_bare)then
      +    elseif(settings%with_executable)then
      +        ! create next section of fpm.toml
      +        call mkdir(join_path(settings%name, 'app'))
      +        ! create NAME/app or stop
      +        if(settings%with_full)then
      +           tomlfile=[character(len=80) ::  tomlfile, &
      +           &'  #-----------------------------------                                          ',&
      +           &'  ## Application-specific declarations                                          ',&
      +           &'  #-----------------------------------                                          ',&
      +           &'  # Now lets begin entries for the TOML tables (lines beginning with "[[")      ',&
      +           &'  # that describe the program sources -- applications, tests, and examples.     ',&
      +           &'  #                                                                             ',&
      +           &'  # First we will configuration individual applications run with "fpm run".     ',&
      +           &'  #                                                                             ',&
      +           &'  #   + the "name" entry for the executable to be built must always             ',&
      +           &'  #     be specified. The name must satisfy the rules for a Fortran             ',&
      +           &'  #     variable name. This will be the name of the binary installed by         ',&
      +           &'  #     the "install" subcommand and used on the "run" subcommand.              ',&
      +           &'  #   + The source directory for each executable can be adjusted by the         ',&
      +           &'  #     "source-dir" entry.                                                     ',&
      +           &'  #   + The basename of the source file containing the program body can         ',&
      +           &'  #     be specified with the "main" entry.                                     ',&
      +           &'  #   + Executables can also specify their own external package and             ',&
      +           &'  #     library link dependencies.                                              ',&
      +           &'  #                                                                             ',&
      +           &'  #     Currently, like a global dependency any external package dependency     ',&
      +           &'  #     will be available for all codes. It is up to the developer to ensure    ',&
      +           &'  #     that nothing except the application programs specified rely upon it.    ',&
      +           &'  #                                                                             ',&
      +           &'  # Note if your application needs to use a module internally, but you do not   ',&
      +           &'  # intend to build it as a library to be used in other projects, you can       ',&
      +           &'  # include the module in your program source file or directory as well.        ',&
      +           &'                                                                                ',&
      +           &'[[executable]]                                                                  ',&
      +           &'name="'//bname//'"',&
      +           &'source-dir="app"                                                                ',&
      +           &'main="main.f90"                                                                 ',&
      +           &'                                                                                ',&
      +           &'  # You may repeat this pattern to define additional applications. For instance,',&
      +           &'  # the following sample illustrates all accepted options, where "link" and     ',&
      +           &'  # "executable.dependencies" keys are the same as the global external library  ',&
      +           &'  # links and package dependencies described previously except they apply       ',&
      +           &'  # only to this executable:                                                    ',&
      +           &'                                                                                ',&
      +           &'#[[ executable ]]                                                               ',&
      +           &'#name = "app-name"                                                              ',&
      +           &'#source-dir = "prog"                                                            ',&
      +           &'#main = "program.f90"                                                           ',&
      +           &'#link = "z"                                                                     ',&
      +           &'#[executable.dependencies]                                                      ',&
      +           &'#M_CLI   = { git = "https://github.com/urbanjost/M_CLI.git" }                   ',&
      +           &'#helloff = { git = "https://gitlab.com/everythingfunctional/helloff.git" }      ',&
      +           &'#M_path  = { git = "https://github.com/urbanjost/M_path.git" }                  ',&
      +           &'']
      +        endif
      +
      +        if(exists(bname//'/src/'))then
      +            littlefile=[character(len=80) ::          &
      +            &'program main',                          &
      +            &'  use '//to_fortran_name(bname)//', only: say_hello',    &
      +            &'  implicit none',                       &
      +            &'',                                      &
      +            &'  call say_hello()',                    &
      +            &'end program main']
      +        else
      +            littlefile=[character(len=80) ::                 &
      +            &'program main',                                 &
      +            &'  implicit none',                              &
      +            &'',                                             &
      +            &'  print *, "hello from project '//bname//'"',  &
      +            &'end program main']
      +        endif
      +        call warnwrite(join_path(settings%name, 'app/main.f90'), littlefile)
      +    endif
      +
      +    if(settings%with_bare)then
      +    elseif(settings%with_test)then
      +
      +       ! create NAME/test or stop
      +       call mkdir(join_path(settings%name, 'test'))
      +        ! create next section of fpm.toml
      +        if(settings%with_full)then
      +           tomlfile=[character(len=80) ::  tomlfile ,&
      +           &'[[test]]                                                                        ',&
      +           &'                                                                                ',&
      +           &'  # The same declarations can be made for test programs, which are              ',&
      +           &'  # executed with the "fpm test" command and are not build when your            ',&
      +           &'  # package is used as a dependency by other packages. These are                ',&
      +           &'  # typically unit tests of the package only used during package                ',&
      +           &'  # development.                                                                ',&
      +           &'                                                                                ',&
      +           &'name="runTests"                                                                 ',&
      +           &'source-dir="test"                                                               ',&
      +           &'main="check.f90"                                                                ',&
      +           &'                                                                                ',&
      +           &'  # you may repeat this pattern to add additional explicit test program         ',&
      +           &'  # parameters. The following example contains a sample of all accepted         ',&
      +           &'  # options.                                                                    ',&
      +           &'                                                                                ',&
      +           &'#[[ test ]]                                                                     ',&
      +           &'#name = "tester"                                                                ',&
      +           &'#source-dir="test"                                                              ',&
      +           &'#main="tester.f90"                                                              ',&
      +           &'#link = ["blas", "lapack"]                                                      ',&
      +           &'#[test.dependencies]                                                            ',&
      +           &'#M_CLI2  = { git = "https://github.com/urbanjost/M_CLI2.git" }                  ',&
      +           &'#M_io    = { git = "https://github.com/urbanjost/M_io.git" }                    ',&
      +           &'#M_system= { git = "https://github.com/urbanjost/M_system.git" }                ',&
      +           &'']
      +        endif
      +
      +        littlefile=[character(len=80) ::       &
      +        &'program check',                      &
      +        &'implicit none',                      &
      +        &'',                                   &
      +        &'print *, "Put some tests in here!"', &
      +        &'end program check']
      +        ! create NAME/test/check.f90
      +        call warnwrite(join_path(settings%name, 'test/check.f90'), littlefile)
      +    endif
      +
      +    if(settings%with_bare)then
      +    elseif(settings%with_example)then
      +
      +       ! create NAME/example or stop
      +       call mkdir(join_path(settings%name, 'example'))
      +        ! create next section of fpm.toml
      +        if(settings%with_full)then
      +           tomlfile=[character(len=80) ::  tomlfile, &
      +           &'[[example]]                                                                     ',&
      +           &'                                                                                ',&
      +           &'  # Example applications for a project are defined here.                        ',&
      +           &'  # These are run via "fpm run --example NAME" and like the                     ',&
      +           &'  # test applications, are not built when this package is used as a             ',&
      +           &'  # dependency by other packages.                                               ',&
      +           &'                                                                                ',&
      +           &'name="demo"                                                                     ',&
      +           &'source-dir="example"                                                            ',&
      +           &'main="demo.f90"                                                                 ',&
      +           &'                                                                                ',&
      +           &'  #                                                                             ',&
      +           &'  # you may add additional programs to the example table. The following         ',&
      +           &'  # example contains a sample of all accepted options                           ',&
      +           &'                                                                                ',&
      +           &'#[[ example ]]                                                                  ',&
      +           &'#name = "example-tool"                                                          ',&
      +           &'#source-dir="example"                                                           ',&
      +           &'#main="tool.f90"                                                                ',&
      +           &'#link = "z"                                                                     ',&
      +           &'#[example.dependencies]                                                         ',&
      +           &'#M_kracken95  = { git = "https://github.com/urbanjost/M_kracken95.git" }        ',&
      +           &'#datetime = {git = "https://github.com/wavebitscientific/datetime-fortran.git" }',&
      +           &'']
      +        endif
      +
      +        littlefile=[character(len=80) ::          &
      +        &'program demo',                          &
      +        &'implicit none',                         &
      +        &'',                                      &
      +        &'print *, "Put some examples in here!"', &
      +        &'end program demo']
      +        ! create NAME/example/demo.f90
      +        call warnwrite(join_path(settings%name, 'example/demo.f90'), littlefile)
      +    endif
      +
      +    ! now that built it write NAME/fpm.toml
      +    if( allocated(tomlfile) )then
      +        call validate_toml_data(tomlfile)
      +        call warnwrite(join_path(settings%name, 'fpm.toml'), tomlfile)
      +    else
      +        call create_verified_basic_manifest(join_path(settings%name, 'fpm.toml'))
      +    endif
      +    ! assumes git(1) is installed and in path
      +    if(which('git')/='')then
      +      call run('git init ' // settings%name)
      +    endif
      +contains
      +
      +function git_metadata(what) result(returned)
      +!> get metadata values such as email address and git name from git(1) or return appropriate default
      +  use fpm_filesystem, only : get_temp_filename, getline
      +  character(len=*), intent(in)  :: what     ! keyword designating what git metatdata to query
      +  character(len=:), allocatable :: returned ! value to return for requested keyword
      +  character(len=:), allocatable :: command
      +  character(len=:), allocatable :: temp_filename
      +  character(len=:), allocatable :: iomsg
      +  character(len=:), allocatable :: temp_value
      +  integer :: stat, unit
      +  temp_filename = get_temp_filename()
      +  ! for known keywords set default value for RETURNED and associated git(1) command for query
      +  select case(what)
      +  case('uname')
      +    returned = "Jane Doe"
      +    command = "git config --get user.name > " // temp_filename
      +  case('email')
      +    returned = "jane.doe@example.com"
      +    command = "git config --get user.email > " // temp_filename
      +  case default
      +    write(stderr,'(*(g0,1x))')&
      +    & '<ERROR> *git_metadata* unknown metadata name ',trim(what)
      +    returned=''
      +    return
      +  end select
      +  ! Execute command if git(1) is in command path
      +  if(which('git')/='')then
      +     call run(command, exitstat=stat)
      +     if (stat /= 0) then ! If command failed just return default
      +        return
      +     else ! Command did not return an error so try to read expected output file
      +        open(file=temp_filename, newunit=unit,iostat=stat)
      +        if(stat == 0)then
      +           ! Read file into a scratch variable until status of doing so is checked
      +           call getline(unit, temp_value, stat, iomsg)
      +           if (stat == 0 .and. temp_value /= '') then
      +              ! Return output from successful command
      +              returned=temp_value
      +           endif
      +        endif
      +        ! Always do the CLOSE because a failed open has unpredictable results.
      +        ! Add IOSTAT so a failed close does not cause program to stop
      +        close(unit, status="delete",iostat=stat)
      +     endif
      +  endif
      +end function git_metadata
      +
      +subroutine create_verified_basic_manifest(filename)
      +!> create a basic but verified default manifest file
      +use tomlf, only : toml_table, toml_serialize
      +use fpm_toml, only : set_value
      +use fpm_manifest_package, only : package_config_t, new_package
      +use fpm_error, only : error_t
      +implicit none
      +character(len=*),intent(in) :: filename
      +   type(toml_table)            :: table
      +   type(package_config_t)      :: package
      +   type(error_t), allocatable  :: error
      +   integer                     :: lun
      +   character(len=8)            :: date
      +   character(:), allocatable   :: output
      +
      +    if(exists(filename))then
      +       write(stderr,'(*(g0,1x))')'<INFO>  ',filename,&
      +       & 'already exists. Not overwriting'
      +       return
      +    endif
      +    !> get date to put into metadata in manifest file "fpm.toml"
      +    call date_and_time(DATE=date)
      +    table = toml_table()
      +    call fileopen(filename,lun) ! fileopen stops on error
      +
      +    call set_value(table, "name",       BNAME)
      +    call set_value(table, "version",    "0.1.0")
      +    call set_value(table, "license",    "license")
      +    call set_value(table, "author",     git_metadata('uname'))
      +    call set_value(table, "maintainer", git_metadata('email'))
      +    call set_value(table, "copyright",  'Copyright '//date(1:4)//', '//git_metadata('uname'))
      +    ! continue building of manifest
      +    ! ...
      +    call new_package(package, table, error=error)
      +    if (allocated(error)) call fpm_stop( 3,'')
      +    output = toml_serialize(table)
      +    if(settings%verbose)then
      +       print '(a)', output
      +    endif
      +    write(lun, '(a)') output
      +    call fileclose(lun) ! fileopen stops on error
      +
      +end subroutine create_verified_basic_manifest
      +
      +
      +subroutine validate_toml_data(input)
      +!> verify a string array is a valid fpm.toml file
      +!
      +use tomlf, only : toml_table, toml_load, toml_serialize
      +implicit none
      +character(kind=tfc,len=:),intent(in),allocatable :: input(:)
      +character(len=1), parameter                      :: nl = new_line('a')
      +type(toml_table), allocatable                    :: table
      +character(kind=tfc, len=:), allocatable          :: joined_string
      +
      +! you have to add a newline character by using the intrinsic
      +! function `new_line("a")` to get the lines processed correctly.
      +joined_string = join(input,right=nl)
      +
      +if (allocated(table)) deallocate(table)
      +call toml_load(table, joined_string)
      +if (allocated(table)) then
      +   if(settings%verbose)then
      +      ! If the TOML file is successfully parsed the table will be allocated and
      +      ! can be written by `toml_serialize` to the standard output
      +      print '(a)', toml_serialize(table)
      +   endif
      +   call table%destroy
      +endif
      +
      +end subroutine validate_toml_data
      +
      +end subroutine cmd_new
      +
      +end module fpm_cmd_new
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/package.f90.html b/sourcefile/package.f90.html new file mode 100644 index 0000000000..d5267b4910 --- /dev/null +++ b/sourcefile/package.f90.html @@ -0,0 +1,1301 @@ + + + + + + + + + + + + + package.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      package.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      !> Define the package data containing the meta data from the configuration file.
      +!>
      +!> The package data defines a Fortran type corresponding to the respective
      +!> TOML document, after creating it from a package file no more interaction
      +!> with the TOML document is required.
      +!>
      +!> Every configuration type provides it custom constructor (prefixed with `new_`)
      +!> and knows how to deserialize itself from a TOML document.
      +!> To ensure we find no untracked content in the package file all keywords are
      +!> checked and possible entries have to be explicitly allowed in the `check`
      +!> function.
      +!> If entries are mutally exclusive or interdependent inside the current table
      +!> the `check` function is required to enforce this schema on the data structure.
      +!>
      +!> The package file root allows the following keywords
      +!>
      +!>```toml
      +!>name = "string"
      +!>version = "string"
      +!>license = "string"
      +!>author = "string"
      +!>maintainer = "string"
      +!>copyright = "string"
      +!>[library]
      +!>[dependencies]
      +!>[dev-dependencies]
      +!>[profiles]
      +!>[build]
      +!>[install]
      +!>[fortran]
      +!>[[ executable ]]
      +!>[[ example ]]
      +!>[[ test ]]
      +!>[extra]
      +!>```
      +module fpm_manifest_package
      +    use fpm_manifest_build, only: build_config_t, new_build_config
      +    use fpm_manifest_dependency, only : dependency_config_t, new_dependencies
      +    use fpm_manifest_profile, only : profile_config_t, new_profiles, get_default_profiles
      +    use fpm_manifest_example, only : example_config_t, new_example
      +    use fpm_manifest_executable, only : executable_config_t, new_executable
      +    use fpm_manifest_fortran, only : fortran_config_t, new_fortran_config
      +    use fpm_manifest_library, only : library_config_t, new_library
      +    use fpm_manifest_install, only: install_config_t, new_install_config
      +    use fpm_manifest_test, only : test_config_t, new_test
      +    use fpm_manifest_preprocess, only : preprocess_config_t, new_preprocessors
      +    use fpm_manifest_metapackages, only: metapackage_config_t, new_meta_config
      +    use fpm_filesystem, only : exists, getline, join_path
      +    use fpm_error, only : error_t, fatal_error, syntax_error, bad_name_error
      +    use tomlf, only : toml_table, toml_array, toml_key, toml_stat
      +    use fpm_toml, only : get_value, len, serializable_t, set_value, set_string, set_list, add_table
      +    use fpm_versioning, only : version_t, new_version
      +    implicit none
      +    private
      +
      +    public :: package_config_t, new_package
      +
      +
      +    interface unique_programs
      +        module procedure :: unique_programs1
      +        module procedure :: unique_programs2
      +    end interface unique_programs
      +
      +
      +    !> Package meta data
      +    type, extends(serializable_t) :: package_config_t
      +
      +        !> Name of the package
      +        character(len=:), allocatable :: name
      +
      +        !> Package version
      +        type(version_t) :: version
      +
      +        !> Build configuration data
      +        type(build_config_t) :: build
      +
      +        !> Metapackage data
      +        type(metapackage_config_t) :: meta
      +
      +        !> Installation configuration data
      +        type(install_config_t) :: install
      +
      +        !> Fortran meta data
      +        type(fortran_config_t) :: fortran
      +
      +        !> License meta data
      +        character(len=:), allocatable :: license
      +
      +        !> Author meta data
      +        character(len=:), allocatable :: author
      +
      +        !> Maintainer meta data
      +        character(len=:), allocatable :: maintainer
      +
      +        !> Copyright meta data
      +        character(len=:), allocatable :: copyright
      +
      +        !> Library meta data
      +        type(library_config_t), allocatable :: library
      +
      +        !> Executable meta data
      +        type(executable_config_t), allocatable :: executable(:)
      +
      +        !> Dependency meta data
      +        type(dependency_config_t), allocatable :: dependency(:)
      +
      +        !> Development dependency meta data
      +        type(dependency_config_t), allocatable :: dev_dependency(:)
      +
      +        !> Profiles meta data
      +        type(profile_config_t), allocatable :: profiles(:)
      +
      +        !> Example meta data
      +        type(example_config_t), allocatable :: example(:)
      +
      +        !> Test meta data
      +        type(test_config_t), allocatable :: test(:)
      +
      +        !> Preprocess meta data
      +        type(preprocess_config_t), allocatable :: preprocess(:)
      +
      +    contains
      +
      +        !> Print information on this instance
      +        procedure :: info
      +
      +        !> Serialization interface
      +        procedure :: serializable_is_same => manifest_is_same
      +        procedure :: dump_to_toml
      +        procedure :: load_from_toml
      +
      +    end type package_config_t
      +
      +    character(len=*), parameter, private :: class_name = 'package_config_t'
      +
      +
      +contains
      +
      +
      +    !> Construct a new package configuration from a TOML data structure
      +    subroutine new_package(self, table, root, error)
      +
      +        !> Instance of the package configuration
      +        type(package_config_t), intent(out) :: self
      +
      +        !> Instance of the TOML data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> Root directory of the manifest
      +        character(len=*), intent(in), optional :: root
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        ! Backspace (8), tabulator (9), newline (10), formfeed (12) and carriage
      +        ! return (13) are invalid in package names
      +        character(len=*), parameter :: invalid_chars = &
      +           achar(8) // achar(9) // achar(10) // achar(12) // achar(13)
      +        type(toml_table), pointer :: child, node
      +        type(toml_array), pointer :: children
      +        character(len=:), allocatable :: version, version_file
      +        integer :: ii, nn, stat, io
      +
      +        call check(table, error)
      +        if (allocated(error)) return
      +
      +        call get_value(table, "name", self%name)
      +        if (.not.allocated(self%name)) then
      +           call syntax_error(error, "Could not retrieve package name")
      +           return
      +        end if
      +        if (bad_name_error(error,'package',self%name))then
      +           return
      +        endif
      +
      +        call get_value(table, "license", self%license)
      +        call get_value(table, "author", self%author)
      +        call get_value(table, "maintainer", self%maintainer)
      +        call get_value(table, "copyright", self%copyright)
      +
      +        if (len(self%name) <= 0) then
      +            call syntax_error(error, "Package name must be a non-empty string")
      +            return
      +        end if
      +
      +        ii = scan(self%name, invalid_chars)
      +        if (ii > 0) then
      +            call syntax_error(error, "Package name contains invalid characters")
      +            return
      +        end if
      +
      +        call get_value(table, "build", child, requested=.true., stat=stat)
      +        if (stat /= toml_stat%success) then
      +            call fatal_error(error, "Type mismatch for build entry, must be a table")
      +            return
      +        end if
      +        call new_build_config(self%build, child, self%name, error)
      +        if (allocated(error)) return
      +
      +        call get_value(table, "install", child, requested=.true., stat=stat)
      +        if (stat /= toml_stat%success) then
      +            call fatal_error(error, "Type mismatch for install entry, must be a table")
      +            return
      +        end if
      +        call new_install_config(self%install, child, error)
      +        if (allocated(error)) return
      +
      +        call get_value(table, "fortran", child, requested=.true., stat=stat)
      +        if (stat /= toml_stat%success) then
      +            call fatal_error(error, "Type mismatch for fortran entry, must be a table")
      +            return
      +        end if
      +        call new_fortran_config(self%fortran, child, error)
      +        if (allocated(error)) return
      +
      +        call get_value(table, "version", version, "0")
      +        call new_version(self%version, version, error)
      +        if (allocated(error) .and. present(root)) then
      +            version_file = join_path(root, version)
      +            if (exists(version_file)) then
      +                deallocate(error)
      +                open(file=version_file, newunit=io, iostat=stat)
      +                if (stat == 0) then
      +                    call getline(io, version, iostat=stat)
      +                end if
      +                if (stat == 0) then
      +                    close(io, iostat=stat)
      +                end if
      +                if (stat == 0) then
      +                    call new_version(self%version, version, error)
      +                else
      +                    call fatal_error(error, "Reading version number from file '" &
      +                        & //version_file//"' failed")
      +                end if
      +            end if
      +        end if
      +        if (allocated(error)) return
      +
      +        call get_value(table, "dependencies", child, requested=.false.)
      +        if (associated(child)) then
      +            call new_dependencies(self%dependency, child, root, self%meta, error)
      +            if (allocated(error)) return
      +        end if
      +
      +        call get_value(table, "dev-dependencies", child, requested=.false.)
      +        if (associated(child)) then
      +            call new_dependencies(self%dev_dependency, child, root, error=error)
      +            if (allocated(error)) return
      +        end if
      +
      +        call get_value(table, "library", child, requested=.false.)
      +        if (associated(child)) then
      +            allocate(self%library)
      +            call new_library(self%library, child, error)
      +            if (allocated(error)) return
      +        end if
      +
      +        call get_value(table, "profiles", child, requested=.false.)
      +        if (associated(child)) then
      +            call new_profiles(self%profiles, child, error)
      +            if (allocated(error)) return
      +        else
      +            self%profiles = get_default_profiles(error)
      +            if (allocated(error)) return
      +        end if
      +
      +        call get_value(table, "executable", children, requested=.false.)
      +        if (associated(children)) then
      +            nn = len(children)
      +            allocate(self%executable(nn))
      +            do ii = 1, nn
      +                call get_value(children, ii, node, stat=stat)
      +                if (stat /= toml_stat%success) then
      +                    call fatal_error(error, "Could not retrieve executable from array entry")
      +                    exit
      +                end if
      +                call new_executable(self%executable(ii), node, error)
      +                if (allocated(error)) exit
      +            end do
      +            if (allocated(error)) return
      +
      +            call unique_programs(self%executable, error)
      +            if (allocated(error)) return
      +        end if
      +
      +        call get_value(table, "example", children, requested=.false.)
      +        if (associated(children)) then
      +            nn = len(children)
      +            allocate(self%example(nn))
      +            do ii = 1, nn
      +                call get_value(children, ii, node, stat=stat)
      +                if (stat /= toml_stat%success) then
      +                    call fatal_error(error, "Could not retrieve example from array entry")
      +                    exit
      +                end if
      +                call new_example(self%example(ii), node, error)
      +                if (allocated(error)) exit
      +            end do
      +            if (allocated(error)) return
      +
      +            call unique_programs(self%example, error)
      +            if (allocated(error)) return
      +
      +            if (allocated(self%executable)) then
      +                call unique_programs(self%executable, self%example, error)
      +                if (allocated(error)) return
      +            end if
      +        end if
      +
      +        call get_value(table, "test", children, requested=.false.)
      +        if (associated(children)) then
      +            nn = len(children)
      +            allocate(self%test(nn))
      +            do ii = 1, nn
      +                call get_value(children, ii, node, stat=stat)
      +                if (stat /= toml_stat%success) then
      +                    call fatal_error(error, "Could not retrieve test from array entry")
      +                    exit
      +                end if
      +                call new_test(self%test(ii), node, error)
      +                if (allocated(error)) exit
      +            end do
      +            if (allocated(error)) return
      +
      +            call unique_programs(self%test, error)
      +            if (allocated(error)) return
      +        end if
      +
      +        call get_value(table, "preprocess", child, requested=.false.)
      +        if (associated(child)) then
      +            call new_preprocessors(self%preprocess, child, error)
      +            if (allocated(error)) return
      +        end if
      +    end subroutine new_package
      +
      +
      +    !> Check local schema for allowed entries
      +    subroutine check(table, error)
      +
      +        !> Instance of the TOML data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        type(toml_key), allocatable :: list(:)
      +        logical :: name_present
      +        integer :: ikey
      +
      +        name_present = .false.
      +
      +        call table%get_keys(list)
      +
      +        if (size(list) < 1) then
      +            call syntax_error(error, "Package file is empty")
      +            return
      +        end if
      +
      +        do ikey = 1, size(list)
      +            select case(list(ikey)%key)
      +            case default
      +                call syntax_error(error, "Key "//list(ikey)%key//" is not allowed in package file")
      +                exit
      +
      +            case("name")
      +                name_present = .true.
      +
      +            case("version", "license", "author", "maintainer", "copyright", &
      +                    & "description", "keywords", "categories", "homepage", "build", &
      +                    & "dependencies", "dev-dependencies", "profiles", "test", "executable", &
      +                    & "example", "library", "install", "extra", "preprocess", "fortran")
      +                continue
      +
      +            end select
      +        end do
      +        if (allocated(error)) return
      +
      +        if (.not.name_present) then
      +            call syntax_error(error, "Package name is not provided, please add a name entry")
      +        end if
      +
      +    end subroutine check
      +
      +
      +    !> Write information on instance
      +    subroutine info(self, unit, verbosity)
      +
      +        !> Instance of the package configuration
      +        class(package_config_t), intent(in) :: self
      +
      +        !> Unit for IO
      +        integer, intent(in) :: unit
      +
      +        !> Verbosity of the printout
      +        integer, intent(in), optional :: verbosity
      +
      +        integer :: pr, ii
      +        character(len=*), parameter :: fmt = '("#", 1x, a, t30, a)', &
      +            & fmti = '("#", 1x, a, t30, i0)'
      +
      +        if (present(verbosity)) then
      +            pr = verbosity
      +        else
      +            pr = 1
      +        end if
      +
      +        if (pr < 1) return
      +
      +        write(unit, fmt) "Package"
      +        if (allocated(self%name)) then
      +            write(unit, fmt) "- name", self%name
      +        end if
      +
      +        call self%build%info(unit, pr - 1)
      +
      +        call self%install%info(unit, pr - 1)
      +
      +        if (allocated(self%library)) then
      +            write(unit, fmt) "- target", "archive"
      +            call self%library%info(unit, pr - 1)
      +        end if
      +
      +        if (allocated(self%executable)) then
      +            if (size(self%executable) > 1 .or. pr > 2) then
      +                write(unit, fmti) "- executables", size(self%executable)
      +            end if
      +            do ii = 1, size(self%executable)
      +                call self%executable(ii)%info(unit, pr - 1)
      +            end do
      +        end if
      +
      +        if (allocated(self%dependency)) then
      +            if (size(self%dependency) > 1 .or. pr > 2) then
      +                write(unit, fmti) "- dependencies", size(self%dependency)
      +            end if
      +            do ii = 1, size(self%dependency)
      +                call self%dependency(ii)%info(unit, pr - 1)
      +            end do
      +        end if
      +
      +        if (allocated(self%example)) then
      +            if (size(self%example) > 1 .or. pr > 2) then
      +                write(unit, fmti) "- examples", size(self%example)
      +            end if
      +            do ii = 1, size(self%example)
      +                call self%example(ii)%info(unit, pr - 1)
      +            end do
      +        end if
      +
      +        if (allocated(self%test)) then
      +            if (size(self%test) > 1 .or. pr > 2) then
      +                write(unit, fmti) "- tests", size(self%test)
      +            end if
      +            do ii = 1, size(self%test)
      +                call self%test(ii)%info(unit, pr - 1)
      +            end do
      +        end if
      +
      +        if (allocated(self%dev_dependency)) then
      +            if (size(self%dev_dependency) > 1 .or. pr > 2) then
      +                write(unit, fmti) "- development deps.", size(self%dev_dependency)
      +            end if
      +            do ii = 1, size(self%dev_dependency)
      +                call self%dev_dependency(ii)%info(unit, pr - 1)
      +            end do
      +        end if
      +
      +        if (allocated(self%profiles)) then
      +            if (size(self%profiles) > 1 .or. pr > 2) then
      +                write(unit, fmti) "- profiles", size(self%profiles)
      +            end if
      +            do ii = 1, size(self%profiles)
      +                call self%profiles(ii)%info(unit, pr - 1)
      +            end do
      +        end if
      +
      +    end subroutine info
      +
      +
      +    !> Check whether or not the names in a set of executables are unique
      +    subroutine unique_programs1(executable, error)
      +
      +        !> Array of executables
      +        class(executable_config_t), intent(in) :: executable(:)
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        integer :: i, j
      +
      +        do i = 1, size(executable)
      +            do j = 1, i - 1
      +                if (executable(i)%name == executable(j)%name) then
      +                    call fatal_error(error, "The program named '"//&
      +                        executable(j)%name//"' is duplicated. "//&
      +                        "Unique program names are required.")
      +                    exit
      +                end if
      +            end do
      +        end do
      +        if (allocated(error)) return
      +
      +    end subroutine unique_programs1
      +
      +
      +    !> Check whether or not the names in a set of executables are unique
      +    subroutine unique_programs2(executable_i, executable_j, error)
      +
      +        !> Array of executables
      +        class(executable_config_t), intent(in) :: executable_i(:)
      +
      +        !> Array of executables
      +        class(executable_config_t), intent(in) :: executable_j(:)
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        integer :: i, j
      +
      +        do i = 1, size(executable_i)
      +            do j = 1, size(executable_j)
      +                if (executable_i(i)%name == executable_j(j)%name) then
      +                    call fatal_error(error, "The program named '"//&
      +                        executable_j(j)%name//"' is duplicated. "//&
      +                        "Unique program names are required.")
      +                    exit
      +                end if
      +            end do
      +        end do
      +        if (allocated(error)) return
      +
      +    end subroutine unique_programs2
      +
      +   logical function manifest_is_same(this,that)
      +      class(package_config_t), intent(in) :: this
      +      class(serializable_t), intent(in) :: that
      +
      +      integer :: ii
      +
      +      manifest_is_same = .false.
      +
      +      select type (other=>that)
      +         type is (package_config_t)
      +         if (allocated(this%name).neqv.allocated(other%name)) return
      +            if (allocated(this%name) .and. allocated(other%name)) then
      +                if (.not.this%name==other%name) return
      +            end if
      +            if (.not.this%version==other%version) return
      +            if (.not.this%build==other%build) return
      +            if (.not.this%install==other%install) return
      +            if (.not.this%fortran==other%fortran) return
      +            if (allocated(this%license).neqv.allocated(other%license)) return
      +            if (allocated(this%license)) then
      +                if (.not.this%license==other%license) return
      +            end if
      +            if (allocated(this%author).neqv.allocated(other%author)) return
      +            if (allocated(this%author)) then
      +                if (.not.this%author==other%author) return
      +            end if
      +            if (allocated(this%maintainer).neqv.allocated(other%maintainer)) return
      +            if (allocated(this%maintainer)) then
      +                if (.not.this%maintainer==other%maintainer) return
      +            end if
      +            if (allocated(this%copyright).neqv.allocated(other%copyright)) return
      +            if (allocated(this%copyright)) then
      +                if (.not.this%copyright==other%copyright) return
      +            end if
      +            if (allocated(this%library).neqv.allocated(other%library)) return
      +            if (allocated(this%library)) then
      +                if (.not.this%library==other%library) return
      +            endif
      +            if (allocated(this%executable).neqv.allocated(other%executable)) return
      +            if (allocated(this%executable)) then
      +                if (.not.size(this%executable)==size(other%executable)) return
      +                do ii=1,size(this%executable)
      +                    if (.not.this%executable(ii)==other%executable(ii)) return
      +                end do
      +            end if
      +            if (allocated(this%dependency).neqv.allocated(other%dependency)) return
      +            if (allocated(this%dependency)) then
      +                if (.not.size(this%dependency)==size(other%dependency)) return
      +                do ii=1,size(this%dependency)
      +                    if (.not.this%dependency(ii)==other%dependency(ii)) return
      +                end do
      +            end if
      +            if (allocated(this%dev_dependency).neqv.allocated(other%dev_dependency)) return
      +            if (allocated(this%dev_dependency)) then
      +                if (.not.size(this%dev_dependency)==size(other%dev_dependency)) return
      +                do ii=1,size(this%dev_dependency)
      +                    if (.not.this%dev_dependency(ii)==other%dev_dependency(ii)) return
      +                end do
      +            end if
      +            if (allocated(this%profiles).neqv.allocated(other%profiles)) return
      +            if (allocated(this%profiles)) then
      +                if (.not.size(this%profiles)==size(other%profiles)) return
      +                do ii=1,size(this%profiles)
      +                    if (.not.this%profiles(ii)==other%profiles(ii)) return
      +                end do
      +            end if
      +            if (allocated(this%example).neqv.allocated(other%example)) return
      +            if (allocated(this%example)) then
      +                if (.not.size(this%example)==size(other%example)) return
      +                do ii=1,size(this%example)
      +                    if (.not.this%example(ii)==other%example(ii)) return
      +                end do
      +            end if
      +            if (allocated(this%preprocess).neqv.allocated(other%preprocess)) return
      +            if (allocated(this%preprocess)) then
      +                if (.not.size(this%preprocess)==size(other%preprocess)) return
      +                do ii=1,size(this%preprocess)
      +                    if (.not.this%preprocess(ii)==other%preprocess(ii)) return
      +                end do
      +            end if
      +            if (allocated(this%test).neqv.allocated(other%test)) return
      +            if (allocated(this%test)) then
      +                if (.not.size(this%test)==size(other%test)) return
      +                do ii=1,size(this%test)
      +                    if (.not.this%test(ii)==other%test(ii)) return
      +                end do
      +            end if
      +
      +         class default
      +            ! Not the same type
      +            return
      +      end select
      +
      +      !> All checks passed!
      +      manifest_is_same = .true.
      +
      +    end function manifest_is_same
      +
      +    !> Dump manifest to toml table
      +    subroutine dump_to_toml(self, table, error)
      +
      +       !> Instance of the serializable object
      +       class(package_config_t), intent(inout) :: self
      +
      +       !> Data structure
      +       type(toml_table), intent(inout) :: table
      +
      +       !> Error handling
      +       type(error_t), allocatable, intent(out) :: error
      +
      +       integer :: ii
      +       type(toml_table), pointer :: ptr,ptr_pkg
      +       character(30) :: unnamed
      +       character(128) :: profile_name
      +
      +       call set_string(table, "name", self%name, error, class_name)
      +       if (allocated(error)) return
      +       call set_string(table, "version", self%version%s(), error, class_name)
      +       if (allocated(error)) return
      +       call set_string(table, "license", self%license, error, class_name)
      +       if (allocated(error)) return
      +       call set_string(table, "author", self%author, error, class_name)
      +       if (allocated(error)) return
      +       call set_string(table, "maintainer", self%maintainer, error, class_name)
      +       if (allocated(error)) return
      +       call set_string(table, "copyright", self%copyright, error, class_name)
      +       if (allocated(error)) return
      +
      +       call add_table(table, "build", ptr, error, class_name)
      +       if (allocated(error)) return
      +       call self%build%dump_to_toml(ptr, error)
      +       if (allocated(error)) return
      +
      +       call add_table(table, "fortran", ptr, error, class_name)
      +       if (allocated(error)) return
      +       call self%fortran%dump_to_toml(ptr, error)
      +       if (allocated(error)) return
      +
      +       call add_table(table, "install", ptr, error, class_name)
      +       if (allocated(error)) return
      +       call self%install%dump_to_toml(ptr, error)
      +       if (allocated(error)) return
      +
      +       if (allocated(self%library)) then
      +           call add_table(table, "library", ptr, error, class_name)
      +           if (allocated(error)) return
      +           call self%library%dump_to_toml(ptr, error)
      +           if (allocated(error)) return
      +       end if
      +
      +       if (allocated(self%executable)) then
      +
      +           call add_table(table, "executable", ptr_pkg)
      +           if (.not. associated(ptr_pkg)) then
      +              call fatal_error(error, class_name//" cannot create 'executable' table ")
      +              return
      +           end if
      +
      +           do ii = 1, size(self%executable)
      +
      +              associate (pkg => self%executable(ii))
      +
      +                 !> Because dependencies are named, fallback if this has no name
      +                 !> So, serialization will work regardless of size(self%dep) == self%ndep
      +                 if (len_trim(pkg%name)==0) then
      +                    write(unnamed,1) 'EXECUTABLE',ii
      +                    call add_table(ptr_pkg, trim(unnamed), ptr, error, class_name//'(executable)')
      +                 else
      +                    call add_table(ptr_pkg, pkg%name, ptr, error, class_name//'(executable)')
      +                 end if
      +                 if (allocated(error)) return
      +                 call pkg%dump_to_toml(ptr, error)
      +                 if (allocated(error)) return
      +
      +              end associate
      +
      +           end do
      +       end if
      +
      +       if (allocated(self%dependency)) then
      +
      +           call add_table(table, "dependencies", ptr_pkg)
      +           if (.not. associated(ptr_pkg)) then
      +              call fatal_error(error, class_name//" cannot create 'dependencies' table ")
      +              return
      +           end if
      +
      +           do ii = 1, size(self%dependency)
      +
      +              associate (pkg => self%dependency(ii))
      +
      +                 !> Because dependencies are named, fallback if this has no name
      +                 !> So, serialization will work regardless of size(self%dep) == self%ndep
      +                 if (len_trim(pkg%name)==0) then
      +                    write(unnamed,1) 'DEPENDENCY',ii
      +                    call add_table(ptr_pkg, trim(unnamed), ptr, error, class_name//'(dependencies)')
      +                 else
      +                    call add_table(ptr_pkg, pkg%name, ptr, error, class_name//'(dependencies)')
      +                 end if
      +                 if (allocated(error)) return
      +                 call pkg%dump_to_toml(ptr, error)
      +                 if (allocated(error)) return
      +
      +              end associate
      +
      +           end do
      +       end if
      +
      +       if (allocated(self%dev_dependency)) then
      +
      +           call add_table(table, "dev-dependencies", ptr_pkg)
      +           if (.not. associated(ptr_pkg)) then
      +              call fatal_error(error, class_name//" cannot create 'dev-dependencies' table ")
      +              return
      +           end if
      +
      +           do ii = 1, size(self%dev_dependency)
      +
      +              associate (pkg => self%dev_dependency(ii))
      +
      +                 !> Because dependencies are named, fallback if this has no name
      +                 !> So, serialization will work regardless of size(self%dep) == self%ndep
      +                 if (len_trim(pkg%name)==0) then
      +                    write(unnamed,1) 'DEV-DEPENDENCY',ii
      +                    call add_table(ptr_pkg, trim(unnamed), ptr, error, class_name//'(dev-dependencies)')
      +                 else
      +                    call add_table(ptr_pkg, pkg%name, ptr, error, class_name//'(dev-dependencies)')
      +                 end if
      +                 if (allocated(error)) return
      +                 call pkg%dump_to_toml(ptr, error)
      +                 if (allocated(error)) return
      +
      +              end associate
      +
      +           end do
      +       end if
      +
      +       if (allocated(self%profiles)) then
      +
      +           call add_table(table, "profiles", ptr_pkg)
      +           if (.not. associated(ptr_pkg)) then
      +              call fatal_error(error, class_name//" cannot create 'profiles' table ")
      +              return
      +           end if
      +
      +           do ii = 1, size(self%profiles)
      +
      +              associate (pkg => self%profiles(ii))
      +
      +                 !> Duplicate profile names are possible, as multiple profiles are possible with the
      +                 !> same name, same compiler, etc. So, use a unique name here
      +                 write(profile_name,2) ii
      +                 call add_table(ptr_pkg, trim(profile_name), ptr, error, class_name//'(profiles)')
      +                 if (allocated(error)) return
      +                 call pkg%dump_to_toml(ptr, error)
      +                 if (allocated(error)) return
      +
      +              end associate
      +
      +           end do
      +       end if
      +
      +       if (allocated(self%example)) then
      +
      +           call add_table(table, "example", ptr_pkg)
      +           if (.not. associated(ptr_pkg)) then
      +              call fatal_error(error, class_name//" cannot create 'example' table ")
      +              return
      +           end if
      +
      +           do ii = 1, size(self%example)
      +
      +              associate (pkg => self%example(ii))
      +
      +                 !> Because dependencies are named, fallback if this has no name
      +                 !> So, serialization will work regardless of size(self%dep) == self%ndep
      +                 if (len_trim(pkg%name)==0) then
      +                    write(unnamed,1) 'EXAMPLE',ii
      +                    call add_table(ptr_pkg, trim(unnamed), ptr, error, class_name//'(example)')
      +                 else
      +                    call add_table(ptr_pkg, pkg%name, ptr, error, class_name//'(example)')
      +                 end if
      +                 if (allocated(error)) return
      +                 call pkg%dump_to_toml(ptr, error)
      +                 if (allocated(error)) return
      +
      +              end associate
      +
      +           end do
      +       end if
      +
      +       if (allocated(self%test)) then
      +
      +           call add_table(table, "test", ptr_pkg)
      +           if (.not. associated(ptr_pkg)) then
      +              call fatal_error(error, class_name//" cannot create 'test' table ")
      +              return
      +           end if
      +
      +           do ii = 1, size(self%test)
      +
      +              associate (pkg => self%test(ii))
      +
      +                 !> Because dependencies are named, fallback if this has no name
      +                 !> So, serialization will work regardless of size(self%dep) == self%ndep
      +                 if (len_trim(pkg%name)==0) then
      +                    write(unnamed,1) 'TEST',ii
      +                    call add_table(ptr_pkg, trim(unnamed), ptr, error, class_name//'(test)')
      +                 else
      +                    call add_table(ptr_pkg, pkg%name, ptr, error, class_name//'(test)')
      +                 end if
      +                 if (allocated(error)) return
      +                 call pkg%dump_to_toml(ptr, error)
      +                 if (allocated(error)) return
      +
      +              end associate
      +
      +           end do
      +       end if
      +
      +       if (allocated(self%preprocess)) then
      +
      +           call add_table(table, "preprocess", ptr_pkg)
      +           if (.not. associated(ptr_pkg)) then
      +              call fatal_error(error, class_name//" cannot create 'preprocess' table ")
      +              return
      +           end if
      +
      +           do ii = 1, size(self%preprocess)
      +
      +              associate (pkg => self%preprocess(ii))
      +
      +                 !> Because dependencies are named, fallback if this has no name
      +                 !> So, serialization will work regardless of size(self%dep) == self%ndep
      +                 if (len_trim(pkg%name)==0) then
      +                    write(unnamed,1) 'PREPROCESS',ii
      +                    call add_table(ptr_pkg, trim(unnamed), ptr, error, class_name//'(preprocess)')
      +                 else
      +                    call add_table(ptr_pkg, pkg%name, ptr, error, class_name//'(preprocess)')
      +                 end if
      +                 if (allocated(error)) return
      +                 call pkg%dump_to_toml(ptr, error)
      +                 if (allocated(error)) return
      +
      +              end associate
      +
      +           end do
      +       end if
      +
      +       1 format('UNNAMED_',a,'_',i0)
      +       2 format('PROFILE_',i0)
      +
      +     end subroutine dump_to_toml
      +
      +     !> Read manifest from toml table (no checks made at this stage)
      +     subroutine load_from_toml(self, table, error)
      +
      +        !> Instance of the serializable object
      +        class(package_config_t), intent(inout) :: self
      +
      +        !> Data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        type(toml_key), allocatable :: keys(:),pkg_keys(:)
      +        integer :: ii, jj
      +        character(len=:), allocatable :: flag
      +        type(toml_table), pointer :: ptr,ptr_pkg
      +
      +        call table%get_keys(keys)
      +
      +        call get_value(table, "name", self%name)
      +        call get_value(table, "license", self%license)
      +        call get_value(table, "author", self%author)
      +        call get_value(table, "maintainer", self%maintainer)
      +        call get_value(table, "copyright", self%copyright)
      +        call get_value(table, "version", flag)
      +        call new_version(self%version, flag, error)
      +        if (allocated(error)) then
      +           error%message = class_name//': version error from TOML table - '//error%message
      +           return
      +        endif
      +
      +        if (allocated(self%library)) deallocate(self%library)
      +        if (allocated(self%executable)) deallocate(self%executable)
      +        if (allocated(self%dependency)) deallocate(self%dependency)
      +        if (allocated(self%dev_dependency)) deallocate(self%dev_dependency)
      +        if (allocated(self%profiles)) deallocate(self%profiles)
      +        if (allocated(self%example)) deallocate(self%example)
      +        if (allocated(self%test)) deallocate(self%test)
      +        if (allocated(self%preprocess)) deallocate(self%preprocess)
      +        sub_deps: do ii = 1, size(keys)
      +
      +           select case (keys(ii)%key)
      +              case ("build")
      +                   call get_value(table, keys(ii), ptr)
      +                   if (.not.associated(ptr)) then
      +                      call fatal_error(error,class_name//': error retrieving '//keys(ii)%key//' table')
      +                      return
      +                   end if
      +                   call self%build%load_from_toml(ptr, error)
      +                   if (allocated(error)) return
      +
      +              case ("install")
      +                   call get_value(table, keys(ii), ptr)
      +                   if (.not.associated(ptr)) then
      +                      call fatal_error(error,class_name//': error retrieving '//keys(ii)%key//' table')
      +                      return
      +                   end if
      +                   call self%install%load_from_toml(ptr, error)
      +
      +              case ("fortran")
      +                   call get_value(table, keys(ii), ptr)
      +                   if (.not.associated(ptr)) then
      +                      call fatal_error(error,class_name//': error retrieving '//keys(ii)%key//' table')
      +                      return
      +                   end if
      +                   call self%fortran%load_from_toml(ptr, error)
      +
      +              case ("library")
      +
      +                   allocate(self%library)
      +                   call get_value(table, keys(ii), ptr)
      +                   if (.not.associated(ptr)) then
      +                      call fatal_error(error,class_name//': error retrieving '//keys(ii)%key//' table')
      +                      return
      +                   end if
      +                   call self%library%load_from_toml(ptr, error)
      +
      +              case ("executable")
      +
      +                   call get_value(table, keys(ii), ptr)
      +                   if (.not.associated(ptr)) then
      +                      call fatal_error(error,class_name//': error retrieving executable table')
      +                      return
      +                   end if
      +
      +                   !> Read all packages
      +                   call ptr%get_keys(pkg_keys)
      +                   allocate(self%executable(size(pkg_keys)))
      +
      +                   do jj = 1, size(pkg_keys)
      +                      call get_value(ptr, pkg_keys(jj), ptr_pkg)
      +                      call self%executable(jj)%load_from_toml(ptr_pkg, error)
      +                      if (allocated(error)) return
      +                   end do
      +
      +              case ("dependencies")
      +
      +                   call get_value(table, keys(ii), ptr)
      +                   if (.not.associated(ptr)) then
      +                      call fatal_error(error,class_name//': error retrieving dependency table')
      +                      return
      +                   end if
      +
      +                   !> Read all packages
      +                   call ptr%get_keys(pkg_keys)
      +                   allocate(self%dependency(size(pkg_keys)))
      +
      +                   do jj = 1, size(pkg_keys)
      +                      call get_value(ptr, pkg_keys(jj), ptr_pkg)
      +                      call self%dependency(jj)%load_from_toml(ptr_pkg, error)
      +                      if (allocated(error)) return
      +                   end do
      +
      +              case ("dev-dependencies")
      +
      +                   call get_value(table, keys(ii), ptr)
      +                   if (.not.associated(ptr)) then
      +                      call fatal_error(error,class_name//': error retrieving dev-dependencies table')
      +                      return
      +                   end if
      +
      +                   !> Read all packages
      +                   call ptr%get_keys(pkg_keys)
      +                   allocate(self%dev_dependency(size(pkg_keys)))
      +
      +                   do jj = 1, size(pkg_keys)
      +                      call get_value(ptr, pkg_keys(jj), ptr_pkg)
      +                      call self%dev_dependency(jj)%load_from_toml(ptr_pkg, error)
      +                      if (allocated(error)) return
      +                   end do
      +
      +              case ("profiles")
      +
      +                   call get_value(table, keys(ii), ptr)
      +                   if (.not.associated(ptr)) then
      +                      call fatal_error(error,class_name//': error retrieving profiles table')
      +                      return
      +                   end if
      +
      +                   !> Read all packages
      +                   call ptr%get_keys(pkg_keys)
      +                   allocate(self%profiles(size(pkg_keys)))
      +
      +                   do jj = 1, size(pkg_keys)
      +                      call get_value(ptr, pkg_keys(jj), ptr_pkg)
      +                      call self%profiles(jj)%load_from_toml(ptr_pkg, error)
      +                      if (allocated(error)) return
      +                   end do
      +
      +              case ("example")
      +
      +                   call get_value(table, keys(ii), ptr)
      +                   if (.not.associated(ptr)) then
      +                      call fatal_error(error,class_name//': error retrieving example table')
      +                      return
      +                   end if
      +
      +                   !> Read all packages
      +                   call ptr%get_keys(pkg_keys)
      +                   allocate(self%example(size(pkg_keys)))
      +
      +                   do jj = 1, size(pkg_keys)
      +                      call get_value(ptr, pkg_keys(jj), ptr_pkg)
      +                      call self%example(jj)%load_from_toml(ptr_pkg, error)
      +                      if (allocated(error)) return
      +                   end do
      +
      +              case ("test")
      +
      +                   call get_value(table, keys(ii), ptr)
      +                   if (.not.associated(ptr)) then
      +                      call fatal_error(error,class_name//': error retrieving test table')
      +                      return
      +                   end if
      +
      +                   !> Read all packages
      +                   call ptr%get_keys(pkg_keys)
      +                   allocate(self%test(size(pkg_keys)))
      +
      +                   do jj = 1, size(pkg_keys)
      +                      call get_value(ptr, pkg_keys(jj), ptr_pkg)
      +                      call self%test(jj)%load_from_toml(ptr_pkg, error)
      +                      if (allocated(error)) return
      +                   end do
      +
      +              case ("preprocess")
      +
      +                   call get_value(table, keys(ii), ptr)
      +                   if (.not.associated(ptr)) then
      +                      call fatal_error(error,class_name//': error retrieving preprocess table')
      +                      return
      +                   end if
      +
      +                   !> Read all packages
      +                   call ptr%get_keys(pkg_keys)
      +                   allocate(self%preprocess(size(pkg_keys)))
      +
      +                   do jj = 1, size(pkg_keys)
      +                      call get_value(ptr, pkg_keys(jj), ptr_pkg)
      +                      call self%preprocess(jj)%load_from_toml(ptr_pkg, error)
      +                      if (allocated(error)) return
      +                   end do
      +
      +              case default
      +                    cycle sub_deps
      +           end select
      +
      +        end do sub_deps
      +
      +     end subroutine load_from_toml
      +
      +end module fpm_manifest_package
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/preprocess.f90.html b/sourcefile/preprocess.f90.html new file mode 100644 index 0000000000..1eb345fd6d --- /dev/null +++ b/sourcefile/preprocess.f90.html @@ -0,0 +1,573 @@ + + + + + + + + + + + + + preprocess.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      preprocess.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      !> Implementation of the meta data for preprocessing.
      +!>
      +!> A preprocess table can currently have the following fields
      +!>
      +!> ```toml
      +!> [preprocess]
      +!> [preprocess.cpp]
      +!> suffixes = ["F90", "f90"]
      +!> directories = ["src/feature1", "src/models"]
      +!> macros = []
      +!> ```
      +
      +module fpm_manifest_preprocess
      +   use fpm_error, only : error_t, syntax_error
      +   use fpm_strings, only : string_t, operator(==)
      +   use tomlf, only : toml_table, toml_key, toml_stat
      +   use fpm_toml, only : get_value, get_list, serializable_t, set_value, set_list, &
      +                        set_string
      +   use,intrinsic :: iso_fortran_env, only : stderr=>error_unit
      +   implicit none
      +   private
      +
      +   public :: preprocess_config_t, new_preprocessors, operator(==)
      +
      +   !> Configuration meta data for a preprocessor
      +   type, extends(serializable_t) :: preprocess_config_t
      +
      +      !> Name of the preprocessor
      +      character(len=:), allocatable :: name
      +
      +      !> Suffixes of the files to be preprocessed
      +      type(string_t), allocatable :: suffixes(:)
      +
      +      !> Directories to search for files to be preprocessed
      +      type(string_t), allocatable :: directories(:)
      +
      +      !> Macros to be defined for the preprocessor
      +      type(string_t), allocatable :: macros(:)
      +
      +   contains
      +
      +      !> Print information on this instance
      +      procedure :: info
      +      
      +      !> Initialization
      +      procedure, private :: new_cpp_config_with_macros
      +      procedure, private :: new_preprocess_config
      +      generic   :: new => new_cpp_config_with_macros, new_preprocess_config
      +
      +      !> Serialization interface
      +      procedure :: serializable_is_same => preprocess_is_same
      +      procedure :: dump_to_toml
      +      procedure :: load_from_toml
      +
      +      !> Operations
      +      procedure :: destroy
      +      procedure :: add_config
      +
      +      !> Properties
      +      procedure :: is_cpp
      +      procedure :: is_fypp
      +
      +   end type preprocess_config_t
      +
      +   character(*), parameter, private :: class_name = 'preprocess_config_t'
      +
      +contains
      +
      +   !> Construct a new cpp preprocessor configuration with a list of macros
      +   subroutine new_cpp_config_with_macros(self, macros)
      +
      +      !> Instance of the preprocess configuration
      +      class(preprocess_config_t), intent(out) :: self
      +      
      +      !> List of macros
      +      type(string_t), intent(in) :: macros(:)
      +      
      +      call self%destroy()
      +      
      +      !> Set cpp
      +      self%name = "cpp"
      +      
      +      !> Set macros
      +      if (size(macros)<=0) then 
      +         allocate(self%macros(0))
      +      else
      +         allocate(self%macros, source=macros)
      +      end if
      +      
      +   end subroutine new_cpp_config_with_macros
      +
      +   !> Construct a new preprocess configuration from TOML data structure
      +   subroutine new_preprocess_config(self, table, error)
      +
      +      !> Instance of the preprocess configuration
      +      class(preprocess_config_t), intent(out) :: self
      +
      +      !> Instance of the TOML data structure.
      +      type(toml_table), intent(inout) :: table
      +
      +      !> Error handling
      +      type(error_t), allocatable, intent(out) :: error
      +
      +      call check(table, error)
      +      if (allocated(error)) return
      +
      +      call table%get_key(self%name)
      +
      +      call get_list(table, "suffixes", self%suffixes, error)
      +      if (allocated(error)) return
      +
      +      call get_list(table, "directories", self%directories, error)
      +      if (allocated(error)) return
      +
      +      call get_list(table, "macros", self%macros, error)
      +      if (allocated(error)) return
      +
      +   end subroutine new_preprocess_config
      +
      +   !> Check local schema for allowed entries
      +   subroutine check(table, error)
      +
      +      !> Instance of the TOML data structure.
      +      type(toml_table), intent(inout) :: table
      +
      +      !> Error handling
      +      type(error_t), allocatable, intent(inout) :: error
      +
      +      character(len=:), allocatable :: name
      +      type(toml_key), allocatable :: list(:)
      +      integer :: ikey
      +
      +      call table%get_key(name)
      +      call table%get_keys(list)
      +
      +      do ikey = 1, size(list)
      +         select case(list(ikey)%key)
      +         !> Valid keys.
      +         case("suffixes", "directories", "macros")
      +         case default
      +            call syntax_error(error, "Key '"//list(ikey)%key//"' not allowed in preprocessor '"//name//"'."); exit
      +         end select
      +      end do
      +   end subroutine check
      +
      +   !> Construct new preprocess array from a TOML data structure.
      +   subroutine new_preprocessors(preprocessors, table, error)
      +
      +      !> Instance of the preprocess configuration
      +      type(preprocess_config_t), allocatable, intent(out) :: preprocessors(:)
      +
      +      !> Instance of the TOML data structure
      +      type(toml_table), intent(inout) :: table
      +
      +      !> Error handling
      +      type(error_t), allocatable, intent(out) :: error
      +
      +      type(toml_table), pointer :: node
      +      type(toml_key), allocatable :: list(:)
      +      integer :: iprep, stat
      +
      +      call table%get_keys(list)
      +
      +      ! An empty table is not allowed
      +      if (size(list) == 0) then
      +         call syntax_error(error, "No preprocessors defined")
      +      end if
      +
      +      allocate(preprocessors(size(list)))
      +      do iprep = 1, size(list)
      +         call get_value(table, list(iprep)%key, node, stat=stat)
      +         if (stat /= toml_stat%success) then
      +            call syntax_error(error, "Preprocessor "//list(iprep)%key//" must be a table entry")
      +            exit
      +         end if
      +         call preprocessors(iprep)%new(node, error)
      +         if (allocated(error)) exit
      +      end do
      +
      +   end subroutine new_preprocessors
      +
      +   !> Write information on this instance
      +   subroutine info(self, unit, verbosity)
      +
      +      !> Instance of the preprocess configuration
      +      class(preprocess_config_t), intent(in) :: self
      +
      +      !> Unit for IO
      +      integer, intent(in) :: unit
      +
      +      !> Verbosity of the printout
      +      integer, intent(in), optional :: verbosity
      +
      +      integer :: pr, ilink
      +      character(len=*), parameter :: fmt = '("#", 1x, a, t30, a)'
      +
      +      if (present(verbosity)) then
      +         pr = verbosity
      +      else
      +         pr = 1
      +      end if
      +
      +      if (pr < 1) return
      +
      +      write(unit, fmt) "Preprocessor"
      +      if (allocated(self%name)) then
      +         write(unit, fmt) "- name", self%name
      +      end if
      +      if (allocated(self%suffixes)) then
      +         write(unit, fmt) " - suffixes"
      +         do ilink = 1, size(self%suffixes)
      +            write(unit, fmt) "   - " // self%suffixes(ilink)%s
      +         end do
      +      end if
      +      if (allocated(self%directories)) then
      +         write(unit, fmt) " - directories"
      +         do ilink = 1, size(self%directories)
      +            write(unit, fmt) "   - " // self%directories(ilink)%s
      +         end do
      +      end if
      +      if (allocated(self%macros)) then
      +         write(unit, fmt) " - macros"
      +         do ilink = 1, size(self%macros)
      +            write(unit, fmt) "   - " // self%macros(ilink)%s
      +         end do
      +      end if
      +
      +   end subroutine info
      +
      +   logical function preprocess_is_same(this,that)
      +      class(preprocess_config_t), intent(in) :: this
      +      class(serializable_t), intent(in) :: that
      +
      +      integer :: istr
      +
      +      preprocess_is_same = .false.
      +
      +      select type (other=>that)
      +         type is (preprocess_config_t)
      +            if (allocated(this%name).neqv.allocated(other%name)) return
      +            if (allocated(this%name)) then
      +                if (.not.(this%name==other%name)) return
      +            endif
      +
      +            if (.not.(this%suffixes==other%suffixes)) return
      +            if (.not.(this%directories==other%directories)) return
      +            if (.not.(this%macros==other%macros)) return
      +
      +         class default
      +            ! Not the same type
      +            return
      +      end select
      +
      +      !> All checks passed!
      +      preprocess_is_same = .true.
      +
      +    end function preprocess_is_same
      +
      +    !> Dump install config to toml table
      +    subroutine dump_to_toml(self, table, error)
      +
      +       !> Instance of the serializable object
      +       class(preprocess_config_t), intent(inout) :: self
      +
      +       !> Data structure
      +       type(toml_table), intent(inout) :: table
      +
      +       !> Error handling
      +       type(error_t), allocatable, intent(out) :: error
      +
      +       call set_string(table, "name", self%name, error)
      +       if (allocated(error)) return
      +       call set_list(table, "suffixes", self%suffixes, error)
      +       if (allocated(error)) return
      +       call set_list(table, "directories", self%directories, error)
      +       if (allocated(error)) return
      +       call set_list(table, "macros", self%macros, error)
      +       if (allocated(error)) return
      +
      +     end subroutine dump_to_toml
      +
      +     !> Read install config from toml table (no checks made at this stage)
      +     subroutine load_from_toml(self, table, error)
      +
      +        !> Instance of the serializable object
      +        class(preprocess_config_t), intent(inout) :: self
      +
      +        !> Data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        call get_value(table, "name", self%name)
      +        call get_list(table, "suffixes", self%suffixes, error)
      +        if (allocated(error)) return
      +        call get_list(table, "directories", self%directories, error)
      +        if (allocated(error)) return
      +        call get_list(table, "macros", self%macros, error)
      +        if (allocated(error)) return
      +
      +     end subroutine load_from_toml
      +
      +    !> Clean preprocessor structure
      +    elemental subroutine destroy(this)
      +       class(preprocess_config_t), intent(inout) :: this
      +
      +       if (allocated(this%name))deallocate(this%name)
      +       if (allocated(this%suffixes))deallocate(this%suffixes)
      +       if (allocated(this%directories))deallocate(this%directories)
      +       if (allocated(this%macros))deallocate(this%macros)
      +
      +    end subroutine destroy
      +
      +    !> Add preprocessor settings
      +    subroutine add_config(this,that)
      +       class(preprocess_config_t), intent(inout) :: this
      +        type(preprocess_config_t), intent(in) :: that
      +
      +        if (.not.that%is_cpp()) then
      +            write(stderr, '(a)') 'Warning: Preprocessor ' // that%name // &
      +                                 ' is not supported; will ignore it'
      +            return
      +        end if
      +
      +        if (.not.allocated(this%name)) this%name = that%name
      +
      +        ! Add macros
      +        if (allocated(that%macros)) then
      +            if (allocated(this%macros)) then
      +                this%macros = [this%macros, that%macros]
      +            else
      +                allocate(this%macros, source = that%macros)
      +            end if
      +        endif
      +
      +        ! Add suffixes
      +        if (allocated(that%suffixes)) then
      +            if (allocated(this%suffixes)) then
      +                this%suffixes = [this%suffixes, that%suffixes]
      +            else
      +                allocate(this%suffixes, source = that%suffixes)
      +            end if
      +        endif
      +
      +        ! Add directories
      +        if (allocated(that%directories)) then
      +            if (allocated(this%directories)) then
      +                this%directories = [this%directories, that%directories]
      +            else
      +                allocate(this%directories, source = that%directories)
      +            end if
      +        endif
      +
      +    end subroutine add_config
      +
      +    ! Check cpp
      +    logical function is_cpp(this)
      +       class(preprocess_config_t), intent(in) :: this
      +       is_cpp = .false.
      +       if (allocated(this%name)) is_cpp = this%name == "cpp"
      +    end function is_cpp
      +
      +    ! Check cpp
      +    logical function is_fypp(this)
      +       class(preprocess_config_t), intent(in) :: this
      +       is_fypp = .false.
      +       if (allocated(this%name)) is_fypp = this%name == "fypp"
      +    end function is_fypp
      +
      +end module fpm_manifest_preprocess
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/profiles.f90.html b/sourcefile/profiles.f90.html new file mode 100644 index 0000000000..8ccfc473b4 --- /dev/null +++ b/sourcefile/profiles.f90.html @@ -0,0 +1,1442 @@ + + + + + + + + + + + + + profiles.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      profiles.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      !> Implementation of the meta data for compiler flag profiles.
      +!>
      +!> A profiles table can currently have the following subtables:
      +!> Profile names - any string, if omitted, flags are appended to all matching profiles
      +!> Compiler - any from the following list, omitting it yields an error
      +!>
      +!> - "gfortran"
      +!> - "ifort"
      +!> - "ifx"
      +!> - "pgfortran"
      +!> - "nvfortran"
      +!> - "flang"
      +!> - "caf"
      +!> - "f95"
      +!> - "lfortran"
      +!> - "lfc"
      +!> - "nagfor"
      +!> - "crayftn"
      +!> - "xlf90"
      +!> - "ftn95"
      +!>
      +!> OS - any from the following list, if omitted, the profile is used if and only
      +!> if there is no profile perfectly matching the current configuration
      +!>
      +!> - "linux"
      +!> - "macos"
      +!> - "windows"
      +!> - "cygwin"
      +!> - "solaris"
      +!> - "freebsd"
      +!> - "openbsd"
      +!> - "unknown"
      +!>
      +!> Each of the subtables currently supports the following fields:
      +!>```toml
      +!>[profiles.debug.gfortran.linux]
      +!> flags="-Wall -g -Og"
      +!> c-flags="-g O1"
      +!> cxx-flags="-g O1"
      +!> link-time-flags="-xlinkopt"
      +!> files={"hello_world.f90"="-Wall -O3"}
      +!>```
      +!>
      +module fpm_manifest_profile
      +    use fpm_error, only : error_t, syntax_error, fatal_error, fpm_stop
      +    use tomlf, only : toml_table, toml_key, toml_stat
      +    use fpm_toml, only : get_value, serializable_t, set_value, &
      +                         set_string, add_table
      +    use fpm_strings, only: lower
      +    use fpm_environment, only: get_os_type, OS_UNKNOWN, OS_LINUX, OS_MACOS, OS_WINDOWS, &
      +                             OS_CYGWIN, OS_SOLARIS, OS_FREEBSD, OS_OPENBSD, OS_NAME
      +    use fpm_filesystem, only: join_path
      +    implicit none
      +    public :: profile_config_t, new_profile, new_profiles, get_default_profiles, &
      +            & info_profile, find_profile, DEFAULT_COMPILER
      +
      +    !> Name of the default compiler
      +    character(len=*), parameter :: DEFAULT_COMPILER = 'gfortran'
      +    integer, parameter :: OS_ALL = -1
      +    character(len=:), allocatable :: path
      +
      +    !> Type storing file name - file scope compiler flags pairs
      +    type, extends(serializable_t) :: file_scope_flag
      +
      +      !> Name of the file
      +      character(len=:), allocatable :: file_name
      +
      +      !> File scope flags
      +      character(len=:), allocatable :: flags
      +
      +      contains
      +
      +          !> Serialization interface
      +          procedure :: serializable_is_same => file_scope_same
      +          procedure :: dump_to_toml => file_scope_dump
      +          procedure :: load_from_toml => file_scope_load
      +
      +    end type file_scope_flag
      +
      +    !> Configuration meta data for a profile
      +    type, extends(serializable_t) :: profile_config_t
      +      !> Name of the profile
      +      character(len=:), allocatable :: profile_name
      +
      +      !> Name of the compiler
      +      character(len=:), allocatable :: compiler
      +
      +      !> Value repesenting OS
      +      integer :: os_type = OS_ALL
      +
      +      !> Fortran compiler flags
      +      character(len=:), allocatable :: flags
      +
      +      !> C compiler flags
      +      character(len=:), allocatable :: c_flags
      +
      +      !> C++ compiler flags
      +      character(len=:), allocatable :: cxx_flags
      +
      +      !> Link time compiler flags
      +      character(len=:), allocatable :: link_time_flags
      +
      +      !> File scope flags
      +      type(file_scope_flag), allocatable :: file_scope_flags(:)
      +
      +      !> Is this profile one of the built-in ones?
      +      logical :: is_built_in = .false.
      +
      +      contains
      +
      +        !> Print information on this instance
      +        procedure :: info
      +
      +        !> Serialization interface
      +        procedure :: serializable_is_same => profile_same
      +        procedure :: dump_to_toml => profile_dump
      +        procedure :: load_from_toml => profile_load
      +
      +    end type profile_config_t
      +
      +    contains
      +
      +      !> Construct a new profile configuration from a TOML data structure
      +      function new_profile(profile_name, compiler, os_type, flags, c_flags, cxx_flags, &
      +                           link_time_flags, file_scope_flags, is_built_in) &
      +                      & result(profile)
      +
      +        !> Name of the profile
      +        character(len=*), intent(in) :: profile_name
      +
      +        !> Name of the compiler
      +        character(len=*), intent(in) :: compiler
      +
      +        !> Type of the OS
      +        integer, intent(in) :: os_type
      +
      +        !> Fortran compiler flags
      +        character(len=*), optional, intent(in) :: flags
      +
      +        !> C compiler flags
      +        character(len=*), optional, intent(in) :: c_flags
      +
      +        !> C++ compiler flags
      +        character(len=*), optional, intent(in) :: cxx_flags
      +
      +        !> Link time compiler flags
      +        character(len=*), optional, intent(in) :: link_time_flags
      +
      +        !> File scope flags
      +        type(file_scope_flag), optional, intent(in) :: file_scope_flags(:)
      +
      +        !> Is this profile one of the built-in ones?
      +        logical, optional, intent(in) :: is_built_in
      +
      +        type(profile_config_t) :: profile
      +
      +        profile%profile_name = profile_name
      +        profile%compiler = compiler
      +        profile%os_type = os_type
      +        if (present(flags)) then
      +          profile%flags = flags
      +        else
      +          profile%flags = ""
      +        end if
      +        if (present(c_flags)) then
      +          profile%c_flags = c_flags
      +        else
      +          profile%c_flags = ""
      +        end if
      +        if (present(cxx_flags)) then
      +          profile%cxx_flags = cxx_flags
      +        else
      +          profile%cxx_flags = ""
      +        end if
      +        if (present(link_time_flags)) then
      +          profile%link_time_flags = link_time_flags
      +        else
      +          profile%link_time_flags = ""
      +        end if
      +        if (present(file_scope_flags)) then
      +           profile%file_scope_flags = file_scope_flags
      +        end if
      +        if (present(is_built_in)) then
      +           profile%is_built_in = is_built_in
      +        else
      +           profile%is_built_in = .false.
      +        end if
      +
      +      end function new_profile
      +
      +      !> Check if compiler name is a valid compiler name
      +      subroutine validate_compiler_name(compiler_name, is_valid)
      +
      +        !> Name of a compiler
      +        character(len=:), allocatable, intent(in) :: compiler_name
      +
      +        !> Boolean value of whether compiler_name is valid or not
      +        logical, intent(out) :: is_valid
      +        select case(compiler_name)
      +          case("gfortran", "ifort", "ifx", "pgfortran", "nvfortran", "flang", "caf", &
      +                        & "f95", "lfortran", "lfc", "nagfor", "crayftn", "xlf90", "ftn95")
      +            is_valid = .true.
      +          case default
      +            is_valid = .false.
      +        end select
      +      end subroutine validate_compiler_name
      +
      +      !> Check if os_name is a valid name of a supported OS
      +      subroutine validate_os_name(os_name, is_valid)
      +
      +        !> Name of an operating system
      +        character(len=:), allocatable, intent(in) :: os_name
      +
      +        !> Boolean value of whether os_name is valid or not
      +        logical, intent(out) :: is_valid
      +
      +        select case (os_name)
      +          case ("linux", "macos", "windows", "cygwin", "solaris", "freebsd", &
      +                          & "openbsd", "unknown")
      +            is_valid = .true.
      +          case default
      +            is_valid = .false.
      +        end select
      +
      +      end subroutine validate_os_name
      +
      +      !> Match os_type enum to a lowercase string with name of OS
      +      subroutine match_os_type(os_name, os_type)
      +
      +        !> Name of operating system
      +        character(len=:), allocatable, intent(in) :: os_name
      +
      +        !> Enum representing type of OS
      +        integer, intent(out) :: os_type
      +
      +        select case (os_name)
      +          case ("linux");   os_type = OS_LINUX
      +          case ("macos");   os_type = OS_MACOS
      +          case ("windows"); os_type = OS_WINDOWS
      +          case ("cygwin");  os_type = OS_CYGWIN
      +          case ("solaris"); os_type = OS_SOLARIS
      +          case ("freebsd"); os_type = OS_FREEBSD
      +          case ("openbsd"); os_type = OS_OPENBSD
      +          case ("all");     os_type = OS_ALL
      +          case default;     os_type = OS_UNKNOWN
      +        end select
      +
      +      end subroutine match_os_type
      +
      +      !> Match lowercase string with name of OS to os_type enum
      +      function os_type_name(os_type)
      +
      +        !> Name of operating system
      +        character(len=:), allocatable :: os_type_name
      +
      +        !> Enum representing type of OS
      +        integer, intent(in) :: os_type
      +
      +        select case (os_type)
      +          case (OS_ALL); os_type_name = "all"
      +          case default; os_type_name = lower(OS_NAME(os_type))
      +        end select
      +
      +      end function os_type_name
      +
      +      subroutine validate_profile_table(profile_name, compiler_name, key_list, table, error, os_valid)
      +
      +        !> Name of profile
      +        character(len=:), allocatable, intent(in) :: profile_name
      +
      +        !> Name of compiler
      +        character(len=:), allocatable, intent(in) :: compiler_name
      +
      +        !> List of keys in the table
      +        type(toml_key), allocatable, intent(in) :: key_list(:)
      +
      +        !> Table containing OS tables
      +        type(toml_table), pointer, intent(in) :: table
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        !> Was called with valid operating system
      +        logical, intent(in) :: os_valid
      +
      +        character(len=:), allocatable :: flags, c_flags, cxx_flags, link_time_flags, key_name, file_name, file_flags, err_message
      +        type(toml_table), pointer :: files
      +        type(toml_key), allocatable :: file_list(:)
      +        integer :: ikey, ifile, stat
      +        logical :: is_valid
      +
      +        if (size(key_list).ge.1) then
      +          do ikey=1,size(key_list)
      +            key_name = key_list(ikey)%key
      +            if (key_name.eq.'flags') then
      +              call get_value(table, 'flags', flags, stat=stat)
      +              if (stat /= toml_stat%success) then
      +                call syntax_error(error, "flags has to be a key-value pair")
      +                return
      +              end if
      +            else if (key_name.eq.'c-flags') then
      +              call get_value(table, 'c-flags', c_flags, stat=stat)
      +              if (stat /= toml_stat%success) then
      +                call syntax_error(error, "c-flags has to be a key-value pair")
      +                return
      +              end if
      +            else if (key_name.eq.'cxx-flags') then
      +              call get_value(table, 'cxx-flags', cxx_flags, stat=stat)
      +              if (stat /= toml_stat%success) then
      +                call syntax_error(error, "cxx-flags has to be a key-value pair")
      +                return
      +              end if
      +            else if (key_name.eq.'link-time-flags') then
      +              call get_value(table, 'link-time-flags', link_time_flags, stat=stat)
      +              if (stat /= toml_stat%success) then
      +                call syntax_error(error, "link-time-flags has to be a key-value pair")
      +                return
      +              end if
      +            else if (key_name.eq.'files') then
      +              call get_value(table, 'files', files, stat=stat)
      +              if (stat /= toml_stat%success) then
      +                call syntax_error(error, "files has to be a table")
      +                return
      +              end if
      +              call files%get_keys(file_list)
      +              do ifile=1,size(file_list)
      +                file_name = file_list(ifile)%key
      +                call get_value(files, file_name, file_flags, stat=stat)
      +                if (stat /= toml_stat%success) then
      +                  call syntax_error(error, "file scope flags has to be a key-value pair")
      +                  return
      +                end if
      +              end do
      +            else if (.not. os_valid) then
      +                call validate_os_name(key_name, is_valid)
      +                err_message = "Unexpected key " // key_name // " found in profile table "//profile_name//" "//compiler_name//"."
      +                if (.not. is_valid) call syntax_error(error, err_message)
      +            else
      +                err_message = "Unexpected key " // key_name // " found in profile table "//profile_name//" "//compiler_name//"."
      +                call syntax_error(error, err_message)
      +            end if
      +          end do
      +        end if
      +
      +        if (allocated(error)) return
      +
      +      end subroutine validate_profile_table
      +
      +      !> Look for flags, c-flags, link-time-flags key-val pairs
      +      !> and files table in a given table and create new profiles
      +      subroutine get_flags(profile_name, compiler_name, os_type, key_list, table, profiles, profindex, os_valid)
      +
      +        !> Name of profile
      +        character(len=:), allocatable, intent(in) :: profile_name
      +
      +        !> Name of compiler
      +        character(len=:), allocatable, intent(in) :: compiler_name
      +
      +        !> OS type
      +        integer, intent(in) :: os_type
      +
      +        !> List of keys in the table
      +        type(toml_key), allocatable, intent(in) :: key_list(:)
      +
      +        !> Table containing OS tables
      +        type(toml_table), pointer, intent(in) :: table
      +
      +        !> List of profiles
      +        type(profile_config_t), allocatable, intent(inout) :: profiles(:)
      +
      +        !> Index in the list of profiles
      +        integer, intent(inout) :: profindex
      +
      +        !> Was called with valid operating system
      +        logical, intent(in) :: os_valid
      +
      +        character(len=:), allocatable :: flags, c_flags, cxx_flags, link_time_flags, key_name, file_name, file_flags, err_message
      +        type(toml_table), pointer :: files
      +        type(toml_key), allocatable :: file_list(:)
      +        type(file_scope_flag), allocatable :: file_scope_flags(:)
      +        integer :: ikey, ifile, stat
      +        logical :: is_valid
      +
      +        call get_value(table, 'flags', flags)
      +        call get_value(table, 'c-flags', c_flags)
      +        call get_value(table, 'cxx-flags', cxx_flags)
      +        call get_value(table, 'link-time-flags', link_time_flags)
      +        call get_value(table, 'files', files)
      +        if (associated(files)) then
      +          call files%get_keys(file_list)
      +          allocate(file_scope_flags(size(file_list)))
      +          do ifile=1,size(file_list)
      +            file_name = file_list(ifile)%key
      +            call get_value(files, file_name, file_flags)
      +            associate(cur_file=>file_scope_flags(ifile))
      +              if (.not.(path.eq."")) file_name = join_path(path, file_name)
      +              cur_file%file_name = file_name
      +              cur_file%flags = file_flags
      +            end associate
      +          end do
      +        end if
      +
      +        profiles(profindex) = new_profile(profile_name, compiler_name, os_type, &
      +                 & flags, c_flags, cxx_flags, link_time_flags, file_scope_flags)
      +        profindex = profindex + 1
      +      end subroutine get_flags
      +
      +      !> Traverse operating system tables to obtain number of profiles
      +      subroutine traverse_oss_for_size(profile_name, compiler_name, os_list, table, profiles_size, error)
      +
      +        !> Name of profile
      +        character(len=:), allocatable, intent(in) :: profile_name
      +
      +        !> Name of compiler
      +        character(len=:), allocatable, intent(in) :: compiler_name
      +
      +        !> List of OSs in table with profile name and compiler name given
      +        type(toml_key), allocatable, intent(in) :: os_list(:)
      +
      +        !> Table containing OS tables
      +        type(toml_table), pointer, intent(in) :: table
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        !> Number of profiles in list of profiles
      +        integer, intent(inout) :: profiles_size
      +
      +        type(toml_key), allocatable :: key_list(:)
      +        character(len=:), allocatable :: os_name, l_os_name
      +        type(toml_table), pointer :: os_node
      +        integer :: ios, stat
      +        logical :: is_valid, key_val_added, is_key_val
      +
      +        if (size(os_list)<1) return
      +        key_val_added = .false.
      +        do ios = 1, size(os_list)
      +          os_name = os_list(ios)%key
      +          call validate_os_name(os_name, is_valid)
      +          if (is_valid) then
      +            call get_value(table, os_name, os_node, stat=stat)
      +            if (stat /= toml_stat%success) then
      +              call syntax_error(error, "os "//os_name//" has to be a table")
      +              return
      +            end if
      +            call os_node%get_keys(key_list)
      +            profiles_size = profiles_size + 1
      +            call validate_profile_table(profile_name, compiler_name, key_list, os_node, error, .true.)
      +          else
      +            ! Not lowercase OS name
      +            l_os_name = lower(os_name)
      +            call validate_os_name(l_os_name, is_valid)
      +            if (is_valid) then
      +              call fatal_error(error,'*traverse_oss*:Error: Name of the operating system must be a lowercase string.')
      +            end if
      +            if (allocated(error)) return
      +
      +            ! Missing OS name
      +            is_key_val = .false.
      +            os_name = os_list(ios)%key
      +            call get_value(table, os_name, os_node, stat=stat)
      +            if (stat /= toml_stat%success) then
      +              is_key_val = .true.
      +            end if
      +            os_node=>table
      +            if (is_key_val.and..not.key_val_added) then
      +              key_val_added = .true.
      +              is_key_val = .false.
      +              profiles_size = profiles_size + 1
      +            else if (.not.is_key_val) then
      +              profiles_size = profiles_size + 1
      +            end if
      +            call validate_profile_table(profile_name, compiler_name, os_list, os_node, error, .false.)
      +          end if
      +        end do
      +      end subroutine traverse_oss_for_size
      +
      +
      +      !> Traverse operating system tables to obtain profiles
      +      subroutine traverse_oss(profile_name, compiler_name, os_list, table, profiles, profindex, error)
      +
      +        !> Name of profile
      +        character(len=:), allocatable, intent(in) :: profile_name
      +
      +        !> Name of compiler
      +        character(len=:), allocatable, intent(in) :: compiler_name
      +
      +        !> List of OSs in table with profile name and compiler name given
      +        type(toml_key), allocatable, intent(in) :: os_list(:)
      +
      +        !> Table containing OS tables
      +        type(toml_table), pointer, intent(in) :: table
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        !> List of profiles
      +        type(profile_config_t), allocatable, intent(inout) :: profiles(:)
      +
      +        !> Index in the list of profiles
      +        integer, intent(inout) :: profindex
      +
      +        type(toml_key), allocatable :: key_list(:)
      +        character(len=:), allocatable :: os_name, l_os_name
      +        type(toml_table), pointer :: os_node
      +        integer :: ios, stat, os_type
      +        logical :: is_valid, is_key_val
      +
      +        if (size(os_list)<1) return
      +        do ios = 1, size(os_list)
      +          os_name = os_list(ios)%key
      +          call validate_os_name(os_name, is_valid)
      +          if (is_valid) then
      +            call get_value(table, os_name, os_node, stat=stat)
      +            if (stat /= toml_stat%success) then
      +              call syntax_error(error, "os "//os_name//" has to be a table")
      +              return
      +            end if
      +            call os_node%get_keys(key_list)
      +            call match_os_type(os_name, os_type)
      +            call get_flags(profile_name, compiler_name, os_type, key_list, os_node, profiles, profindex, .true.)
      +          else
      +            ! Not lowercase OS name
      +            l_os_name = lower(os_name)
      +            call validate_os_name(l_os_name, is_valid)
      +            if (is_valid) then
      +              call fatal_error(error,'*traverse_oss*:Error: Name of the operating system must be a lowercase string.')
      +            end if
      +            if (allocated(error)) return
      +
      +            ! Missing OS name
      +            is_key_val = .false.
      +            os_name = os_list(ios)%key
      +            call get_value(table, os_name, os_node, stat=stat)
      +            if (stat /= toml_stat%success) then
      +              is_key_val = .true.
      +            end if
      +            os_node=>table
      +            os_type = OS_ALL
      +            call get_flags(profile_name, compiler_name, os_type, os_list, os_node, profiles, profindex, .false.)
      +          end if
      +        end do
      +      end subroutine traverse_oss
      +
      +      !> Traverse compiler tables
      +      subroutine traverse_compilers(profile_name, comp_list, table, error, profiles_size, profiles, profindex)
      +
      +        !> Name of profile
      +        character(len=:), allocatable, intent(in) :: profile_name
      +
      +        !> List of OSs in table with profile name given
      +        type(toml_key), allocatable, intent(in) :: comp_list(:)
      +
      +        !> Table containing compiler tables
      +        type(toml_table), pointer, intent(in) :: table
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        !> Number of profiles in list of profiles
      +        integer, intent(inout), optional :: profiles_size
      +
      +        !> List of profiles
      +        type(profile_config_t), allocatable, intent(inout), optional :: profiles(:)
      +
      +        !> Index in the list of profiles
      +        integer, intent(inout), optional :: profindex
      +
      +        character(len=:), allocatable :: compiler_name
      +        type(toml_table), pointer :: comp_node
      +        type(toml_key), allocatable :: os_list(:)
      +        integer :: icomp, stat
      +        logical :: is_valid
      +
      +        if (size(comp_list)<1) return
      +        do icomp = 1, size(comp_list)
      +          call validate_compiler_name(comp_list(icomp)%key, is_valid)
      +          if (is_valid) then
      +            compiler_name = comp_list(icomp)%key
      +            call get_value(table, compiler_name, comp_node, stat=stat)
      +            if (stat /= toml_stat%success) then
      +              call syntax_error(error, "Compiler "//comp_list(icomp)%key//" must be a table entry")
      +              exit
      +            end if
      +            call comp_node%get_keys(os_list)
      +            if (present(profiles_size)) then
      +              call traverse_oss_for_size(profile_name, compiler_name, os_list, comp_node, profiles_size, error)
      +              if (allocated(error)) return
      +            else
      +              if (.not.(present(profiles).and.present(profindex))) then
      +                call fatal_error(error, "Both profiles and profindex have to be present")
      +                return
      +              end if
      +              call traverse_oss(profile_name, compiler_name, os_list, comp_node, &
      +                                & profiles, profindex, error)
      +              if (allocated(error)) return
      +            end if
      +          else
      +            call fatal_error(error,'*traverse_compilers*:Error: Compiler name not specified or invalid.')
      +          end if
      +        end do
      +      end subroutine traverse_compilers
      +
      +      !> Construct new profiles array from a TOML data structure
      +      subroutine new_profiles(profiles, table, error)
      +
      +        !> Instance of the dependency configuration
      +        type(profile_config_t), allocatable, intent(out) :: profiles(:)
      +
      +        !> Instance of the TOML data structure
      +        type(toml_table), target, intent(inout) :: table
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        type(toml_table), pointer :: prof_node
      +        type(toml_key), allocatable :: prof_list(:)
      +        type(toml_key), allocatable :: comp_list(:)
      +        type(toml_key), allocatable :: os_list(:)
      +        character(len=:), allocatable :: profile_name, compiler_name
      +        integer :: profiles_size, iprof, stat, profindex
      +        logical :: is_valid
      +        type(profile_config_t), allocatable :: default_profiles(:)
      +
      +        path = ''
      +
      +        default_profiles = get_default_profiles(error)
      +        if (allocated(error)) return
      +        call table%get_keys(prof_list)
      +
      +        if (size(prof_list) < 1) return
      +
      +        profiles_size = 0
      +
      +        do iprof = 1, size(prof_list)
      +          profile_name = prof_list(iprof)%key
      +          call validate_compiler_name(profile_name, is_valid)
      +          if (is_valid) then
      +            profile_name = "all"
      +            comp_list = prof_list(iprof:iprof)
      +            prof_node=>table
      +            call traverse_compilers(profile_name, comp_list, prof_node, error, profiles_size=profiles_size)
      +            if (allocated(error)) return
      +          else
      +            call validate_os_name(profile_name, is_valid)
      +            if (is_valid) then
      +              os_list = prof_list(iprof:iprof)
      +              profile_name = 'all'
      +              compiler_name = DEFAULT_COMPILER
      +              call traverse_oss_for_size(profile_name, compiler_name, os_list, table, profiles_size, error)
      +              if (allocated(error)) return
      +            else
      +              call get_value(table, profile_name, prof_node, stat=stat)
      +              if (stat /= toml_stat%success) then
      +                call syntax_error(error, "Profile "//prof_list(iprof)%key//" must be a table entry")
      +                exit
      +              end if
      +              call prof_node%get_keys(comp_list)
      +              call traverse_compilers(profile_name, comp_list, prof_node, error, profiles_size=profiles_size)
      +              if (allocated(error)) return
      +            end if
      +          end if
      +        end do
      +
      +        profiles_size = profiles_size + size(default_profiles)
      +        allocate(profiles(profiles_size))
      +
      +        do profindex=1, size(default_profiles)
      +          profiles(profindex) = default_profiles(profindex)
      +        end do
      +
      +        do iprof = 1, size(prof_list)
      +          profile_name = prof_list(iprof)%key
      +          call validate_compiler_name(profile_name, is_valid)
      +          if (is_valid) then
      +            profile_name = "all"
      +            comp_list = prof_list(iprof:iprof)
      +            prof_node=>table
      +            call traverse_compilers(profile_name, comp_list, prof_node, error, profiles=profiles, profindex=profindex)
      +            if (allocated(error)) return
      +          else
      +            call validate_os_name(profile_name, is_valid)
      +            if (is_valid) then
      +              os_list = prof_list(iprof:iprof)
      +              profile_name = 'all'
      +              compiler_name = DEFAULT_COMPILER
      +              prof_node=>table
      +              call traverse_oss(profile_name, compiler_name, os_list, prof_node, profiles, profindex, error)
      +              if (allocated(error)) return
      +            else
      +              call get_value(table, profile_name, prof_node, stat=stat)
      +              call prof_node%get_keys(comp_list)
      +              call traverse_compilers(profile_name, comp_list, prof_node, error, profiles=profiles, profindex=profindex)
      +              if (allocated(error)) return
      +            end if
      +          end if
      +        end do
      +
      +        ! Apply profiles with profile name 'all' to matching profiles
      +        do iprof = 1,size(profiles)
      +          if (profiles(iprof)%profile_name.eq.'all') then
      +            do profindex = 1,size(profiles)
      +              if (.not.(profiles(profindex)%profile_name.eq.'all') &
      +                      & .and.(profiles(profindex)%compiler.eq.profiles(iprof)%compiler) &
      +                      & .and.(profiles(profindex)%os_type.eq.profiles(iprof)%os_type)) then
      +                profiles(profindex)%flags=profiles(profindex)%flags// &
      +                        & " "//profiles(iprof)%flags
      +                profiles(profindex)%c_flags=profiles(profindex)%c_flags// &
      +                        & " "//profiles(iprof)%c_flags
      +                profiles(profindex)%cxx_flags=profiles(profindex)%cxx_flags// &
      +                        & " "//profiles(iprof)%cxx_flags
      +                profiles(profindex)%link_time_flags=profiles(profindex)%link_time_flags// &
      +                        & " "//profiles(iprof)%link_time_flags
      +              end if
      +            end do
      +          end if
      +        end do
      +      end subroutine new_profiles
      +
      +      !> Construct an array of built-in profiles
      +      function get_default_profiles(error) result(default_profiles)
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        type(profile_config_t), allocatable :: default_profiles(:)
      +
      +        default_profiles = [ &
      +              & new_profile('release', &
      +                & 'caf', &
      +                & OS_ALL, &
      +                & flags=' -O3 -Wimplicit-interface -fPIC -fmax-errors=1 -funroll-loops', &
      +                & is_built_in=.true.), &
      +              & new_profile('release', &
      +                & 'gfortran', &
      +                & OS_ALL, &
      +                & flags=' -O3 -Wimplicit-interface -fPIC -fmax-errors=1 -funroll-loops -fcoarray=single', &
      +                & is_built_in=.true.), &
      +              & new_profile('release', &
      +                & 'f95', &
      +                & OS_ALL, &
      +                & flags=' -O3 -Wimplicit-interface -fPIC -fmax-errors=1 -ffast-math -funroll-loops', &
      +                & is_built_in=.true.), &
      +              & new_profile('release', &
      +                & 'nvfortran', &
      +                & OS_ALL, &
      +                & flags = ' -Mbackslash', &
      +                & is_built_in=.true.), &
      +              & new_profile('release', &
      +                & 'ifort', &
      +                & OS_ALL, &
      +                & flags = ' -fp-model precise -pc64 -align all -error-limit 1 -reentrancy&
      +                          & threaded -nogen-interfaces -assume byterecl', &
      +                & is_built_in=.true.), &
      +              & new_profile('release', &
      +                & 'ifort', &
      +                & OS_WINDOWS, &
      +                & flags = ' /fp:precise /align:all /error-limit:1 /reentrancy:threaded&
      +                          & /nogen-interfaces /assume:byterecl', &
      +                & is_built_in=.true.), &
      +              & new_profile('release', &
      +                & 'ifx', &
      +                & OS_ALL, &
      +                & flags = ' -fp-model=precise -pc64 -align all -error-limit 1 -reentrancy&
      +                          & threaded -nogen-interfaces -assume byterecl', &
      +                & is_built_in=.true.), &
      +              & new_profile('release', &
      +                & 'ifx', &
      +                & OS_WINDOWS, &
      +                & flags = ' /fp:precise /align:all /error-limit:1 /reentrancy:threaded&
      +                          & /nogen-interfaces /assume:byterecl', &
      +                & is_built_in=.true.), &
      +              & new_profile('release', &
      +                &'nagfor', &
      +                & OS_ALL, &
      +                & flags = ' -O4 -coarray=single -PIC', &
      +                & is_built_in=.true.), &
      +              & new_profile('release', &
      +                &'lfortran', &
      +                & OS_ALL, &
      +                & flags = ' flag_lfortran_opt', &
      +                & is_built_in=.true.), &
      +              & new_profile('debug', &
      +                & 'caf', &
      +                & OS_ALL, &
      +                & flags = ' -Wall -Wextra -Wimplicit-interface -fPIC -fmax-errors=1 -g -fcheck=bounds&
      +                          & -fcheck=array-temps -fbacktrace', &
      +                & is_built_in=.true.), &
      +              & new_profile('debug', &
      +                & 'gfortran', &
      +                & OS_ALL, &
      +                & flags = ' -Wall -Wextra -Wimplicit-interface -fPIC -fmax-errors=1 -g -fcheck=bounds&
      +                          & -fcheck=array-temps -fbacktrace -fcoarray=single', &
      +                & is_built_in=.true.), &
      +              & new_profile('debug', &
      +                & 'f95', &
      +                & OS_ALL, &
      +                & flags = ' -Wall -Wextra -Wimplicit-interface -fPIC -fmax-errors=1 -g -fcheck=bounds&
      +                          & -fcheck=array-temps -Wno-maybe-uninitialized -Wno-uninitialized -fbacktrace', &
      +                & is_built_in=.true.), &
      +              & new_profile('debug', &
      +                & 'nvfortran', &
      +                & OS_ALL, &
      +                & flags = ' -Minform=inform -Mbackslash -g -Mbounds -Mchkptr -Mchkstk -traceback', &
      +                & is_built_in=.true.), &
      +              & new_profile('debug', &
      +                & 'ifort', &
      +                & OS_ALL, &
      +                & flags = ' -warn all -check all -error-limit 1 -O0 -g -assume byterecl -traceback', &
      +                & is_built_in=.true.), &
      +              & new_profile('debug', &
      +                & 'ifort', &
      +                & OS_WINDOWS, &
      +                & flags = ' /warn:all /check:all /error-limit:1&
      +                          & /Od /Z7 /assume:byterecl /traceback', &
      +                & is_built_in=.true.), &
      +              & new_profile('debug', &
      +                & 'ifx', &
      +                & OS_ALL, &
      +                & flags = ' -warn all -check all -error-limit 1 -O0 -g -assume byterecl -traceback', &
      +                & is_built_in=.true.), &
      +              & new_profile('debug', &
      +                & 'ifx', &
      +                & OS_WINDOWS, &
      +                & flags = ' /warn:all /check:all /error-limit:1 /Od /Z7 /assume:byterecl', &
      +                & is_built_in=.true.), &
      +              & new_profile('debug', &
      +                & 'ifx', &
      +                & OS_WINDOWS, &
      +                & flags = ' /warn:all /check:all /error-limit:1 /Od /Z7 /assume:byterecl', &
      +                & is_built_in=.true.), &
      +              & new_profile('debug', &
      +                & 'lfortran', &
      +                & OS_ALL, &
      +                & flags = '', &
      +                & is_built_in=.true.) &
      +              &]
      +      end function get_default_profiles
      +
      +      !> Write information on instance
      +      subroutine info(self, unit, verbosity)
      +
      +        !> Instance of the profile configuration
      +        class(profile_config_t), intent(in) :: self
      +
      +        !> Unit for IO
      +        integer, intent(in) :: unit
      +
      +        !> Verbosity of the printout
      +        integer, intent(in), optional :: verbosity
      +
      +        integer :: pr
      +        character(len=*), parameter :: fmt = '("#", 1x, a, t30, a)'
      +
      +        if (present(verbosity)) then
      +            pr = verbosity
      +        else
      +            pr = 1
      +        end if
      +
      +        write(unit, fmt) "Profile"
      +        if (allocated(self%profile_name)) then
      +            write(unit, fmt) "- profile name", self%profile_name
      +        end if
      +
      +        if (allocated(self%compiler)) then
      +            write(unit, fmt) "- compiler", self%compiler
      +        end if
      +
      +        write(unit, fmt) "- os", os_type_name(self%os_type)
      +
      +        if (allocated(self%flags)) then
      +            write(unit, fmt) "- compiler flags", self%flags
      +        end if
      +
      +      end subroutine info
      +
      +      !> Print a representation of profile_config_t
      +      function info_profile(profile) result(s)
      +
      +        !> Profile to be represented
      +        type(profile_config_t), intent(in) :: profile
      +
      +        !> String representation of given profile
      +        character(:), allocatable :: s
      +
      +        integer :: i
      +
      +        s = "profile_config_t("
      +        s = s // 'profile_name="' // profile%profile_name // '"'
      +        s = s // ', compiler="' // profile%compiler // '"'
      +        s = s // ", os_type="
      +        select case(profile%os_type)
      +        case (OS_UNKNOWN)
      +          s = s // "OS_UNKNOWN"
      +        case (OS_LINUX)
      +          s = s // "OS_LINUX"
      +        case (OS_MACOS)
      +          s = s // "OS_MACOS"
      +        case (OS_WINDOWS)
      +          s = s // "OS_WINDOWS"
      +        case (OS_CYGWIN)
      +          s = s // "OS_CYGWIN"
      +        case (OS_SOLARIS)
      +          s = s // "OS_SOLARIS"
      +        case (OS_FREEBSD)
      +          s = s // "OS_FREEBSD"
      +        case (OS_OPENBSD)
      +          s = s // "OS_OPENBSD"
      +        case (OS_ALL)
      +          s = s // "OS_ALL"
      +        case default
      +          s = s // "INVALID"
      +        end select
      +        if (allocated(profile%flags)) s = s // ', flags="' // profile%flags // '"'
      +        if (allocated(profile%c_flags)) s = s // ', c_flags="' // profile%c_flags // '"'
      +        if (allocated(profile%cxx_flags)) s = s // ', cxx_flags="' // profile%cxx_flags // '"'
      +        if (allocated(profile%link_time_flags)) s = s // ', link_time_flags="' // profile%link_time_flags // '"'
      +        if (allocated(profile%file_scope_flags)) then
      +          do i=1,size(profile%file_scope_flags)
      +            s = s // ', flags for '//profile%file_scope_flags(i)%file_name// &
      +                    & ' ="' // profile%file_scope_flags(i)%flags // '"'
      +          end do
      +        end if
      +        s = s // ")"
      +
      +      end function info_profile
      +
      +      !> Look for profile with given configuration in array profiles
      +      subroutine find_profile(profiles, profile_name, compiler, os_type, found_matching, chosen_profile)
      +
      +        !> Array of profiles
      +        type(profile_config_t), allocatable, intent(in) :: profiles(:)
      +
      +        !> Name of profile
      +        character(:), allocatable, intent(in) :: profile_name
      +
      +        !> Name of compiler
      +        character(:), allocatable, intent(in) :: compiler
      +
      +        !> Type of operating system (enum)
      +        integer, intent(in) :: os_type
      +
      +        !> Boolean value containing true if matching profile was found
      +        logical, intent(out) :: found_matching
      +
      +        !> Last matching profile in the profiles array
      +        type(profile_config_t), intent(out) :: chosen_profile
      +
      +        character(:), allocatable :: curr_profile_name
      +        character(:), allocatable :: curr_compiler
      +        integer :: curr_os
      +        integer :: i, priority, curr_priority
      +
      +        found_matching = .false.
      +        if (size(profiles) < 1) return
      +        ! Try to find profile with matching OS type
      +        do i=1,size(profiles)
      +          curr_profile_name = profiles(i)%profile_name
      +          curr_compiler = profiles(i)%compiler
      +          curr_os = profiles(i)%os_type
      +          if (curr_profile_name.eq.profile_name) then
      +            if (curr_compiler.eq.compiler) then
      +              if (curr_os.eq.os_type) then
      +                chosen_profile = profiles(i)
      +                found_matching = .true.
      +              end if
      +            end if
      +          end if
      +        end do
      +        ! Try to find profile with OS type 'all'
      +        if (.not. found_matching) then
      +          do i=1,size(profiles)
      +            curr_profile_name = profiles(i)%profile_name
      +            curr_compiler = profiles(i)%compiler
      +            curr_os = profiles(i)%os_type
      +            if (curr_profile_name.eq.profile_name) then
      +              if (curr_compiler.eq.compiler) then
      +                if (curr_os.eq.OS_ALL) then
      +                  chosen_profile = profiles(i)
      +                  found_matching = .true.
      +                end if
      +              end if
      +            end if
      +          end do
      +        end if
      +      end subroutine find_profile
      +
      +
      +      logical function file_scope_same(this,that)
      +          class(file_scope_flag), intent(in) :: this
      +          class(serializable_t), intent(in) :: that
      +
      +          file_scope_same = .false.
      +
      +          select type (other=>that)
      +             type is (file_scope_flag)
      +                if (allocated(this%file_name).neqv.allocated(other%file_name)) return
      +                if (allocated(this%file_name)) then
      +                    if (.not.(this%file_name==other%file_name)) return
      +                endif
      +                if (allocated(this%flags).neqv.allocated(other%flags)) return
      +                if (allocated(this%flags)) then
      +                    if (.not.(this%flags==other%flags)) return
      +                endif
      +
      +             class default
      +                ! Not the same type
      +                return
      +          end select
      +
      +          !> All checks passed!
      +          file_scope_same = .true.
      +
      +    end function file_scope_same
      +
      +    !> Dump to toml table
      +    subroutine file_scope_dump(self, table, error)
      +
      +       !> Instance of the serializable object
      +       class(file_scope_flag), intent(inout) :: self
      +
      +       !> Data structure
      +       type(toml_table), intent(inout) :: table
      +
      +       !> Error handling
      +       type(error_t), allocatable, intent(out) :: error
      +
      +       call set_string(table, "file-name", self%file_name, error)
      +       if (allocated(error)) return
      +       call set_string(table, "flags", self%flags, error)
      +       if (allocated(error)) return
      +
      +     end subroutine file_scope_dump
      +
      +     !> Read from toml table (no checks made at this stage)
      +     subroutine file_scope_load(self, table, error)
      +
      +        !> Instance of the serializable object
      +        class(file_scope_flag), intent(inout) :: self
      +
      +        !> Data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        call get_value(table, "file-name", self%file_name)
      +        call get_value(table, "flags", self%flags)
      +
      +     end subroutine file_scope_load
      +
      +      logical function profile_same(this,that)
      +          class(profile_config_t), intent(in) :: this
      +          class(serializable_t), intent(in) :: that
      +
      +          integer :: ii
      +
      +          profile_same = .false.
      +
      +          select type (other=>that)
      +             type is (profile_config_t)
      +                if (allocated(this%profile_name).neqv.allocated(other%profile_name)) return
      +                if (allocated(this%profile_name)) then
      +                    if (.not.(this%profile_name==other%profile_name)) return
      +                endif
      +                if (allocated(this%compiler).neqv.allocated(other%compiler)) return
      +                if (allocated(this%compiler)) then
      +                    if (.not.(this%compiler==other%compiler)) return
      +                endif
      +                if (this%os_type/=other%os_type) return
      +                if (allocated(this%flags).neqv.allocated(other%flags)) return
      +                if (allocated(this%flags)) then
      +                    if (.not.(this%flags==other%flags)) return
      +                endif
      +                if (allocated(this%c_flags).neqv.allocated(other%c_flags)) return
      +                if (allocated(this%c_flags)) then
      +                    if (.not.(this%c_flags==other%c_flags)) return
      +                endif
      +                if (allocated(this%cxx_flags).neqv.allocated(other%cxx_flags)) return
      +                if (allocated(this%cxx_flags)) then
      +                    if (.not.(this%cxx_flags==other%cxx_flags)) return
      +                endif
      +                if (allocated(this%link_time_flags).neqv.allocated(other%link_time_flags)) return
      +                if (allocated(this%link_time_flags)) then
      +                    if (.not.(this%link_time_flags==other%link_time_flags)) return
      +                endif
      +
      +                if (allocated(this%file_scope_flags).neqv.allocated(other%file_scope_flags)) return
      +                if (allocated(this%file_scope_flags)) then
      +                    if (.not.size(this%file_scope_flags)==size(other%file_scope_flags)) return
      +                    do ii=1,size(this%file_scope_flags)
      +                        print *, 'check ii-th file scope: ',ii
      +                       if (.not.this%file_scope_flags(ii)==other%file_scope_flags(ii)) return
      +                    end do
      +                endif
      +
      +                if (this%is_built_in.neqv.other%is_built_in) return
      +
      +             class default
      +                ! Not the same type
      +                return
      +          end select
      +
      +          !> All checks passed!
      +          profile_same = .true.
      +
      +    end function profile_same
      +
      +    !> Dump to toml table
      +    subroutine profile_dump(self, table, error)
      +
      +       !> Instance of the serializable object
      +       class(profile_config_t), intent(inout) :: self
      +
      +       !> Data structure
      +       type(toml_table), intent(inout) :: table
      +
      +       !> Error handling
      +       type(error_t), allocatable, intent(out) :: error
      +
      +       !> Local variables
      +       integer :: ierr, ii
      +       type(toml_table), pointer :: ptr_deps, ptr
      +       character(len=30) :: unnamed
      +
      +       call set_string(table, "profile-name", self%profile_name, error)
      +       if (allocated(error)) return
      +       call set_string(table, "compiler", self%compiler, error)
      +       if (allocated(error)) return
      +       call set_string(table,"os-type",os_type_name(self%os_type), error, 'profile_config_t')
      +       if (allocated(error)) return
      +       call set_string(table, "flags", self%flags, error)
      +       if (allocated(error)) return
      +       call set_string(table, "c-flags", self%c_flags, error)
      +       if (allocated(error)) return
      +       call set_string(table, "cxx-flags", self%cxx_flags, error)
      +       if (allocated(error)) return
      +       call set_string(table, "link-time-flags", self%link_time_flags, error)
      +       if (allocated(error)) return
      +
      +       if (allocated(self%file_scope_flags)) then
      +
      +           ! Create dependency table
      +           call add_table(table, "file-scope-flags", ptr_deps)
      +           if (.not. associated(ptr_deps)) then
      +              call fatal_error(error, "profile_config_t cannot create file scope table ")
      +              return
      +           end if
      +
      +           do ii = 1, size(self%file_scope_flags)
      +              associate (dep => self%file_scope_flags(ii))
      +
      +                 !> Because files need a name, fallback if this has no name
      +                 if (len_trim(dep%file_name)==0) then
      +                    write(unnamed,1) ii
      +                    call add_table(ptr_deps, trim(unnamed), ptr)
      +                 else
      +                    call add_table(ptr_deps, dep%file_name, ptr)
      +                 end if
      +                 if (.not. associated(ptr)) then
      +                    call fatal_error(error, "profile_config_t cannot create entry for file "//dep%file_name)
      +                    return
      +                 end if
      +                 call dep%dump_to_toml(ptr, error)
      +                 if (allocated(error)) return
      +              end associate
      +           end do
      +
      +       endif
      +
      +       call set_value(table, "is-built-in", self%is_built_in, error, 'profile_config_t')
      +       if (allocated(error)) return
      +
      +       1 format('UNNAMED_FILE_',i0)
      +
      +     end subroutine profile_dump
      +
      +     !> Read from toml table (no checks made at this stage)
      +     subroutine profile_load(self, table, error)
      +
      +        !> Instance of the serializable object
      +        class(profile_config_t), intent(inout) :: self
      +
      +        !> Data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        !> Local variables
      +        character(len=:), allocatable :: flag
      +        integer :: ii, jj
      +        type(toml_table), pointer :: ptr_dep, ptr
      +        type(toml_key), allocatable :: keys(:),dep_keys(:)
      +
      +        call table%get_keys(keys)
      +
      +        call get_value(table, "profile-name", self%profile_name)
      +        call get_value(table, "compiler", self%compiler)
      +        call get_value(table,"os-type",flag)
      +        call match_os_type(flag, self%os_type)
      +        call get_value(table, "flags", self%flags)
      +        call get_value(table, "c-flags", self%c_flags)
      +        call get_value(table, "cxx-flags", self%cxx_flags)
      +        call get_value(table, "link-time-flags", self%link_time_flags)
      +        call get_value(table, "is-built-in", self%is_built_in, error, 'profile_config_t')
      +        if (allocated(error)) return
      +
      +        if (allocated(self%file_scope_flags)) deallocate(self%file_scope_flags)
      +        sub_deps: do ii = 1, size(keys)
      +
      +           select case (keys(ii)%key)
      +              case ("file-scope-flags")
      +
      +               call get_value(table, keys(ii), ptr)
      +               if (.not.associated(ptr)) then
      +                  call fatal_error(error,'profile_config_t: error retrieving file_scope_flags table')
      +                  return
      +               end if
      +
      +               !> Read all packages
      +               call ptr%get_keys(dep_keys)
      +               allocate(self%file_scope_flags(size(dep_keys)))
      +
      +               do jj = 1, size(dep_keys)
      +
      +                   call get_value(ptr, dep_keys(jj), ptr_dep)
      +                   call self%file_scope_flags(jj)%load_from_toml(ptr_dep, error)
      +                   if (allocated(error)) return
      +
      +               end do
      +
      +           end select
      +        end do sub_deps
      +
      +     end subroutine profile_load
      +
      +
      +end module fpm_manifest_profile
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/publish.f90.html b/sourcefile/publish.f90.html new file mode 100644 index 0000000000..8017299b34 --- /dev/null +++ b/sourcefile/publish.f90.html @@ -0,0 +1,322 @@ + + + + + + + + + + + + + publish.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      publish.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      !> Upload a package to the registry using the `publish` command.
      +!>
      +!> To upload a package you need to provide a token that will be linked to your username and created for a namespace.
      +!> The token can be obtained from the registry website. It can be used as `fpm publish --token <token>`.
      +module fpm_cmd_publish
      +  use fpm_command_line, only: fpm_publish_settings
      +  use fpm_manifest, only: package_config_t, get_package_data
      +  use fpm_model, only: fpm_model_t
      +  use fpm_error, only: error_t, fpm_stop
      +  use fpm_versioning, only: version_t
      +  use fpm_filesystem, only: exists, join_path, get_temp_filename, delete_file
      +  use fpm_git, only: git_archive
      +  use fpm_downloader, only: downloader_t
      +  use fpm_strings, only: string_t
      +  use fpm_settings, only: official_registry_base_url
      +  use fpm, only: build_model
      +
      +  implicit none
      +  private
      +  public :: cmd_publish
      +
      +contains
      +
      +  !> The `publish` command first builds the root package to obtain all the relevant information such as the
      +  !> package version. It then creates a tarball of the package and uploads it to the registry.
      +  subroutine cmd_publish(settings)
      +    type(fpm_publish_settings), intent(inout) :: settings
      +
      +    type(package_config_t) :: package
      +    type(fpm_model_t) :: model
      +    type(error_t), allocatable :: error
      +    type(version_t), allocatable :: version
      +    type(string_t), allocatable :: upload_data(:)
      +    character(len=:), allocatable :: tmp_file
      +    type(downloader_t) :: downloader
      +    integer :: i
      +
      +    ! Get package data to determine package version.
      +    call get_package_data(package, 'fpm.toml', error, apply_defaults=.true.)
      +    if (allocated(error)) call fpm_stop(1, '*cmd_build* Package error: '//error%message)
      +    version = package%version
      +
      +    if (settings%show_package_version) then
      +      print *, version%s(); return
      +    end if
      +
      +    !> Checks before uploading the package.
      +    if (.not. allocated(package%license)) call fpm_stop(1, 'No license specified in fpm.toml.')
      +    if (.not. package%build%module_naming) call fpm_stop(1, 'The package does not meet the module naming requirements. '// &
      +      & 'Please set "module-naming = true" in fpm.toml [build] or specify a custom module prefix.')
      +    if (.not. allocated(version)) call fpm_stop(1, 'No version specified in fpm.toml.')
      +    if (version%s() == '0') call fpm_stop(1, 'Invalid version: "'//version%s()//'".')
      +    if (.not. exists('fpm.toml')) call fpm_stop(1, "Cannot find 'fpm.toml' file. Are you in the project root?")
      +
      +    ! Build model to obtain dependency tree.
      +    call build_model(model, settings%fpm_build_settings, package, error)
      +    if (allocated(error)) call fpm_stop(1, '*cmd_build* Model error: '//error%message)
      +
      +    ! Check if package contains git dependencies. Only publish packages without git dependencies.
      +    do i = 1, model%deps%ndep
      +      if (allocated(model%deps%dep(i)%git)) then
      +        call fpm_stop(1, 'Do not publish packages containing git dependencies. '// &
      +        & "Please upload '"//model%deps%dep(i)%name//"' to the registry first.")
      +      end if
      +    end do
      +
      +    tmp_file = get_temp_filename()
      +    call git_archive('.', tmp_file, 'HEAD', additional_files=['fpm_model.json'], verbose=settings%verbose, error=error)
      +    if (allocated(error)) call fpm_stop(1, '*cmd_publish* Archive error: '//error%message)
      +    call model%dump('fpm_model.json', error, json=.true.)
      +    if (allocated(error)) call fpm_stop(1, '*cmd_publish* Model dump error: '//error%message)
      +
      +    upload_data = [ &
      +    & string_t('package_name="'//package%name//'"'), &
      +    & string_t('package_license="'//package%license//'"'), &
      +    & string_t('package_version="'//version%s()//'"'), &
      +    & string_t('tarball=@"'//tmp_file//'"') &
      +    & ]
      +
      +    if (allocated(settings%token)) upload_data = [upload_data, string_t('upload_token="'//settings%token//'"')]
      +
      +    if (settings%show_upload_data) then
      +      call print_upload_data(upload_data); return
      +    end if
      +
      +    ! Make sure a token is provided for publishing.
      +    if (allocated(settings%token)) then
      +      if (settings%token == '') then
      +        call delete_file(tmp_file); call fpm_stop(1, 'No token provided.')
      +      end if
      +    else
      +      call delete_file(tmp_file); call fpm_stop(1, 'No token provided.')
      +    end if
      +
      +    if (settings%verbose) then
      +      call print_upload_data(upload_data)
      +      print *, ''
      +    end if
      +
      +    ! Perform network request and validate package, token etc. on the backend once
      +    ! https://github.com/fortran-lang/registry/issues/41 is resolved.
      +    if (settings%is_dry_run) then
      +      print *, 'Dry run successful. Generated tarball: ', tmp_file; return
      +    end if
      +
      +    call downloader%upload_form(official_registry_base_url//'/packages', upload_data, settings%verbose, error)
      +    call delete_file(tmp_file)
      +    if (allocated(error)) call fpm_stop(1, '*cmd_publish* Upload error: '//error%message)
      +  end
      +
      +  subroutine print_upload_data(upload_data)
      +    type(string_t), intent(in) :: upload_data(:)
      +    integer :: i
      +
      +    print *, 'Upload data:'
      +    do i = 1, size(upload_data)
      +      print *, upload_data(i)%s
      +    end do
      +  end
      +end
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/test.f90.html b/sourcefile/test.f90.html new file mode 100644 index 0000000000..16784a7d01 --- /dev/null +++ b/sourcefile/test.f90.html @@ -0,0 +1,381 @@ + + + + + + + + + + + + + test.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      test.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      !> Implementation of the meta data for a test.
      +!>
      +!> The test data structure is effectively a decorated version of an executable
      +!> and shares most of its properties, except for the defaults and can be
      +!> handled under most circumstances just like any other executable.
      +!>
      +!> A test table can currently have the following fields
      +!>
      +!>```toml
      +!>[[ test ]]
      +!>name = "string"
      +!>source-dir = "path"
      +!>main = "file"
      +!>link = ["lib"]
      +!>[test.dependencies]
      +!>```
      +module fpm_manifest_test
      +    use fpm_manifest_dependency, only : new_dependencies
      +    use fpm_manifest_executable, only : executable_config_t
      +    use fpm_error, only : error_t, syntax_error, bad_name_error
      +    use tomlf, only : toml_table, toml_key, toml_stat
      +    use fpm_toml, only : get_value, get_list
      +    implicit none
      +    private
      +
      +    public :: test_config_t, new_test
      +
      +
      +    !> Configuation meta data for an test
      +    type, extends(executable_config_t) :: test_config_t
      +
      +    contains
      +
      +        !> Print information on this instance
      +        procedure :: info
      +
      +    end type test_config_t
      +
      +
      +contains
      +
      +
      +    !> Construct a new test configuration from a TOML data structure
      +    subroutine new_test(self, table, error)
      +
      +        !> Instance of the test configuration
      +        type(test_config_t), intent(out) :: self
      +
      +        !> Instance of the TOML data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        type(toml_table), pointer :: child
      +
      +        call check(table, error)
      +        if (allocated(error)) return
      +
      +        call get_value(table, "name", self%name)
      +        if (.not.allocated(self%name)) then
      +           call syntax_error(error, "Could not retrieve test name")
      +           return
      +        end if
      +        if (bad_name_error(error,'test',self%name))then
      +           return
      +        endif
      +        call get_value(table, "source-dir", self%source_dir, "test")
      +        call get_value(table, "main", self%main, "main.f90")
      +
      +        call get_value(table, "dependencies", child, requested=.false.)
      +        if (associated(child)) then
      +            call new_dependencies(self%dependency, child, error=error)
      +            if (allocated(error)) return
      +        end if
      +
      +        call get_list(table, "link", self%link, error)
      +        if (allocated(error)) return
      +
      +    end subroutine new_test
      +
      +
      +    !> Check local schema for allowed entries
      +    subroutine check(table, error)
      +
      +        !> Instance of the TOML data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        type(toml_key), allocatable :: list(:)
      +        logical :: name_present
      +        integer :: ikey
      +
      +        name_present = .false.
      +
      +        call table%get_keys(list)
      +
      +        if (size(list) < 1) then
      +            call syntax_error(error, "Test section does not provide sufficient entries")
      +            return
      +        end if
      +
      +        do ikey = 1, size(list)
      +            select case(list(ikey)%key)
      +            case default
      +                call syntax_error(error, "Key "//list(ikey)%key//" is not allowed in test entry")
      +                exit
      +
      +            case("name")
      +                name_present = .true.
      +
      +            case("source-dir", "main", "dependencies", "link")
      +                continue
      +
      +            end select
      +        end do
      +        if (allocated(error)) return
      +
      +        if (.not.name_present) then
      +            call syntax_error(error, "Test name is not provided, please add a name entry")
      +        end if
      +
      +    end subroutine check
      +
      +
      +    !> Write information on instance
      +    subroutine info(self, unit, verbosity)
      +
      +        !> Instance of the test configuration
      +        class(test_config_t), intent(in) :: self
      +
      +        !> Unit for IO
      +        integer, intent(in) :: unit
      +
      +        !> Verbosity of the printout
      +        integer, intent(in), optional :: verbosity
      +
      +        integer :: pr, ii
      +        character(len=*), parameter :: fmt = '("#", 1x, a, t30, a)', &
      +            & fmti = '("#", 1x, a, t30, i0)'
      +
      +        if (present(verbosity)) then
      +            pr = verbosity
      +        else
      +            pr = 1
      +        end if
      +
      +        if (pr < 1) return
      +
      +        write(unit, fmt) "Test target"
      +        if (allocated(self%name)) then
      +            write(unit, fmt) "- name", self%name
      +        end if
      +        if (allocated(self%source_dir)) then
      +            if (self%source_dir /= "test" .or. pr > 2) then
      +                write(unit, fmt) "- source directory", self%source_dir
      +            end if
      +        end if
      +        if (allocated(self%main)) then
      +            if (self%main /= "main.f90" .or. pr > 2) then
      +                write(unit, fmt) "- test source", self%main
      +            end if
      +        end if
      +
      +        if (allocated(self%dependency)) then
      +            if (size(self%dependency) > 1 .or. pr > 2) then
      +                write(unit, fmti) "- dependencies", size(self%dependency)
      +            end if
      +            do ii = 1, size(self%dependency)
      +                call self%dependency(ii)%info(unit, pr - 1)
      +            end do
      +        end if
      +
      +    end subroutine info
      +
      +
      +end module fpm_manifest_test
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/toml.f90.html b/sourcefile/toml.f90.html new file mode 100644 index 0000000000..124bfd21df --- /dev/null +++ b/sourcefile/toml.f90.html @@ -0,0 +1,1057 @@ + + + + + + + + + + + + + toml.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      toml.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      !># Interface to TOML processing library
      +!>
      +!> This module acts as a proxy to the `toml-f` public Fortran API and allows
      +!> to selectively expose components from the library to `fpm`.
      +!> The interaction with `toml-f` data types outside of this module should be
      +!> limited to tables, arrays and key-lists, most of the necessary interactions
      +!> are implemented in the building interface with the `get_value` and `set_value`
      +!> procedures.
      +!>
      +!> This module allows to implement features necessary for `fpm`, which are
      +!> not yet available in upstream `toml-f`.
      +!>
      +!> For more details on the library used see the
      +!> [TOML-Fortran](https://toml-f.github.io/toml-f) developer pages.
      +module fpm_toml
      +    use fpm_error, only: error_t, fatal_error, file_not_found_error
      +    use fpm_strings, only: string_t, str_ends_with, lower
      +    use tomlf, only: toml_table, toml_array, toml_key, toml_stat, get_value, &
      +        & set_value, toml_parse, toml_error, new_table, add_table, add_array, &
      +        & toml_serialize, len, toml_load, toml_value
      +    use tomlf_de_parser, only: parse
      +    use jonquil, only: json_serialize, json_error, json_value, json_object, json_load, &
      +                       cast_to_object
      +    use iso_fortran_env, only: int64
      +    implicit none
      +    private
      +
      +    public :: read_package_file, toml_table, toml_array, toml_key, toml_stat, &
      +              get_value, set_value, get_list, new_table, add_table, add_array, len, &
      +              toml_error, toml_serialize, toml_load, check_keys, set_list, set_string, &
      +              name_is_json, has_list
      +
      +    !> An abstract interface for any fpm class that should be fully serializable to/from TOML/JSON
      +    type, abstract, public :: serializable_t
      +
      +        contains
      +
      +        !> Dump to TOML table, unit, file
      +        procedure(to_toml), deferred :: dump_to_toml
      +        procedure, non_overridable, private :: dump_to_file
      +        procedure, non_overridable, private :: dump_to_unit
      +        generic :: dump => dump_to_toml, dump_to_file, dump_to_unit
      +
      +        !> Load from TOML table, unit, file
      +        procedure(from_toml), deferred :: load_from_toml
      +        procedure, non_overridable, private :: load_from_file
      +        procedure, non_overridable, private :: load_from_unit
      +        generic :: load => load_from_toml, load_from_file, load_from_unit
      +
      +        !> Serializable entities need a way to check that they're equal
      +        procedure(is_equal), deferred :: serializable_is_same
      +        generic :: operator(==) => serializable_is_same
      +
      +        !> Test load/write roundtrip
      +        procedure, non_overridable :: test_serialization
      +
      +    end type serializable_t
      +
      +    !> add_table: fpm interface
      +    interface add_table
      +        module procedure add_table_fpm
      +    end interface add_table
      +
      +    !> set_value: fpm interface
      +    interface set_value
      +        module procedure set_logical
      +        module procedure set_integer
      +        module procedure set_integer_64
      +    end interface set_value
      +
      +    interface set_string
      +        module procedure set_character
      +        module procedure set_string_type
      +    end interface set_string
      +
      +    !> get_value: fpm interface
      +    interface get_value
      +        module procedure get_logical
      +        module procedure get_integer
      +        module procedure get_integer_64
      +        module procedure get_char
      +        module procedure get_string
      +    end interface get_value
      +
      +
      +    abstract interface
      +
      +      !> Write object to TOML datastructure
      +      subroutine to_toml(self, table, error)
      +        import serializable_t,toml_table,error_t
      +        implicit none
      +
      +        !> Instance of the serializable object
      +        class(serializable_t), intent(inout) :: self
      +
      +        !> Data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +      end subroutine to_toml
      +
      +      !> Read dependency tree from TOML data structure
      +      subroutine from_toml(self, table, error)
      +        import serializable_t,toml_table,error_t
      +        implicit none
      +
      +        !> Instance of the serializable object
      +        class(serializable_t), intent(inout) :: self
      +
      +        !> Data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +      end subroutine from_toml
      +
      +      !> Compare two serializable objects
      +      logical function is_equal(this,that)
      +         import serializable_t
      +         class(serializable_t), intent(in) :: this,that
      +      end function is_equal
      +
      +    end interface
      +
      +contains
      +
      +    !> Test serialization of a serializable object
      +    subroutine test_serialization(self, message, error)
      +        class(serializable_t), intent(inout) :: self
      +        character(len=*), intent(in) :: message
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        integer :: iunit, ii
      +        class(serializable_t), allocatable :: copy
      +        character(len=4), parameter :: formats(2) = ['TOML','JSON']
      +
      +        all_formats: do ii = 1, 2
      +
      +            open(newunit=iunit,form='formatted',action='readwrite',status='scratch')
      +
      +            !> Dump to scratch file
      +            call self%dump(iunit, error, json=ii==2)
      +            if (allocated(error)) then
      +                error%message = formats(ii)//': '//error%message
      +                return
      +            endif
      +
      +            !> Load from scratch file
      +            rewind(iunit)
      +            allocate(copy,mold=self)
      +            call copy%load(iunit,error, json=ii==2)
      +            if (allocated(error)) then
      +                error%message = formats(ii)//': '//error%message
      +                return
      +            endif
      +            close(iunit)
      +
      +            !> Check same
      +            if (.not.(self==copy)) then
      +                call fatal_error(error,'serializable object failed '//formats(ii)//&
      +                                       ' write/reread test: '//trim(message))
      +                return
      +            end if
      +            deallocate(copy)
      +
      +        end do all_formats
      +
      +    end subroutine test_serialization
      +
      +
      +    !> Write serializable object to a formatted Fortran unit
      +    subroutine dump_to_unit(self, unit, error, json)
      +        !> Instance of the dependency tree
      +        class(serializable_t), intent(inout) :: self
      +        !> Formatted unit
      +        integer, intent(in) :: unit
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +        !> Optional JSON format requested?
      +        logical, optional, intent(in) :: json
      +
      +        type(toml_table) :: table
      +        logical :: is_json
      +
      +        is_json = .false.; if (present(json)) is_json = json
      +
      +        table = toml_table()
      +        call self%dump(table, error)
      +
      +        if (is_json) then
      +
      +!            !> Deactivate JSON serialization for now
      +!            call fatal_error(error, 'JSON serialization option is not yet available')
      +!            return
      +
      +            write (unit, '(a)') json_serialize(table)
      +        else
      +            write (unit, '(a)') toml_serialize(table)
      +        end if
      +
      +        call table%destroy()
      +
      +    end subroutine dump_to_unit
      +
      +    !> Write serializable object to file
      +    subroutine dump_to_file(self, file, error, json)
      +        !> Instance of the dependency tree
      +        class(serializable_t), intent(inout) :: self
      +        !> File name
      +        character(len=*), intent(in) :: file
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +        !> Optional JSON format
      +        logical, optional, intent(in) :: json
      +
      +        integer :: unit
      +
      +        open (file=file, newunit=unit)
      +        call self%dump(unit, error, json)
      +        close (unit)
      +        if (allocated(error)) return
      +
      +    end subroutine dump_to_file
      +
      +    !> Read dependency tree from file
      +    subroutine load_from_file(self, file, error, json)
      +        !> Instance of the dependency tree
      +        class(serializable_t), intent(inout) :: self
      +        !> File name
      +        character(len=*), intent(in) :: file
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +        !> Optional JSON format
      +        logical, optional, intent(in) :: json
      +
      +        integer :: unit
      +        logical :: exist
      +
      +        inquire (file=file, exist=exist)
      +        if (.not. exist) return
      +
      +        open (file=file, newunit=unit)
      +        call self%load(unit, error, json)
      +        close (unit)
      +    end subroutine load_from_file
      +
      +    !> Read dependency tree from file
      +    subroutine load_from_unit(self, unit, error, json)
      +        !> Instance of the dependency tree
      +        class(serializable_t), intent(inout) :: self
      +        !> File name
      +        integer, intent(in) :: unit
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +        !> Optional JSON format
      +        logical, optional, intent(in) :: json
      +
      +        type(toml_error), allocatable :: local_error
      +        type(toml_table), allocatable :: table
      +        type(toml_table), pointer     :: jtable
      +        class(toml_value), allocatable :: object
      +        logical :: is_json
      +
      +        is_json = .false.; if (present(json)) is_json = json
      +
      +        if (is_json) then
      +
      +           !> init JSON interpreter
      +           call json_load(object, unit, error=local_error)
      +           if (allocated(local_error)) then
      +              allocate (error)
      +              call move_alloc(local_error%message, error%message)
      +              return
      +           end if
      +
      +           jtable => cast_to_object(object)
      +           if (.not.associated(jtable)) then
      +              call fatal_error(error,'cannot initialize JSON table ')
      +              return
      +           end if
      +
      +           !> Read object from TOML table
      +           call self%load(jtable, error)
      +
      +        else
      +
      +           !> use default TOML parser
      +           call toml_load(table, unit, error=local_error)
      +
      +           if (allocated(local_error)) then
      +              allocate (error)
      +              call move_alloc(local_error%message, error%message)
      +              return
      +           end if
      +
      +           !> Read object from TOML table
      +           call self%load(table, error)
      +
      +        endif
      +
      +        if (allocated(error)) return
      +
      +    end subroutine load_from_unit
      +
      +    !> Process the configuration file to a TOML data structure
      +    subroutine read_package_file(table, manifest, error)
      +
      +        !> TOML data structure
      +        type(toml_table), allocatable, intent(out) :: table
      +
      +        !> Name of the package configuration file
      +        character(len=*), intent(in) :: manifest
      +
      +        !> Error status of the operation
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        type(toml_error), allocatable :: parse_error
      +        integer :: unit
      +        logical :: exist
      +
      +        inquire (file=manifest, exist=exist)
      +
      +        if (.not. exist) then
      +            call file_not_found_error(error, manifest)
      +            return
      +        end if
      +
      +        open(file=manifest, newunit=unit)
      +        call toml_load(table, unit, error=parse_error)
      +        close(unit)
      +
      +        if (allocated(parse_error)) then
      +            allocate (error)
      +            call move_alloc(parse_error%message, error%message)
      +            return
      +        end if
      +
      +    end subroutine read_package_file
      +
      +    !> Check if an instance of the TOML data structure contains a list
      +    logical function has_list(table, key)
      +
      +        !> Instance of the TOML data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> Key to read from
      +        character(len=*), intent(in) :: key
      +
      +        type(toml_array), pointer :: children
      +
      +        has_list = .false.
      +
      +        if (.not.table%has_key(key)) return
      +
      +        call get_value(table, key, children, requested=.false.)
      +
      +        ! There is an allocated list
      +        has_list = associated(children)
      +
      +    end function has_list
      +
      +
      +    subroutine get_list(table, key, list, error)
      +
      +        !> Instance of the TOML data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> Key to read from
      +        character(len=*), intent(in) :: key
      +
      +        !> List of strings to read
      +        type(string_t), allocatable, intent(out) :: list(:)
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        integer :: stat, ilist, nlist
      +        type(toml_array), pointer :: children
      +        character(len=:), allocatable :: str
      +
      +        if (.not.table%has_key(key)) return
      +
      +        call get_value(table, key, children, requested=.false.)
      +        if (associated(children)) then
      +            nlist = len(children)
      +            allocate (list(nlist))
      +            do ilist = 1, nlist
      +                call get_value(children, ilist, str, stat=stat)
      +                if (stat /= toml_stat%success) then
      +                    call fatal_error(error, "Entry in "//key//" field cannot be read")
      +                    exit
      +                end if
      +                call move_alloc(str, list(ilist)%s)
      +            end do
      +            if (allocated(error)) return
      +        else
      +            call get_value(table, key, str, stat=stat)
      +            if (stat /= toml_stat%success) then
      +                call fatal_error(error, "Entry in "//key//" field cannot be read")
      +                return
      +            end if
      +            if (allocated(str)) then
      +                allocate (list(1))
      +                call move_alloc(str, list(1)%s)
      +            end if
      +        end if
      +
      +    end subroutine get_list
      +
      +    ! Set string array
      +    subroutine set_list(table, key, list, error)
      +
      +        !> Instance of the string array
      +        type(string_t), allocatable, intent(in) :: list(:)
      +
      +        !> Key to save to
      +        character(len=*), intent(in) :: key
      +
      +        !> Instance of the toml table
      +        type(toml_table), intent(inout) :: table
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        !> Local variables
      +        integer :: stat, ilist
      +        type(toml_array), pointer :: children
      +        character(len=:), allocatable :: str
      +
      +        !> Set no key if array is not present
      +        if (.not.allocated(list)) return
      +
      +        !> Check the key is not empty
      +        if (len_trim(key)<=0) then
      +            call fatal_error(error, 'key is empty dumping string array to TOML table')
      +            return
      +        end if
      +
      +        if (size(list)/=1) then ! includes empty list case
      +
      +            !> String array
      +            call add_array(table, key, children, stat)
      +            if (stat /= toml_stat%success) then
      +                call fatal_error(error, "Cannot set array table in "//key//" field")
      +                return
      +            end if
      +
      +            do ilist = 1, size(list)
      +                  call set_value(children, ilist, list(ilist)%s, stat=stat)
      +                  if (stat /= toml_stat%success) then
      +                      call fatal_error(error, "Cannot store array entry in "//key//" field")
      +                      return
      +                  end if
      +            end do
      +
      +        else
      +
      +            ! Single value: set string
      +            call set_value(table, key, list(1)%s, stat=stat)
      +
      +            if (stat /= toml_stat%success) &
      +            call fatal_error(error, "Cannot store entry in "//key//" field")
      +
      +            return
      +        end if
      +
      +    end subroutine set_list
      +
      +    !> Function wrapper to set a character(len=:), allocatable variable to a toml table
      +    subroutine set_character(table, key, var, error, whereAt)
      +
      +        !> Instance of the TOML data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> List of keys to check.
      +        character(len=*), intent(in) :: key
      +
      +        !> The character variable
      +        character(len=*), optional, intent(in) :: var
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        !> Optional description
      +        character(len=*), intent(in), optional :: whereAt
      +
      +        integer :: ierr
      +
      +        !> Check the key is not empty
      +        if (len_trim(key)<=0) then
      +            call fatal_error(error, 'key is empty setting character string to TOML table')
      +            if (present(whereAt)) error%message = whereAt//': '//error%message
      +            return
      +        end if
      +
      +        if (present(var)) then
      +            call set_value(table, key, var, ierr)
      +            if (ierr/=toml_stat%success) then
      +                call fatal_error(error,'cannot set character key <'//key//'> in TOML table')
      +                if (present(whereAt)) error%message = whereAt//': '//error%message
      +                return
      +            end if
      +        endif
      +
      +    end subroutine set_character
      +
      +    !> Function wrapper to set a logical variable to a toml table, returning an fpm error
      +    subroutine set_logical(table, key, var, error, whereAt)
      +
      +        !> Instance of the TOML data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> The key
      +        character(len=*), intent(in) :: key
      +
      +        !> The variable
      +        logical, intent(in) :: var
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        !> Optional description
      +        character(len=*), intent(in), optional :: whereAt
      +
      +        integer :: ierr
      +
      +        call set_value(table, key, var, stat=ierr)
      +        if (ierr/=toml_stat%success) then
      +            call fatal_error(error,'cannot set logical key <'//key//'> in TOML table')
      +            if (present(whereAt)) error%message = whereAt//': '//error%message
      +            return
      +        end if
      +
      +    end subroutine set_logical
      +
      +    !> Function wrapper to set a default integer variable to a toml table, returning an fpm error
      +    subroutine set_integer(table, key, var, error, whereAt)
      +
      +        !> Instance of the TOML data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> The key
      +        character(len=*), intent(in) :: key
      +
      +        !> The variable
      +        integer, intent(in) :: var
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        !> Optional description
      +        character(len=*), intent(in), optional :: whereAt
      +
      +        integer :: ierr
      +
      +        call set_value(table, key, var, stat=ierr)
      +        if (ierr/=toml_stat%success) then
      +            call fatal_error(error,'cannot set integer key <'//key//'> in TOML table')
      +            if (present(whereAt)) error%message = whereAt//': '//error%message
      +            return
      +        end if
      +
      +    end subroutine set_integer
      +
      +    !> Function wrapper to set a default integer variable to a toml table, returning an fpm error
      +    subroutine set_integer_64(table, key, var, error, whereAt)
      +
      +        !> Instance of the TOML data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> The key
      +        character(len=*), intent(in) :: key
      +
      +        !> The variable
      +        integer(int64), intent(in) :: var
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        !> Optional description
      +        character(len=*), intent(in), optional :: whereAt
      +
      +        integer :: ierr
      +
      +        call set_value(table, key, var, stat=ierr)
      +        if (ierr/=toml_stat%success) then
      +            call fatal_error(error,'cannot set integer(int64) key <'//key//'> in TOML table')
      +            if (present(whereAt)) error%message = whereAt//': '//error%message
      +            return
      +        end if
      +
      +    end subroutine set_integer_64
      +
      +    !> Function wrapper to set a character(len=:), allocatable variable to a toml table
      +    subroutine set_string_type(table, key, var, error, whereAt)
      +
      +        !> Instance of the TOML data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> List of keys to check.
      +        character(len=*), intent(in) :: key
      +
      +        !> The character variable
      +        type(string_t), intent(in) :: var
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        !> Optional description
      +        character(len=*), intent(in), optional :: whereAt
      +
      +        call set_character(table, key, var%s, error, whereAt)
      +
      +    end subroutine set_string_type
      +
      +    !> Function wrapper to add a toml table and return an fpm error
      +    subroutine add_table_fpm(table, key, ptr, error, whereAt)
      +
      +        !> Instance of the TOML data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> Table key
      +        character(len=*), intent(in) :: key
      +
      +        !> The character variable
      +        type(toml_table), pointer, intent(out) :: ptr
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        !> Optional description
      +        character(len=*), intent(in), optional :: whereAt
      +
      +        integer :: ierr
      +
      +        !> Nullify pointer
      +        nullify(ptr)
      +
      +        call add_table(table, key, ptr, ierr)
      +        if (ierr/=toml_stat%success) then
      +            call fatal_error(error,'cannot add <'//key//'> table in TOML table')
      +            if (present(whereAt)) error%message = whereAt//': '//error%message
      +            return
      +        end if
      +
      +    end subroutine add_table_fpm
      +
      +    !> Function wrapper to get a logical variable from a toml table, returning an fpm error
      +    subroutine get_logical(table, key, var, error, whereAt)
      +
      +        !> Instance of the TOML data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> The key
      +        character(len=*), intent(in) :: key
      +
      +        !> The variable
      +        logical, intent(inout) :: var
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        !> Optional description
      +        character(len=*), intent(in), optional :: whereAt
      +
      +        integer :: ierr
      +
      +        call get_value(table, key, var, stat=ierr)
      +        if (ierr/=toml_stat%success) then
      +            call fatal_error(error,'cannot get logical key <'//key//'> from TOML table')
      +            if (present(whereAt)) error%message = whereAt//': '//error%message
      +            return
      +        end if
      +
      +    end subroutine get_logical
      +
      +    !> Function wrapper to get a default integer variable from a toml table, returning an fpm error
      +    subroutine get_integer(table, key, var, error, whereAt)
      +
      +        !> Instance of the TOML data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> The key
      +        character(len=*), intent(in) :: key
      +
      +        !> The variable
      +        integer, intent(inout) :: var
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        !> Optional description
      +        character(len=*), intent(in), optional :: whereAt
      +
      +        integer :: ierr
      +
      +        call get_value(table, key, var, stat=ierr)
      +        if (ierr/=toml_stat%success) then
      +            call fatal_error(error,'cannot get integer key <'//key//'> from TOML table')
      +            if (present(whereAt)) error%message = whereAt//': '//error%message
      +            return
      +        end if
      +
      +    end subroutine get_integer
      +
      +    !> Function wrapper to get a default string variable from a toml table, returning an fpm error
      +    subroutine get_string(table, key, var, error, whereAt)
      +
      +        !> Instance of the TOML data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> The key
      +        character(len=*), intent(in) :: key
      +
      +        !> The variable
      +        type(string_t), intent(inout) :: var
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        !> Optional description
      +        character(len=*), intent(in), optional :: whereAt
      +
      +        call get_char(table, key, var%s, error, whereAt)
      +
      +    end subroutine get_string
      +
      +    !> Function wrapper to get a default character variable from a toml table, returning an fpm error
      +    subroutine get_char(table, key, var, error, whereAt)
      +
      +        !> Instance of the TOML data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> The key
      +        character(len=*), intent(in) :: key
      +
      +        !> The variable
      +        character(len=:), allocatable, intent(inout) :: var
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        !> Optional description
      +        character(len=*), intent(in), optional :: whereAt
      +
      +        integer :: ierr
      +
      +        call get_value(table, key, var, stat=ierr)
      +        if (ierr/=toml_stat%success) then
      +            call fatal_error(error,'cannot get string key <'//key//'> from TOML table')
      +            if (present(whereAt)) error%message = whereAt//': '//error%message
      +            return
      +        end if
      +
      +    end subroutine get_char
      +
      +    !> Function wrapper to get a integer(int64) variable from a toml table, returning an fpm error
      +    subroutine get_integer_64(table, key, var, error, whereAt)
      +
      +        !> Instance of the TOML data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> The key
      +        character(len=*), intent(in) :: key
      +
      +        !> The variable
      +        integer(int64), intent(inout) :: var
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        !> Optional description
      +        character(len=*), intent(in), optional :: whereAt
      +
      +        integer :: ierr
      +
      +        call get_value(table, key, var, stat=ierr)
      +        if (ierr/=toml_stat%success) then
      +            call fatal_error(error,'cannot get integer(int64) key <'//key//'> from TOML table')
      +            if (present(whereAt)) error%message = whereAt//': '//error%message
      +            return
      +        end if
      +
      +    end subroutine get_integer_64
      +
      +    !> Check if table contains only keys that are part of the list. If a key is
      +    !> found that is not part of the list, an error is allocated.
      +    subroutine check_keys(table, valid_keys, error)
      +
      +        !> Instance of the TOML data structure
      +        type(toml_table), intent(inout) :: table
      +
      +        !> List of keys to check.
      +        character(len=*), intent(in) :: valid_keys(:)
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        type(toml_key), allocatable :: keys(:)
      +        type(toml_table), pointer :: child
      +        character(:), allocatable :: name, value, valid_keys_string
      +        integer :: ikey, ivalid
      +
      +        call table%get_key(name)
      +        call table%get_keys(keys)
      +
      +        do ikey = 1, size(keys)
      +            if (.not. any(keys(ikey)%key == valid_keys)) then
      +                ! Generate error message
      +                valid_keys_string = new_line('a')//new_line('a')
      +                do ivalid = 1, size(valid_keys)
      +                    valid_keys_string = valid_keys_string//trim(valid_keys(ivalid))//new_line('a')
      +                end do
      +                allocate (error)
      +                error%message = "Key '"//keys(ikey)%key//"' not allowed in the '"// &
      +                & name//"' table."//new_line('a')//new_line('a')//'Valid keys: '//valid_keys_string
      +                return
      +            end if
      +
      +            ! Check if value can be mapped or else (wrong type) show error message with the error location.
      +            ! Right now, it can only be mapped to a string or to a child node, but this can be extended in the future.
      +            call get_value(table, keys(ikey)%key, value)
      +            if (.not. allocated(value)) then
      +
      +                ! If value is not a string, check if it is a child node
      +                call get_value(table, keys(ikey)%key, child)
      +
      +                if (.not.associated(child)) then
      +                    allocate (error)
      +                    error%message = "'"//name//"' has an invalid '"//keys(ikey)%key//"' entry."
      +                    return
      +                endif
      +            end if
      +        end do
      +
      +    end subroutine check_keys
      +
      +    !> Choose between JSON or TOML based on a file name
      +    logical function name_is_json(filename)
      +        character(*), intent(in) :: filename
      +
      +        character(*), parameter :: json_identifier = ".json"
      +
      +        name_is_json = .false.
      +
      +        if (len_trim(filename)<len(json_identifier)) return
      +
      +        name_is_json = str_ends_with(lower(filename),json_identifier)
      +
      +    end function name_is_json
      +
      +end module fpm_toml
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/update.f90.html b/sourcefile/update.f90.html new file mode 100644 index 0000000000..a10ab8bfe4 --- /dev/null +++ b/sourcefile/update.f90.html @@ -0,0 +1,279 @@ + + + + + + + + + + + + + update.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      update.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      module fpm_cmd_update
      +  use fpm_command_line, only : fpm_update_settings
      +  use fpm_dependency, only : dependency_tree_t, new_dependency_tree
      +  use fpm_error, only : error_t, fpm_stop
      +  use fpm_filesystem, only : exists, mkdir, join_path, delete_file, filewrite
      +  use fpm_manifest, only : package_config_t, get_package_data
      +  use fpm_toml, only: name_is_json
      +  implicit none
      +  private
      +  public :: cmd_update
      +
      +contains
      +
      +  !> Entry point for the update subcommand
      +  subroutine cmd_update(settings)
      +    !> Representation of the command line arguments
      +    type(fpm_update_settings), intent(in) :: settings
      +
      +    type(package_config_t) :: package
      +    type(dependency_tree_t) :: deps
      +    type(error_t), allocatable :: error
      +    integer :: ii
      +    character(len=:), allocatable :: cache
      +
      +    call get_package_data(package, "fpm.toml", error, apply_defaults=.true.)
      +    call handle_error(error)
      +
      +    if (.not. exists("build")) then
      +      call mkdir("build")
      +      call filewrite(join_path("build", ".gitignore"),["*"])
      +    end if
      +
      +    cache = join_path("build", "cache.toml")
      +    if (settings%clean) call delete_file(cache)
      +
      +    call new_dependency_tree(deps, cache=cache, verbosity=merge(2, 1, settings%verbose), &
      +    & path_to_config=settings%path_to_config)
      +
      +    call deps%add(package, error)
      +    call handle_error(error)
      +
      +    ! Force-update all dependencies if `--clean`
      +    if (settings%clean) then
      +        do ii = 1, deps%ndep
      +            deps%dep(ii)%update = .true.
      +        end do
      +    end if
      +
      +    if (settings%fetch_only) return
      +
      +    if (size(settings%name) == 0) then
      +      call deps%update(error)
      +      call handle_error(error)
      +    else
      +      do ii = 1, size(settings%name)
      +        call deps%update(trim(settings%name(ii)), error)
      +        call handle_error(error)
      +      end do
      +    end if
      +
      +    if (len_trim(settings%dump)>0) then
      +        call deps%dump(trim(settings%dump), error, json=name_is_json(trim(settings%dump)))
      +        call handle_error(error)
      +    end if
      +
      +  end subroutine cmd_update
      +
      +  !> Error handling for this command
      +  subroutine handle_error(error)
      +    !> Potential error
      +    type(error_t), intent(in), optional :: error
      +    if (present(error)) then
      +      call fpm_stop(1, '*cmd_update* error: '//error%message)
      +    end if
      +  end subroutine handle_error
      +
      +end module fpm_cmd_update
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/sourcefile/versioning.f90.html b/sourcefile/versioning.f90.html new file mode 100644 index 0000000000..b3d7228261 --- /dev/null +++ b/sourcefile/versioning.f90.html @@ -0,0 +1,644 @@ + + + + + + + + + + + + + versioning.f90 – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      versioning.f90 + Source File + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      +
      + +
      + +
      + +
      +

      Source Code

      +
      !> Implementation of versioning data for comparing packages
      +module fpm_versioning
      +    use fpm_error, only : error_t, syntax_error
      +    use fpm_strings, only: string_t
      +    use regex_module, only: regex
      +    implicit none
      +    private
      +
      +    public :: version_t, new_version
      +    public :: regex_version_from_text
      +
      +
      +    type :: version_t
      +        private
      +
      +        !> Version numbers found
      +        integer, allocatable :: num(:)
      +
      +    contains
      +
      +        generic :: operator(==) => equals
      +        procedure, private :: equals
      +
      +        generic :: operator(/=) => not_equals
      +        procedure, private :: not_equals
      +
      +        generic :: operator(>) => greater
      +        procedure, private :: greater
      +
      +        generic :: operator(<) => less
      +        procedure, private :: less
      +
      +        generic :: operator(>=) => greater_equals
      +        procedure, private :: greater_equals
      +
      +        generic :: operator(<=) => less_equals
      +        procedure, private :: less_equals
      +
      +        !> Compare a version against a version constraint (x.x.0 <= v < x.x.HUGE)
      +        generic :: operator(.match.) => match
      +        procedure, private :: match
      +
      +        !> Create a printable string from a version data type
      +        procedure :: s
      +
      +    end type version_t
      +
      +
      +    !> Arbitrary internal limit of the version parser
      +    integer, parameter :: max_limit = 3
      +
      +
      +    interface new_version
      +        module procedure :: new_version_from_string
      +        module procedure :: new_version_from_int
      +    end interface new_version
      +
      +
      +contains
      +
      +
      +    !> Create a new version from a string
      +    subroutine new_version_from_int(self, num)
      +
      +        !> Instance of the versioning data
      +        type(version_t), intent(out) :: self
      +
      +        !> Subversion numbers to define version data
      +        integer, intent(in) :: num(:)
      +
      +        self%num = num
      +
      +    end subroutine new_version_from_int
      +
      +
      +    !> Create a new version from a string
      +    subroutine new_version_from_string(self, string, error)
      +
      +        !> Instance of the versioning data
      +        type(version_t), intent(out) :: self
      +
      +        !> String describing the version information
      +        character(len=*), intent(in) :: string
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        integer :: istart, iend, stat, nn
      +        integer :: num(max_limit)
      +        logical :: is_number
      +
      +        nn = 0
      +        iend = 0
      +        istart = 0
      +        is_number = .false.
      +
      +        do while(iend < len(string))
      +            call next(string, istart, iend, is_number, error)
      +            if (allocated(error)) exit
      +            if (is_number) then
      +                if (nn >= max_limit) then
      +                    call token_error(error, string, istart, iend, &
      +                        & "Too many subversions found")
      +                    exit
      +                end if
      +                nn = nn + 1
      +                read(string(istart:iend), *, iostat=stat) num(nn)
      +                if (stat /= 0) then
      +                    call token_error(error, string, istart, iend, &
      +                        & "Failed to parse version number")
      +                    exit
      +                end if
      +            end if
      +        end do
      +        if (allocated(error)) return
      +        if (.not.is_number) then
      +            call token_error(error, string, istart, iend, &
      +                & "Expected version number, but no characters are left")
      +            return
      +        end if
      +
      +        call new_version(self, num(:nn))
      +
      +    end subroutine new_version_from_string
      +
      +
      +    !> Tokenize a version string
      +    subroutine next(string, istart, iend, is_number, error)
      +
      +        !> String describing the version information
      +        character(len=*), intent(in) :: string
      +
      +        !> Start of last token, start of next token on exit
      +        integer, intent(inout) :: istart
      +
      +        !> End of last token on entry, end of next token on exit
      +        integer, intent(inout) :: iend
      +
      +        !> Token produced is a number
      +        logical, intent(inout) :: is_number
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        integer :: ii, nn
      +        logical :: was_number
      +        character :: tok
      +
      +        was_number = is_number
      +        nn = len(string)
      +
      +        if (iend >= nn) then
      +            istart = nn
      +            iend = nn
      +            return
      +        end if
      +
      +        ii = min(iend + 1, nn)
      +        tok = string(ii:ii)
      +
      +        is_number = tok /= '.'
      +        if (is_number .eqv. was_number) then
      +            call token_error(error, string, istart, ii, &
      +                & "Unexpected token found")
      +            return
      +        end if
      +
      +        if (.not.is_number) then
      +            is_number = .false.
      +            istart = ii
      +            iend = ii
      +            return
      +        end if
      +
      +        istart = ii
      +        do ii = min(iend + 1, nn), nn
      +            tok = string(ii:ii)
      +            select case(tok)
      +            case default
      +                call token_error(error, string, istart, ii, &
      +                    & "Invalid character in version number")
      +                exit
      +            case('.')
      +                exit
      +            case('0', '1', '2', '3', '4', '5', '6', '7', '8', '9')
      +                iend = ii
      +                cycle
      +            end select
      +        end do
      +
      +    end subroutine next
      +
      +
      +    !> Create an error on an invalid token, provide some visual context as well
      +    subroutine token_error(error, string, istart, iend, message)
      +
      +        !> Error handling
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        !> String describing the version information
      +        character(len=*), intent(in) :: string
      +
      +        !> Start of last token, start of next token on exit
      +        integer, intent(in) :: istart
      +
      +        !> End of last token on entry, end of next token on exit
      +        integer, intent(in) :: iend
      +
      +        !> Error message
      +        character(len=*), intent(in) :: message
      +
      +        character(len=*), parameter :: nl = new_line('a')
      +
      +        allocate(error)
      +        error%message = message // nl // "  | " // string // nl // &
      +            & "  |" // repeat('-', istart) // repeat('^', iend - istart + 1)
      +
      +    end subroutine token_error
      +
      +
      +    pure function s(self) result(string)
      +
      +        !> Version number
      +        class(version_t), intent(in) :: self
      +
      +        !> Character representation of the version
      +        character(len=:), allocatable :: string
      +
      +        integer, parameter :: buffersize = 64
      +        character(len=buffersize) :: buffer
      +        integer :: ii
      +
      +        do ii = 1, ndigits(self)
      +            if (allocated(string)) then
      +                write(buffer, '(".", i0)') self%num(ii)
      +                string = string // trim(buffer)
      +            else
      +                write(buffer, '(i0)') self%num(ii)
      +                string = trim(buffer)
      +            end if
      +        end do
      +
      +        if (.not.allocated(string)) then
      +            string = '0'
      +        end if
      +
      +    end function s
      +
      +
      +    !> Check to version numbers for equality
      +    elemental function equals(lhs, rhs) result(is_equal)
      +
      +        !> First version number
      +        class(version_t), intent(in) :: lhs
      +
      +        !> Second version number
      +        class(version_t), intent(in) :: rhs
      +
      +        !> Version match
      +        logical :: is_equal
      +
      +        is_equal = .not.(lhs > rhs)
      +        if (is_equal) then
      +            is_equal = .not.(rhs > lhs)
      +        end if
      +
      +    end function equals
      +
      +
      +    !> Check two versions for inequality
      +    elemental function not_equals(lhs, rhs) result(not_equal)
      +
      +        !> First version number
      +        class(version_t), intent(in) :: lhs
      +
      +        !> Second version number
      +        class(version_t), intent(in) :: rhs
      +
      +        !> Version mismatch
      +        logical :: not_equal
      +
      +        not_equal = lhs > rhs
      +        if (.not.not_equal) then
      +            not_equal = rhs > lhs
      +        end if
      +
      +    end function not_equals
      +
      +
      +    !> Relative comparison of two versions
      +    elemental function greater(lhs, rhs) result(is_greater)
      +
      +        !> First version number
      +        class(version_t), intent(in) :: lhs
      +
      +        !> Second version number
      +        class(version_t), intent(in) :: rhs
      +
      +        !> First version is greater
      +        logical :: is_greater
      +
      +        integer :: ii, lhs_size, rhs_size
      +
      +        do ii = 1, min(ndigits(lhs),ndigits(rhs))
      +            if (lhs%num(ii) /= rhs%num(ii)) then
      +                is_greater = lhs%num(ii) > rhs%num(ii)
      +                return
      +            end if
      +        end do
      +
      +        is_greater = ndigits(lhs) > ndigits(rhs)
      +        if (is_greater) then
      +            do ii = ndigits(rhs) + 1, ndigits(lhs)
      +                is_greater = lhs%num(ii) > 0
      +                if (is_greater) return
      +            end do
      +        end if
      +
      +    end function greater
      +
      +
      +    !> Relative comparison of two versions
      +    elemental function less(lhs, rhs) result(is_less)
      +
      +        !> First version number
      +        class(version_t), intent(in) :: lhs
      +
      +        !> Second version number
      +        class(version_t), intent(in) :: rhs
      +
      +        !> First version is less
      +        logical :: is_less
      +
      +        is_less = rhs > lhs
      +
      +    end function less
      +
      +
      +    !> Relative comparison of two versions
      +    elemental function greater_equals(lhs, rhs) result(is_greater_equal)
      +
      +        !> First version number
      +        class(version_t), intent(in) :: lhs
      +
      +        !> Second version number
      +        class(version_t), intent(in) :: rhs
      +
      +        !> First version is greater or equal
      +        logical :: is_greater_equal
      +
      +        is_greater_equal = .not. (rhs > lhs)
      +
      +    end function greater_equals
      +
      +
      +    !> Relative comparison of two versions
      +    elemental function less_equals(lhs, rhs) result(is_less_equal)
      +
      +        !> First version number
      +        class(version_t), intent(in) :: lhs
      +
      +        !> Second version number
      +        class(version_t), intent(in) :: rhs
      +
      +        !> First version is less or equal
      +        logical :: is_less_equal
      +
      +        is_less_equal = .not. (lhs > rhs)
      +
      +    end function less_equals
      +
      +
      +    !> Try to match first version against second version
      +    elemental function match(lhs, rhs)
      +
      +        !> First version number
      +        class(version_t), intent(in) :: lhs
      +
      +        !> Second version number
      +        class(version_t), intent(in) :: rhs
      +
      +        !> Version match following semantic versioning rules
      +        logical :: match
      +
      +        type(version_t) :: tmp
      +
      +        match = .not.(rhs > lhs)
      +        if (match) then
      +            tmp%num = rhs%num
      +            tmp%num(size(tmp%num)) = tmp%num(size(tmp%num)) + 1
      +            match = tmp > lhs
      +        end if
      +
      +    end function match
      +
      +    !> Number of digits
      +    elemental integer function ndigits(self)
      +       class(version_t), intent(in) :: self
      +
      +       if (allocated(self%num)) then
      +          ndigits = size(self%num)
      +       else
      +          ndigits = 0
      +       end if
      +
      +    end function ndigits
      +
      +    ! Extract canonical version flags "1.0.0" or "1.0" as the first instance inside a text
      +    ! (whatever long) using regex
      +    type(string_t) function regex_version_from_text(text,what,error) result(ver)
      +        character(*), intent(in) :: text
      +        character(*), intent(in) :: what
      +        type(error_t), allocatable, intent(out) :: error
      +
      +        integer :: ire, length
      +
      +        if (len_trim(text)<=0) then
      +            call syntax_error(error,'cannot retrieve '//what//' version: empty input string')
      +            return
      +        end if
      +
      +        ! Extract 3-sized version "1.0.4"
      +        ire = regex(text,'\d+\.\d+\.\d+',length=length)
      +        if (ire>0 .and. length>0) then
      +            ! Parse version into the object (this should always work)
      +            ver = string_t(text(ire:ire+length-1))
      +        else
      +
      +            ! Try 2-sized version "1.0"
      +            ire = regex(text,'\d+\.\d+',length=length)
      +
      +            if (ire>0 .and. length>0) then
      +                ver = string_t(text(ire:ire+length-1))
      +            else
      +                call syntax_error(error,'cannot retrieve '//what//' version.')
      +            end if
      +
      +        end if
      +
      +    end function regex_version_from_text
      +
      +end module fpm_versioning
      +
      + +
      +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/src/fpm/manifest/build.f90 b/src/build.f90 similarity index 100% rename from src/fpm/manifest/build.f90 rename to src/build.f90 diff --git a/src/fpm/manifest/dependency.f90 b/src/dependency.f90 similarity index 100% rename from src/fpm/manifest/dependency.f90 rename to src/dependency.f90 diff --git a/src/fpm/downloader.f90 b/src/downloader.f90 similarity index 100% rename from src/fpm/downloader.f90 rename to src/downloader.f90 diff --git a/src/fpm/error.f90 b/src/error.f90 similarity index 100% rename from src/fpm/error.f90 rename to src/error.f90 diff --git a/src/fpm/manifest/example.f90 b/src/example.f90 similarity index 100% rename from src/fpm/manifest/example.f90 rename to src/example.f90 diff --git a/src/fpm/manifest/executable.f90 b/src/executable.f90 similarity index 100% rename from src/fpm/manifest/executable.f90 rename to src/executable.f90 diff --git a/src/fpm/cmd/export.f90 b/src/export.f90 similarity index 100% rename from src/fpm/cmd/export.f90 rename to src/export.f90 diff --git a/src/filesystem_utilities.c b/src/filesystem_utilities.c deleted file mode 100644 index 73f0c8aaa9..0000000000 --- a/src/filesystem_utilities.c +++ /dev/null @@ -1,31 +0,0 @@ -#include -#include - -#if defined(__APPLE__) && !defined(__aarch64__) && !defined(__ppc__) && !defined(__i386__) -DIR * opendir$INODE64( const char * dirName ); -struct dirent * readdir$INODE64( DIR * dir ); -#define opendir opendir$INODE64 -#define readdir readdir$INODE64 -#endif - -int c_is_dir(const char *path) -{ - struct stat m; - int r = stat(path, &m); - return r == 0 && S_ISDIR(m.st_mode); -} - -const char *get_d_name(struct dirent *d) -{ - return (const char *) d->d_name; -} - -DIR *c_opendir(const char *dirname) -{ - return opendir(dirname); -} - -struct dirent *c_readdir(DIR *dirp) -{ - return readdir(dirp); -} diff --git a/src/fpm/manifest/fortran.f90 b/src/fortran.f90 similarity index 100% rename from src/fpm/manifest/fortran.f90 rename to src/fortran.f90 diff --git a/src/fpm/dependency.f90 b/src/fpm/dependency.f90 deleted file mode 100644 index a12e3d44ff..0000000000 --- a/src/fpm/dependency.f90 +++ /dev/null @@ -1,1844 +0,0 @@ -!> # Dependency management -!> -!> ## Fetching dependencies and creating a dependency tree -!> -!> Dependencies on the top-level can be specified from: -!> -!> - `package%dependencies` -!> - `package%dev_dependencies` -!> - `package%executable(:)%dependencies` -!> - `package%test(:)%dependencies` -!> -!> Each dependency is fetched in some way and provides a path to its package -!> manifest. -!> The `package%dependencies` of the dependencies are resolved recursively. -!> -!> To initialize the dependency tree all dependencies are recursively fetched -!> and stored in a flat data structure to avoid retrieving a package twice. -!> The data structure used to store this information should describe the current -!> status of the dependency tree. Important information are: -!> -!> - name of the package -!> - version of the package -!> - path to the package root -!> -!> Additionally, for version controlled dependencies the following should be -!> stored along with the package: -!> -!> - the upstream url -!> - the current checked out revision -!> -!> Fetching a remote (version controlled) dependency turns it for our purpose -!> into a local path dependency which is handled by the same means. -!> -!> ## Updating dependencies -!> -!> For a given dependency tree all top-level dependencies can be updated. -!> We have two cases to consider, a remote dependency and a local dependency, -!> again, remote dependencies turn into local dependencies by fetching. -!> Therefore we will update remote dependencies by simply refetching them. -!> -!> For remote dependencies we have to refetch if the revision in the manifest -!> changes or the upstream HEAD has changed (for branches _and_ tags). -!> -!> @Note For our purpose a tag is just a fancy branch name. Tags can be delete and -!> modified afterwards, therefore they do not differ too much from branches -!> from our perspective. -!> -!> For the latter case we only know if we actually fetch from the upstream URL. -!> -!> In case of local (and fetched remote) dependencies we have to read the package -!> manifest and compare its dependencies against our dependency tree, any change -!> requires updating the respective dependencies as well. -!> -!> ## Handling dependency compatibilties -!> -!> Currenly ignored. First come, first serve. -module fpm_dependency - use, intrinsic :: iso_fortran_env, only: output_unit - use fpm_environment, only: get_os_type, OS_WINDOWS, os_is_unix - use fpm_error, only: error_t, fatal_error - use fpm_filesystem, only: exists, join_path, mkdir, canon_path, windows_path, list_files, is_dir, basename, & - os_delete_dir, get_temp_filename, parent_dir - use fpm_git, only: git_target_revision, git_target_default, git_revision, serializable_t - use fpm_manifest, only: package_config_t, dependency_config_t, get_package_data, get_package_dependencies - use fpm_manifest_dependency, only: manifest_has_changed, dependency_destroy - use fpm_manifest_preprocess, only: operator(==) - use fpm_strings, only: string_t, operator(.in.), operator(==), str - use tomlf, only: toml_table, toml_key, toml_error, toml_load, toml_stat, toml_array, len, add_array - use fpm_toml, only: toml_serialize, get_value, set_value, add_table, set_string, get_list, set_list - use fpm_versioning, only: version_t, new_version - use fpm_settings, only: fpm_global_settings, get_global_settings, official_registry_base_url - use fpm_downloader, only: downloader_t - use jonquil, only: json_object - implicit none - private - - public :: dependency_tree_t, new_dependency_tree, dependency_node_t, new_dependency_node, resize, & - & check_and_read_pkg_data, destroy_dependency_node - - !> Overloaded reallocation interface - interface resize - module procedure :: resize_dependency_node - end interface resize - - !> Dependency node in the projects dependency tree - type, extends(dependency_config_t) :: dependency_node_t - !> Actual version of this dependency - type(version_t), allocatable :: version - !> Installation prefix of this dependencies - character(len=:), allocatable :: proj_dir - !> Checked out revision of the version control system - character(len=:), allocatable :: revision - !> Dependency is handled - logical :: done = .false. - !> Dependency should be updated - logical :: update = .false. - !> Dependency was loaded from a cache - logical :: cached = .false. - !> Package dependencies of this node - type(string_t), allocatable :: package_dep(:) - contains - - !> Update dependency from project manifest. - procedure :: register - - !> Get dependency from the registry. - procedure :: get_from_registry - procedure, private :: get_from_local_registry - !> Print information on this instance - procedure :: info - - !> Serialization interface - procedure :: serializable_is_same => dependency_node_is_same - procedure :: dump_to_toml => node_dump_to_toml - procedure :: load_from_toml => node_load_from_toml - - end type dependency_node_t - - !> Respresentation of a projects dependencies - !> - !> The dependencies are stored in a simple array for now, this can be replaced - !> with a binary-search tree or a hash table in the future. - type, extends(serializable_t) :: dependency_tree_t - !> Unit for IO - integer :: unit = output_unit - !> Verbosity of printout - integer :: verbosity = 1 - !> Installation prefix for dependencies - character(len=:), allocatable :: dep_dir - !> Number of currently registered dependencies - integer :: ndep = 0 - !> Flattend list of all dependencies - type(dependency_node_t), allocatable :: dep(:) - !> Cache file - character(len=:), allocatable :: cache - !> Custom path to the global config file - character(len=:), allocatable :: path_to_config - - contains - - !> Overload procedure to add new dependencies to the tree - generic :: add => add_project, add_project_dependencies, add_dependencies, & - add_dependency, add_dependency_node - !> Main entry point to add a project - procedure, private :: add_project - !> Add a project and its dependencies to the dependency tree - procedure, private :: add_project_dependencies - !> Add a list of dependencies to the dependency tree - procedure, private :: add_dependencies - !> Add a single dependency to the dependency tree - procedure, private :: add_dependency - !> Add a single dependency node to the dependency tree - procedure, private :: add_dependency_node - !> Resolve dependencies - generic :: resolve => resolve_dependencies, resolve_dependency - !> Resolve dependencies - procedure, private :: resolve_dependencies - !> Resolve dependency - procedure, private :: resolve_dependency - !> True if entity can be found - generic :: has => has_dependency - !> True if dependency is part of the tree - procedure, private :: has_dependency - !> Find a dependency in the tree - generic :: find => find_name - !> Find a dependency by its name - procedure, private :: find_name - !> Establish local link order for a node's package dependencies - procedure :: local_link_order - !> Depedendncy resolution finished - procedure :: finished - !> Reading of dependency tree - generic :: load_cache => load_cache_from_file, load_cache_from_unit, load_cache_from_toml - !> Read dependency tree from file - procedure, private :: load_cache_from_file - !> Read dependency tree from formatted unit - procedure, private :: load_cache_from_unit - !> Read dependency tree from TOML data structure - procedure, private :: load_cache_from_toml - !> Writing of dependency tree - generic :: dump_cache => dump_cache_to_file, dump_cache_to_unit, dump_cache_to_toml - !> Write dependency tree to file - procedure, private :: dump_cache_to_file - !> Write dependency tree to formatted unit - procedure, private :: dump_cache_to_unit - !> Write dependency tree to TOML data structure - procedure, private :: dump_cache_to_toml - !> Update dependency tree - generic :: update => update_dependency, update_tree - !> Update a list of dependencies - procedure, private :: update_dependency - !> Update all dependencies in the tree - procedure, private :: update_tree - - !> Serialization interface - procedure :: serializable_is_same => dependency_tree_is_same - procedure :: dump_to_toml => tree_dump_to_toml - procedure :: load_from_toml => tree_load_from_toml - - end type dependency_tree_t - - !> Common output format for writing to the command line - character(len=*), parameter :: out_fmt = '("#", *(1x, g0))' - -contains - - !> Create a new dependency tree - subroutine new_dependency_tree(self, verbosity, cache, path_to_config) - !> Instance of the dependency tree - type(dependency_tree_t), intent(out) :: self - !> Verbosity of printout - integer, intent(in), optional :: verbosity - !> Name of the cache file - character(len=*), intent(in), optional :: cache - !> Path to the global config file. - character(len=*), intent(in), optional :: path_to_config - - call resize(self%dep) - self%dep_dir = join_path("build", "dependencies") - - if (present(verbosity)) self%verbosity = verbosity - - if (present(cache)) self%cache = cache - - if (present(path_to_config)) self%path_to_config = path_to_config - - end subroutine new_dependency_tree - - !> Create a new dependency node from a configuration - subroutine new_dependency_node(self, dependency, version, proj_dir, update) - !> Instance of the dependency node - type(dependency_node_t), intent(out) :: self - !> Dependency configuration data - type(dependency_config_t), intent(in) :: dependency - !> Version of the dependency - type(version_t), intent(in), optional :: version - !> Installation prefix of the dependency - character(len=*), intent(in), optional :: proj_dir - !> Dependency should be updated - logical, intent(in), optional :: update - - self%dependency_config_t = dependency - - if (present(version)) then - self%version = version - end if - - if (present(proj_dir)) then - self%proj_dir = proj_dir - end if - - if (present(update)) then - self%update = update - end if - - end subroutine new_dependency_node - - !> Write information on instance - subroutine info(self, unit, verbosity) - - !> Instance of the dependency configuration - class(dependency_node_t), intent(in) :: self - - !> Unit for IO - integer, intent(in) :: unit - - !> Verbosity of the printout - integer, intent(in), optional :: verbosity - - integer :: pr, i - character(len=*), parameter :: fmt = '("#", 1x, a, t30, a)' - - if (present(verbosity)) then - pr = verbosity - else - pr = 1 - end if - - !> Call base object info - call self%dependency_config_t%info(unit, pr) - - if (allocated(self%version)) then - write (unit, fmt) "- version", self%version%s() - end if - - if (allocated(self%proj_dir)) then - write (unit, fmt) "- dir", self%proj_dir - end if - - if (allocated(self%revision)) then - write (unit, fmt) "- revision", self%revision - end if - - write (unit, fmt) "- done", merge('YES', 'NO ', self%done) - write (unit, fmt) "- update", merge('YES', 'NO ', self%update) - - if (allocated(self%package_dep)) then - write(unit, fmt) " - package_dep " - do i = 1, size(self%package_dep) - write(unit, fmt) " - " // self%package_dep(i)%s - end do - end if - - end subroutine info - - !> Add project dependencies, each depth level after each other. - !> - !> We implement this algorithm in an interative rather than a recursive fashion - !> as a choice of design. - subroutine add_project(self, package, error) - !> Instance of the dependency tree - class(dependency_tree_t), intent(inout) :: self - !> Project configuration to add - type(package_config_t), intent(in) :: package - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(dependency_config_t) :: dependency - type(dependency_tree_t) :: cached - character(len=*), parameter :: root = '.' - integer :: id - - if (.not. exists(self%dep_dir)) then - call mkdir(self%dep_dir) - end if - - ! Create this project as the first dependency node (depth 0) - dependency%name = package%name - dependency%path = root - call self%add(dependency, error) - if (allocated(error)) return - - ! Resolve the root project - call self%resolve(root, error) - if (allocated(error)) return - - ! Add the root project dependencies (depth 1) - call self%add(package, root, .true., error) - if (allocated(error)) return - - ! After resolving all dependencies, check if we have cached ones to avoid updates - if (allocated(self%cache)) then - call new_dependency_tree(cached, verbosity=self%verbosity,cache=self%cache) - call cached%load_cache(self%cache, error) - if (allocated(error)) return - - ! Skip root node - do id = 2, cached%ndep - cached%dep(id)%cached = .true. - call self%add(cached%dep(id), error) - if (allocated(error)) return - end do - end if - - ! Now decent into the dependency tree, level for level - do while (.not. self%finished()) - call self%resolve(root, error) - if (allocated(error)) exit - end do - if (allocated(error)) return - - ! Resolve internal dependency graph and remove temporary package storage - call resolve_dependency_graph(self, package, error) - if (allocated(error)) return - - if (allocated(self%cache)) then - call self%dump_cache(self%cache, error) - if (allocated(error)) return - end if - - end subroutine add_project - - subroutine resolve_dependency_graph(self, main, error) - !> Instance of the dependency tree - class(dependency_tree_t), intent(inout) :: self - !> Main project configuration - type(package_config_t), intent(in) :: main - !> Error handling - type(error_t), allocatable, intent(out) :: error - - integer :: i,nit - integer, parameter :: MAXIT = 50 - logical, allocatable :: finished(:) - type(string_t), allocatable :: old_package_dep(:) - - if (self%ndep<1) then - call fatal_error(error, "Trying to compute the dependency graph of an empty tree") - return - end if - - nit = 0 - allocate(finished(self%ndep),source=.false.) - do while (.not.all(finished) .and. nit=MAXIT) call fatal_error(error, "Infinite loop detected computing the dependency graph") - - contains - - pure logical function all_alloc(this,that) - type(string_t), intent(in), allocatable :: this(:),that(:) - all_alloc = .false. - if (allocated(this).neqv.allocated(that)) return - if (.not.allocated(this)) then - all_alloc = .true. - else - if (size(this)/=size(that)) return - if (.not.(this==that)) return - all_alloc = .true. - end if - end function all_alloc - - end subroutine resolve_dependency_graph - - !> Add a project and its dependencies to the dependency tree - recursive subroutine add_project_dependencies(self, package, root, main, error) - !> Instance of the dependency tree - class(dependency_tree_t), intent(inout) :: self - !> Project configuration to add - type(package_config_t), intent(in) :: package - !> Current project root directory - character(len=*), intent(in) :: root - !> Is the main project - logical, intent(in) :: main - !> Error handling - type(error_t), allocatable, intent(out) :: error - - integer :: ii - - if (allocated(package%dependency)) then - call self%add(package%dependency, error) - if (allocated(error)) return - end if - - if (main) then - if (allocated(package%dev_dependency)) then - call self%add(package%dev_dependency, error) - if (allocated(error)) return - end if - - if (allocated(package%executable)) then - do ii = 1, size(package%executable) - if (allocated(package%executable(ii)%dependency)) then - call self%add(package%executable(ii)%dependency, error) - if (allocated(error)) exit - end if - end do - if (allocated(error)) return - end if - - if (allocated(package%example)) then - do ii = 1, size(package%example) - if (allocated(package%example(ii)%dependency)) then - call self%add(package%example(ii)%dependency, error) - if (allocated(error)) exit - end if - end do - if (allocated(error)) return - end if - - if (allocated(package%test)) then - do ii = 1, size(package%test) - if (allocated(package%test(ii)%dependency)) then - call self%add(package%test(ii)%dependency, error) - if (allocated(error)) exit - end if - end do - if (allocated(error)) return - end if - end if - - !> Ensure allocation fits - call resize(self%dep,self%ndep) - - end subroutine add_project_dependencies - - !> Add a list of dependencies to the dependency tree - subroutine add_dependencies(self, dependency, error) - !> Instance of the dependency tree - class(dependency_tree_t), intent(inout) :: self - !> Dependency configuration to add - type(dependency_config_t), intent(in) :: dependency(:) - !> Error handling - type(error_t), allocatable, intent(out) :: error - - integer :: ii, ndep - - ndep = size(self%dep) - if (ndep < size(dependency) + self%ndep) then - call resize(self%dep, ndep + ndep/2 + size(dependency)) - end if - - do ii = 1, size(dependency) - call self%add(dependency(ii), error) - if (allocated(error)) exit - end do - if (allocated(error)) return - - !> Ensure allocation fits ndep - call resize(self%dep,self%ndep) - - end subroutine add_dependencies - - !> Add a single dependency node to the dependency tree - !> Dependency nodes contain additional information (version, git, revision) - subroutine add_dependency_node(self, dependency, error) - !> Instance of the dependency tree - class(dependency_tree_t), intent(inout) :: self - !> Dependency configuration to add - type(dependency_node_t), intent(in) :: dependency - !> Error handling - type(error_t), allocatable, intent(out) :: error - - integer :: id - - if (self%has_dependency(dependency)) then - ! A dependency with this same name is already in the dependency tree. - ! Check if it needs to be updated - id = self%find(dependency%name) - - ! If this dependency was in the cache, and we're now requesting a different version - ! in the manifest, ensure it is marked for update. Otherwise, if we're just querying - ! the same dependency from a lower branch of the dependency tree, the existing one from - ! the manifest has priority - if (dependency%cached) then - if (dependency_has_changed(dependency, self%dep(id), self%verbosity, self%unit)) then - if (self%verbosity > 0) write (self%unit, out_fmt) "Dependency change detected:", dependency%name - self%dep(id)%update = .true. - else - ! Store the cached one - self%dep(id) = dependency - self%dep(id)%update = .false. - end if - end if - else - - !> Safety: reallocate if necessary - if (size(self%dep)==self%ndep) call resize(self%dep,self%ndep+1) - - ! New dependency: add from scratch - self%ndep = self%ndep + 1 - self%dep(self%ndep) = dependency - self%dep(self%ndep)%update = .false. - end if - - end subroutine add_dependency_node - - !> Add a single dependency to the dependency tree - subroutine add_dependency(self, dependency, error) - !> Instance of the dependency tree - class(dependency_tree_t), intent(inout) :: self - !> Dependency configuration to add - type(dependency_config_t), intent(in) :: dependency - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(dependency_node_t) :: node - - call new_dependency_node(node, dependency) - call add_dependency_node(self, node, error) - - end subroutine add_dependency - - !> Update dependency tree - subroutine update_dependency(self, name, error) - !> Instance of the dependency tree - class(dependency_tree_t), intent(inout) :: self - !> Name of the dependency to update - character(len=*), intent(in) :: name - !> Error handling - type(error_t), allocatable, intent(out) :: error - - integer :: id - character(len=:), allocatable :: proj_dir, root - - id = self%find(name) - root = "." - - if (id <= 0) then - call fatal_error(error, "Cannot update dependency '"//name//"'") - return - end if - - associate (dep => self%dep(id)) - if (allocated(dep%git) .and. dep%update) then - if (self%verbosity > 0) write (self%unit, out_fmt) "Update:", dep%name - proj_dir = join_path(self%dep_dir, dep%name) - call dep%git%checkout(proj_dir, error) - if (allocated(error)) return - - ! Unset dependency and remove updatable attribute - dep%done = .false. - dep%update = .false. - - ! Now decent into the dependency tree, level for level - do while (.not. self%finished()) - call self%resolve(root, error) - if (allocated(error)) exit - end do - if (allocated(error)) return - end if - end associate - - end subroutine update_dependency - - !> Update whole dependency tree - subroutine update_tree(self, error) - !> Instance of the dependency tree - class(dependency_tree_t), intent(inout) :: self - !> Error handling - type(error_t), allocatable, intent(out) :: error - - integer :: i - - ! Update dependencies where needed - do i = 1, self%ndep - call self%update(self%dep(i)%name, error) - if (allocated(error)) return - end do - - end subroutine update_tree - - !> Resolve all dependencies in the tree - subroutine resolve_dependencies(self, root, error) - !> Instance of the dependency tree - class(dependency_tree_t), intent(inout) :: self - !> Current installation prefix - character(len=*), intent(in) :: root - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(fpm_global_settings) :: global_settings - character(:), allocatable :: parent_directory - integer :: ii - - ! Register path to global config file if it was entered via the command line. - if (allocated(self%path_to_config)) then - if (len_trim(self%path_to_config) > 0) then - parent_directory = parent_dir(self%path_to_config) - - if (len_trim(parent_directory) == 0) then - global_settings%path_to_config_folder = "." - else - global_settings%path_to_config_folder = parent_directory - end if - - global_settings%config_file_name = basename(self%path_to_config) - end if - end if - - call get_global_settings(global_settings, error) - if (allocated(error)) return - - do ii = 1, self%ndep - call self%resolve(self%dep(ii), global_settings, root, error) - if (allocated(error)) exit - end do - - if (allocated(error)) return - - end subroutine resolve_dependencies - - !> Resolve a single dependency node - subroutine resolve_dependency(self, dependency, global_settings, root, error) - !> Instance of the dependency tree - class(dependency_tree_t), intent(inout) :: self - !> Dependency configuration to add - type(dependency_node_t), intent(inout) :: dependency - !> Global configuration settings. - type(fpm_global_settings), intent(in) :: global_settings - !> Current installation prefix - character(len=*), intent(in) :: root - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(package_config_t) :: package - character(len=:), allocatable :: manifest, proj_dir, revision - logical :: fetch - - if (dependency%done) return - - fetch = .false. - if (allocated(dependency%proj_dir)) then - proj_dir = dependency%proj_dir - else if (allocated(dependency%path)) then - proj_dir = join_path(root, dependency%path) - else if (allocated(dependency%git)) then - proj_dir = join_path(self%dep_dir, dependency%name) - fetch = .not. exists(proj_dir) - if (fetch) then - call dependency%git%checkout(proj_dir, error) - if (allocated(error)) return - end if - else - call dependency%get_from_registry(proj_dir, global_settings, error) - if (allocated(error)) return - end if - - if (allocated(dependency%git)) then - call git_revision(proj_dir, revision, error) - if (allocated(error)) return - end if - - manifest = join_path(proj_dir, "fpm.toml") - call get_package_data(package, manifest, error) - if (allocated(error)) return - - call dependency%register(package, proj_dir, fetch, revision, error) - if (allocated(error)) return - - - if (self%verbosity > 1) then - write (self%unit, out_fmt) & - "Dep:", dependency%name, "version", dependency%version%s(), & - "at", dependency%proj_dir - end if - - call self%add(package, proj_dir, .false., error) - if (allocated(error)) return - - end subroutine resolve_dependency - - !> Get a dependency from the registry. Whether the dependency is fetched - !> from a local, a custom remote or the official registry is determined - !> by the global configuration settings. - subroutine get_from_registry(self, target_dir, global_settings, error, downloader_) - - !> Instance of the dependency configuration. - class(dependency_node_t), intent(in) :: self - - !> The target directory of the dependency. - character(:), allocatable, intent(out) :: target_dir - - !> Global configuration settings. - type(fpm_global_settings), intent(in) :: global_settings - - !> Error handling. - type(error_t), allocatable, intent(out) :: error - - !> Downloader instance. - class(downloader_t), optional, intent(in) :: downloader_ - - character(:), allocatable :: cache_path, target_url, tmp_file - type(version_t) :: version - integer :: stat, unit - type(json_object) :: json - class(downloader_t), allocatable :: downloader - - if (present(downloader_)) then - downloader = downloader_ - else - allocate (downloader) - end if - - ! Use local registry if it was specified in the global config file. - if (allocated(global_settings%registry_settings%path)) then - call self%get_from_local_registry(target_dir, global_settings%registry_settings%path, error); return - end if - - ! Include namespace and package name in the cache path. - cache_path = join_path(global_settings%registry_settings%cache_path, self%namespace, self%name) - - ! Check cache before downloading from the remote registry if a specific version was requested. When no specific - ! version was requested, do network request first to check which is the newest version. - if (allocated(self%requested_version)) then - if (exists(join_path(cache_path, self%requested_version%s(), 'fpm.toml'))) then - print *, "Using cached version of '", join_path(self%namespace, self%name, self%requested_version%s()), "'." - target_dir = join_path(cache_path, self%requested_version%s()); return - end if - end if - - tmp_file = get_temp_filename() - open (newunit=unit, file=tmp_file, action='readwrite', iostat=stat) - if (stat /= 0) then - call fatal_error(error, "Error creating temporary file for downloading package '"//self%name//"'."); return - end if - - ! Include namespace and package name in the target url and download package data. - target_url = global_settings%registry_settings%url//'/packages/'//self%namespace//'/'//self%name - call downloader%get_pkg_data(target_url, self%requested_version, tmp_file, json, error) - close (unit, status='delete') - if (allocated(error)) return - - ! Verify package data and read relevant information. - call check_and_read_pkg_data(json, self, target_url, version, error) - if (allocated(error)) return - - ! Open new tmp file for downloading the actual package. - open (newunit=unit, file=tmp_file, action='readwrite', iostat=stat) - if (stat /= 0) then - call fatal_error(error, "Error creating temporary file for downloading package '"//self%name//"'."); return - end if - - ! Include version number in the cache path. If no cached version exists, download it. - cache_path = join_path(cache_path, version%s()) - if (.not. exists(join_path(cache_path, 'fpm.toml'))) then - if (is_dir(cache_path)) call os_delete_dir(os_is_unix(), cache_path) - call mkdir(cache_path) - - call downloader%get_file(target_url, tmp_file, error) - if (allocated(error)) then - close (unit, status='delete'); return - end if - - ! Unpack the downloaded package to the final location. - call downloader%unpack(tmp_file, cache_path, error) - close (unit, status='delete') - if (allocated(error)) return - end if - - target_dir = cache_path - - end subroutine get_from_registry - - subroutine check_and_read_pkg_data(json, node, download_url, version, error) - type(json_object), intent(inout) :: json - class(dependency_node_t), intent(in) :: node - character(:), allocatable, intent(out) :: download_url - type(version_t), intent(out) :: version - type(error_t), allocatable, intent(out) :: error - - integer :: code, stat - type(json_object), pointer :: p, q - character(:), allocatable :: version_key, version_str, error_message, namespace, name - - namespace = "" - name = "UNNAMED_NODE" - if (allocated(node%namespace)) namespace = node%namespace - if (allocated(node%name)) name = node%name - - if (.not. json%has_key('code')) then - call fatal_error(error, "Failed to download '"//join_path(namespace, name)//"': No status code."); return - end if - - call get_value(json, 'code', code, stat=stat) - if (stat /= 0) then - call fatal_error(error, "Failed to download '"//join_path(namespace, name)//"': "// & - & "Failed to read status code."); return - end if - - if (code /= 200) then - if (.not. json%has_key('message')) then - call fatal_error(error, "Failed to download '"//join_path(namespace, name)//"': No error message."); return - end if - - call get_value(json, 'message', error_message, stat=stat) - if (stat /= 0) then - call fatal_error(error, "Failed to download '"//join_path(namespace, name)//"': "// & - & "Failed to read error message."); return - end if - - call fatal_error(error, "Failed to download '"//join_path(namespace, name)//"'. Status code: '"// & - & str(code)//"'. Error message: '"//error_message//"'."); return - end if - - if (.not. json%has_key('data')) then - call fatal_error(error, "Failed to download '"//join_path(namespace, name)//"': No data."); return - end if - - call get_value(json, 'data', p, stat=stat) - if (stat /= 0) then - call fatal_error(error, "Failed to read package data for '"//join_path(namespace, name)//"'."); return - end if - - if (allocated(node%requested_version)) then - version_key = 'version_data' - else - version_key = 'latest_version_data' - end if - - if (.not. p%has_key(version_key)) then - call fatal_error(error, "Failed to download '"//join_path(namespace, name)//"': No version data."); return - end if - - call get_value(p, version_key, q, stat=stat) - if (stat /= 0) then - call fatal_error(error, "Failed to retrieve version data for '"//join_path(namespace, name)//"'."); return - end if - - if (.not. q%has_key('download_url')) then - call fatal_error(error, "Failed to download '"//join_path(namespace, name)//"': No download url."); return - end if - - call get_value(q, 'download_url', download_url, stat=stat) - if (stat /= 0) then - call fatal_error(error, "Failed to read download url for '"//join_path(namespace, name)//"'."); return - end if - - download_url = official_registry_base_url//download_url - - if (.not. q%has_key('version')) then - call fatal_error(error, "Failed to download '"//join_path(namespace, name)//"': No version found."); return - end if - - call get_value(q, 'version', version_str, stat=stat) - if (stat /= 0) then - call fatal_error(error, "Failed to read version data for '"//join_path(namespace, name)//"'."); return - end if - - call new_version(version, version_str, error) - if (allocated(error)) then - call fatal_error(error, "'"//version_str//"' is not a valid version for '"// & - & join_path(namespace, name)//"'."); return - end if - end subroutine - - !> Get the dependency from a local registry. - subroutine get_from_local_registry(self, target_dir, registry_path, error) - - !> Instance of the dependency configuration. - class(dependency_node_t), intent(in) :: self - - !> The target directory to download the dependency to. - character(:), allocatable, intent(out) :: target_dir - - !> The path to the local registry. - character(*), intent(in) :: registry_path - - !> Error handling. - type(error_t), allocatable, intent(out) :: error - - character(:), allocatable :: path_to_name - type(string_t), allocatable :: files(:) - type(version_t), allocatable :: versions(:) - type(version_t) :: version - integer :: i - - path_to_name = join_path(registry_path, self%namespace, self%name) - - if (.not. exists(path_to_name)) then - call fatal_error(error, "Dependency resolution of '"//self%name// & - & "': Directory '"//path_to_name//"' doesn't exist."); return - end if - - call list_files(path_to_name, files) - if (size(files) == 0) then - call fatal_error(error, "No versions of '"//self%name//"' found in '"//path_to_name//"'."); return - end if - - ! Version requested, find it in the cache. - if (allocated(self%requested_version)) then - do i = 1, size(files) - ! Identify directory that matches the version number. - if (files(i)%s == join_path(path_to_name, self%requested_version%s()) .and. is_dir(files(i)%s)) then - if (.not. exists(join_path(files(i)%s, 'fpm.toml'))) then - call fatal_error(error, "'"//files(i)%s//"' is missing an 'fpm.toml' file."); return - end if - target_dir = files(i)%s; return - end if - end do - call fatal_error(error, "Version '"//self%requested_version%s()//"' not found in '"//path_to_name//"'") - return - end if - - ! No specific version requested, therefore collect available versions. - allocate (versions(0)) - do i = 1, size(files) - if (is_dir(files(i)%s)) then - call new_version(version, basename(files(i)%s), error) - if (allocated(error)) return - versions = [versions, version] - end if - end do - - if (size(versions) == 0) then - call fatal_error(error, "No versions found in '"//path_to_name//"'"); return - end if - - ! Find the latest version. - version = versions(1) - do i = 1, size(versions) - if (versions(i) > version) version = versions(i) - end do - - path_to_name = join_path(path_to_name, version%s()) - - if (.not. exists(join_path(path_to_name, 'fpm.toml'))) then - call fatal_error(error, "'"//path_to_name//"' is missing an 'fpm.toml' file."); return - end if - - target_dir = path_to_name - end subroutine get_from_local_registry - - !> True if dependency is part of the tree - pure logical function has_dependency(self, dependency) - !> Instance of the dependency tree - class(dependency_tree_t), intent(in) :: self - !> Dependency configuration to check - class(dependency_node_t), intent(in) :: dependency - - has_dependency = self%find(dependency%name) /= 0 - - end function has_dependency - - !> Find a dependency in the dependency tree - pure function find_name(self, name) result(pos) - !> Instance of the dependency tree - class(dependency_tree_t), intent(in) :: self - !> Dependency configuration to add - character(len=*), intent(in) :: name - !> Index of the dependency - integer :: pos - - integer :: ii - - pos = 0 - do ii = 1, self%ndep - if (name == self%dep(ii)%name) then - pos = ii - exit - end if - end do - - end function find_name - - !> Check if we are done with the dependency resolution - pure function finished(self) - !> Instance of the dependency tree - class(dependency_tree_t), intent(in) :: self - !> All dependencies are updated - logical :: finished - - finished = all(self%dep(:self%ndep)%done) - - end function finished - - !> Update dependency from project manifest - subroutine register(node, package, root, fetch, revision, error) - !> Instance of the dependency node - class(dependency_node_t), intent(inout) :: node - !> Package configuration data - type(package_config_t), intent(in) :: package - - !> Project has been fetched - logical, intent(in) :: fetch - !> Root directory of the project - character(len=*), intent(in) :: root - !> Git revision of the project - character(len=*), intent(in), optional :: revision - !> Error handling - type(error_t), allocatable, intent(out) :: error - - logical :: update - - update = .false. - if (node%name /= package%name) then - call fatal_error(error, "Dependency name '"//package%name// & - & "' found, but expected '"//node%name//"' instead") - return - end if - - node%version = package%version - node%proj_dir = root - - if (allocated(node%git) .and. present(revision)) then - node%revision = revision - if (.not. fetch) then - ! Change in revision ID was checked already. Only update if ALL git information is missing - update = .not. allocated(node%git%url) - end if - end if - - if (update) node%update = update - node%done = .true. - - end subroutine register - - !> Capture the list of "required" packages while the manifest is loaded. - !> This subroutine should be called during the "resolve" phase, i.e. when the whole - !> dependency tree has been built already - subroutine get_required_packages(tree, node_ID, error) - !> Instance of the dependency tree - class(dependency_tree_t), intent(inout) :: tree - !> Instance of the dependency node - integer, intent(in) :: node_ID - !> Error handling - type(error_t), allocatable, intent(out) :: error - - integer :: nreq,k,id - type(dependency_config_t), allocatable :: dependency(:) - type(package_config_t) :: manifest - logical :: required(tree%ndep),main - - associate(node => tree%dep(node_ID)) - - ! Is the main project - main = node_ID==1 - - ! Get manifest - call get_package_data(manifest, join_path(node%proj_dir,"fpm.toml"), error) - if (allocated(error)) return - - call get_package_dependencies(manifest, main, dependency) - nreq = size(dependency) - - ! Translate names -> indices - required = .false. - - do k = 1, nreq - - id = tree%find(dependency(k)%name) - if (id<=0) then - ! Shouldn't happen because tree already contains every dep - call fatal_error(error, "Internal error: "//trim(node%name)// & - & " cannot find resolved dependency "//trim(dependency(k)%name)//" in tree") - return - end if - - ! Recurse dependencies - call recurse_deps(tree, id, required) - - end do - - ! Recursed list - nreq = count(required) - if (allocated(node%package_dep)) deallocate(node%package_dep) - allocate(node%package_dep(nreq)) - k = 0 - do id=1,tree%ndep - if (.not.required(id)) cycle - k = k+1 - node%package_dep(k) = string_t(tree%dep(id)%name) - end do - - endassociate - - contains - - recursive subroutine recurse_deps(tree, id, required) - class(dependency_tree_t), intent(in) :: tree - integer, intent(in) :: id - logical, intent(inout) :: required(:) - - integer :: j,dep_id - - if (required(id)) return - - required(id) = .true. - if (allocated(tree%dep(id)%package_dep)) then - do j = 1, size(tree%dep(id)%package_dep) - dep_id = tree%find(tree%dep(id)%package_dep(j)%s) - call recurse_deps(tree, dep_id, required) - end do - end if - end subroutine recurse_deps - - end subroutine get_required_packages - - !> Build a correct topological link order for a given dependency node. - !> - !> This routine returns the list of dependencies required to build `root_id`, - !> sorted such that each dependency appears *before* any node that depends on it. - !> This is suitable for correct linker ordering: `-lA -lB` means B can use symbols from A. - !> - !> The returned list includes both the transitive dependencies and the node itself. - !> Example: if node 3 requires [5, 7, 9, 2] and 9 also requires 2, - !> then the result will ensure that 2 appears before 9, etc. - subroutine local_link_order(tree, root_id, order, error) - !> The full dependency graph - class(dependency_tree_t), intent(in) :: tree - !> Index of the node for which to compute link order (e.g., the target being linked) - integer, intent(in) :: root_id - !> Ordered list of dependency indices (subset of tree%dep(:)) in link-safe order - integer, allocatable, intent(out) :: order(:) - !> Optional fatal error if a cycle is detected (not expected) - type(error_t), allocatable, intent(out) :: error - - !> Track which nodes have been visited - logical, allocatable :: visited(:) - !> Work stack holding post-order DFS traversal - integer, allocatable :: stack(:) - !> Total number of nodes and current stack position - integer :: n, top - - n = tree%ndep - allocate(visited(n), source=.false.) - allocate(stack(n), source=0) - top = 0 - - !> Depth-First Search from root node - call dfs(root_id,visited,stack,top,error) - if (allocated(error)) return - - !> The final link order is the reverse of the DFS post-order - allocate(order(top)) - if (top>0) order(:) = stack(:top) - - contains - - !> Recursive depth-first search, post-order - recursive subroutine dfs(i,visited,stack,top,error) - integer, intent(in) :: i - logical, intent(inout) :: visited(:) - integer, intent(inout) :: stack(:),top - type(error_t), allocatable, intent(out) :: error - integer :: k, id - - if (.not.(i>0 .and. i<=tree%ndep)) then - call fatal_error(error,'package graph failed: invalid dependency ID') - return - end if - if (visited(i)) return - - visited(i) = .true. - - ! Visit all required dependencies before this node - if (allocated(tree%dep(i)%package_dep)) then - do k = 1, size(tree%dep(i)%package_dep) - id = tree%find(tree%dep(i)%package_dep(k)%s) - - if (.not.(id>0 .and. id<=tree%ndep)) then - call fatal_error(error,'package graph failed: cannot find '//tree%dep(i)%package_dep(k)%s) - return - end if - - call dfs(id, visited, stack, top, error) - if (allocated(error)) return - end do - end if - - ! Now that all dependencies are handled, record this node - top = top + 1 - stack(top) = i - end subroutine dfs - - end subroutine local_link_order - - !> Read dependency tree from file - subroutine load_cache_from_file(self, file, error) - !> Instance of the dependency tree - class(dependency_tree_t), intent(inout) :: self - !> File name - character(len=*), intent(in) :: file - !> Error handling - type(error_t), allocatable, intent(out) :: error - - integer :: unit - logical :: exist - - inquire (file=file, exist=exist) - if (.not. exist) return - - open (file=file, newunit=unit) - call self%load_cache(unit, error) - close (unit) - end subroutine load_cache_from_file - - !> Read dependency tree from file - subroutine load_cache_from_unit(self, unit, error) - !> Instance of the dependency tree - class(dependency_tree_t), intent(inout) :: self - !> File name - integer, intent(in) :: unit - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_error), allocatable :: parse_error - type(toml_table), allocatable :: table - - call toml_load(table, unit, error=parse_error) - - if (allocated(parse_error)) then - allocate (error) - call move_alloc(parse_error%message, error%message) - return - end if - - call self%load_cache(table, error) - if (allocated(error)) return - - end subroutine load_cache_from_unit - - !> Read dependency tree from TOML data structure - subroutine load_cache_from_toml(self, table, error) - !> Instance of the dependency tree - class(dependency_tree_t), intent(inout) :: self - !> Data structure - type(toml_table), intent(inout) :: table - !> Error handling - type(error_t), allocatable, intent(out) :: error - - integer :: ndep, ii - logical :: is_unix - character(len=:), allocatable :: version, url, obj, rev, proj_dir - type(toml_key), allocatable :: list(:) - type(toml_table), pointer :: ptr - - call table%get_keys(list) - - ndep = size(self%dep) - if (ndep < size(list) + self%ndep) then - call resize(self%dep, ndep + ndep/2 + size(list)) - end if - - is_unix = get_os_type() /= OS_WINDOWS - - do ii = 1, size(list) - call get_value(table, list(ii)%key, ptr) - call get_value(ptr, "version", version) - call get_value(ptr, "proj-dir", proj_dir) - call get_value(ptr, "git", url) - call get_value(ptr, "obj", obj) - call get_value(ptr, "rev", rev) - if (.not. allocated(proj_dir)) cycle - self%ndep = self%ndep + 1 - associate (dep => self%dep(self%ndep)) - dep%name = list(ii)%key - if (is_unix) then - dep%proj_dir = proj_dir - else - dep%proj_dir = windows_path(proj_dir) - end if - dep%done = .false. - if (allocated(version)) then - if (.not. allocated(dep%version)) allocate (dep%version) - call new_version(dep%version, version, error) - if (allocated(error)) exit - end if - if (allocated(url)) then - if (allocated(obj)) then - dep%git = git_target_revision(url, obj) - else - dep%git = git_target_default(url) - end if - if (allocated(rev)) then - dep%revision = rev - end if - else - dep%path = proj_dir - end if - end associate - end do - if (allocated(error)) return - - self%ndep = size(list) - end subroutine load_cache_from_toml - - !> Write dependency tree to file - subroutine dump_cache_to_file(self, file, error) - !> Instance of the dependency tree - class(dependency_tree_t), intent(inout) :: self - !> File name - character(len=*), intent(in) :: file - !> Error handling - type(error_t), allocatable, intent(out) :: error - - integer :: unit - - open (file=file, newunit=unit) - call self%dump_cache(unit, error) - close (unit) - if (allocated(error)) return - - end subroutine dump_cache_to_file - - !> Write dependency tree to file - subroutine dump_cache_to_unit(self, unit, error) - !> Instance of the dependency tree - class(dependency_tree_t), intent(inout) :: self - !> Formatted unit - integer, intent(in) :: unit - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - - table = toml_table() - call self%dump_cache(table, error) - - write (unit, '(a)') toml_serialize(table) - - end subroutine dump_cache_to_unit - - !> Write dependency tree to TOML datastructure - subroutine dump_cache_to_toml(self, table, error) - !> Instance of the dependency tree - class(dependency_tree_t), intent(inout) :: self - !> Data structure - type(toml_table), intent(inout) :: table - !> Error handling - type(error_t), allocatable, intent(out) :: error - - integer :: ii - type(toml_table), pointer :: ptr - character(len=:), allocatable :: proj_dir - - do ii = 1, self%ndep - associate (dep => self%dep(ii)) - call add_table(table, dep%name, ptr) - if (.not. associated(ptr)) then - call fatal_error(error, "Cannot create entry for "//dep%name) - exit - end if - if (allocated(dep%version)) then - call set_value(ptr, "version", dep%version%s()) - end if - proj_dir = canon_path(dep%proj_dir) - call set_value(ptr, "proj-dir", proj_dir) - if (allocated(dep%git)) then - call set_value(ptr, "git", dep%git%url) - if (allocated(dep%git%object)) then - call set_value(ptr, "obj", dep%git%object) - end if - if (allocated(dep%revision)) then - call set_value(ptr, "rev", dep%revision) - end if - end if - end associate - end do - if (allocated(error)) return - - end subroutine dump_cache_to_toml - - !> Reallocate a list of dependencies - pure subroutine resize_dependency_node(var, n) - !> Instance of the array to be resized - type(dependency_node_t), allocatable, intent(inout) :: var(:) - !> Dimension of the final array size - integer, intent(in), optional :: n - - type(dependency_node_t), allocatable :: tmp(:) - integer :: this_size, new_size - integer, parameter :: initial_size = 16 - - if (allocated(var)) then - this_size = size(var, 1) - call move_alloc(var, tmp) - else - this_size = initial_size - end if - - if (present(n)) then - new_size = n - else - new_size = this_size + this_size/2 + 1 - end if - - allocate (var(new_size)) - - if (allocated(tmp)) then - this_size = min(size(tmp, 1), size(var, 1)) - var(:this_size) = tmp(:this_size) - deallocate (tmp) - end if - - end subroutine resize_dependency_node - - !> Check if a dependency node has changed - logical function dependency_has_changed(cached, manifest, verbosity, iunit) result(has_changed) - !> Two instances of the same dependency to be compared - type(dependency_node_t), intent(in) :: cached, manifest - - !> Log verbosity - integer, intent(in) :: verbosity, iunit - - integer :: ip - - has_changed = .true. - - !> All the following entities must be equal for the dependency to not have changed - if (manifest_has_changed(cached=cached, manifest=manifest, verbosity=verbosity, iunit=iunit)) return - - !> For now, only perform the following checks if both are available. A dependency in cache.toml - !> will always have this metadata; a dependency from fpm.toml which has not been fetched yet - !> may not have it - if (allocated(cached%version) .and. allocated(manifest%version)) then - if (cached%version /= manifest%version) then - if (verbosity > 1) write (iunit, out_fmt) "VERSION has changed: "//cached%version%s()//" vs. "//manifest%version%s() - return - end if - else - if (verbosity > 1) write (iunit, out_fmt) "VERSION has changed presence " - end if - if (allocated(cached%revision) .and. allocated(manifest%revision)) then - if (cached%revision /= manifest%revision) then - if (verbosity > 1) write (iunit, out_fmt) "REVISION has changed: "//cached%revision//" vs. "//manifest%revision - return - end if - else - if (verbosity > 1) write (iunit, out_fmt) "REVISION has changed presence " - end if - if (allocated(cached%proj_dir) .and. allocated(manifest%proj_dir)) then - if (cached%proj_dir /= manifest%proj_dir) then - if (verbosity > 1) write (iunit, out_fmt) "PROJECT DIR has changed: "//cached%proj_dir//" vs. "//manifest%proj_dir - return - end if - else - if (verbosity > 1) write (iunit, out_fmt) "PROJECT DIR has changed presence " - end if - if (allocated(cached%preprocess) .eqv. allocated(manifest%preprocess)) then - if (allocated(cached%preprocess)) then - if (size(cached%preprocess) /= size(manifest%preprocess)) then - if (verbosity > 1) write (iunit, out_fmt) "PREPROCESS has changed size" - return - end if - do ip=1,size(cached%preprocess) - if (.not.(cached%preprocess(ip) == manifest%preprocess(ip))) then - if (verbosity > 1) write (iunit, out_fmt) "PREPROCESS config has changed" - return - end if - end do - endif - else - if (verbosity > 1) write (iunit, out_fmt) "PREPROCESS has changed presence " - return - end if - - !> All checks passed: the two dependencies have no differences - has_changed = .false. - - end function dependency_has_changed - - !> Check that two dependency nodes are equal - logical function dependency_node_is_same(this,that) - class(dependency_node_t), intent(in) :: this - class(serializable_t), intent(in) :: that - - dependency_node_is_same = .false. - - select type (other=>that) - type is (dependency_node_t) - - ! Base class must match - if (.not.(this%dependency_config_t==other%dependency_config_t)) return - - ! Extension must match - if (.not.(this%done .eqv.other%done)) return - if (.not.(this%update.eqv.other%update)) return - if (.not.(this%cached.eqv.other%cached)) return - - if (allocated(this%proj_dir) .neqv. allocated(other%proj_dir)) return - if (allocated(this%proj_dir)) then - if (.not.(this%proj_dir==other%proj_dir)) return - endif - if (allocated(this%revision) .neqv. allocated(other%revision)) return - if (allocated(this%revision)) then - if (.not.(this%revision==other%revision)) return - endif - - if (allocated(this%version).neqv.allocated(other%version)) return - if (allocated(this%version)) then - if (.not.(this%version==other%version)) return - endif - - if (allocated(this%package_dep).neqv.allocated(other%package_dep)) return - if (allocated(this%package_dep)) then - if (.not.size(this%package_dep)==size(other%package_dep)) return - if (.not.(this%package_dep==other%package_dep)) return - endif - - class default - ! Not the same type - return - end select - - !> All checks passed! - dependency_node_is_same = .true. - - end function dependency_node_is_same - - !> Dump dependency to toml table - subroutine node_dump_to_toml(self, table, error) - - !> Instance of the serializable object - class(dependency_node_t), intent(inout) :: self - - !> Data structure - type(toml_table), intent(inout) :: table - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - integer :: i,n,ierr - type(toml_array), pointer :: array - - ! Dump parent class - call self%dependency_config_t%dump_to_toml(table, error) - if (allocated(error)) return - - if (allocated(self%version)) then - call set_string(table, "version", self%version%s(), error,'dependency_node_t') - if (allocated(error)) return - endif - call set_string(table, "proj-dir", self%proj_dir, error, 'dependency_node_t') - if (allocated(error)) return - call set_string(table, "revision", self%revision, error, 'dependency_node_t') - if (allocated(error)) return - call set_value(table, "done", self%done, error, 'dependency_node_t') - if (allocated(error)) return - call set_value(table, "update", self%update, error, 'dependency_node_t') - if (allocated(error)) return - call set_value(table, "cached", self%cached, error, 'dependency_node_t') - if (allocated(error)) return - call set_list(table, "package-dep",self%package_dep, error) - if (allocated(error)) return - - end subroutine node_dump_to_toml - - !> Read dependency from toml table (no checks made at this stage) - subroutine node_load_from_toml(self, table, error) - - !> Instance of the serializable object - class(dependency_node_t), intent(inout) :: self - - !> Data structure - type(toml_table), intent(inout) :: table - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - !> Local variables - character(len=:), allocatable :: version - integer :: ierr,i,n - type(toml_array), pointer :: array - - call destroy_dependency_node(self) - - ! Load parent class - call self%dependency_config_t%load_from_toml(table, error) - if (allocated(error)) return - - call get_value(table, "done", self%done, error, 'dependency_node_t') - if (allocated(error)) return - call get_value(table, "update", self%update, error, 'dependency_node_t') - if (allocated(error)) return - call get_value(table, "cached", self%cached, error, 'dependency_node_t') - if (allocated(error)) return - - call get_value(table, "proj-dir", self%proj_dir) - call get_value(table, "revision", self%revision) - - call get_value(table, "version", version) - if (allocated(version)) then - allocate(self%version) - call new_version(self%version, version, error) - if (allocated(error)) then - error%message = 'dependency_node_t: version error from TOML table - '//error%message - return - endif - end if - - call get_list(table,"package-dep",self%package_dep, error) - if (allocated(error)) return - - end subroutine node_load_from_toml - - !> Destructor - elemental subroutine destroy_dependency_node(self) - - class(dependency_node_t), intent(inout) :: self - - integer :: ierr - - call dependency_destroy(self) - - deallocate(self%version,stat=ierr) - deallocate(self%proj_dir,stat=ierr) - deallocate(self%revision,stat=ierr) - deallocate(self%package_dep,stat=ierr) - self%done = .false. - self%update = .false. - self%cached = .false. - - end subroutine destroy_dependency_node - - !> Check that two dependency trees are equal - logical function dependency_tree_is_same(this,that) - class(dependency_tree_t), intent(in) :: this - class(serializable_t), intent(in) :: that - - integer :: ii - - dependency_tree_is_same = .false. - - select type (other=>that) - type is (dependency_tree_t) - - if (.not.(this%unit==other%unit)) return - if (.not.(this%verbosity==other%verbosity)) return - if (allocated(this%dep_dir) .neqv. allocated(other%dep_dir)) return - if (allocated(this%dep_dir)) then - if (.not.(this%dep_dir==other%dep_dir)) return - endif - if (.not.(this%ndep==other%ndep)) return - if (.not.(allocated(this%dep).eqv.allocated(other%dep))) return - if (allocated(this%dep)) then - if (.not.(size(this%dep)==size(other%dep))) return - do ii = 1, size(this%dep) - if (.not.(this%dep(ii)==other%dep(ii))) return - end do - endif - if (allocated(this%cache) .neqv. allocated(other%cache)) return - if (allocated(this%cache)) then - if (.not.(this%cache==other%cache)) return - endif - - class default - ! Not the same type - return - end select - - !> All checks passed! - dependency_tree_is_same = .true. - - end function dependency_tree_is_same - - !> Dump dependency to toml table - subroutine tree_dump_to_toml(self, table, error) - - !> Instance of the serializable object - class(dependency_tree_t), intent(inout) :: self - - !> Data structure - type(toml_table), intent(inout) :: table - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - integer :: ierr, ii - type(toml_table), pointer :: ptr_deps,ptr - character(27) :: unnamed - - call set_value(table, "unit", self%unit, error, 'dependency_tree_t') - if (allocated(error)) return - call set_value(table, "verbosity", self%verbosity, error, 'dependency_tree_t') - if (allocated(error)) return - call set_string(table, "dep-dir", self%dep_dir, error, 'dependency_tree_t') - if (allocated(error)) return - call set_string(table, "cache", self%cache, error, 'dependency_tree_t') - if (allocated(error)) return - call set_value(table, "ndep", self%ndep, error, 'dependency_tree_t') - if (allocated(error)) return - - if (allocated(self%dep)) then - - ! Create dependency table - call add_table(table, "dependencies", ptr_deps) - if (.not. associated(ptr_deps)) then - call fatal_error(error, "dependency_tree_t cannot create dependency table ") - return - end if - - do ii = 1, size(self%dep) - associate (dep => self%dep(ii)) - - !> Because dependencies are named, fallback if this has no name - !> So, serialization will work regardless of size(self%dep) == self%ndep - if (.not. allocated(dep%name)) then - write(unnamed,1) ii - call add_table(ptr_deps, trim(unnamed), ptr) - else if (len_trim(dep%name)==0) then - write(unnamed,1) ii - call add_table(ptr_deps, trim(unnamed), ptr) - else - call add_table(ptr_deps, dep%name, ptr) - end if - if (.not. associated(ptr)) then - call fatal_error(error, "dependency_tree_t cannot create entry for dependency "//dep%name) - return - end if - call dep%dump_to_toml(ptr, error) - if (allocated(error)) return - end associate - end do - - endif - - 1 format('UNNAMED_DEPENDENCY_',i0) - - end subroutine tree_dump_to_toml - - !> Read dependency from toml table (no checks made at this stage) - subroutine tree_load_from_toml(self, table, error) - - !> Instance of the serializable object - class(dependency_tree_t), intent(inout) :: self - - !> Data structure - type(toml_table), intent(inout) :: table - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - !> Local variables - type(toml_key), allocatable :: keys(:),dep_keys(:) - type(toml_table), pointer :: ptr_deps,ptr - integer :: ii, jj, ierr - - call table%get_keys(keys) - - call get_value(table, "unit", self%unit, error, 'dependency_tree_t') - if (allocated(error)) return - call get_value(table, "verbosity", self%verbosity, error, 'dependency_tree_t') - if (allocated(error)) return - call get_value(table, "ndep", self%ndep, error, 'dependency_tree_t') - if (allocated(error)) return - call get_value(table, "dep-dir", self%dep_dir) - call get_value(table, "cache", self%cache) - - find_deps_table: do ii = 1, size(keys) - if (keys(ii)%key=="dependencies") then - - call get_value(table, keys(ii), ptr_deps) - if (.not.associated(ptr_deps)) then - call fatal_error(error,'dependency_tree_t: error retrieving dependency table from TOML table') - return - end if - - !> Read all dependencies - call ptr_deps%get_keys(dep_keys) - call resize(self%dep, size(dep_keys)) - - do jj = 1, size(dep_keys) - - call get_value(ptr_deps, dep_keys(jj), ptr) - call self%dep(jj)%load_from_toml(ptr, error) - if (allocated(error)) return - - end do - - exit find_deps_table - - endif - end do find_deps_table - - end subroutine tree_load_from_toml - - -end module fpm_dependency diff --git a/src/fpm/manifest/install.f90 b/src/fpm/manifest/install.f90 deleted file mode 100644 index 97634837fe..0000000000 --- a/src/fpm/manifest/install.f90 +++ /dev/null @@ -1,181 +0,0 @@ -!> Implementation of the installation configuration. -!> -!> An install table can currently have the following fields -!> -!>```toml -!>library = bool -!>``` -module fpm_manifest_install - use fpm_error, only : error_t, fatal_error, syntax_error - use tomlf, only : toml_table, toml_key, toml_stat - use fpm_toml, only : get_value, set_value, serializable_t - implicit none - private - - public :: install_config_t, new_install_config - - !> Configuration data for installation - type, extends(serializable_t) :: install_config_t - - !> Install library with this project - logical :: library = .false. - - !> Install tests with this project - logical :: test = .false. - - contains - - !> Print information on this instance - procedure :: info - - !> Serialization interface - procedure :: serializable_is_same => install_conf_same - procedure :: dump_to_toml - procedure :: load_from_toml - - end type install_config_t - - character(*), parameter, private :: class_name = 'install_config_t' - -contains - - !> Create a new installation configuration from a TOML data structure - subroutine new_install_config(self, table, error) - - !> Instance of the install configuration - type(install_config_t), intent(out) :: self - - !> Instance of the TOML data structure - type(toml_table), intent(inout) :: table - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - call check(table, error) - if (allocated(error)) return - - call get_value(table, "library", self%library, .false.) - call get_value(table, "test", self%test, .false.) - - end subroutine new_install_config - - - !> Check local schema for allowed entries - subroutine check(table, error) - - !> Instance of the TOML data structure - type(toml_table), intent(inout) :: table - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_key), allocatable :: list(:) - integer :: ikey - - call table%get_keys(list) - if (size(list) < 1) return - - do ikey = 1, size(list) - select case(list(ikey)%key) - case default - call syntax_error(error, "Key "//list(ikey)%key//" is not allowed in install table") - exit - case("library","test") - continue - end select - end do - if (allocated(error)) return - - end subroutine check - - !> Write information on install configuration instance - subroutine info(self, unit, verbosity) - - !> Instance of the build configuration - class(install_config_t), intent(in) :: self - - !> Unit for IO - integer, intent(in) :: unit - - !> Verbosity of the printout - integer, intent(in), optional :: verbosity - - integer :: pr - character(len=*), parameter :: fmt = '("#", 1x, a, t30, a)' - - if (present(verbosity)) then - pr = verbosity - else - pr = 1 - end if - - if (pr < 1) return - - write(unit, fmt) "Install configuration" - write(unit, fmt) " - library install", trim(merge("enabled ", "disabled", self%library)) - write(unit, fmt) " - test install", trim(merge("enabled ", "disabled", self%test)) - - end subroutine info - - logical function install_conf_same(this,that) - class(install_config_t), intent(in) :: this - class(serializable_t), intent(in) :: that - - install_conf_same = .false. - - select type (other=>that) - type is (install_config_t) - if (this%library.neqv.other%library) return - if (this%test.neqv.other%test) return - class default - ! Not the same type - return - end select - - !> All checks passed! - install_conf_same = .true. - - end function install_conf_same - - !> Dump install config to toml table - subroutine dump_to_toml(self, table, error) - - !> Instance of the serializable object - class(install_config_t), intent(inout) :: self - - !> Data structure - type(toml_table), intent(inout) :: table - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - call set_value(table, "library", self%library, error, class_name) - if (allocated(error)) return - - call set_value(table, "test", self%test, error, class_name) - if (allocated(error)) return - - end subroutine dump_to_toml - - !> Read install config from toml table (no checks made at this stage) - subroutine load_from_toml(self, table, error) - - !> Instance of the serializable object - class(install_config_t), intent(inout) :: self - - !> Data structure - type(toml_table), intent(inout) :: table - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - integer :: stat - - call get_value(table, "library", self%library, error, class_name) - if (allocated(error)) return - call get_value(table, "test", self%test, error, class_name) - if (allocated(error)) return - - end subroutine load_from_toml - -end module fpm_manifest_install diff --git a/src/fpm_environment.c b/src/fpm_environment.c deleted file mode 100644 index 34a3140840..0000000000 --- a/src/fpm_environment.c +++ /dev/null @@ -1,38 +0,0 @@ -#include -#include - -/// @brief Set environment variable using the C standard library -/// @param envname: points to a string containing the name of an environment variable to be added or altered. -/// @param envval: points to the value the environment variable is set to -/// @param overwrite: flag to determine whether an old value should be overwritten -/// @return success flag, 0 on successful execution -int c_setenv(const char *envname, const char *envval, int overwrite) { -#ifndef _WIN32 - return setenv(envname, envval, overwrite); -#else - int errcode = 0; - if(!overwrite) { - size_t envsize = 0; - errcode = getenv_s(&envsize, NULL, 0, envname); - if (errcode || envsize) return errcode; - } - return _putenv_s(envname, envval); -#endif -} - -/// @brief Delete environment variable using the C standard library -/// @param envname: points to a string containing the name of an environment variable. -/// @return success flag, 0 on successful execution -int c_unsetenv(const char *envname) { -#ifndef _WIN32 - return unsetenv(envname); -#else - char* str = malloc(64*sizeof(char)); - *str = '\0'; - int errcode = _putenv_s(envname,str); - // Windows returns a non-0 code when setting empty variable - if (errcode==-1) errcode=0; - free(str); - return errcode; -#endif -} diff --git a/src/metapackage/fpm_meta_base.f90 b/src/fpm_meta_base.f90 similarity index 100% rename from src/metapackage/fpm_meta_base.f90 rename to src/fpm_meta_base.f90 diff --git a/src/metapackage/fpm_meta_blas.f90 b/src/fpm_meta_blas.f90 similarity index 100% rename from src/metapackage/fpm_meta_blas.f90 rename to src/fpm_meta_blas.f90 diff --git a/src/metapackage/fpm_meta_hdf5.f90 b/src/fpm_meta_hdf5.f90 similarity index 100% rename from src/metapackage/fpm_meta_hdf5.f90 rename to src/fpm_meta_hdf5.f90 diff --git a/src/metapackage/fpm_meta_minpack.f90 b/src/fpm_meta_minpack.f90 similarity index 100% rename from src/metapackage/fpm_meta_minpack.f90 rename to src/fpm_meta_minpack.f90 diff --git a/src/metapackage/fpm_meta_mpi.f90 b/src/fpm_meta_mpi.f90 similarity index 100% rename from src/metapackage/fpm_meta_mpi.f90 rename to src/fpm_meta_mpi.f90 diff --git a/src/metapackage/fpm_meta_netcdf.f90 b/src/fpm_meta_netcdf.f90 similarity index 100% rename from src/metapackage/fpm_meta_netcdf.f90 rename to src/fpm_meta_netcdf.f90 diff --git a/src/metapackage/fpm_meta_openmp.f90 b/src/fpm_meta_openmp.f90 similarity index 100% rename from src/metapackage/fpm_meta_openmp.f90 rename to src/fpm_meta_openmp.f90 diff --git a/src/metapackage/fpm_meta_stdlib.f90 b/src/fpm_meta_stdlib.f90 similarity index 100% rename from src/metapackage/fpm_meta_stdlib.f90 rename to src/fpm_meta_stdlib.f90 diff --git a/src/metapackage/fpm_meta_util.f90 b/src/fpm_meta_util.f90 similarity index 100% rename from src/metapackage/fpm_meta_util.f90 rename to src/fpm_meta_util.f90 diff --git a/src/fpm_os.c b/src/fpm_os.c deleted file mode 100644 index c423c3a28b..0000000000 --- a/src/fpm_os.c +++ /dev/null @@ -1,20 +0,0 @@ -#include -#include - -/// @brief Determine the absolute, canonicalized path for a given path. -/// @param path -/// @param resolved_path -/// @param maxLength -/// @return -char* c_realpath(char* path, char* resolved_path, int maxLength) { -// Checking macro in C because it doesn't work with gfortran on Windows, even -// when exported manually. -#ifndef _WIN32 - return realpath(path, resolved_path); -#else - return _fullpath(resolved_path, path, maxLength); -#endif -} - - - diff --git a/src/fpm/fpm_release.F90 b/src/fpm_release.F90 similarity index 100% rename from src/fpm/fpm_release.F90 rename to src/fpm_release.F90 diff --git a/src/fpm/git.f90 b/src/git.f90 similarity index 100% rename from src/fpm/git.f90 rename to src/git.f90 diff --git a/src/fpm/cmd/install.f90 b/src/install.f90 similarity index 100% rename from src/fpm/cmd/install.f90 rename to src/install.f90 diff --git a/src/fpm/installer.f90 b/src/installer.f90 similarity index 100% rename from src/fpm/installer.f90 rename to src/installer.f90 diff --git a/src/fpm/manifest/library.f90 b/src/library.f90 similarity index 100% rename from src/fpm/manifest/library.f90 rename to src/library.f90 diff --git a/app/main.f90 b/src/main.f90 similarity index 100% rename from app/main.f90 rename to src/main.f90 diff --git a/src/fpm/manifest.f90 b/src/manifest.f90 similarity index 100% rename from src/fpm/manifest.f90 rename to src/manifest.f90 diff --git a/src/fpm/manifest/meta.f90 b/src/meta.f90 similarity index 100% rename from src/fpm/manifest/meta.f90 rename to src/meta.f90 diff --git a/src/fpm/cmd/new.f90 b/src/new.f90 similarity index 100% rename from src/fpm/cmd/new.f90 rename to src/new.f90 diff --git a/src/fpm/manifest/package.f90 b/src/package.f90 similarity index 100% rename from src/fpm/manifest/package.f90 rename to src/package.f90 diff --git a/src/fpm/manifest/preprocess.f90 b/src/preprocess.f90 similarity index 100% rename from src/fpm/manifest/preprocess.f90 rename to src/preprocess.f90 diff --git a/src/fpm/manifest/profiles.f90 b/src/profiles.f90 similarity index 100% rename from src/fpm/manifest/profiles.f90 rename to src/profiles.f90 diff --git a/src/ptycheck/LICENSE b/src/ptycheck/LICENSE deleted file mode 100644 index 90ee59f15c..0000000000 --- a/src/ptycheck/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015-2016 K.Takata - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - diff --git a/src/ptycheck/isatty.c b/src/ptycheck/isatty.c deleted file mode 100644 index 9b7f519cb9..0000000000 --- a/src/ptycheck/isatty.c +++ /dev/null @@ -1,33 +0,0 @@ -// This file provides a `c_isatty` wrapper function to check if `stdout` is connected -// to a terminal or not. This wrapper is required for better portability, specifically -// for supporting the MS Windows command prompt and the MinTTY terminal used by MSYS2. - -#include //for isatty() -#include //for fileno() - -#ifdef __MINGW64__ -// ptycheck/iscygpty allows us to check if connected to MinTTY in MSYS2 on Windows -#include "iscygpty.h" -#endif - -// Check if `stdout` is connected to a terminal -// Returns 1 if is a terminal, and 0 otherwise -int c_isatty(void) -{ - - if (isatty(fileno(stdout))){ - return 1; - } else { - - #ifdef __MINGW64__ - if (is_cygpty(fileno(stdout))){ - return 1; - } else { - return 0; - } - #endif - - return 0; - } - -} \ No newline at end of file diff --git a/src/ptycheck/iscygpty.c b/src/ptycheck/iscygpty.c deleted file mode 100644 index 722f88f2f4..0000000000 --- a/src/ptycheck/iscygpty.c +++ /dev/null @@ -1,185 +0,0 @@ -/* - * iscygpty.c -- part of ptycheck - * https://github.com/k-takata/ptycheck - * - * Copyright (c) 2015-2017 K.Takata - * - * You can redistribute it and/or modify it under the terms of either - * the MIT license (as described below) or the Vim license. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifdef _WIN32 - -#include -#include -#include -#include - -#ifdef USE_FILEEXTD -/* VC 7.1 or earlier doesn't support SAL. */ -# if !defined(_MSC_VER) || (_MSC_VER < 1400) -# define __out -# define __in -# define __in_opt -# endif -/* Win32 FileID API Library: - * http://www.microsoft.com/en-us/download/details.aspx?id=22599 - * Needed for WinXP. */ -# include -#else /* USE_FILEEXTD */ -/* VC 8 or earlier. */ -# if defined(_MSC_VER) && (_MSC_VER < 1500) -# ifdef ENABLE_STUB_IMPL -# define STUB_IMPL -# else -# error "Win32 FileID API Library is required for VC2005 or earlier." -# endif -# endif -#endif /* USE_FILEEXTD */ - - -#include "iscygpty.h" - -//#define USE_DYNFILEID -#ifdef USE_DYNFILEID -typedef BOOL (WINAPI *pfnGetFileInformationByHandleEx)( - HANDLE hFile, - FILE_INFO_BY_HANDLE_CLASS FileInformationClass, - LPVOID lpFileInformation, - DWORD dwBufferSize -); -static pfnGetFileInformationByHandleEx pGetFileInformationByHandleEx = NULL; - -# ifndef USE_FILEEXTD -static BOOL WINAPI stub_GetFileInformationByHandleEx( - HANDLE hFile, - FILE_INFO_BY_HANDLE_CLASS FileInformationClass, - LPVOID lpFileInformation, - DWORD dwBufferSize - ) -{ - return FALSE; -} -# endif - -static void setup_fileid_api(void) -{ - if (pGetFileInformationByHandleEx != NULL) { - return; - } - pGetFileInformationByHandleEx = (pfnGetFileInformationByHandleEx) - GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), - "GetFileInformationByHandleEx"); - if (pGetFileInformationByHandleEx == NULL) { -# ifdef USE_FILEEXTD - pGetFileInformationByHandleEx = GetFileInformationByHandleEx; -# else - pGetFileInformationByHandleEx = stub_GetFileInformationByHandleEx; -# endif - } -} -#else -# define pGetFileInformationByHandleEx GetFileInformationByHandleEx -# define setup_fileid_api() -#endif - - -#define is_wprefix(s, prefix) \ - (wcsncmp((s), (prefix), sizeof(prefix) / sizeof(WCHAR) - 1) == 0) - -/* Check if the fd is a cygwin/msys's pty. */ -int is_cygpty(int fd) -{ -#ifdef STUB_IMPL - return 0; -#else - HANDLE h; - int size = sizeof(FILE_NAME_INFO) + sizeof(WCHAR) * (MAX_PATH - 1); - FILE_NAME_INFO *nameinfo; - WCHAR *p = NULL; - - setup_fileid_api(); - - h = (HANDLE) _get_osfhandle(fd); - if (h == INVALID_HANDLE_VALUE) { - return 0; - } - /* Cygwin/msys's pty is a pipe. */ - if (GetFileType(h) != FILE_TYPE_PIPE) { - return 0; - } - nameinfo = malloc(size + sizeof(WCHAR)); - if (nameinfo == NULL) { - return 0; - } - /* Check the name of the pipe: - * '\{cygwin,msys}-XXXXXXXXXXXXXXXX-ptyN-{from,to}-master' */ - if (pGetFileInformationByHandleEx(h, FileNameInfo, nameinfo, size)) { - nameinfo->FileName[nameinfo->FileNameLength / sizeof(WCHAR)] = L'\0'; - p = nameinfo->FileName; - if (is_wprefix(p, L"\\cygwin-")) { /* Cygwin */ - p += 8; - } else if (is_wprefix(p, L"\\msys-")) { /* MSYS and MSYS2 */ - p += 6; - } else { - p = NULL; - } - if (p != NULL) { - while (*p && isxdigit(*p)) /* Skip 16-digit hexadecimal. */ - ++p; - if (is_wprefix(p, L"-pty")) { - p += 4; - } else { - p = NULL; - } - } - if (p != NULL) { - while (*p && isdigit(*p)) /* Skip pty number. */ - ++p; - if (is_wprefix(p, L"-from-master")) { - //p += 12; - } else if (is_wprefix(p, L"-to-master")) { - //p += 10; - } else { - p = NULL; - } - } - } - free(nameinfo); - return (p != NULL); -#endif /* STUB_IMPL */ -} - -/* Check if at least one cygwin/msys pty is used. */ -int is_cygpty_used(void) -{ - int fd, ret = 0; - - for (fd = 0; fd < 3; fd++) { - ret |= is_cygpty(fd); - } - return ret; -} - -#endif /* _WIN32 */ - -/* vim: set ts=4 sw=4: */ diff --git a/src/ptycheck/iscygpty.h b/src/ptycheck/iscygpty.h deleted file mode 100644 index 82fd0affbd..0000000000 --- a/src/ptycheck/iscygpty.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * iscygpty.h -- part of ptycheck - * https://github.com/k-takata/ptycheck - * - * Copyright (c) 2015-2017 K.Takata - * - * You can redistribute it and/or modify it under the terms of either - * the MIT license (as described below) or the Vim license. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef _ISCYGPTY_H -#define _ISCYGPTY_H - -#ifdef _WIN32 -int is_cygpty(int fd); -int is_cygpty_used(void); -#else -#define is_cygpty(fd) 0 -#define is_cygpty_used() 0 -#endif - -#endif /* _ISCYGPTY_H */ diff --git a/src/fpm/cmd/publish.f90 b/src/publish.f90 similarity index 100% rename from src/fpm/cmd/publish.f90 rename to src/publish.f90 diff --git a/src/fpm/manifest/test.f90 b/src/test.f90 similarity index 100% rename from src/fpm/manifest/test.f90 rename to src/test.f90 diff --git a/src/fpm/toml.f90 b/src/toml.f90 similarity index 100% rename from src/fpm/toml.f90 rename to src/toml.f90 diff --git a/src/fpm/cmd/update.f90 b/src/update.f90 similarity index 100% rename from src/fpm/cmd/update.f90 rename to src/update.f90 diff --git a/src/fpm/versioning.f90 b/src/versioning.f90 similarity index 100% rename from src/fpm/versioning.f90 rename to src/versioning.f90 diff --git a/test/cli_test/cli_test.f90 b/test/cli_test/cli_test.f90 deleted file mode 100644 index 975b80812b..0000000000 --- a/test/cli_test/cli_test.f90 +++ /dev/null @@ -1,291 +0,0 @@ -program main - -! for each set of command options, call this command recursively which will print the resulting parameters with a -! given test command CMD from the TEST() array. -! -! Then read the expected values as a NAMELIST group from the test array and compare the expected -! results with the actual results. -! -! the PARSE() subroutine is a copy of the app/main.f90 program except it creates and writes a NAMELIST file instead -! of actually calling the subcommands. -! -! The program will exit with a non-zero status if any of the tests fail - -use, intrinsic :: iso_fortran_env, only : compiler_version, compiler_options -implicit none - -! convenient arbitrary sizes for test - -! assuming no name over 15 characters to make output have shorter lines -character(len=15),allocatable :: name(:),act_name(:) ; namelist/act_cli/act_name -integer,parameter :: max_names=10 - -character(len=:),allocatable :: command -character(len=:),allocatable :: cmd -integer :: cstat, estat -integer :: act_cstat, act_estat -integer :: i, ios -logical :: w_e,act_w_e ; namelist/act_cli/act_w_e -logical :: w_t,act_w_t ; namelist/act_cli/act_w_t -logical :: c_s,act_c_s ; namelist/act_cli/act_c_s -logical :: c_a,act_c_a ; namelist/act_cli/act_c_a -logical :: reg_c,act_reg_c ; namelist/act_cli/act_reg_c -logical :: show_v,act_show_v ; namelist/act_cli/act_show_v -logical :: show_u_d,act_show_u_d; namelist/act_cli/act_show_u_d -logical :: dry_run,act_dry_run ; namelist/act_cli/act_dry_run -character(len=:), allocatable :: token, act_token ; namelist/act_cli/act_token - -character(len=:), allocatable :: profile,act_profile ; namelist/act_cli/act_profile -character(len=:), allocatable :: args,act_args ; namelist/act_cli/act_args -namelist/expected/cmd,cstat,estat,w_e,w_t,c_s,c_a,reg_c,name,profile,args,show_v,show_u_d,dry_run,token -integer :: lun -logical,allocatable :: tally(:) -logical,allocatable :: subtally(:) -character(len=256) :: message - -! table of arguments to pass to program and expected non-default values for that execution in NAMELIST group format -character(len=*),parameter :: tests(*)= [ character(len=256) :: & - -'CMD="new", ESTAT=1,', & -!'CMD="new -unknown", ESTAT=2,', & -'CMD="new my_project another yet_another -test", ESTAT=2,', & -'CMD="new my_project --app", W_E=T, NAME="my_project",', & -'CMD="new my_project --app --test", W_E=T,W_T=T, NAME="my_project",', & -'CMD="new my_project --test", W_T=T, NAME="my_project",', & -'CMD="new my_project", W_E=T,W_T=T, NAME="my_project",', & - -'CMD="run", ', & -'CMD="run my_project", NAME="my_project", ', & -'CMD="run proj1 p2 project3", NAME="proj1","p2","project3", ', & -'CMD="run proj1 p2 project3 --profile debug", NAME="proj1","p2","project3",profile="debug",', & -'CMD="run proj1 p2 project3 --profile release", NAME="proj1","p2","project3",profile="release",', & -'CMD="run proj1 p2 project3 --profile release -- arg1 -x ""and a long one""", & - &NAME="proj1","p2","project3",profile="release",ARGS="""arg1"" ""-x"" ""and a long one""", ', & - -'CMD="test", ', & -'CMD="test my_project", NAME="my_project", ', & -'CMD="test proj1 p2 project3", NAME="proj1","p2","project3", ', & -'CMD="test proj1 p2 project3 --profile debug", NAME="proj1","p2","project3",profile="debug",', & -'CMD="test proj1 p2 project3 --profile release", NAME="proj1","p2","project3",profile="release",', & -'CMD="test proj1 p2 project3 --profile release -- arg1 -x ""and a long one""", & - &NAME="proj1","p2","project3",profile="release" ARGS="""arg1"" ""-x"" ""and a long one""", ', & - -'CMD="build", NAME=, profile="",ARGS="",', & -'CMD="build --profile release", NAME=, profile="release",ARGS="",', & - -'CMD="clean", NAME=, ARGS="",', & -'CMD="clean --skip", C_S=T, NAME=, ARGS="",', & -'CMD="clean --all", C_A=T, NAME=, ARGS="",', & -'CMD="clean --registry-cache", REG_C=T, NAME=, ARGS="",', & -'CMD="publish --token abc --show-package-version", SHOW_V=T, NAME=, token="abc",ARGS="",', & -'CMD="publish --token abc --show-upload-data", SHOW_U_D=T, NAME=, token="abc",ARGS="",', & -'CMD="publish --token abc --dry-run", DRY_RUN=T, NAME=, token="abc",ARGS="",', & -'CMD="publish --token abc", NAME=, token="abc",ARGS="",', & -' ' ] -character(len=256) :: readme(3) - -readme(1)='&EXPECTED' ! top and bottom line for a NAMELIST group read from TEST() used to set the expected values -readme(3)=' /' -tally=[logical ::] ! an array that tabulates the command test results as pass or fail. - -if(command_argument_count()==0)then ! assume if called with no arguments to do the tests. This means you cannot - ! have a test of no parameters. Could improve on this. - ! if called with parameters assume this is a test and call the routine to - ! parse the resulting values after calling the CLI command line parser - ! and write the NAMELIST group so it can be read and tested against the - ! expected results - write(*,*)'start tests of the CLI command line parser' - command=repeat(' ',4096) - call get_command_argument(0,command) - command=trim(command) - write(*,*)'command=',command - - do i=1,size(tests) - if(tests(i)==' ')then - open(file='_test_cli',newunit=lun,delim='quote') - close(unit=lun,status='delete') - exit - endif - ! blank out name group EXPECTED - name=[(repeat(' ',len(name)),i=1,max_names)] ! the words on the command line sans the subcommand name - profile='' ! --profile PROF - w_e=.false. ! --app - w_t=.false. ! --test - c_s=.false. ! --skip - c_a=.false. ! --all - reg_c=.false. ! --registry-cache - show_v=.false. ! --show-package-version - show_u_d=.false. ! --show-upload-data - dry_run=.false. ! --dry-run - token='' ! --token TOKEN - args=repeat(' ',132) ! -- ARGS - cmd=repeat(' ',132) ! the command line arguments to test - cstat=0 ! status values from EXECUTE_COMMAND_LINE() - estat=0 - readme(2)=' '//tests(i) ! select command options to test for CMD and set nondefault expected values - read(readme,nml=expected) - - write(*,'(*(g0))')'START: TEST ',i,' CMD=',trim(cmd) - ! call this program which will crack command line and write results to scratch file _test_cli - call execute_command_line(command//' '//trim(cmd),cmdstat=act_cstat,exitstat=act_estat) - if(cstat==act_cstat.and.estat==act_estat)then - if(estat==0)then - open(file='_test_cli',newunit=lun,delim='quote') - act_name=[(repeat(' ',len(act_name)),i=1,max_names)] - act_profile='' - act_w_e=.false. - act_w_t=.false. - act_c_s=.false. - act_c_a=.false. - act_reg_c=.false. - act_show_v=.false. - act_show_u_d=.false. - act_dry_run=.false. - act_token='' - act_args=repeat(' ',132) - read(lun,nml=act_cli,iostat=ios,iomsg=message) - if(ios/=0)then - write(*,'(a)')'ERROR:',trim(message) - endif - close(unit=lun) - ! compare results to expected values - subtally=[logical ::] - call test_test('NAME',all(act_name==name)) - call test_test('PROFILE',act_profile==profile) - call test_test('SKIP',act_c_s.eqv.c_s) - call test_test('ALL',act_c_a.eqv.c_a) - call test_test('REGISTRY-CACHE',act_reg_c.eqv.reg_c) - call test_test('WITH_EXPECTED',act_w_e.eqv.w_e) - call test_test('WITH_TESTED',act_w_t.eqv.w_t) - call test_test('WITH_TEST',act_w_t.eqv.w_t) - call test_test('SHOW-PACKAGE-VERSION',act_show_v.eqv.show_v) - call test_test('SHOW-UPLOAD-DATA',act_show_u_d.eqv.show_u_d) - call test_test('DRY-RUN',act_dry_run.eqv.dry_run) - call test_test('TOKEN',act_token==token) - call test_test('ARGS',act_args==args) - if(all(subtally))then - write(*,'(*(g0))')'PASSED: TEST ',i,' STATUS: expected ',cstat,' ',estat,' actual ',act_cstat,' ',act_estat,& - & ' for [',trim(cmd),']' - tally=[tally,.true.] - else - write(*,'(*(g0))')'FAILED: TEST ',i,' STATUS: expected ',cstat,' ',estat,' actual ',act_cstat,' ',act_estat,& - & ' for [',trim(cmd),']' - print '(4a)', & - 'This file was compiled by ', & - compiler_version(), & - ' using the options ', & - compiler_options() - write(*,nml=act_cli,delim='quote') - tally=[tally,.false.] - endif - else - write(*,'(*(g0))')'PASSED: TEST ',i,' EXPECTED BAD STATUS: expected ',cstat,' ',estat, & - ' actual ',act_cstat,' ',act_estat,' for [',trim(cmd),']' - tally=[tally,.true.] - endif - else - write(*,'(*(g0))')'FAILED: TEST ',i,'BAD STATUS: expected ',cstat,' ',estat,' actual ',act_cstat,' ',act_estat,& - ' for [',trim(cmd),']' - tally=[tally,.false.] - endif - enddo - ! write up total results and if anything failed exit with a non-zero status - write(*,'(*(g0))')'TALLY;',tally - if(all(tally))then - write(*,'(*(g0))')'PASSED: all ',count(tally),' tests passed ' - else - write(*,*)'FAILED: PASSED=',count(tally),' FAILED=',count(.not.tally) - stop 4 - endif -else - ! call this program with arguments - !============================================= - debugit: block - integer :: j, ilen - character(len=256) :: big_argument - write(*,*)'arguments seen directly by program' - do j=1,command_argument_count() - call get_command_argument(number=j,value=big_argument,length=ilen) - write(*,'(*(g0))')j,'[',big_argument(:ilen),']' - enddo - end block debugit - !============================================= - call parse() -endif - -contains - -subroutine test_test(name,tst) -character(len=*) :: name -logical,intent(in) :: tst - !!write(*,'(*(g0,1x))')' SUBTEST ',name,' ',merge('PASSED','FAILED',tst) - subtally=[subtally,tst] -end subroutine test_test - -subroutine parse() -! all the extended types for settings from the main program -use fpm_command_line, only: & - fpm_cmd_settings, & - fpm_new_settings, & - fpm_build_settings, & - fpm_run_settings, & - fpm_test_settings, & - fpm_clean_settings, & - fpm_install_settings, & - get_command_line_settings, & - fpm_publish_settings -use fpm, only: cmd_run, cmd_clean -use fpm_cmd_install, only: cmd_install -use fpm_cmd_new, only: cmd_new -use fpm_cmd_publish, only: cmd_publish -class(fpm_cmd_settings), allocatable :: cmd_settings -! duplicates the calls as seen in the main program for fpm -call get_command_line_settings(cmd_settings) - -allocate (character(len=len(name)) :: act_name(0) ) -act_args='' -act_w_e=.false. -act_w_t=.false. -act_c_s=.false. -act_c_a=.false. -act_reg_c=.false. -act_show_v=.false. -act_show_u_d=.false. -act_dry_run=.false. -act_token='' -act_profile='' - -select type(settings=>cmd_settings) -type is (fpm_new_settings) - act_w_e=settings%with_executable - act_w_t=settings%with_test - act_name=[trim(settings%name)] -type is (fpm_build_settings) - act_profile=settings%profile -type is (fpm_run_settings) - act_profile=settings%profile - act_name=settings%name - if (allocated(settings%args)) act_args=settings%args -type is (fpm_test_settings) - act_profile=settings%profile - act_name=settings%name - if (allocated(settings%args)) act_args=settings%args -type is (fpm_clean_settings) - act_c_s=settings%clean_skip - act_c_a=settings%clean_all - act_reg_c=settings%registry_cache -type is (fpm_install_settings) -type is (fpm_publish_settings) - act_show_v=settings%show_package_version - act_show_u_d=settings%show_upload_data - act_dry_run=settings%is_dry_run - act_token=settings%token -end select - -open(file='_test_cli',newunit=lun,delim='quote') -write(lun,nml=act_cli,delim='quote') -close(unit=lun) - -end subroutine parse - -end program main diff --git a/test/fpm_test/main.f90 b/test/fpm_test/main.f90 deleted file mode 100644 index d272761f93..0000000000 --- a/test/fpm_test/main.f90 +++ /dev/null @@ -1,112 +0,0 @@ -!> Driver for unit testing -program fpm_testing - use, intrinsic :: iso_fortran_env, only : error_unit - use testsuite, only : run_testsuite, new_testsuite, testsuite_t, select_suite, run_selected - use test_toml, only : collect_toml - use test_compiler, only : collect_compiler - use test_manifest, only : collect_manifest - use test_filesystem, only : collect_filesystem - use test_source_parsing, only : collect_source_parsing - use test_module_dependencies, only : collect_module_dependencies - use test_package_dependencies, only : collect_package_dependencies - use test_backend, only: collect_backend - use test_installer, only : collect_installer - use test_versioning, only : collect_versioning - use test_settings, only : collect_settings - use test_os, only: collect_os - - implicit none - integer :: stat, is - character(len=:), allocatable :: suite_name, test_name - type(testsuite_t), allocatable :: suite(:) - character(len=*), parameter :: fmt = '("#", *(1x, a))' - - stat = 0 - - suite = [ & - & new_testsuite("fpm_toml", collect_toml), & - & new_testsuite("fpm_manifest", collect_manifest), & - & new_testsuite("fpm_filesystem", collect_filesystem), & - & new_testsuite("fpm_source_parsing", collect_source_parsing), & - & new_testsuite("fpm_module_dependencies", collect_module_dependencies), & - & new_testsuite("fpm_package_dependencies", collect_package_dependencies), & - & new_testsuite("fpm_test_backend", collect_backend), & - & new_testsuite("fpm_installer", collect_installer), & - & new_testsuite("fpm_versioning", collect_versioning), & - & new_testsuite("fpm_settings", collect_settings), & - & new_testsuite("fpm_os", collect_os), & - & new_testsuite("fpm_compiler", collect_compiler) & - & ] - - call get_argument(1, suite_name) - call get_argument(2, test_name) - - if (allocated(suite_name)) then - is = select_suite(suite, suite_name) - if (is > 0 .and. is <= size(suite)) then - if (allocated(test_name)) then - write(error_unit, fmt) "Suite:", suite(is)%name - call run_selected(suite(is)%collect, test_name, error_unit, stat) - if (stat < 0) then - error stop 1 - end if - else - write(error_unit, fmt) "Testing:", suite(is)%name - call run_testsuite(suite(is)%collect, error_unit, stat) - end if - else - write(error_unit, fmt) "Available testsuites" - do is = 1, size(suite) - write(error_unit, fmt) "-", suite(is)%name - end do - error stop 1 - end if - else - do is = 1, size(suite) - write(error_unit, fmt) "Testing:", suite(is)%name - call run_testsuite(suite(is)%collect, error_unit, stat) - end do - end if - - if (stat > 0) then - write(error_unit, '(i0, 1x, a)') stat, "test(s) failed!" - error stop 1 - end if - - -contains - - - !> Obtain the command line argument at a given index - subroutine get_argument(idx, arg) - - !> Index of command line argument, range [0:command_argument_count()] - integer, intent(in) :: idx - - !> Command line argument - character(len=:), allocatable, intent(out) :: arg - - integer :: length, arg_stat - - call get_command_argument(idx, length=length, status=arg_stat) - if (arg_stat /= 0) then - return - endif - - allocate(character(len=length) :: arg, stat=arg_stat) - if (arg_stat /= 0) then - return - endif - - if (length > 0) then - call get_command_argument(idx, arg, status=arg_stat) - if (arg_stat /= 0) then - deallocate(arg) - return - end if - end if - - end subroutine get_argument - - -end program fpm_testing diff --git a/test/fpm_test/test_backend.f90 b/test/fpm_test/test_backend.f90 deleted file mode 100644 index e936856c9f..0000000000 --- a/test/fpm_test/test_backend.f90 +++ /dev/null @@ -1,523 +0,0 @@ -!> Define tests for the `fpm_backend` module (build scheduling) -module test_backend - use testsuite, only : new_unittest, unittest_t, error_t, test_failed - use test_module_dependencies, only: operator(.in.) - use fpm_filesystem, only: exists, mkdir, get_temp_filename - use fpm_targets, only: build_target_t, build_target_ptr, & - FPM_TARGET_OBJECT, FPM_TARGET_ARCHIVE, FPM_TARGET_SHARED, & - add_target, add_dependency - use fpm_backend, only: sort_target, schedule_targets - use fpm_strings, only: string_t - use fpm_environment, only: OS_LINUX - use fpm_compile_commands, only: compile_command_t, compile_command_table_t - implicit none - private - - public :: collect_backend - -contains - - - !> Collect all exported unit tests - subroutine collect_backend(testsuite) - - !> Collection of tests - type(unittest_t), allocatable, intent(out) :: testsuite(:) - - testsuite = [ & - & new_unittest("target-sort", test_target_sort), & - & new_unittest("target-sort-skip-all", test_target_sort_skip_all), & - & new_unittest("target-sort-rebuild-all", test_target_sort_rebuild_all), & - & new_unittest("target-shared-sort", test_target_shared), & - & new_unittest("schedule-targets", test_schedule_targets), & - & new_unittest("schedule-targets-empty", test_schedule_empty), & - & new_unittest("serialize-compile-commands", compile_commands_roundtrip), & - & new_unittest("compile-commands-write", compile_commands_register_from_cmd), & - & new_unittest("compile-commands-register-string", compile_commands_register_from_string) & - ] - - end subroutine collect_backend - - - !> Check scheduling of objects with dependencies - subroutine test_target_sort(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(build_target_ptr), allocatable :: targets(:) - - integer :: i - - targets = new_test_package() - - ! Perform depth-first topological sort of targets - do i=1,size(targets) - - call sort_target(targets(i)%ptr) - - end do - - ! Check target states: all targets scheduled - do i=1,size(targets) - - if (.not.targets(i)%ptr%touched) then - call test_failed(error,"Target touched flag not set") - return - end if - - if (.not.targets(i)%ptr%sorted) then - call test_failed(error,"Target sort flag not set") - return - end if - - if (targets(i)%ptr%skip) then - call test_failed(error,"Target skip flag set incorrectly") - return - end if - - if (targets(i)%ptr%schedule < 0) then - call test_failed(error,"Target schedule not set") - return - end if - - end do - - ! Check all objects sheduled before library - do i=2,size(targets) - - if (targets(i)%ptr%schedule >= targets(1)%ptr%schedule) then - call test_failed(error,"Object dependency scheduled after dependent library target") - return - end if - - end do - - ! Check target 4 schedule before targets 2 & 3 - do i=2,3 - if (targets(4)%ptr%schedule >= targets(i)%ptr%schedule) then - call test_failed(error,"Object dependency scheduled after dependent object target") - return - end if - end do - - end subroutine test_target_sort - - - - !> Check incremental rebuild for existing archive - !> all object sources are unmodified: all objects should be skipped - subroutine test_target_sort_skip_all(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(build_target_ptr), allocatable :: targets(:) - - integer :: fh, i - - targets = new_test_package() - - do i=2,size(targets) - - ! Mimick unmodified sources - allocate(targets(i)%ptr%source) - targets(i)%ptr%source%digest = i - targets(i)%ptr%digest_cached = i - - end do - - ! Mimick archive already exists - open(newunit=fh,file=targets(1)%ptr%output_file,status="unknown") - close(fh) - - ! Perform depth-first topological sort of targets - do i=1,size(targets) - - call sort_target(targets(i)%ptr) - - end do - - ! Check target states: all targets skipped - do i=1,size(targets) - - if (.not.targets(i)%ptr%touched) then - call test_failed(error,"Target touched flag not set") - return - end if - - if (targets(i)%ptr%sorted) then - call test_failed(error,"Target sort flag set incorrectly") - return - end if - - if (.not.targets(i)%ptr%skip) then - call test_failed(error,"Target skip flag set incorrectly") - return - end if - - end do - - end subroutine test_target_sort_skip_all - - - !> Check incremental rebuild for existing archive - !> all but lowest source modified: all objects should be rebuilt - subroutine test_target_sort_rebuild_all(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(build_target_ptr), allocatable :: targets(:) - - integer :: fh, i - - targets = new_test_package() - - do i=2,3 - - ! Mimick unmodified sources - allocate(targets(i)%ptr%source) - targets(i)%ptr%source%digest = i - targets(i)%ptr%digest_cached = i - - end do - - ! Mimick archive already exists - open(newunit=fh,file=targets(1)%ptr%output_file,status="unknown") - close(fh) - - ! Perform depth-first topological sort of targets - do i=1,size(targets) - - call sort_target(targets(i)%ptr) - - end do - - ! Check target states: all targets scheduled - do i=1,size(targets) - - if (.not.targets(i)%ptr%sorted) then - call test_failed(error,"Target sort flag not set") - return - end if - - if (targets(i)%ptr%skip) then - call test_failed(error,"Target skip flag set incorrectly") - return - end if - - end do - - end subroutine test_target_sort_rebuild_all - - - !> Check construction of target queue and schedule - subroutine test_schedule_targets(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(build_target_ptr), allocatable :: targets(:) - - integer :: i, j - type(build_target_ptr), allocatable :: queue(:) - integer, allocatable :: schedule_ptr(:) - - targets = new_test_package() - - ! Perform depth-first topological sort of targets - do i=1,size(targets) - - call sort_target(targets(i)%ptr) - - end do - - ! Construct build schedule queue - call schedule_targets(queue, schedule_ptr, targets) - - ! Check all targets enqueued - do i=1,size(targets) - - if (.not.(targets(i)%ptr.in.queue)) then - - call test_failed(error,"Target not found in build queue") - return - - end if - - end do - - ! Check schedule structure - if (schedule_ptr(1) /= 1) then - - call test_failed(error,"schedule_ptr(1) does not point to start of the queue") - return - - end if - - if (schedule_ptr(size(schedule_ptr)) /= size(queue)+1) then - - call test_failed(error,"schedule_ptr(end) does not point to end of the queue") - return - - end if - - do i=1,size(schedule_ptr)-1 - - do j=schedule_ptr(i),(schedule_ptr(i+1)-1) - - if (queue(j)%ptr%schedule /= i) then - - call test_failed(error,"Target scheduled in the wrong region") - return - - end if - - end do - - end do - - end subroutine test_schedule_targets - - - !> Check construction of target queue and schedule - !> when there's nothing to do (all targets skipped) - subroutine test_schedule_empty(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(build_target_ptr), allocatable :: targets(:) - - integer :: i - type(build_target_ptr), allocatable :: queue(:) - integer, allocatable :: schedule_ptr(:) - - targets = new_test_package() - - do i=1,size(targets) - - targets(i)%ptr%skip = .true. - - end do - - ! Perform depth-first topological sort of targets - do i=1,size(targets) - - call sort_target(targets(i)%ptr) - - end do - - ! Construct build schedule queue - call schedule_targets(queue, schedule_ptr, targets) - - ! Check queue is empty - if (size(queue) > 0) then - - call test_failed(error,"Expecting an empty build queue, but not empty") - return - - end if - - ! Check schedule loop is not entered - do i=1,size(schedule_ptr)-1 - - call test_failed(error,"Attempted to run an empty schedule") - return - - end do - - end subroutine test_schedule_empty - - - !> Helper to generate target objects with dependencies - function new_test_package() result(targets) - - type(build_target_ptr), allocatable :: targets(:) - integer :: i - - call add_target(targets,'test-package',FPM_TARGET_ARCHIVE,get_temp_filename()) - - call add_target(targets,'test-package',FPM_TARGET_OBJECT,get_temp_filename()) - - call add_target(targets,'test-package',FPM_TARGET_OBJECT,get_temp_filename()) - - call add_target(targets,'test-package',FPM_TARGET_OBJECT,get_temp_filename()) - - ! Library depends on all objects - call add_dependency(targets(1)%ptr,targets(2)%ptr) - call add_dependency(targets(1)%ptr,targets(3)%ptr) - call add_dependency(targets(1)%ptr,targets(4)%ptr) - - ! Inter-object dependency - ! targets 2 & 3 depend on target 4 - call add_dependency(targets(2)%ptr,targets(4)%ptr) - call add_dependency(targets(3)%ptr,targets(4)%ptr) - - end function new_test_package - - subroutine compile_commands_roundtrip(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(compile_command_t) :: cmd - type(compile_command_table_t) :: cc - integer :: i - - call cmd%test_serialization('compile_command: empty', error) - if (allocated(error)) return - - cmd = compile_command_t(directory = string_t("/test/dir"), & - arguments = [string_t("gfortran"), & - string_t("-c"), string_t("main.f90"), & - string_t("-o"), string_t("main.o")], & - file = string_t("main.f90")) - - call cmd%test_serialization('compile_command: non-empty', error) - if (allocated(error)) return - - call cc%test_serialization('compile_command_table: empty', error) - if (allocated(error)) return - - do i=1,10 - call cc%register(cmd,error) - if (allocated(error)) return - end do - - call cc%test_serialization('compile_command_table: non-empty', error) - if (allocated(error)) return - - end subroutine compile_commands_roundtrip - - subroutine compile_commands_register_from_cmd(error) - type(error_t), allocatable, intent(out) :: error - - type(compile_command_table_t) :: table - type(compile_command_t) :: cmd - integer :: i - - cmd = compile_command_t(directory = string_t("/src"), & - arguments = [string_t("gfortran"), & - string_t("-c"), string_t("example.f90"), & - string_t("-o"), string_t("example.o")], & - file = string_t("example.f90")) - - call table%register(cmd, error) - if (allocated(error)) return - - if (.not.allocated(table%command)) then - call test_failed(error, "Command table not allocated after registration") - return - endif - - if (size(table%command) /= 1) then - call test_failed(error, "Expected one registered command") - return - endif - - if (table%command(1)%file%s /= "example.f90") then - call test_failed(error, "Registered file mismatch") - return - endif - - end subroutine compile_commands_register_from_cmd - - subroutine compile_commands_register_from_string(error) - type(error_t), allocatable, intent(out) :: error - - type(compile_command_table_t) :: table - character(len=*), parameter :: cmd_line = "gfortran -c example.f90 -o example.o" - - ! Register a raw command line string - call table%register(cmd_line, OS_LINUX, error) - if (allocated(error)) return - - if (.not.allocated(table%command)) then - call test_failed(error, "Command table not allocated after string registration") - return - end if - - if (size(table%command) /= 1) then - call test_failed(error, "Expected one registered command after string registration") - return - end if - - if (.not.allocated(table%command(1)%arguments)) then - call test_failed(error, "Command arguments not allocated") - return - end if - - if (size(table%command(1)%arguments) /= 5) then - call test_failed(error, "Wrong number of parsed arguments, should be 5") - return - end if - - if (table%command(1)%arguments(1)%s /= "gfortran") then - call test_failed(error, "Expected 'gfortran' as first argument") - return - end if - - if (table%command(1)%arguments(3)%s /= "example.f90") then - call test_failed(error, "Expected 'example.f90' as third argument") - return - end if - - end subroutine compile_commands_register_from_string - - !> Check sorting and scheduling for shared library targets - subroutine test_target_shared(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(build_target_ptr), allocatable :: targets(:) - integer :: i - - ! Create a new test package with a shared library - call add_target(targets, 'test-shared', FPM_TARGET_SHARED, get_temp_filename()) - call add_target(targets, 'test-shared', FPM_TARGET_OBJECT, get_temp_filename()) - call add_target(targets, 'test-shared', FPM_TARGET_OBJECT, get_temp_filename()) - - ! Shared library depends on the two object files - call add_dependency(targets(1)%ptr, targets(2)%ptr) - call add_dependency(targets(1)%ptr, targets(3)%ptr) - - ! Perform topological sort - do i = 1, size(targets) - call sort_target(targets(i)%ptr) - end do - - ! Check scheduling and flags - do i = 1, size(targets) - if (.not.targets(i)%ptr%touched) then - call test_failed(error, "Shared: Target not touched") - return - end if - if (.not.targets(i)%ptr%sorted) then - call test_failed(error, "Shared: Target not sorted") - return - end if - if (targets(i)%ptr%skip) then - call test_failed(error, "Shared: Target incorrectly skipped") - return - end if - end do - - ! Check dependencies scheduled before the shared lib - if (targets(2)%ptr%schedule >= targets(1)%ptr%schedule) then - call test_failed(error, "Shared: Object 2 scheduled after shared lib") - return - end if - if (targets(3)%ptr%schedule >= targets(1)%ptr%schedule) then - call test_failed(error, "Shared: Object 3 scheduled after shared lib") - return - end if - - end subroutine test_target_shared - - - - -end module test_backend diff --git a/test/fpm_test/test_compiler.f90 b/test/fpm_test/test_compiler.f90 deleted file mode 100644 index 1472b86f4c..0000000000 --- a/test/fpm_test/test_compiler.f90 +++ /dev/null @@ -1,197 +0,0 @@ -!> Define tests for the `fpm_compiler` module -module test_compiler - use testsuite, only : new_unittest, unittest_t, error_t, test_failed, & - & check_string - use fpm_environment, only : OS_WINDOWS, OS_LINUX - use fpm_compiler , only : compiler_t, new_compiler, tokenize_flags - use fpm_strings , only : string_t, operator(==) - use fpm_command_line, only: get_fpm_env - use fpm_compile_commands, only: compile_command_table_t - implicit none - private - - public :: collect_compiler - - -contains - - !> Collect all exported unit tests - subroutine collect_compiler(testsuite) - !> Collection of tests - type(unittest_t), allocatable, intent(out) :: testsuite(:) - - testsuite = [ & - & new_unittest("check-fortran-source-runs", test_check_fortran_source_runs), & - & new_unittest("tokenize-flags", test_tokenize_flags), & - & new_unittest("compile-commands-unix", test_register_compile_command_unix), & - & new_unittest("compile-commands-windows", test_register_compile_command_windows)] - - end subroutine collect_compiler - - subroutine test_check_fortran_source_runs(error) - !> Error handling - type(error_t), allocatable, intent(out) :: error - - character(:), allocatable :: fc,cc,cxx - - - type(compiler_t) :: compiler - - !> Get default compiler - fc = get_fpm_env("FC", default="gfortran") - cc = get_fpm_env("CC", default=" ") - cxx = get_fpm_env("CXX", default=" ") - - call new_compiler(compiler, fc, cc, cxx, echo=.false., verbose=.false.) - - if (compiler%is_unknown()) then - call test_failed(error, "Cannot initialize Fortran compiler") - return - end if - - !> Test fortran-source runs - if (.not.compiler%check_fortran_source_runs("print *, 'Hello world!'; end")) then - call test_failed(error, "Cannot run Fortran hello world") - return - end if - - !> Test with invalid flags - if (compiler%check_fortran_source_runs("print *, 'Hello world!'; end", & - link_flags=" -some-really-invalid-link-flag")) then - call test_failed(error, "Invalid link flags did not trigger an error") - return - end if - if (compiler%check_fortran_source_runs("print *, 'Hello world!'; end", & - compile_flags=" -certainly-not-a-build/flag")) then - call test_failed(error, "Invalid compile flags did not trigger an error") - return - end if - if (compiler%check_fortran_source_runs("print *, 'Hello world!'; end", & - compile_flags=" -certainly-not-a-build/flag", & - link_flags=" -some-really-invalid-link-flag")) then - call test_failed(error, "Invalid build and link flags did not trigger an error") - return - end if - - !> Test the flag check wrapper - if (compiler%check_flags_supported(compile_flags='-Werror=unknown-flag') & - .and. .not. compiler%is_intel()) then ! Intel will not trigger an error - call test_failed(error, "Invalid compile flags did not trigger an error") - return - end if - if (compiler%check_flags_supported(compile_flags='-not-a-compile-flag')) then - call test_failed(error, "Invalid compile flags did not trigger an error") - return - end if - if (compiler%check_flags_supported(link_flags='-Wl,--nonexistent-linker-option')) then - call test_failed(error, "Invalid link flags did not trigger an error") - return - end if - if (compiler%check_flags_supported(compile_flags='-Werror=eunknown-flag', & - link_flags='-Wl,--nonexistent-linker-option')) then - call test_failed(error, "Invalid compile and link flags did not trigger an error") - return - end if - - end subroutine test_check_fortran_source_runs - - subroutine test_tokenize_flags(error) - type(error_t), allocatable, intent(out) :: error - - character(:), allocatable :: flags - type(string_t), allocatable :: tokens(:) - integer :: i - - flags = '-I/path/to/include -I /test -I"/path/to/include with spaces" ' // & - '-I "spaces here too" -L/path/to/lib -lmylib -O2 -g -Wall' - call tokenize_flags(flags, tokens) - - do i = 1, size(tokens) - print *, "Tokens ", i, ": ", tokens(i)%s - end do - - if (tokens(1)%s /= '-I/path/to/include') then - call test_failed(error, "Tokenization of flags failed: expected '-I/path/to/include'") - return - end if - if (tokens(2)%s /= '-I/test') then - call test_failed(error, "Tokenization of flags failed: expected '-I/test'") - return - end if - if (tokens(3)%s /= '-I"/path/to/include with spaces"') then - call test_failed(error, 'Tokenization of flags failed: expected -I"/path/to/include with spaces"') - return - end if - - if (size(tokens) /= 9) then - call test_failed(error, "Tokenization of flags failed: expected 9 tokens") - return - end if - - end subroutine test_tokenize_flags - - subroutine test_register_compile_command_unix(error) - type(error_t), allocatable, intent(out) :: error - - type(compile_command_table_t) :: table - type(string_t), allocatable :: expected(:) - integer :: i - - call table%register('gfortran -c -I/usr/include -O2 -Wall main.f90', OS_LINUX, error) - if (allocated(error)) return - - if (size(table%command) /= 1) then - call test_failed(error, "Expected 1 command registered") - return - end if - - associate(c => table%command(1)) - ! Expect these arguments in order - expected = [ string_t('gfortran'), string_t('-c'), & - string_t('-I/usr/include'), string_t('-O2'), & - string_t('-Wall'), string_t('main.f90') ] - - if (.not. c%arguments == expected) then - do i = 1, size(c%arguments) - print *, "Argument", i, ":", c%arguments(i)%s - end do - call test_failed(error, "Unix compile command arguments did not match expected tokens") - return - end if - end associate - end subroutine test_register_compile_command_unix - - subroutine test_register_compile_command_windows(error) - type(error_t), allocatable, intent(out) :: error - - type(compile_command_table_t) :: table - type(string_t), allocatable :: expected(:) - integer :: i - - call table%register('ifort /c /I"C:\Program Files\Libs" /O2 /W4 main.f90', OS_WINDOWS, error) - if (allocated(error)) return - - if (size(table%command) /= 1) then - call test_failed(error, "Expected 1 command registered") - return - end if - - associate(c => table%command(1)) - ! Expected Windows-style tokens - expected = [ string_t('ifort'), string_t('/c'), & - string_t('/IC:\Program Files\Libs'), string_t('/O2'), & - string_t('/W4'), string_t('main.f90') ] - - if (.not. c%arguments == expected) then - do i = 1, size(c%arguments) - print *, "Argument", i, ":", c%arguments(i)%s - end do - call test_failed(error, "Windows compile command arguments did not match expected tokens") - return - end if - end associate - end subroutine test_register_compile_command_windows - - - -end module test_compiler diff --git a/test/fpm_test/test_filesystem.f90 b/test/fpm_test/test_filesystem.f90 deleted file mode 100644 index 4c8d499bbf..0000000000 --- a/test/fpm_test/test_filesystem.f90 +++ /dev/null @@ -1,433 +0,0 @@ -module test_filesystem - use testsuite, only: new_unittest, unittest_t, error_t, test_failed - use fpm_filesystem, only: canon_path, is_dir, mkdir, os_delete_dir, & - join_path, is_absolute_path, get_home, & - delete_file, read_lines, get_temp_filename - use fpm_environment, only: OS_WINDOWS, get_os_type, os_is_unix - use fpm_strings, only: string_t, split_lines_first_last - implicit none - private - - public :: collect_filesystem - -contains - - !> Collect all exported unit tests - subroutine collect_filesystem(tests) - - !> Collection of tests - type(unittest_t), allocatable, intent(out) :: tests(:) - - tests = [ & - & new_unittest("canon-path", test_canon_path), & - & new_unittest("create-delete-directory", test_mkdir_rmdir), & - & new_unittest("test-is-absolute-path", test_is_absolute_path), & - & new_unittest("test-get-home", test_get_home), & - & new_unittest("test-split-lines-first-last", test_split_lines_first_last), & - & new_unittest("test-crlf-lines", test_dir_with_crlf) & - ] - - end subroutine collect_filesystem - - subroutine test_canon_path(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - call check_string(error, & - & canon_path("git/project/src/origin"), "git/project/src/origin") - if (allocated(error)) return - - call check_string(error, & - & canon_path("./project/src/origin"), "project/src/origin") - if (allocated(error)) return - - call check_string(error, & - & canon_path("./project/src///origin/"), "project/src/origin") - if (allocated(error)) return - - call check_string(error, & - & canon_path("../project/./src/origin/"), "../project/src/origin") - if (allocated(error)) return - - call check_string(error, & - & canon_path("/project//src/origin/"), "/project/src/origin") - if (allocated(error)) return - - call check_string(error, & - & canon_path("/project/src/../origin/"), "/project/origin") - if (allocated(error)) return - - call check_string(error, & - & canon_path("/project/src/../origin/.."), "/project") - if (allocated(error)) return - - call check_string(error, & - & canon_path("/project/src//../origin/."), "/project/origin") - if (allocated(error)) return - - call check_string(error, & - & canon_path("../project/src/./../origin/."), "../project/origin") - if (allocated(error)) return - - call check_string(error, & - & canon_path("../project/src/../../../origin/."), "../../origin") - if (allocated(error)) return - - call check_string(error, & - & canon_path("/../.."), "/") - if (allocated(error)) return - - call check_string(error, & - & canon_path("././././././/////a/b/.///././////.///c/../../../"), ".") - if (allocated(error)) return - - call check_string(error, & - & canon_path("/./././././/////a/b/.///././////.///c/../../../"), "/") - if (allocated(error)) return - - end subroutine test_canon_path - - !> Check a character variable against a reference value - subroutine check_string(error, actual, expected) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - !> Actual string value - character(len=*), intent(in) :: actual - - !> Expected string value - character(len=*), intent(in) :: expected - - if (actual /= expected) then - call test_failed(error, & - "Character value mismatch "// & - "expected '"//expected//"' but got '"//actual//"'") - end if - - end subroutine check_string - - subroutine test_mkdir_rmdir(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - call check_mkdir(error, join_path("tmpdir", "subdir")) - if (allocated(error)) return - - call check_rmdir(error, "tmpdir") - if (allocated(error)) return - - end subroutine test_mkdir_rmdir - - !> Create a directory and verify its existence - subroutine check_mkdir(error, path) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - !> Directory path - character(len=*), intent(in) :: path - - ! Directory shouldn't exist before it's created - if (is_dir(path)) then - call test_failed(error, & - "Directory path "//path//" already exists before its creation") - return - end if - - ! Create directory - call mkdir(path) - - ! Check that directory is indeed created - if (.not. is_dir(path)) then - call test_failed(error, & - "Directory path "//path//" cannot be created") - end if - - end subroutine check_mkdir - - !> Create a directory and verify its existence - subroutine check_rmdir(error, path) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - !> Directory path - character(len=*), intent(in) :: path - - ! Directory should exist before it's deleted - if (.not. is_dir(path)) then - call test_failed(error, & - "Directory path "//path//" doesn't exist before its deletion") - return - end if - - ! Delete directory - call os_delete_dir(os_is_unix(), path) - - ! Check that directory is indeed deleted - if (is_dir(path)) then - call test_failed(error, & - "Directory path "//path//" cannot be deleted") - end if - - end subroutine check_rmdir - - subroutine test_is_absolute_path(error) - type(error_t), allocatable, intent(out) :: error - - ! Unix tests - if (is_absolute_path('.', is_unix=.true.)) then - call test_failed(error, "Path '.' isn't absolute") - return - end if - - if (is_absolute_path('abc', is_unix=.true.)) then - call test_failed(error, "Path 'abc' isn't absolute") - return - end if - - if (is_absolute_path('~a', is_unix=.true.)) then - call test_failed(error, "Path '~a' isn't absolute") - return - end if - - if (is_absolute_path('C:', is_unix=.true.)) then - call test_failed(error, "Path 'C:' isn't absolute on Unix") - return - end if - - if (is_absolute_path('~', is_unix=.true.)) then - call test_failed(error, "Path '~' isn't absolute") - return - end if - - if (is_absolute_path('~/', is_unix=.true.)) then - call test_failed(error, "Path '~/' isn't absolute") - return - end if - - if (.not. is_absolute_path('/', is_unix=.true.)) then - call test_failed(error, "Path '/' is absolute") - return - end if - - if (.not. is_absolute_path('/a', is_unix=.true.)) then - call test_failed(error, "Path '/a' is absolute") - return - end if - - ! Windows tests - if (is_absolute_path('abc', is_unix=.false.)) then - call test_failed(error, "Path 'abc' isn't absolute") - return - end if - - if (is_absolute_path('..', is_unix=.false.)) then - call test_failed(error, "Path '..' isn't absolute") - return - end if - - if (is_absolute_path('~', is_unix=.false.)) then - call test_failed(error, "Path '~' isn't absolute") - return - end if - - if (is_absolute_path('/', is_unix=.false.)) then - call test_failed(error, "Path '/' isn't absolute on Windows") - return - end if - - if (is_absolute_path('c/', is_unix=.false.)) then - call test_failed(error, "Path 'c/' isn't absolute") - return - end if - - if (is_absolute_path('1:', is_unix=.false.)) then - call test_failed(error, "Path '1:' isn't absolute") - return - end if - - if (is_absolute_path('C', is_unix=.false.)) then - call test_failed(error, "Path 'C' isn't absolute") - return - end if - - if (.not. is_absolute_path('C:', is_unix=.false.)) then - call test_failed(error, "Path 'C:' is absolute") - return - end if - - if (.not. is_absolute_path('x:', is_unix=.false.)) then - call test_failed(error, "Path 'x:' is absolute") - return - end if - - if (.not. is_absolute_path('x:xyz', is_unix=.false.)) then - call test_failed(error, "Path 'x:xyz' is absolute") - return - end if - - end subroutine test_is_absolute_path - - subroutine test_get_home(error) - type(error_t), allocatable, intent(out) :: error - character(len=:), allocatable :: home - character(len=*), parameter :: letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' - - call get_home(home, error) - if (allocated(error)) return - - if (os_is_unix()) then - if (home(1:1) /= '/') then - call test_failed(error, "This doesn't seem to be the correct home path: '"//home//"'") - return - end if - else - if (index(letters, home(1:1)) == 0 .or. home(2:2) /= ':') then - call test_failed(error, "This doesn't seem to be the correct home path: '"//home//"'") - return - end if - end if - - end subroutine test_get_home - - ! Test line splitting on MS windows - subroutine test_split_lines_first_last(error) - !> Error handling - type(error_t), allocatable, intent(out) :: error - - character, parameter :: CR = achar(13) - character, parameter :: LF = new_line('A') - character(*), parameter :: CRLF = CR//LF - integer, allocatable :: first(:), last(:) - - call split_lines_first_last(CR//LF//'line1'//CR//'line2'//LF//'line3'//CR//LF//'hello', first, last) - if (.not.(all(first==[3,9,15,22]) .and. all(last==[7,13,19,26]))) then - call test_failed(error, "Test split_lines_first_last #1 failed") - return - end if - - call split_lines_first_last('single_line', first, last) - if (.not.(all(first==[1]) .and. all(last==[11]))) then - call test_failed(error, "Test split_lines_first_last #2 failed") - return - end if - - call split_lines_first_last(CR//LF//CR//LF//'test', first, last) - if (.not.(all(first == [5]) .and. all(last == [8]))) then - call test_failed(error, "Test split_lines_first_last #3 failed") - return - end if - - call split_lines_first_last('a'//CR//'b'//LF//'c'//CR//LF//'d', first, last) - if (.not.(all(first == [1, 3, 5, 8]) .and. all(last == [1, 3, 5, 8]))) then - call test_failed(error, "Test split_lines_first_last #4 failed") - return - end if - - call split_lines_first_last('', first, last) - if (.not.(size(first) == 0 .and. size(last) == 0)) then - call test_failed(error, "Test split_lines_first_last #5 failed") - return - end if - - call split_lines_first_last('build.f90'//CRLF//& - 'dependency.f90'//CRLF//& - 'example.f90'//CRLF//& - 'executable.f90'//CRLF//& - 'fortran.f90'//CRLF, & - first, last) - - if (.not.(all(first == [1,12,28,41,57]) .and. all(last == [9,25,38,54,67]))) then - call test_failed(error, "Test split_lines_first_last #6 failed") - return - end if - - end subroutine test_split_lines_first_last - - ! On MS windows, directory listings are printed to files with CR//LF endings. - ! Check that the lines can be properly read back from such files. - subroutine test_dir_with_crlf(error) - type(error_t), allocatable, intent(out) :: error - - character, parameter :: CR = achar(13) - character, parameter :: LF = new_line('A') - character(*), parameter :: CRLF = CR//LF - - character(*), parameter :: test_lines = 'build.f90'//CRLF//& - 'dependency.f90'//CRLF//& - 'example.f90'//CRLF//& - 'executable.f90'//CRLF//& - 'fortran.f90'//CRLF - - type(string_t), allocatable :: lines(:) - character(len=:), allocatable :: temp_file - character(256) :: msg - integer :: unit, i, ios - - temp_file = get_temp_filename() - - open(newunit=unit,file=temp_file,access='stream',action='write',iostat=ios) - if (ios/=0) then - call test_failed(error, "cannot create temporary file") - return - end if - - write(unit,iostat=ios) test_lines - if (ios/=0) then - call test_failed(error, "cannot write to temporary file") - return - end if - - close(unit,iostat=ios) - if (ios/=0) then - call test_failed(error, "cannot close temporary file") - return - end if - - lines = read_lines(temp_file) - - if (.not.allocated(lines)) then - write(msg, 1) 'no output' - call test_failed(error, msg) - return - end if - - if (size(lines)/=5) then - write(msg, 1) 'wrong number of lines: expected ',5,', actual ',size(lines) - call test_failed(error, msg) - return - end if - - if (lines(1)%s/='build.f90') then - call test_failed(error, "Failed reading file with CRLF: at build.f90") - return - end if - if (lines(2)%s/='dependency.f90') then - call test_failed(error, "Failed reading file with CRLF: at dependency.f90") - return - end if - if (lines(3)%s/='example.f90') then - call test_failed(error, "Failed reading file with CRLF: at example.f90") - return - end if - if (lines(4)%s/='executable.f90') then - call test_failed(error, "Failed reading file with CRLF: at executable.f90") - return - end if - if (lines(5)%s/='fortran.f90') then - call test_failed(error, "Failed reading file with CRLF: at fortran.f90") - return - end if - - call delete_file(temp_file) - - 1 format("Failed reading file with CRLF: ",a,:,i0,:,a,:,i0) - - end subroutine test_dir_with_crlf - - -end module test_filesystem diff --git a/test/fpm_test/test_installer.f90 b/test/fpm_test/test_installer.f90 deleted file mode 100644 index edc5838d88..0000000000 --- a/test/fpm_test/test_installer.f90 +++ /dev/null @@ -1,235 +0,0 @@ -!> Define tests for the `fpm_installer` module -!> -!> The tests here setup a mock environment to allow testing for Unix and Windows -!> platforms at the same time. -module test_installer - use testsuite, only : new_unittest, unittest_t, error_t, test_failed, & - & check_string - use fpm_environment, only : OS_WINDOWS, OS_LINUX - use fpm_filesystem, only : join_path - use fpm_installer - use fpm_targets, only: build_target_ptr, add_target, FPM_TARGET_ARCHIVE, & - FPM_TARGET_SHARED - implicit none - private - - public :: collect_installer - - - type, extends(installer_t) :: mock_installer_t - character(len=:), allocatable :: expected_dir - character(len=:), allocatable :: expected_run - contains - procedure :: make_dir - procedure :: run - end type mock_installer_t - -contains - - !> Collect all exported unit tests - subroutine collect_installer(testsuite) - !> Collection of tests - type(unittest_t), allocatable, intent(out) :: testsuite(:) - - testsuite = [ & - & new_unittest("install-lib", test_install_lib), & - & new_unittest("install-pkgconfig", test_install_pkgconfig), & - & new_unittest("install-sitepackages", test_install_sitepackages), & - & new_unittest("install-mod", test_install_mod), & - & new_unittest("install-exe-unix", test_install_exe_unix), & - & new_unittest("install-exe-win", test_install_exe_win), & - & new_unittest("install-test-unix", test_install_tests_unix), & - & new_unittest("install-test-win", test_install_tests_win), & - & new_unittest("install-shared-lib-unix", test_install_shared_library_unix)] - - end subroutine collect_installer - - subroutine test_install_exe_unix(error) - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(mock_installer_t) :: mock - type(installer_t) :: installer - - call new_installer(installer, prefix="PREFIX", verbosity=0, copy="mock") - mock%installer_t = installer - mock%os = OS_LINUX - mock%expected_dir = "PREFIX/bin" - mock%expected_run = 'mock "name" "'//mock%expected_dir//'"' - - call mock%install_executable("name", error) - - end subroutine test_install_exe_unix - - subroutine test_install_exe_win(error) - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(mock_installer_t) :: mock - type(installer_t) :: installer - - call new_installer(installer, prefix="PREFIX", verbosity=0, copy="mock") - mock%installer_t = installer - mock%os = OS_WINDOWS - mock%expected_dir = "PREFIX\bin" - mock%expected_run = 'mock "name.exe" "'//mock%expected_dir//'"' - - call mock%install_executable("name", error) - - end subroutine test_install_exe_win - - subroutine test_install_tests_unix(error) - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(mock_installer_t) :: mock - type(installer_t) :: installer - - call new_installer(installer, prefix="PREFIX", testdir="tdir", verbosity=0, copy="mock") - mock%installer_t = installer - mock%os = OS_LINUX - mock%expected_dir = "PREFIX/tdir" - mock%expected_run = 'mock "name" "'//mock%expected_dir//'"' - - call mock%install_test("name", error) - - end subroutine test_install_tests_unix - - subroutine test_install_tests_win(error) - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(mock_installer_t) :: mock - type(installer_t) :: installer - - call new_installer(installer, prefix="PREFIX", testdir="tdir", verbosity=0, copy="mock") - mock%installer_t = installer - mock%os = OS_WINDOWS - mock%expected_dir = "PREFIX\tdir" - mock%expected_run = 'mock "name.exe" "'//mock%expected_dir//'"' - - call mock%install_test("name", error) - - end subroutine test_install_tests_win - - subroutine test_install_lib(error) - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(mock_installer_t) :: mock - type(installer_t) :: installer - type(build_target_ptr), allocatable :: targets(:) - - call new_installer(installer, prefix="PREFIX", verbosity=0, copy="mock") - mock%installer_t = installer - mock%expected_dir = join_path("PREFIX", "lib") - mock%expected_run = 'mock "name" "'//join_path("PREFIX", "lib")//'"' - - call add_target(targets,"name",FPM_TARGET_ARCHIVE,"name") - - call mock%install_library(targets(1)%ptr, error) - - deallocate(targets(1)%ptr) - - end subroutine test_install_lib - - subroutine test_install_pkgconfig(error) - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(mock_installer_t) :: mock - type(installer_t) :: installer - - call new_installer(installer, prefix="PREFIX", verbosity=0, copy="mock") - mock%installer_t = installer - mock%os = OS_WINDOWS - mock%expected_dir = "PREFIX\lib\pkgconfig" - mock%expected_run = 'mock "name" "'//mock%expected_dir//'"' - - call mock%install("name", "lib/pkgconfig", error) - - end subroutine test_install_pkgconfig - - subroutine test_install_sitepackages(error) - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(mock_installer_t) :: mock - type(installer_t) :: installer - - call new_installer(installer, prefix="PREFIX", verbosity=0, copy="mock") - mock%installer_t = installer - mock%os = OS_LINUX - mock%expected_dir = "PREFIX/lib/python3.7/site-packages" - mock%expected_run = 'mock "name" "'//mock%expected_dir//'"' - - call mock%install("name", join_path("lib", "python3.7", "site-packages"), & - error) - - end subroutine test_install_sitepackages - - subroutine test_install_mod(error) - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(mock_installer_t) :: mock - type(installer_t) :: installer - - call new_installer(installer, prefix="PREFIX", verbosity=0, copy="mock") - mock%installer_t = installer - mock%expected_dir = join_path("PREFIX", "include") - mock%expected_run = 'mock "name" "'//join_path("PREFIX", "include")//'"' - - call mock%install_header("name", error) - - end subroutine test_install_mod - - subroutine test_install_shared_library_unix(error) - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(mock_installer_t) :: mock - type(installer_t) :: installer - character(len=*), parameter :: libname = "libname.so" - type(build_target_ptr), allocatable :: targets(:) - - call new_installer(installer, prefix="PREFIX", verbosity=0, copy="mock") - mock%installer_t = installer - mock%expected_dir = join_path("PREFIX", "lib") - mock%expected_run = 'mock "'//libname//'" "'//mock%expected_dir//'"' - - call add_target(targets,"name",FPM_TARGET_SHARED,libname) - - call mock%install_library(targets(1)%ptr, error) - - deallocate(targets(1)%ptr) - - end subroutine test_install_shared_library_unix - - - !> Create a new directory in the prefix - subroutine make_dir(self, dir, error) - !> Instance of the installer - class(mock_installer_t), intent(inout) :: self - !> Directory to be created - character(len=*), intent(in) :: dir - !> Error handling - type(error_t), allocatable, intent(out) :: error - - call check_string(error, self%expected_dir, dir, "dir") - - end subroutine make_dir - - !> Run an installation command - subroutine run(self, command, error) - !> Instance of the installer - class(mock_installer_t), intent(inout) :: self - !> Command to be launched - character(len=*), intent(in) :: command - !> Error handling - type(error_t), allocatable, intent(out) :: error - - call check_string(error, self%expected_run, command, "run") - end subroutine run - -end module test_installer diff --git a/test/fpm_test/test_manifest.f90 b/test/fpm_test/test_manifest.f90 deleted file mode 100644 index 075376d7a8..0000000000 --- a/test/fpm_test/test_manifest.f90 +++ /dev/null @@ -1,1511 +0,0 @@ -!> Define tests for the `fpm_manifest` modules -module test_manifest - use fpm_filesystem, only: get_temp_filename - use testsuite, only : new_unittest, unittest_t, error_t, test_failed, check_string - use fpm_manifest - use fpm_manifest_profile, only: profile_config_t, find_profile - use fpm_strings, only: operator(.in.), string_t - use fpm_error, only: fatal_error, error_t - use tomlf, only : new_table, toml_table, toml_array - use fpm_toml, only : add_table, add_array, get_value, get_list, set_value, set_list - implicit none - private - public :: collect_manifest - -contains - - !> Collect all exported unit tests - subroutine collect_manifest(tests) - - !> Collection of tests - type(unittest_t), allocatable, intent(out) :: tests(:) - - tests = [ & - & new_unittest("valid-manifest", test_valid_manifest), & - & new_unittest("invalid-manifest", test_invalid_manifest, should_fail=.true.), & - & new_unittest("default-library", test_default_library), & - & new_unittest("default-executable", test_default_executable), & - & new_unittest("dependency-empty", test_dependency_empty, should_fail=.true.), & - & new_unittest("dependency-pathtag", test_dependency_pathtag, should_fail=.true.), & - & new_unittest("dependency-gitpath", test_dependency_gitpath, should_fail=.true.), & - & new_unittest("dependency-nourl", test_dependency_nourl, should_fail=.true.), & - & new_unittest("dependency-gitconflict", test_dependency_gitconflict, should_fail=.true.), & - & new_unittest("dependency-invalid-git", test_dependency_invalid_git, should_fail=.true.), & - & new_unittest("dependency-no-namespace", test_dependency_no_namespace, should_fail=.true.), & - & new_unittest("dependency-redundant-v", test_dependency_redundant_v, should_fail=.true.), & - & new_unittest("dependency-wrongkey", test_dependency_wrongkey, should_fail=.true.), & - & new_unittest("dependencies-empty", test_dependencies_empty), & - & new_unittest("dependencies-typeerror", test_dependencies_typeerror, should_fail=.true.), & - & new_unittest("profiles", test_profiles), & - & new_unittest("profiles-keyvalue-table", test_profiles_keyvalue_table, should_fail=.true.), & - & new_unittest("executable-empty", test_executable_empty, should_fail=.true.), & - & new_unittest("executable-typeerror", test_executable_typeerror, should_fail=.true.), & - & new_unittest("executable-noname", test_executable_noname, should_fail=.true.), & - & new_unittest("executable-wrongkey", test_executable_wrongkey, should_fail=.true.), & - & new_unittest("build-config-valid", test_build_valid), & - & new_unittest("build-config-empty", test_build_empty), & - & new_unittest("build-config-invalid-values", test_build_invalid_values, should_fail=.true.), & - & new_unittest("build-key-invalid", test_build_invalid_key), & - & new_unittest("library-empty", test_library_empty), & - & new_unittest("library-wrongkey", test_library_wrongkey, should_fail=.true.), & - & new_unittest("library-list", test_library_list, should_fail=.true.), & - & new_unittest("package-simple", test_package_simple), & - & new_unittest("package-empty", test_package_empty, should_fail=.true.), & - & new_unittest("package-typeerror", test_package_typeerror, should_fail=.true.), & - & new_unittest("package-noname", test_package_noname, should_fail=.true.), & - & new_unittest("package-wrongexe", test_package_wrongexe, should_fail=.true.), & - & new_unittest("package-wrongtest", test_package_wrongtest, should_fail=.true.), & - & new_unittest("package-duplicate", test_package_duplicate, should_fail=.true.), & - & new_unittest("test-simple", test_test_simple), & - & new_unittest("test-empty", test_test_empty, should_fail=.true.), & - & new_unittest("test-typeerror", test_test_typeerror, should_fail=.true.), & - & new_unittest("test-noname", test_test_noname, should_fail=.true.), & - & new_unittest("test-wrongkey", test_test_wrongkey, should_fail=.true.), & - & new_unittest("link-string", test_link_string), & - & new_unittest("link-array", test_link_array), & - & new_unittest("link-error", test_invalid_link, should_fail=.true.), & - & new_unittest("example-simple", test_example_simple), & - & new_unittest("example-empty", test_example_empty, should_fail=.true.), & - & new_unittest("install-library", test_install_library), & - & new_unittest("install-empty", test_install_empty), & - & new_unittest("install-wrongkey", test_install_wrongkey, should_fail=.true.), & - & new_unittest("preprocess-empty", test_preprocess_empty), & - & new_unittest("preprocess-wrongkey", test_preprocess_wrongkey, should_fail=.true.), & - & new_unittest("preprocessors-empty", test_preprocessors_empty, should_fail=.true.), & - & new_unittest("macro-parsing", test_macro_parsing, should_fail=.false.), & - & new_unittest("macro-parsing-dependency", test_macro_parsing_dependency, should_fail=.false.) & - & ] - - end subroutine collect_manifest - - - !> Try to read some unnecessary obscure and convoluted but not invalid package file - subroutine test_valid_manifest(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(package_config_t) :: package - character(len=*), parameter :: manifest = 'fpm-valid-manifest.toml' - integer :: unit - - open(file=manifest, newunit=unit) - write(unit, '(a)') & - & 'name = "example"', & - & '[build]', & - & 'auto-executables = false', & - & 'auto-tests = false', & - & 'module-naming = false', & - & '[dependencies.fpm]', & - & 'git = "https://github.com/fortran-lang/fpm"', & - & '[[executable]]', & - & 'name = "example-1" # comment', & - & 'source-dir = "prog"', & - & '[dependencies]', & - & 'toml-f.git = "git@github.com:toml-f/toml-f.git"', & - & '"toml..f" = { path = ".." }', & - & '[["executable"]]', & - & 'name = "example-2"', & - & 'source-dir = "prog"', & - & '[executable.dependencies]', & - & '[''library'']', & - & 'source-dir = """', & - & 'lib""" # comment', & - & '[preprocess]', & - & '[preprocess.cpp]', & - & 'suffixes = ["F90", "f90"]', & - & 'directories = ["src/feature1", "src/models"]', & - & 'macros = ["FOO", "BAR"]' - close(unit) - - call get_package_data(package, manifest, error) - - open(file=manifest, newunit=unit) - close(unit, status='delete') - - if (allocated(error)) return - - if (package%name /= "example") then - call test_failed(error, "Package name is "//package%name//" but should be example") - return - end if - - if (.not.allocated(package%library)) then - call test_failed(error, "library is not present in package data") - return - end if - - if (.not.allocated(package%executable)) then - call test_failed(error, "executable is not present in package data") - return - end if - - if (size(package%executable) /= 2) then - call test_failed(error, "Number of executables in package is not two") - return - end if - - if (.not.allocated(package%dependency)) then - call test_failed(error, "dependency is not present in package data") - return - end if - - if (size(package%dependency) /= 3) then - call test_failed(error, "Number of dependencies in package is not three") - return - end if - - if (allocated(package%test)) then - call test_failed(error, "test is present in package but not in package file") - return - end if - - if (.not.allocated(package%preprocess)) then - call test_failed(error, "Preprocessor is not present in package data") - return - end if - - if (size(package%preprocess) /= 1) then - call test_failed(error, "Number of preprocessors in package is not one") - return - end if - - ! Test package serialization - call package%test_serialization('test_valid_manifest',error) - if (allocated(error)) return - - end subroutine test_valid_manifest - - - !> Try to read a valid TOML document which represent an invalid package file - subroutine test_invalid_manifest(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(package_config_t) :: package - character(len=*), parameter :: manifest = 'fpm-invalid-manifest.toml' - integer :: unit - - open(file=manifest, newunit=unit) - write(unit, '(a)') & - & '[package]', & - & 'name = "example"', & - & 'version = "0.1.0"' - close(unit) - - call get_package_data(package, manifest, error) - - open(file=manifest, newunit=unit) - close(unit, status='delete') - - end subroutine test_invalid_manifest - - - !> Create a default library - subroutine test_default_library(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(package_config_t) :: package - - allocate(package%library) - call default_library(package%library) - - call check_string(error, package%library%source_dir, "src", & - & "Default library source-dir") - if (allocated(error)) return - - if (.not.allocated(package%library%include_dir)) then - call test_failed(error,"Default include-dir list not allocated") - return - end if - - if (.not.("include".in.package%library%include_dir)) then - call test_failed(error,"'include' not in default include-dir list") - return - end if - - call package%test_serialization('test_default_library',error) - if (allocated(error)) return - - end subroutine test_default_library - - - !> Create a default executable - subroutine test_default_executable(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(package_config_t) :: package - character(len=*), parameter :: name = "default" - - allocate(package%executable(1)) - call default_executable(package%executable(1), name) - - call check_string(error, package%executable(1)%source_dir, "app", & - & "Default executable source-dir") - if (allocated(error)) return - - call check_string(error, package%executable(1)%name, name, & - & "Default executable name") - if (allocated(error)) return - - call package%test_serialization('test_default_executable',error) - if (allocated(error)) return - - end subroutine test_default_executable - - - !> Dependencies cannot be created from empty tables - subroutine test_dependency_empty(error) - use fpm_manifest_dependency - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(dependency_config_t) :: dependency - - call new_table(table) - table%key = "example" - - call new_dependency(dependency, table, error=error) - - end subroutine test_dependency_empty - - - !> Try to create a dependency with conflicting entries - subroutine test_dependency_pathtag(error) - use fpm_manifest_dependency - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - integer :: stat - type(dependency_config_t) :: dependency - - call new_table(table) - table%key = 'example' - call set_value(table, 'path', 'package', stat) - call set_value(table, 'tag', 'v20.1', stat) - - call new_dependency(dependency, table, error=error) - - end subroutine test_dependency_pathtag - - - !> Try to create a dependency with conflicting entries - subroutine test_dependency_nourl(error) - use fpm_manifest_dependency - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - integer :: stat - type(dependency_config_t) :: dependency - - call new_table(table) - table%key = 'example' - call set_value(table, 'tag', 'v20.1', stat) - - call new_dependency(dependency, table, error=error) - - end subroutine test_dependency_nourl - - - !> Try to create a dependency with conflicting entries - subroutine test_dependency_gitpath(error) - use fpm_manifest_dependency - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - integer :: stat - type(dependency_config_t) :: dependency - - call new_table(table) - table%key = 'example' - call set_value(table, 'path', 'package', stat) - call set_value(table, 'git', 'https://gitea.com/fortran-lang/pack', stat) - - call new_dependency(dependency, table, error=error) - - end subroutine test_dependency_gitpath - - - !> Try to create a dependency with conflicting entries - subroutine test_dependency_gitconflict(error) - use fpm_manifest_dependency - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - integer :: stat - type(dependency_config_t) :: dependency - - call new_table(table) - table%key = 'example' - call set_value(table, 'git', 'https://gitea.com/fortran-lang/pack', stat) - call set_value(table, 'branch', 'latest', stat) - call set_value(table, 'tag', 'v20.1', stat) - - call new_dependency(dependency, table, error=error) - - end subroutine test_dependency_gitconflict - - - !> Try to create a git dependency with an invalid source format. - subroutine test_dependency_invalid_git(error) - use fpm_manifest_dependency - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(dependency_config_t) :: dependency - - call new_table(table) - table%key = 'example' - call set_value(table, 'git', 123) ! Not a string - - call new_dependency(dependency, table, error=error) - - end subroutine test_dependency_invalid_git - - !> Namespace is necessary if a dependency is not a git or path dependency - subroutine test_dependency_no_namespace(error) - use fpm_manifest_dependency - - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(dependency_config_t) :: dependency - - call new_table(table) - table%key = 'example' - call set_value(table, 'v', 'abc') - - call new_dependency(dependency, table, error=error) - - end subroutine test_dependency_no_namespace - - !> Do not specify version with a git or path dependency - subroutine test_dependency_redundant_v(error) - use fpm_manifest_dependency - - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(dependency_config_t) :: dependency - - call new_table(table) - table%key = 'example' - call set_value(table, 'v', '0.0.0') - call set_value(table, 'path', 'abc') - - call new_dependency(dependency, table, error=error) - - end subroutine test_dependency_redundant_v - - - !> Try to create a dependency with conflicting entries - subroutine test_dependency_wrongkey(error) - use fpm_manifest_dependency - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - integer :: stat - type(dependency_config_t) :: dependency - - call new_table(table) - table%key = 'example' - call set_value(table, 'not-available', 'anywhere', stat) - - call new_dependency(dependency, table, error=error) - - end subroutine test_dependency_wrongkey - - - !> Dependency tables can be empty - subroutine test_dependencies_empty(error) - use fpm_manifest_dependency - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(dependency_config_t), allocatable :: dependencies(:) - - call new_table(table) - - call new_dependencies(dependencies, table, error=error) - if (allocated(error)) return - - if (allocated(dependencies)) then - call test_failed(error, "Found dependencies in empty table") - end if - - end subroutine test_dependencies_empty - - - !> Add a dependency as an array, which is not supported - subroutine test_dependencies_typeerror(error) - use fpm_manifest_dependency - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(toml_array), pointer :: children - integer :: stat - type(dependency_config_t), allocatable :: dependencies(:) - - call new_table(table) - call add_array(table, 'dep1', children, stat) - - call new_dependencies(dependencies, table, error=error) - - end subroutine test_dependencies_typeerror - - !> Include a table of profiles in toml, check whether they are parsed correctly and stored in package - subroutine test_profiles(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(package_config_t) :: package - character(len=*), parameter :: manifest = 'fpm-profiles.toml' - integer :: unit - character(:), allocatable :: profile_name, compiler - logical :: profile_found - type(profile_config_t) :: chosen_profile - - open(file=manifest, newunit=unit) - write(unit, '(a)') & - & 'name = "example"', & - & '[profiles.release.gfortran.linux]', & - & 'flags = "1" #release.gfortran.linux', & - & '[profiles.release.gfortran]', & - & 'flags = "2" #release.gfortran.all', & - & '[profiles.gfortran.linux]', & - & 'flags = "3" #all.gfortran.linux', & - & '[profiles.gfortran]', & - & 'flags = "4" #all.gfortran.all', & - & '[profiles.release.ifort]', & - & 'flags = "5" #release.ifort.all' - close(unit) - - call get_package_data(package, manifest, error) - - open(file=manifest, newunit=unit) - close(unit, status='delete') - - if (allocated(error)) return - - profile_name = 'release' - compiler = 'gfortran' - call find_profile(package%profiles, profile_name, compiler, 1, profile_found, chosen_profile) - if (.not.(chosen_profile%flags.eq.'1 3')) then - call test_failed(error, "Failed to append flags from profiles named 'all'") - return - end if - - call chosen_profile%test_serialization('profile serialization: '//profile_name//' '//compiler,error) - if (allocated(error)) return - - profile_name = 'release' - compiler = 'gfortran' - call find_profile(package%profiles, profile_name, compiler, 3, profile_found, chosen_profile) - if (.not.(chosen_profile%flags.eq.'2 4')) then - call test_failed(error, "Failed to choose profile with OS 'all'") - return - end if - - call chosen_profile%test_serialization('profile serialization: '//profile_name//' '//compiler,error) - if (allocated(error)) return - - profile_name = 'publish' - compiler = 'gfortran' - call find_profile(package%profiles, profile_name, compiler, 1, profile_found, chosen_profile) - if (allocated(chosen_profile%flags)) then - call test_failed(error, "Profile named "//profile_name//" should not exist") - return - end if - - call chosen_profile%test_serialization('profile serialization: '//profile_name//' '//compiler,error) - if (allocated(error)) return - - profile_name = 'debug' - compiler = 'ifort' - call find_profile(package%profiles, profile_name, compiler, 3, profile_found, chosen_profile) - if (.not.(chosen_profile%flags.eq.& - ' /warn:all /check:all /error-limit:1 /Od /Z7 /assume:byterecl /traceback')) then - call test_failed(error, "Failed to load built-in profile "//profile_name) - return - end if - - call chosen_profile%test_serialization('profile serialization: '//profile_name//' '//compiler,error) - if (allocated(error)) return - - profile_name = 'release' - compiler = 'ifort' - call find_profile(package%profiles, profile_name, compiler, 1, profile_found, chosen_profile) - if (.not.(chosen_profile%flags.eq.'5')) then - call test_failed(error, "Failed to overwrite built-in profile") - return - end if - - call chosen_profile%test_serialization('profile serialization: '//profile_name//' '//compiler,error) - if (allocated(error)) return - - end subroutine test_profiles - - !> 'flags' is a key-value entry, test should fail as it is defined as a table - subroutine test_profiles_keyvalue_table(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(package_config_t) :: package - character(len=*), parameter :: manifest = 'fpm-profiles-error.toml' - integer :: unit - - open(file=manifest, newunit=unit) - write(unit, '(a)') & - & 'name = "example"', & - & '[profiles.linux.flags]' - close(unit) - - call get_package_data(package, manifest, error) - - open(file=manifest, newunit=unit) - close(unit, status='delete') - end subroutine test_profiles_keyvalue_table - - !> Executables cannot be created from empty tables - subroutine test_executable_empty(error) - use fpm_manifest_executable - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(executable_config_t) :: executable - - call new_table(table) - - call new_executable(executable, table, error) - - end subroutine test_executable_empty - - - !> Pass a wrong TOML type to the name field of the executable - subroutine test_executable_typeerror(error) - use fpm_manifest_executable - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(toml_table), pointer :: child - integer :: stat - type(executable_config_t) :: executable - - call new_table(table) - call add_table(table, 'name', child, stat) - - call new_executable(executable, table, error) - - end subroutine test_executable_typeerror - - - !> Pass a TOML table with insufficient entries to the executable constructor - subroutine test_executable_noname(error) - use fpm_manifest_executable - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(toml_table), pointer :: child - integer :: stat - type(executable_config_t) :: executable - - call new_table(table) - call add_table(table, 'dependencies', child, stat) - - call new_executable(executable, table, error) - - end subroutine test_executable_noname - - - !> Pass a TOML table with not allowed keys - subroutine test_executable_wrongkey(error) - use fpm_manifest_executable - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(toml_table), pointer :: child - integer :: stat - type(executable_config_t) :: executable - - call new_table(table) - call add_table(table, 'wrong-field', child, stat) - - call new_executable(executable, table, error) - - end subroutine test_executable_wrongkey - - - !> Try to read values from the [build] table - subroutine test_build_valid(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(package_config_t) :: package - character(:), allocatable :: temp_file - integer :: unit - - allocate(temp_file, source=get_temp_filename()) - - open(file=temp_file, newunit=unit) - write(unit, '(a)') & - & 'name = "example"', & - & '[build]', & - & 'auto-executables = false', & - & 'auto-tests = false', & - & 'module-naming = true' - close(unit) - - call get_package_data(package, temp_file, error) - - if (allocated(error)) return - - if (package%build%auto_executables) then - call test_failed(error, "Wrong value of 'auto-executables' read, expecting .false.") - return - end if - - if (package%build%auto_tests) then - call test_failed(error, "Wrong value of 'auto-tests' read, expecting .false.") - return - end if - - if (.not. package%build%module_naming) then - call test_failed(error, "Wrong value of 'module-naming' read, expecting .true.") - return - end if - - end subroutine test_build_valid - - - !> Try to read values from the [build] table - subroutine test_build_invalid_key(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(package_config_t) :: package - character(:), allocatable :: temp_file - integer :: unit - type(error_t), allocatable :: build_error - - allocate(temp_file, source=get_temp_filename()) - - open(file=temp_file, newunit=unit) - write(unit, '(a)') & - & 'name = "example"', & - & '[build]', & - & 'auto-executables = false', & - & 'auto-tests = false ', & - & 'module-naming = true ', & - & 'this-will-fail = true ' - close(unit) - - call get_package_data(package, temp_file, build_error) - - ! Error message should contain both package name and key name - if (allocated(build_error)) then - - if (.not.index(build_error%message,'this-will-fail')>0) then - call fatal_error(error, 'no invalid key name is printed to output') - return - end if - - if (.not.index(build_error%message,'example')>0) then - call fatal_error(error, 'no package name is printed to output') - return - end if - - else - call fatal_error(error, 'no error allocated on invalid [build] section key ') - return - end if - - end subroutine test_build_invalid_key - - - !> Try to read values from an empty [build] table - subroutine test_build_empty(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(package_config_t) :: package - character(:), allocatable :: temp_file - integer :: unit - - allocate(temp_file, source=get_temp_filename()) - - open(file=temp_file, newunit=unit) - write(unit, '(a)') & - & 'name = "example"', & - & '[build]', & - & '[library]' - close(unit) - - call get_package_data(package, temp_file, error) - - if (allocated(error)) return - - if (.not.package%build%auto_executables) then - call test_failed(error, "Wrong default value of 'auto-executables' read, expecting .true.") - return - end if - - if (.not.package%build%auto_tests) then - call test_failed(error, "Wrong default value of 'auto-tests' read, expecting .true.") - return - end if - - if (package%build%module_naming) then - call test_failed(error, "Wrong default value of 'module-naming' read, expecting .false.") - return - end if - - end subroutine test_build_empty - - - !> Try to read values from a [build] table with invalid values - subroutine test_build_invalid_values(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(package_config_t) :: package - character(:), allocatable :: temp_file - integer :: unit - - allocate(temp_file, source=get_temp_filename()) - - open(file=temp_file, newunit=unit) - write(unit, '(a)') & - & 'name = "example"', & - & '[build]', & - & 'auto-executables = "false"' - close(unit) - - call get_package_data(package, temp_file, error) - - end subroutine test_build_invalid_values - - - !> Libraries can be created from empty tables - subroutine test_library_empty(error) - use fpm_manifest_library - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(library_config_t) :: library - - call new_table(table) - - call new_library(library, table, error) - if (allocated(error)) return - - call check_string(error, library%source_dir, "src", & - & "Default library source-dir") - if (allocated(error)) return - - if (.not.allocated(library%include_dir)) then - call test_failed(error,"Default include-dir list not allocated") - return - end if - - if (.not.("include".in.library%include_dir)) then - call test_failed(error,"'include' not in default include-dir list") - return - end if - - end subroutine test_library_empty - - - !> Pass a TOML table with not allowed keys - subroutine test_library_wrongkey(error) - use fpm_manifest_library - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(toml_table), pointer :: child - integer :: stat - type(library_config_t) :: library - - call new_table(table) - call add_table(table, 'not-allowed', child, stat) - - call new_library(library, table, error) - - end subroutine test_library_wrongkey - - !> Pass a TOML table with not allowed source dirs - subroutine test_library_list(error) - use fpm_manifest_library - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(string_t), allocatable :: source_dirs(:) - type(toml_table) :: table - type(library_config_t) :: library - - source_dirs = [string_t("src1"),string_t("src2")] - call new_table (table) - call set_list (table, "source-dir", source_dirs, error) - call new_library(library, table, error) - - end subroutine test_library_list - - !> Pass a TOML table with a 1-sized source dir list - subroutine test_library_listone(error) - use fpm_manifest_library - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(package_config_t) :: package - character(:), allocatable :: temp_file - integer :: unit - - open(file=temp_file, newunit=unit) - write(unit, '(a)') & - & 'name = "example"', & - & '[library]', & - & 'source-dir = ["my-src"]' - close(unit) - - call get_package_data(package, temp_file, error) - - end subroutine test_library_listone - - !> Packages cannot be created from empty tables - subroutine test_package_simple(error) - use fpm_manifest_package - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(toml_table), pointer :: child, child2 - type(toml_array), pointer :: children - integer :: stat - type(package_config_t) :: package - - call new_table(table) - call set_value(table, 'name', 'example', stat) - call set_value(table, 'license', 'MIT', stat) - call add_table(table, 'dev-dependencies', child, stat) - call add_table(child, 'pkg1', child2, stat) - call set_value(child2, 'git', 'https://github.com/fortran-lang/pkg1', stat) - call add_table(child, 'pkg2', child2) - call set_value(child2, 'git', 'https://gitlab.com/fortran-lang/pkg2', stat) - call set_value(child2, 'branch', 'devel', stat) - call add_table(child, 'pkg3', child2) - call set_value(child2, 'git', 'https://bitbucket.org/fortran-lang/pkg3', stat) - call set_value(child2, 'rev', '9fceb02d0ae598e95dc970b74767f19372d61af8', stat) - call add_table(child, 'pkg4', child2) - call set_value(child2, 'git', 'https://gitea.com/fortran-lang/pkg4', stat) - call set_value(child2, 'tag', 'v1.8.5-rc3', stat) - call add_array(table, 'test', children, stat) - call add_table(children, child, stat) - call set_value(child, 'name', 'tester', stat) - - call new_package(package, table, error=error) - - end subroutine test_package_simple - - - !> Packages cannot be created from empty tables - subroutine test_package_empty(error) - use fpm_manifest_package - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(package_config_t) :: package - - call new_table(table) - - call new_package(package, table, error=error) - - end subroutine test_package_empty - - - !> Create an array in the package name, which should cause an error - subroutine test_package_typeerror(error) - use fpm_manifest_package - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(toml_array), pointer :: child - integer :: stat - type(package_config_t) :: package - - call new_table(table) - call add_array(table, "name", child, stat) - - call new_package(package, table, error=error) - - end subroutine test_package_typeerror - - - !> Try to create a new package without a name field - subroutine test_package_noname(error) - use fpm_manifest_package - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(toml_table), pointer :: child - integer :: stat - type(package_config_t) :: package - - call new_table(table) - call add_table(table, "library", child, stat) - call add_table(table, "dev-dependencies", child, stat) - call add_table(table, "dependencies", child, stat) - - call new_package(package, table, error=error) - - end subroutine test_package_noname - - - !> Try to read executables from a mixed type array - subroutine test_package_wrongexe(error) - use fpm_manifest_package - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(toml_array), pointer :: children, children2 - integer :: stat - type(package_config_t) :: package - - call new_table(table) - call set_value(table, 'name', 'example', stat) - call add_array(table, 'executable', children, stat) - call add_array(children, children2, stat) - - call new_package(package, table, error=error) - - end subroutine test_package_wrongexe - - - !> Try to read tests from a mixed type array - subroutine test_package_wrongtest(error) - use fpm_manifest_package - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(toml_array), pointer :: children, children2 - integer :: stat - type(package_config_t) :: package - - call new_table(table) - call set_value(table, 'name', 'example', stat) - call add_array(table, 'test', children, stat) - call add_array(children, children2, stat) - - call new_package(package, table, error=error) - - end subroutine test_package_wrongtest - - - !> Try to read tests from a mixed type array - subroutine test_package_duplicate(error) - use fpm_manifest_package - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(toml_table), pointer :: child - type(toml_array), pointer :: children - integer :: stat - type(package_config_t) :: package - - table = toml_table() - call set_value(table, 'name', 'example', stat) - call add_array(table, 'test', children, stat) - call add_table(children, child, stat) - call set_value(child, 'name', 'prog', stat) - call add_table(children, child, stat) - call set_value(child, 'name', 'prog', stat) - - call new_package(package, table, error=error) - - end subroutine test_package_duplicate - - - !> Tests cannot be created from empty tables - subroutine test_test_simple(error) - use fpm_manifest_test - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(toml_table), pointer :: child - integer :: stat - type(test_config_t) :: test - - call new_table(table) - call set_value(table, 'name', 'example', stat) - call set_value(table, 'source-dir', 'tests', stat) - call set_value(table, 'main', 'tester.f90', stat) - call add_table(table, 'dependencies', child, stat) - - call new_test(test, table, error) - if (allocated(error)) return - - call check_string(error, test%main, "tester.f90", "Test main") - if (allocated(error)) return - - end subroutine test_test_simple - - - !> Tests cannot be created from empty tables - subroutine test_test_empty(error) - use fpm_manifest_test - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(test_config_t) :: test - - call new_table(table) - - call new_test(test, table, error) - - end subroutine test_test_empty - - - !> Pass a wrong TOML type to the name field of the test - subroutine test_test_typeerror(error) - use fpm_manifest_test - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(toml_table), pointer :: child - integer :: stat - type(test_config_t) :: test - - call new_table(table) - call add_table(table, 'name', child, stat) - - call new_test(test, table, error) - - end subroutine test_test_typeerror - - - !> Pass a TOML table with insufficient entries to the test constructor - subroutine test_test_noname(error) - use fpm_manifest_test - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(toml_table), pointer :: child - integer :: stat - type(test_config_t) :: test - - call new_table(table) - call add_table(table, 'dependencies', child, stat) - - call new_test(test, table, error) - - end subroutine test_test_noname - - - !> Pass a TOML table with not allowed keys - subroutine test_test_wrongkey(error) - use fpm_manifest_test - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(toml_table), pointer :: child - integer :: stat - type(test_config_t) :: test - - call new_table(table) - call add_table(table, 'not-supported', child, stat) - - call new_test(test, table, error) - - end subroutine test_test_wrongkey - - - !> Create a simple example entry - subroutine test_example_simple(error) - use fpm_manifest_example - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(toml_table), pointer :: child - integer :: stat - type(example_config_t) :: example - - call new_table(table) - call set_value(table, 'name', 'example', stat) - call set_value(table, 'source-dir', 'demos', stat) - call set_value(table, 'main', 'demo.f90', stat) - call add_table(table, 'dependencies', child, stat) - - call new_example(example, table, error) - if (allocated(error)) return - - call check_string(error, example%main, "demo.f90", "Example main") - if (allocated(error)) return - - end subroutine test_example_simple - - - !> Examples cannot be created from empty tables - subroutine test_example_empty(error) - use fpm_manifest_example - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(example_config_t) :: example - - call new_table(table) - - call new_example(example, table, error) - - end subroutine test_example_empty - - - !> Test link options - subroutine test_link_string(error) - use fpm_manifest_build - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - integer :: stat - type(build_config_t) :: build - - table = toml_table() - call set_value(table, "link", "z", stat=stat) - - call new_build_config(build, table, 'test_link_string', error) - if (allocated(error)) return - - !> Test serialization roundtrip - call build%test_serialization('test_link_string', error) - if (allocated(error)) return - - end subroutine test_link_string - - - !> Test link options - subroutine test_link_array(error) - use fpm_manifest_build - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(toml_array), pointer :: children - integer :: stat - type(build_config_t) :: build - - table = toml_table() - call add_array(table, "link", children, stat=stat) - call set_value(children, 1, "blas", stat=stat) - call set_value(children, 2, "lapack", stat=stat) - - call new_build_config(build, table, 'test_link_array', error) - if (allocated(error)) return - - !> Test serialization roundtrip - call build%test_serialization('test_link_array', error) - if (allocated(error)) return - - end subroutine test_link_array - - - !> Test link options - subroutine test_invalid_link(error) - use fpm_manifest_build - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(toml_table), pointer :: child - integer :: stat - type(build_config_t) :: build - - table = toml_table() - call add_table(table, "link", child, stat=stat) - - call new_build_config(build, table, 'test_invalid_link', error) - - end subroutine test_invalid_link - - - subroutine test_install_library(error) - use fpm_manifest_install - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(install_config_t) :: install - - table = toml_table() - call set_value(table, "library", .true.) - - call new_install_config(install, table, error) - if (allocated(error)) return - - if (.not.install%library) then - call test_failed(error, "Library entry should be true") - return - end if - - end subroutine test_install_library - - - subroutine test_install_empty(error) - use fpm_manifest_install - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(install_config_t) :: install - - table = toml_table() - - call new_install_config(install, table, error) - if (allocated(error)) return - - if (install%library) then - call test_failed(error, "Library default should be false") - return - end if - - end subroutine test_install_empty - - - subroutine test_install_wrongkey(error) - use fpm_manifest_install - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(install_config_t) :: install - - table = toml_table() - call set_value(table, "prefix", "/some/install/path") - - call new_install_config(install, table, error) - - end subroutine test_install_wrongkey - - subroutine test_preprocess_empty(error) - use fpm_manifest_preprocess - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(preprocess_config_t) :: preprocess - - call new_table(table) - table%key = "example" - - call preprocess%new(table, error) - - end subroutine test_preprocess_empty - - !> Pass a TOML table with not allowed keys - subroutine test_preprocess_wrongkey(error) - use fpm_manifest_preprocess - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(toml_table), pointer :: child - integer :: stat - type(preprocess_config_t) :: preprocess - - call new_table(table) - table%key = 'example' - call add_table(table, 'wrong-field', child, stat) - - call preprocess%new(table, error) - - end subroutine test_preprocess_wrongkey - - !> Preprocess table cannot be empty. - subroutine test_preprocessors_empty(error) - use fpm_manifest_preprocess - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(preprocess_config_t), allocatable :: preprocessors(:) - - call new_table(table) - - call new_preprocessors(preprocessors, table, error) - if (allocated(error)) return - - end subroutine test_preprocessors_empty - - !> Test macro parsing function get_macros_from_manifest - subroutine test_macro_parsing(error) - use fpm_compiler, only: get_macros, compiler_enum - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(package_config_t) :: package - character(:), allocatable :: temp_file,pkg_ver - integer :: unit - integer(compiler_enum) :: id - - allocate(temp_file, source=get_temp_filename()) - - open(file=temp_file, newunit=unit) - write(unit, '(a)') & - & 'name = "example"', & - & 'version = "0.1.0"', & - & '[preprocess]', & - & '[preprocess.cpp]', & - & 'macros = ["FOO", "BAR=2", "VERSION={version}"]' - close(unit) - - call get_package_data(package, temp_file, error) - - if (allocated(error)) return - - pkg_ver = package%version%s() - - if (get_macros(id, package%preprocess(1)%macros, pkg_ver) /= " -DFOO -DBAR=2 -DVERSION=0.1.0") then - call test_failed(error, "Macros were not parsed correctly") - end if - - end subroutine test_macro_parsing - - !> Test macro parsing of the package and its dependency. - subroutine test_macro_parsing_dependency(error) - use fpm_compiler, only: get_macros, compiler_enum - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - character(len=:), allocatable :: macros_package, macros_dependency - - type(package_config_t) :: package, dependency - - character(:), allocatable :: toml_file_package - character(:), allocatable :: toml_file_dependency - character(:), allocatable :: pkg_ver,dep_ver - - integer :: unit - integer(compiler_enum) :: id - - allocate(toml_file_package, source=get_temp_filename()) - allocate(toml_file_dependency, source=get_temp_filename()) - - open(file=toml_file_package, newunit=unit) - write(unit, '(a)') & - & 'name = "example"', & - & 'version = "0.1.0"', & - & '[dependencies]', & - & '[dependencies.dependency-name]', & - & 'git = "https://github.com/fortran-lang/dependency-name"', & - & '[preprocess]', & - & '[preprocess.cpp]', & - & 'macros = ["FOO", "BAR=2", "VERSION={version}"]' - close(unit) - - open(file=toml_file_dependency, newunit=unit) - write(unit, '(a)') & - & 'name = "dependency-name"', & - & 'version = "0.2.0"', & - & '[preprocess]', & - & '[preprocess.cpp]', & - & 'macros = ["FOO1", "BAR2=2", "VERSION={version}"]' - close(unit) - - call get_package_data(package, toml_file_package, error) - - if (allocated(error)) return - - call get_package_data(dependency, toml_file_dependency, error) - - if (allocated(error)) return - - pkg_ver = package%version%s() - dep_ver = dependency%version%s() - - macros_package = get_macros(id, package%preprocess(1)%macros, pkg_ver) - macros_dependency = get_macros(id, dependency%preprocess(1)%macros, dep_ver) - if (macros_package == macros_dependency) then - call test_failed(error, "Macros of package and dependency should not be equal") - end if - - end subroutine test_macro_parsing_dependency - -end module test_manifest diff --git a/test/fpm_test/test_module_dependencies.f90 b/test/fpm_test/test_module_dependencies.f90 deleted file mode 100644 index afb87eb302..0000000000 --- a/test/fpm_test/test_module_dependencies.f90 +++ /dev/null @@ -1,1150 +0,0 @@ -!> Define tests for the `fpm_sources` module (module dependency checking) -module test_module_dependencies - use testsuite, only : new_unittest, unittest_t, error_t, test_failed - use fpm_targets, only: targets_from_sources, resolve_module_dependencies, & - build_target_t, build_target_ptr, & - FPM_TARGET_EXECUTABLE, FPM_TARGET_OBJECT, FPM_TARGET_ARCHIVE - use fpm_model, only: fpm_model_t, srcfile_t, & - FPM_UNIT_UNKNOWN, FPM_UNIT_PROGRAM, FPM_UNIT_MODULE, & - FPM_UNIT_SUBMODULE, FPM_UNIT_SUBPROGRAM, FPM_UNIT_CSOURCE, & - FPM_UNIT_CHEADER, FPM_SCOPE_UNKNOWN, FPM_SCOPE_LIB, & - FPM_SCOPE_DEP, FPM_SCOPE_APP, FPM_SCOPE_TEST - use fpm_strings, only: string_t, operator(.in.), is_valid_module_name, is_valid_module_prefix - use fpm, only: check_modules_for_duplicates - implicit none - private - - public :: collect_module_dependencies, operator(.in.) - - interface operator(.in.) - module procedure target_in - end interface - -contains - - - !> Collect all exported unit tests - subroutine collect_module_dependencies(testsuite) - - !> Collection of tests - type(unittest_t), allocatable, intent(out) :: testsuite(:) - - testsuite = [ & - & new_unittest("library-module-use", test_library_module_use), & - & new_unittest("program-module-use", test_program_module_use), & - & new_unittest("program-with-module", test_program_with_module), & - & new_unittest("program-own-module-use", test_program_own_module_use), & - & new_unittest("missing-library-use", & - test_missing_library_use, should_fail=.true.), & - & new_unittest("missing-program-use", & - test_missing_program_use, should_fail=.true.), & - & new_unittest("invalid-library-use", & - test_invalid_library_use, should_fail=.true.), & - & new_unittest("package-with-no-duplicates", & - test_package_with_no_module_duplicates), & - & new_unittest("package-with-duplicates-in-same-source", & - test_package_module_duplicates_same_source, should_fail=.true.), & - & new_unittest("package-with-duplicates-in-one-package", & - test_package_module_duplicates_one_package, should_fail=.true.), & - & new_unittest("package-with-duplicates-in-two-packages", & - test_package_module_duplicates_two_packages, should_fail=.true.), & - & new_unittest("subdirectory-module-use", & - test_subdirectory_module_use), & - & new_unittest("invalid-subdirectory-module-use", & - test_invalid_subdirectory_module_use, should_fail=.true.), & - & new_unittest("tree-shake-module", & - test_tree_shake_module, should_fail=.false.), & - & new_unittest("tree-shake-subprogram-with-module", & - test_tree_shake_subprogram_with_module, should_fail=.false.), & - & new_unittest("valid-enforced-module-names", & - check_valid_enforced_module_names, should_fail=.false.), & - & new_unittest("valid-enforced-module-names-dashed", & - check_valid_enforced_module_names_dashed, should_fail=.false.), & - & new_unittest("invalid-enforced-module-names", & - check_invalid_enforced_module_names, should_fail=.false.), & - & new_unittest("invalid-module-names", & - check_invalid_module_names, should_fail=.false.), & - & new_unittest("custom-module-prefixes", & - check_valid_custom_prefix, should_fail=.false.), & - & new_unittest("custom-prefixed-module-names", & - check_custom_prefixed_modules, should_fail=.false.) & - ] - - end subroutine collect_module_dependencies - - - !> Check library module using another library module - subroutine test_library_module_use(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(fpm_model_t) :: model - type(build_target_ptr), allocatable :: targets(:) - - allocate(model%external_modules(0)) - allocate(model%packages(1)) - allocate(model%packages(1)%sources(2)) - - model%package_name = "test" - model%build_prefix = "" - model%packages(1)%name = "package1" - - model%packages(1)%sources(1) = new_test_source(FPM_UNIT_MODULE,file_name="src/my_mod_1.f90", & - scope = FPM_SCOPE_LIB, & - provides=[string_t('my_mod_1')]) - - model%packages(1)%sources(2) = new_test_source(FPM_UNIT_MODULE,file_name="src/my_mod_2.f90", & - scope = FPM_SCOPE_LIB, & - provides=[string_t('my_mod_2')], & - uses=[string_t('my_mod_1')]) - - call targets_from_sources(targets,model,.false.,error=error) - if (allocated(error)) return - - if (allocated(error)) then - return - end if - if (size(targets) /= 3) then - call test_failed(error,'Incorrect number of targets - expecting three') - return - end if - - call check_target(targets(1)%ptr,type=FPM_TARGET_ARCHIVE,n_depends=2, & - deps = [targets(2),targets(3)], & - links = targets(2:3), error=error) - - if (allocated(error)) return - - - call check_target(targets(2)%ptr,type=FPM_TARGET_OBJECT,n_depends=0, & - source=model%packages(1)%sources(1),error=error) - - if (allocated(error)) return - - - call check_target(targets(3)%ptr,type=FPM_TARGET_OBJECT,n_depends=1, & - deps=[targets(2)],source=model%packages(1)%sources(2),error=error) - - if (allocated(error)) return - - end subroutine test_library_module_use - - - !> Check a program using a library module - !> Each program generates two targets: object file and executable - !> - subroutine test_program_module_use(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - call test_scope(FPM_SCOPE_APP,error) - if (allocated(error)) return - - call test_scope(FPM_SCOPE_TEST,error) - if (allocated(error)) return - - contains - - subroutine test_scope(exe_scope,error) - integer, intent(in) :: exe_scope - type(error_t), allocatable, intent(out) :: error - - type(fpm_model_t) :: model - type(build_target_ptr), allocatable :: targets(:) - character(:), allocatable :: scope_str - - allocate(model%external_modules(0)) - allocate(model%packages(1)) - allocate(model%packages(1)%sources(2)) - - model%package_name = "test_scope" - model%build_prefix = "" - model%packages(1)%name = "package1" - - scope_str = merge('FPM_SCOPE_APP ','FPM_SCOPE_TEST',exe_scope==FPM_SCOPE_APP)//' - ' - - model%packages(1)%sources(1) = new_test_source(FPM_UNIT_MODULE,file_name="src/my_mod_1.f90", & - scope = FPM_SCOPE_LIB, & - provides=[string_t('my_mod_1')]) - - model%packages(1)%sources(2) = new_test_source(FPM_UNIT_PROGRAM,file_name="app/my_program.f90", & - scope=exe_scope, & - uses=[string_t('my_mod_1')]) - - call targets_from_sources(targets,model,.false.,error=error) - if (allocated(error)) return - - if (size(targets) /= 4) then - call test_failed(error,scope_str//'Incorrect number of targets - expecting three') - return - end if - - call check_target(targets(1)%ptr,type=FPM_TARGET_ARCHIVE,n_depends=1, & - deps=[targets(2)],links=[targets(2)],error=error) - - if (allocated(error)) return - - call check_target(targets(2)%ptr,type=FPM_TARGET_OBJECT,n_depends=0, & - source=model%packages(1)%sources(1),error=error) - - if (allocated(error)) return - - call check_target(targets(3)%ptr,type=FPM_TARGET_OBJECT,n_depends=1, & - deps=[targets(2)],source=model%packages(1)%sources(2),error=error) - - if (allocated(error)) return - - call check_target(targets(4)%ptr,type=FPM_TARGET_EXECUTABLE,n_depends=2, & - deps=[targets(1),targets(3)], & - links=[targets(3)], error=error) - - if (allocated(error)) return - - end subroutine test_scope - - end subroutine test_program_module_use - - - !> Check program with module in single source file - !> (Resulting target should not include itself as a dependency) - subroutine test_program_with_module(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(fpm_model_t) :: model - type(build_target_ptr), allocatable :: targets(:) - - allocate(model%external_modules(0)) - allocate(model%packages(1)) - allocate(model%packages(1)%sources(1)) - - model%package_name = "test_program_with_module" - model%build_prefix = "" - model%packages(1)%name = "package1" - - model%packages(1)%sources(1) = new_test_source(FPM_UNIT_PROGRAM,file_name="app/my_program.f90", & - scope = FPM_SCOPE_APP, & - provides=[string_t('app_mod')], & - uses=[string_t('app_mod')]) - - call targets_from_sources(targets,model,.false.,error=error) - if (allocated(error)) return - - if (size(targets) /= 2) then - write(*,*) size(targets) - call test_failed(error,'Incorrect number of targets - expecting two') - return - end if - - call check_target(targets(1)%ptr,type=FPM_TARGET_OBJECT,n_depends=0, & - source=model%packages(1)%sources(1),error=error) - - if (allocated(error)) return - - call check_target(targets(2)%ptr,type=FPM_TARGET_EXECUTABLE,n_depends=1, & - deps=[targets(1)],links=[targets(1)],error=error) - - if (allocated(error)) return - - end subroutine test_program_with_module - - - !> Check program using modules in same directory - subroutine test_program_own_module_use(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - call test_scope(FPM_SCOPE_APP,error) - if (allocated(error)) return - - call test_scope(FPM_SCOPE_TEST,error) - if (allocated(error)) return - - contains - - subroutine test_scope(exe_scope,error) - integer, intent(in) :: exe_scope - type(error_t), allocatable, intent(out) :: error - - type(fpm_model_t) :: model - type(build_target_ptr), allocatable :: targets(:) - character(:), allocatable :: scope_str - - allocate(model%external_modules(0)) - allocate(model%packages(1)) - allocate(model%packages(1)%sources(3)) - - model%package_name = "test_scope" - model%build_prefix = "" - model%packages(1)%name = "package1" - - scope_str = merge('FPM_SCOPE_APP ','FPM_SCOPE_TEST',exe_scope==FPM_SCOPE_APP)//' - ' - - model%packages(1)%sources(1) = new_test_source(FPM_UNIT_MODULE,file_name="app/app_mod1.f90", & - scope = exe_scope, & - provides=[string_t('app_mod1')]) - - model%packages(1)%sources(2) = new_test_source(FPM_UNIT_MODULE,file_name="app/app_mod2.f90", & - scope = exe_scope, & - provides=[string_t('app_mod2')],uses=[string_t('app_mod1')]) - - model%packages(1)%sources(3) = new_test_source(FPM_UNIT_PROGRAM,file_name="app/my_program.f90", & - scope=exe_scope, & - uses=[string_t('app_mod2')]) - - call targets_from_sources(targets,model,.false.,error=error) - if (allocated(error)) return - - if (size(targets) /= 4) then - call test_failed(error,scope_str//'Incorrect number of targets - expecting three') - return - end if - - call check_target(targets(1)%ptr,type=FPM_TARGET_OBJECT,n_depends=0, & - source=model%packages(1)%sources(1),error=error) - - if (allocated(error)) return - - call check_target(targets(2)%ptr,type=FPM_TARGET_OBJECT,n_depends=1, & - source=model%packages(1)%sources(2),deps=[targets(1)],error=error) - - if (allocated(error)) return - - call check_target(targets(3)%ptr,type=FPM_TARGET_OBJECT,n_depends=1, & - source=model%packages(1)%sources(3),deps=[targets(2)],error=error) - - if (allocated(error)) return - - call check_target(targets(4)%ptr,type=FPM_TARGET_EXECUTABLE,n_depends=1, & - deps=[targets(3)],links=targets(1:3), error=error) - - if (allocated(error)) return - - end subroutine test_scope - end subroutine test_program_own_module_use - - - !> Check missing library module dependency - subroutine test_missing_library_use(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(fpm_model_t) :: model - type(build_target_ptr), allocatable :: targets(:) - - allocate(model%external_modules(0)) - allocate(model%packages(1)) - allocate(model%packages(1)%sources(2)) - - model%package_name = "test_missing_library_use" - model%build_prefix = "" - model%packages(1)%name = "package1" - - model%packages(1)%sources(1) = new_test_source(FPM_UNIT_MODULE,file_name="src/my_mod_1.f90", & - scope = FPM_SCOPE_LIB, & - provides=[string_t('my_mod_1')]) - - model%packages(1)%sources(2) = new_test_source(FPM_UNIT_MODULE,file_name="src/my_mod_2.f90", & - scope = FPM_SCOPE_LIB, & - provides=[string_t('my_mod_2')], & - uses=[string_t('my_mod_3')]) - - call targets_from_sources(targets,model,.false.,error=error) - - end subroutine test_missing_library_use - - - !> Check missing program module dependency - subroutine test_missing_program_use(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(fpm_model_t) :: model - type(build_target_ptr), allocatable :: targets(:) - - allocate(model%external_modules(0)) - allocate(model%packages(1)) - allocate(model%packages(1)%sources(2)) - - model%package_name = "test_missing_program_use" - model%build_prefix = "" - model%packages(1)%name = "package1" - - model%packages(1)%sources(1) = new_test_source(FPM_UNIT_MODULE,file_name="src/my_mod_1.f90", & - scope = FPM_SCOPE_LIB, & - provides=[string_t('my_mod_1')]) - - model%packages(1)%sources(2) = new_test_source(FPM_UNIT_PROGRAM,file_name="app/my_program.f90", & - scope=FPM_SCOPE_APP, & - uses=[string_t('my_mod_2')]) - - call targets_from_sources(targets,model,.false.,error=error) - - end subroutine test_missing_program_use - - - !> Check library module using a non-library module - subroutine test_invalid_library_use(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(fpm_model_t) :: model - type(build_target_ptr), allocatable :: targets(:) - - allocate(model%external_modules(0)) - allocate(model%packages(1)) - allocate(model%packages(1)%sources(2)) - - model%package_name = "test_invalid_library_use" - model%build_prefix = "" - model%packages(1)%name = "package1" - - model%packages(1)%sources(1) = new_test_source(FPM_UNIT_MODULE,file_name="app/app_mod.f90", & - scope = FPM_SCOPE_APP, & - provides=[string_t('app_mod')]) - - model%packages(1)%sources(2) = new_test_source(FPM_UNIT_MODULE,file_name="src/my_mod.f90", & - scope = FPM_SCOPE_LIB, & - provides=[string_t('my_mod')], & - uses=[string_t('app_mod')]) - - call targets_from_sources(targets,model,.false.,error=error) - - end subroutine test_invalid_library_use - - - !> Check program using a non-library module in a sub-directory - subroutine test_subdirectory_module_use(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(fpm_model_t) :: model - type(build_target_ptr), allocatable :: targets(:) - - allocate(model%external_modules(0)) - allocate(model%packages(1)) - allocate(model%packages(1)%sources(2)) - - model%package_name = "test_subdirectory_module_use" - model%build_prefix = "" - model%packages(1)%name = "package1" - - model%packages(1)%sources(1) = new_test_source(FPM_UNIT_MODULE,file_name="app/subdir/app_mod.f90", & - scope = FPM_SCOPE_APP, & - provides=[string_t('app_mod')]) - - model%packages(1)%sources(2) = new_test_source(FPM_UNIT_PROGRAM,file_name="app/my_program.f90", & - scope=FPM_SCOPE_APP, & - uses=[string_t('app_mod')]) - - call targets_from_sources(targets,model,.false.,error=error) - - end subroutine test_subdirectory_module_use - - !> Check program with no duplicate modules - subroutine test_package_with_no_module_duplicates(error) - - type(error_t), allocatable, intent(out) :: error - - type(fpm_model_t) :: model - logical :: duplicates_found = .false. - - allocate(model%packages(1)) - allocate(model%packages(1)%sources(2)) - - model%package_name = "test_package_with_no_module_duplicates" - model%build_prefix = "" - model%packages(1)%name = "package1" - - model%packages(1)%sources(1) = new_test_source(FPM_UNIT_MODULE,file_name="src/my_mod_1.f90", & - scope = FPM_SCOPE_LIB, provides=[string_t('my_mod_1')]) - - model%packages(1)%sources(2) = new_test_source(FPM_UNIT_MODULE,file_name="src/my_mod_2.f90", & - scope = FPM_SCOPE_LIB, provides=[string_t('my_mod_2')]) - - call check_modules_for_duplicates(model, duplicates_found) - if (duplicates_found) then - call test_failed(error,'Duplicate modules found') - return - end if - end subroutine test_package_with_no_module_duplicates - - !> Check program with duplicate modules in same source file - subroutine test_package_module_duplicates_same_source(error) - - type(error_t), allocatable, intent(out) :: error - - type(fpm_model_t) :: model - logical :: duplicates_found - - allocate(model%packages(1)) - allocate(model%packages(1)%sources(1)) - - model%package_name = "test_package_module_duplicates_same_source" - model%build_prefix = "" - model%packages(1)%name = "package1" - - model%packages(1)%sources(1) = new_test_source(FPM_UNIT_MODULE,file_name="src/my_mod_1.f90", & - scope = FPM_SCOPE_LIB, provides=[string_t('my_mod_1'), string_t('my_mod_1')]) - - call check_modules_for_duplicates(model, duplicates_found) - if (duplicates_found) then - call test_failed(error,'Duplicate modules found') - return - end if - end subroutine test_package_module_duplicates_same_source - - !> Check program with duplicate modules in two different source files in one package - subroutine test_package_module_duplicates_one_package(error) - - type(error_t), allocatable, intent(out) :: error - - type(fpm_model_t) :: model - logical :: duplicates_found - - allocate(model%packages(1)) - allocate(model%packages(1)%sources(2)) - - model%package_name = "test_package_module_duplicates_one_package" - model%build_prefix = "" - model%packages(1)%name = "package1" - - model%packages(1)%sources(1) = new_test_source(FPM_UNIT_MODULE,file_name="src/my_mod_1_a.f90", & - scope = FPM_SCOPE_LIB, provides=[string_t('my_mod_1')]) - - model%packages(1)%sources(2) = new_test_source(FPM_UNIT_MODULE,file_name="src/my_mod_1_b.f90", & - scope = FPM_SCOPE_LIB, provides=[string_t('my_mod_1')]) - - call check_modules_for_duplicates(model, duplicates_found) - if (duplicates_found) then - call test_failed(error,'Duplicate modules found') - return - end if - end subroutine test_package_module_duplicates_one_package - - !> Check program with duplicate modules in two different packages - subroutine test_package_module_duplicates_two_packages(error) - - type(error_t), allocatable, intent(out) :: error - - type(fpm_model_t) :: model - logical :: duplicates_found - - allocate(model%packages(2)) - allocate(model%packages(1)%sources(1)) - allocate(model%packages(2)%sources(1)) - - model%package_name = "test_package_module_duplicates_two_packages" - model%build_prefix = "" - model%packages(1)%name = "package1" - model%packages(2)%name = "package2" - - model%packages(1)%sources(1) = new_test_source(FPM_UNIT_MODULE,file_name="src/subdir1/my_mod_1.f90", & - scope = FPM_SCOPE_LIB, provides=[string_t('my_mod_1')]) - - model%packages(2)%sources(1) = new_test_source(FPM_UNIT_MODULE,file_name="src/subdir2/my_mod_1.f90", & - scope = FPM_SCOPE_LIB, provides=[string_t('my_mod_1')]) - - call check_modules_for_duplicates(model, duplicates_found) - if (duplicates_found) then - call test_failed(error,'Duplicate modules found') - return - end if - end subroutine test_package_module_duplicates_two_packages - - - !> Check tree-shaking of unused modules - !> Unused module should not be included in targets - subroutine test_tree_shake_module(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(fpm_model_t) :: model - type(build_target_ptr), allocatable :: targets(:) - character(:), allocatable :: scope_str - - allocate(model%external_modules(0)) - allocate(model%packages(1)) - allocate(model%packages(1)%sources(4)) - - model%package_name = "test_tree_shake_module" - model%build_prefix = "" - model%packages(1)%name = "package1" - - model%packages(1)%sources(1) = new_test_source(FPM_UNIT_MODULE,file_name="src/my_mod_1.f90", & - scope = FPM_SCOPE_LIB, & - provides=[string_t('my_mod_1')]) ! indirectly used - - model%packages(1)%sources(2) = new_test_source(FPM_UNIT_MODULE,file_name="src/my_mod_2.f90", & - scope = FPM_SCOPE_LIB, & - provides=[string_t('my_mod_2')], & - uses=[string_t('my_mod_1')]) ! directly used - - model%packages(1)%sources(3) = new_test_source(FPM_UNIT_MODULE,file_name="src/my_mod_3.f90", & - scope = FPM_SCOPE_LIB, & - provides=[string_t('my_mod_3')]) ! unused module - - model%packages(1)%sources(4) = new_test_source(FPM_UNIT_PROGRAM,file_name="app/my_program.f90", & - scope=FPM_SCOPE_APP, & - uses=[string_t('my_mod_2')]) - - call targets_from_sources(targets,model,prune=.true.,error=error) - if (allocated(error)) return - - if (size(targets) /= 5) then - call test_failed(error,scope_str//'Incorrect number of targets - expecting five') - return - end if - - call check_target(targets(1)%ptr,type=FPM_TARGET_ARCHIVE,n_depends=2, & - deps=[targets(2),targets(3)], & - links=[targets(2),targets(3)],error=error) - - if (allocated(error)) return - - call check_target(targets(2)%ptr,type=FPM_TARGET_OBJECT,n_depends=0, & - source=model%packages(1)%sources(1),error=error) - - if (allocated(error)) return - - call check_target(targets(3)%ptr,type=FPM_TARGET_OBJECT,n_depends=1, & - deps=[targets(2)],source=model%packages(1)%sources(2),error=error) - - if (allocated(error)) return - - call check_target(targets(4)%ptr,type=FPM_TARGET_OBJECT,n_depends=1, & - deps=[targets(3)],source=model%packages(1)%sources(4),error=error) - - if (allocated(error)) return - - call check_target(targets(5)%ptr,type=FPM_TARGET_EXECUTABLE,n_depends=2, & - deps=[targets(1),targets(4)], & - links=[targets(4)], error=error) - - if (allocated(error)) return - - end subroutine test_tree_shake_module - - - !> Check tree-shaking of modules used via a subprogram source - !> (Subprogram type is a source containing any non-module subroutines/functions) - !> Subprograms cannot be pruned, so neither can their dependencies - subroutine test_tree_shake_subprogram_with_module(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(fpm_model_t) :: model - type(build_target_ptr), allocatable :: targets(:) - character(:), allocatable :: scope_str - - allocate(model%external_modules(0)) - allocate(model%packages(1)) - allocate(model%packages(1)%sources(4)) - - model%package_name = "test_tree_shake_subprogram_with_module" - model%build_prefix = "" - model%packages(1)%name = "package1" - - model%packages(1)%sources(1) = new_test_source(FPM_UNIT_MODULE,file_name="src/my_mod_1.f90", & - scope = FPM_SCOPE_LIB, & - provides=[string_t('my_mod_1')]) ! used via subprogram - - model%packages(1)%sources(2) = new_test_source(FPM_UNIT_SUBPROGRAM,file_name="src/my_subprogram.f90", & - scope = FPM_SCOPE_LIB, & - uses=[string_t('my_mod_1')]) ! subprogram (never pruned) - - model%packages(1)%sources(3) = new_test_source(FPM_UNIT_MODULE,file_name="src/my_mod_3.f90", & - scope = FPM_SCOPE_LIB, & - provides=[string_t('my_mod_3')]) ! unused module - - model%packages(1)%sources(4) = new_test_source(FPM_UNIT_PROGRAM,file_name="app/my_program.f90", & - scope=FPM_SCOPE_APP) - - call targets_from_sources(targets,model,prune=.true.,error=error) - if (allocated(error)) return - - if (size(targets) /= 5) then - call test_failed(error,scope_str//'Incorrect number of targets - expecting five') - return - end if - - call check_target(targets(1)%ptr,type=FPM_TARGET_ARCHIVE,n_depends=2, & - deps=[targets(2)], & - links=[targets(2),targets(3)],error=error) - - if (allocated(error)) return - - call check_target(targets(2)%ptr,type=FPM_TARGET_OBJECT,n_depends=0, & - source=model%packages(1)%sources(1),error=error) - - if (allocated(error)) return - - call check_target(targets(3)%ptr,type=FPM_TARGET_OBJECT,n_depends=1, & - deps=[targets(2)],source=model%packages(1)%sources(2),error=error) - - if (allocated(error)) return - - call check_target(targets(4)%ptr,type=FPM_TARGET_OBJECT,n_depends=0, & - source=model%packages(1)%sources(4),error=error) - - if (allocated(error)) return - - call check_target(targets(5)%ptr,type=FPM_TARGET_EXECUTABLE,n_depends=2, & - deps=[targets(1),targets(4)], & - links=[targets(4)], error=error) - - if (allocated(error)) return - - end subroutine test_tree_shake_subprogram_with_module - - - !> Check program using a non-library module in a differente sub-directory - subroutine test_invalid_subdirectory_module_use(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(fpm_model_t) :: model - type(build_target_ptr), allocatable :: targets(:) - - allocate(model%external_modules(0)) - allocate(model%packages(1)) - allocate(model%packages(1)%sources(2)) - - model%package_name = "test_invalid_subdirectory_module_use" - model%build_prefix = "" - model%packages(1)%name = "package1" - - model%packages(1)%sources(1) = new_test_source(FPM_UNIT_MODULE,file_name="app/diff_dir/app_mod.f90", & - scope = FPM_SCOPE_APP, & - provides=[string_t('app_mod')]) - - model%packages(1)%sources(2) = new_test_source(FPM_UNIT_PROGRAM,file_name="app/prog_dir/my_program.f90", & - scope=FPM_SCOPE_APP, & - uses=[string_t('app_mod')]) - - call targets_from_sources(targets,model,.false.,error=error) - - end subroutine test_invalid_subdirectory_module_use - - !> Helper to create a new srcfile_t - function new_test_source(type,file_name, scope, uses, provides) result(src) - integer, intent(in) :: type - character(*), intent(in) :: file_name - integer, intent(in) :: scope - type(string_t), intent(in), optional :: uses(:) - type(string_t), intent(in), optional :: provides(:) - type(srcfile_t) :: src - - src%file_name = file_name - src%unit_scope = scope - src%unit_type = type - - if (present(provides)) then - src%modules_provided = provides - else - allocate(src%modules_provided(0)) - end if - - if (present(uses)) then - src%modules_used = uses - else - allocate(src%modules_used(0)) - end if - - allocate(src%include_dependencies(0)) - - end function new_test_source - - - !> Helper to check an expected output target - subroutine check_target(target,type,n_depends,deps,links,source,error) - type(build_target_t), intent(in) :: target - integer, intent(in) :: type - integer, intent(in) :: n_depends - type(srcfile_t), intent(in), optional :: source - type(build_target_ptr), intent(in), optional :: deps(:) - type(build_target_ptr), intent(in), optional :: links(:) - type(error_t), intent(out), allocatable :: error - - integer :: i - - if (target%target_type /= type) then - call test_failed(error,'Unexpected target_type for target "'//target%output_file//'"') - return - end if - - if (size(target%dependencies) /= n_depends) then - call test_failed(error,'Wrong number of dependencies for target "'//target%output_file//'"') - return - end if - - if (present(deps)) then - - do i=1,size(deps) - - if (.not.(deps(i)%ptr .in. target%dependencies)) then - call test_failed(error,'Missing dependency ('//deps(i)%ptr%output_file//& - ') for target "'//target%output_file//'"') - return - end if - - end do - - end if - - if (present(links)) then - - do i=1,size(links) - - if (.not.(links(i)%ptr%output_file .in. target%link_objects)) then - call test_failed(error,'Missing object ('//links(i)%ptr%output_file//& - ') for executable "'//target%output_file//'"') - return - end if - - end do - - if (size(links) > size(target%link_objects)) then - - call test_failed(error,'There are missing link objects for target "'& - //target%output_file//'"') - return - - elseif (size(links) < size(target%link_objects)) then - - call test_failed(error,'There are more link objects than expected for target "'& - //target%output_file//'"') - return - - end if - - end if - - if (present(source)) then - - if (allocated(target%source)) then - if (target%source%file_name /= source%file_name) then - call test_failed(error,'Incorrect source ('//target%source%file_name//') for target "'//& - target%output_file//'"'//new_line('a')//' expected "'//source%file_name//'"') - return - end if - - else - call test_failed(error,'Expecting source for target "'//target%output_file//'" but none found') - return - end if - - else - - if (allocated(target%source)) then - call test_failed(error,'Found source ('//target%source%file_name//') for target "'//& - target%output_file//'" but none expected') - return - end if - - end if - - end subroutine check_target - - !> Check several module names whose name is valid and begins with the package name - subroutine check_valid_enforced_module_names(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - integer :: i,j - type(string_t) :: package,modules,prefix - logical, parameter :: enforcing(2) = [.false.,.true.] - character(*), parameter :: package_name = 'my_pkg' - character(len=80), parameter :: module_names(*) = [ character(len=80) :: & - 'my_pkg__mod_1', & - 'my_pkg___mod_1', & - 'my_pkg____mod_1', & - 'my_pkg', & - 'my_pkg__1', & - 'my_pkg__my_pkg' ] - - - package = string_t(package_name) - prefix = string_t("") ! Prefix not used - - do i=1,size(module_names) - - modules = string_t(module_names(i)) - - !> All these names are valid both with and without enforcing - do j=1,2 - if (.not.is_valid_module_name(modules,package,prefix,enforcing(j))) then - call test_failed(error,'Valid dummy module name ['//modules%s//'] of package ['// & - package%s//'] unexpectedly fails naming check (enforcing='// & - merge('T','F',enforcing(j))//').') - return - endif - end do - end do - - end subroutine check_valid_enforced_module_names - - !> Check several module names whose name is valid and begins with the package name - subroutine check_valid_enforced_module_names_dashed(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - integer :: i,j - type(string_t) :: package,modules,prefix - logical, parameter :: enforcing(2) = [.false.,.true.] - character(*), parameter :: package_name = 'my-pkg' - character(len=80), parameter :: module_names(*) = [ character(len=80) :: & - 'my_pkg__mod_1', & - 'my_pkg___mod_1', & - 'my_pkg____mod_1', & - 'my_pkg', & - 'my_pkg__1', & - 'my_pkg__my_pkg' ] - - - package = string_t(package_name) - prefix = string_t("") ! Prefix not used - - do i=1,size(module_names) - - modules = string_t(trim(module_names(i))) - - !> All these names are valid both with and without enforcing - do j=1,2 - if (.not.is_valid_module_name(modules,package,prefix,enforcing(j))) then - call test_failed(error,'Valid dummy module name ['//modules%s//'] of package ['// & - package%s//'] unexpectedly fails naming check (enforcing='// & - merge('T','F',enforcing(j))//').') - return - endif - end do - end do - - end subroutine check_valid_enforced_module_names_dashed - - !> Check several module names whose name is invalid - subroutine check_invalid_enforced_module_names(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - integer :: i - type(string_t) :: package,modules,prefix - character(*), parameter :: package_name = 'my_pkg' - character(len=80), parameter :: module_names(*) = [ character(len=80) :: & - 'mod_1', & - 'my_pkmod_1', & - 'my_mod_1', & - 'pkg_mod_1', & - 'y_pkg_mod_1', & - '_my_pkg_mod_1', & - 'my_pkgmy_mod', & - 'my_pkg_', & - 'my_pkg__' ] - - - package = string_t(package_name) - prefix = string_t("") ! Prefix not used - - !> All these cases should report an invalid name - do i=1,size(module_names) - - modules = string_t(trim(module_names(i))) - - if (is_valid_module_name(modules,package,prefix,.true.)) then - call test_failed(error,'Invalid dummy module name ['//modules%s//'] of package ['// & - package%s//'] unexpectedly passes naming check (enforcing=T).') - return - end if - - end do - - end subroutine check_invalid_enforced_module_names - - !> Check module names whose name does not name the convention: - !> - Begin with a literal - !> - len(name)<=63 - !> - Contains literals, numbers, or underscores only - subroutine check_invalid_module_names(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - integer :: i - type(string_t) :: modules,package,prefix - - !> Examples taken from Metcalf/Reid/Cohen - character(len=80), parameter :: module_names(*) = [ character(len=80) :: & - '1a', & - 'a thing', & - '$sign', & - '_begin_with_underscore', & - 'contains-dashes', & - 'and/other?symbols@2' ] - - package = string_t("") - prefix = string_t("") ! Prefix not used - - !> All these cases should report an invalid name - do i=1,size(module_names) - - modules = string_t(module_names(i)) - - if (is_valid_module_name(modules,package,prefix,.false.)) then - call test_failed(error,'Invalid Fortran module name ['//modules%s//'] ' & - //' unexpectedly passes naming check.') - return - end if - - end do - - end subroutine check_invalid_module_names - - !> Check several module prefixes that are valid - subroutine check_valid_custom_prefix(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - integer :: i - type(string_t) :: prefix - character(len=80), parameter :: valid_prefixes(*) = [ character(len=80) :: & - 'm', & - 'mp', & - 'mypkg', & - 'mypkg123', & - 'mypackage', & - 'tomlf' ] - - character(len=80), parameter :: invalid_prefixes(*) = [ character(len=80) :: & - 'm_', & - 'm-p', & - 'my_pkg', & - 'my-pkg123', & - 'my package', & - 'toml-f', & - '123pkg', & - 'mypkg_' ] - ! All valid - do i=1,size(valid_prefixes) - - prefix = string_t(valid_prefixes(i)) - - !> All these names are valid both with and without enforcing - if (.not.is_valid_module_prefix(prefix)) then - call test_failed(error,'Valid dummy module prefix ['//prefix%s//'] '//& - ' unexpectedly fails naming check.') - return - endif - end do - - ! All invalid - do i=1,size(invalid_prefixes) - - prefix = string_t(invalid_prefixes(i)) - - !> All these names are valid both with and without enforcing - if (is_valid_module_prefix(prefix)) then - call test_failed(error,'Invalid dummy module prefix ['//prefix%s//'] '//& - ' unexpectedly passed naming check.') - return - endif - end do - - end subroutine check_valid_custom_prefix - - !> Check several module prefixes that are valid - subroutine check_custom_prefixed_modules(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - integer :: i - type(string_t) :: prefix,modules,package - character(len=*), parameter :: custom_prefix = 'mp123' - character(len=*), parameter :: package_name = 'my-package' - - character(len=80), parameter :: module_names(*) = [ character(len=80) :: & - 'mp123', & - 'mp123_utils', & - 'mp123__utils', & - 'mp123_test', & - 'mp123_my_module_name',& - 'my_package__utils',& - 'my_package',& - 'my_package__123'] - - character(len=80), parameter :: invalid_names(*) = [ character(len=80) :: & - 'utils', & - 'mp_123_utils', & - 'mypackage__utils', & - 'my_package_utils', & - 'my_package_test'] - - prefix = string_t(custom_prefix) - package = string_t(package_name) - - ! All valid - do i=1,size(module_names) - - modules = string_t(module_names(i)) - - !> All these names are valid both with and without enforcing - if (.not.is_valid_module_name(modules,package,prefix,.true.)) then - call test_failed(error,'Valid prefixed module ['//modules%s//'] ' //& - ' from package ['//package%s//'] with prefix ['//& - prefix%s//'] unexpectedly fails naming check.') - return - endif - end do - - ! All invalid - do i=1,size(invalid_names) - - modules = string_t(invalid_names(i)) - - !> All these names are valid both with and without enforcing - if (is_valid_module_name(modules,package,prefix,.true.)) then - call test_failed(error,'Invalid prefixed module ['//modules%s//'] ' //& - ' from package ['//package%s//'] with prefix ['//& - prefix%s//'] unexpectedly passed naming check.') - return - endif - end do - - end subroutine check_custom_prefixed_modules - - !> Helper to check if a build target is in a list of build_target_ptr - logical function target_in(needle,haystack) - type(build_target_t), intent(in), target :: needle - type(build_target_ptr), intent(in) :: haystack(:) - - integer :: i - - target_in = .false. - do i=1,size(haystack) - - if (associated(haystack(i)%ptr,needle)) then - target_in = .true. - return - end if - - end do - - end function target_in - - -end module test_module_dependencies diff --git a/test/fpm_test/test_os.f90 b/test/fpm_test/test_os.f90 deleted file mode 100644 index a0b5c11a79..0000000000 --- a/test/fpm_test/test_os.f90 +++ /dev/null @@ -1,306 +0,0 @@ -module test_os - use testsuite, only: new_unittest, unittest_t, error_t, test_failed - use fpm_filesystem, only: join_path, mkdir, os_delete_dir, is_dir, get_local_prefix, get_home - use fpm_environment, only: os_is_unix, get_env, set_env, delete_env - use fpm_os, only: get_absolute_path, get_absolute_path_by_cd, get_current_directory - - implicit none - private - public :: collect_os - - character(len=*), parameter :: tmp_folder = 'tmp' - -contains - - !> Collect unit tests. - subroutine collect_os(tests) - - !> Unit tests to collect. - type(unittest_t), allocatable, intent(out) :: tests(:) - - tests = [ & - & new_unittest('empty-path', empty_path, should_fail=.true.), & - & new_unittest('only-tilde', only_tilde), & - & new_unittest('set-environment-variable', set_environment), & - & new_unittest('invalid-tilde-path', invalid_tilde_path, should_fail=.true.), & - & new_unittest('tilde-correct-separator', tilde_correct_separator), & - & new_unittest('tilde-wrong-separator', tilde_wrong_separator, should_fail=.true.), & - & new_unittest('tilde-nonexistent-path', tilde_nonexistent_path, should_fail=.true.), & - & new_unittest('abs-path-nonexisting', abs_path_nonexisting, should_fail=.true.), & - & new_unittest('abs-path-root', abs_path_root), & - & new_unittest('abs-path-home', abs_path_home), & - & new_unittest('abs-path-cd-root', abs_path_home), & - & new_unittest('abs-path-cd-home', abs_path_cd_home), & - & new_unittest('abs-path-cd-current', abs_path_cd_current) & - ] - - end subroutine collect_os - - subroutine delete_tmp_folder - if (is_dir(tmp_folder)) call os_delete_dir(os_is_unix(), tmp_folder) - end - - subroutine empty_path(error) - type(error_t), allocatable, intent(out) :: error - character(len=:), allocatable :: result - call get_absolute_path('', result, error) - end - - subroutine only_tilde(error) - type(error_t), allocatable, intent(out) :: error - character(len=:), allocatable :: result - character(len=:), allocatable :: home - - call get_absolute_path('~', result, error) - - if (allocated(error)) then - call test_failed(error, "Unexpected error resolving '~'") - return - end if - - if (.not. allocated(result)) then - call test_failed(error, "Unexpected null result resolving '~'") - return - end if - - call get_home(home, error) - if (allocated(error)) return - - if (result /= home) then - call test_failed(error, "Result '"//result//"' doesn't equal home directory '"//home//"'") - return - end if - - end subroutine - - subroutine invalid_tilde_path(error) - type(error_t), allocatable, intent(out) :: error - character(len=:), allocatable :: result - call get_absolute_path('~a', result, error) - end - - subroutine tilde_correct_separator(error) - type(error_t), allocatable, intent(out) :: error - character(len=:), allocatable :: result - character(len=:), allocatable :: separator - character(len=:), allocatable :: home - - if (os_is_unix()) then - separator = '/' - else - separator = '\' - end if - - call get_absolute_path('~'//separator, result, error) - if (allocated(error)) return - - call get_home(home, error) - if (allocated(error)) return - - if (result /= home) then - call test_failed(error, "Result '"//result//"' doesn't equal home directory '"//home//"'") - return - end if - end - - subroutine tilde_wrong_separator(error) - type(error_t), allocatable, intent(out) :: error - character(len=:), allocatable :: result - character(len=:), allocatable :: separator - - if (os_is_unix()) then - separator = '\' - else - separator = '/' - end if - - call get_absolute_path('~'//separator, result, error) - end - - !> Entering a non-existing path with ~ should fail. - subroutine tilde_nonexistent_path(error) - type(error_t), allocatable, intent(out) :: error - character(len=:), allocatable :: result - call get_absolute_path('~/abcde', result, error) - end - - !> Entering a non-existing absolute path should fail. - subroutine abs_path_nonexisting(error) - type(error_t), allocatable, intent(out) :: error - character(len=:), allocatable :: result - call get_absolute_path('/abcde', result, error) - end - - !> Get the absolute path of the root directory. - subroutine abs_path_root(error) - type(error_t), allocatable, intent(out) :: error - - character(len=:), allocatable :: home_path, result - - if (os_is_unix()) then - call get_absolute_path('/', result, error) - if (allocated(error)) return - - if (result /= '/') then - call test_failed(error, "Result '"//result//"' doesn't equal input value: '/'"); return - end if - else - home_path = get_env('HOMEDRIVE','') //'\' - - call get_absolute_path(home_path, result, error) - if (allocated(error)) return - - if (result /= home_path) then - call test_failed(error, "Result '"//result//"' doesn't equal input value: '"//home_path//"'"); return - end if - end if - end - - !> Get the absolute path of the home directory. - subroutine abs_path_home(error) - type(error_t), allocatable, intent(out) :: error - - character(len=:), allocatable :: home, result - - call get_home(home, error) - if (allocated(error)) return - - call get_absolute_path(home, result, error) - if (allocated(error)) return - - if (result /= home) then - call test_failed(error, "Result '"//result//"' doesn't equal home directory '"//home//"'"); return - end if - end - - !> Get the absolute path of the root directory using `getcwd`/`_getcwd`. - subroutine abs_path_cd_root(error) - type(error_t), allocatable, intent(out) :: error - - character(len=:), allocatable :: home_path, current_dir_before, current_dir_after, result - - call get_current_directory(current_dir_before, error) - if (allocated(error)) return - - if (os_is_unix()) then - call get_absolute_path_by_cd('/', result, error) - - if (result /= '/') then - call test_failed(error, "Result '"//result//"' doesn't equal input value: '/'"); return - end if - else - home_path = get_env('HOMEDRIVE','')//'\' - - call get_absolute_path_by_cd(home_path, result, error) - - if (result /= home_path) then - call test_failed(error, "Result '"//result//"' doesn't equal input value: '"//home_path//"'"); return - end if - end if - - call get_current_directory(current_dir_after, error) - if (allocated(error)) return - - if (current_dir_before /= current_dir_after) then - call test_failed(error, "Current directory before getting absolute path '"//current_dir_before// & - & "' doesn't equal current directory after getting absolute path '"//current_dir_after//"'."); return - end if - end - - !> Get the absolute path of the root directory using `getcwd`/`_getcwd`. - subroutine abs_path_cd_home(error) - type(error_t), allocatable, intent(out) :: error - - character(len=:), allocatable :: home, current_dir_before, current_dir_after, result - - call get_current_directory(current_dir_before, error) - if (allocated(error)) return - - call get_home(home, error) - if (allocated(error)) return - - call get_absolute_path_by_cd(home, result, error) - if (allocated(error)) return - - call get_current_directory(current_dir_after, error) - if (allocated(error)) return - - if (current_dir_before /= current_dir_after) then - call test_failed(error, "Current directory before getting absolute path '"//current_dir_before// & - & "' doesn't equal current directory after getting absolute path '"//current_dir_after//"'."); return - end if - - if (result /= home) then - call test_failed(error, "Result '"//result//"' doesn't equal home directory '"//home//"'"); return - end if - end - - !> Get the absolute path of the current directory using `getcwd`/`_getcwd`. - subroutine abs_path_cd_current(error) - type(error_t), allocatable, intent(out) :: error - - character(len=:), allocatable :: current_dir, result - - call get_current_directory(current_dir, error) - if (allocated(error)) return - - call get_absolute_path_by_cd('.', result, error) - if (allocated(error)) return - - if (result /= current_dir) then - call test_failed(error, "Result '"//result//"' doesn't equal current directory '"//current_dir//"'"); return - end if - end - - !> Test creation and deletion of an environment variable - subroutine set_environment(error) - type(error_t), allocatable, intent(out) :: error - - character(*), parameter :: vname = 'hiufewhiugw' - character(*), parameter :: vvalue = '1234567890' - - character(:), allocatable :: old_value,new_value,final_value - logical :: success - - !> Ensure there's no such variable - old_value = get_env(vname,default='ERROR') - if (old_value/='ERROR') then - call test_failed(error, "There is already an env variable named "//vname) - return - end if - - !> Create variable - success = set_env(vname,value=vvalue) - if (.not.success) then - call test_failed(error, "Cannot create environment variable "//vname) - return - end if - - !> Check new value - new_value = get_env(vname,default='ERROR') - if (new_value/=vvalue) then - call test_failed(error, "Env "//vname//"="//new_value//'; expected '//vvalue) - return - end if - - !> Delete variable - success = delete_env(vname) - if (.not.success) then - call test_failed(error, "Cannot delete environment variable "//vname) - return - end if - - !> Ensure it does not exist anymore - !> Do not test this on Windows: due to a Windows bug, environment variables do not get deleted - !> https://developercommunity.visualstudio.com/t/-putenv-sname-doesnt-always-delete-windows-copy-of/1587426 - if (os_is_unix()) then - final_value = get_env(vname,default='ERROR') - if (final_value/='ERROR') then - call test_failed(error, "Env "//vname//"="//final_value//'; it should not exist.') - return - end if - endif - - end subroutine set_environment - -end module test_os diff --git a/test/fpm_test/test_package_dependencies.f90 b/test/fpm_test/test_package_dependencies.f90 deleted file mode 100644 index 76809b458e..0000000000 --- a/test/fpm_test/test_package_dependencies.f90 +++ /dev/null @@ -1,1579 +0,0 @@ -!> Define tests for the `fpm_dependency` module -module test_package_dependencies - use fpm_filesystem, only: get_temp_filename - use testsuite, only: new_unittest, unittest_t, error_t, test_failed - use fpm_filesystem, only: is_dir, join_path, filewrite, mkdir, os_delete_dir, exists - use fpm_environment, only: os_is_unix - use fpm_os, only: get_current_directory - use fpm_dependency - use fpm_manifest_dependency - use fpm_manifest_metapackages, only: metapackage_config_t - use fpm_manifest, only: package_config_t, get_package_data - use tomlf, only: toml_table, new_table - use fpm_toml, only: toml_key, add_table, set_value, get_value - use fpm_settings, only: fpm_global_settings, get_registry_settings, get_global_settings - use fpm_downloader, only: downloader_t - use fpm_versioning, only: version_t - use jonquil, only: json_object, json_value, json_loads, cast_to_object - - implicit none - private - - public :: collect_package_dependencies - - character(*), parameter :: tmp_folder = 'tmp' - character(*), parameter :: config_file_name = 'config.toml' - - type, extends(dependency_tree_t) :: mock_dependency_tree_t - contains - procedure, private :: resolve_dependency => resolve_dependency_once - end type mock_dependency_tree_t - - type, extends(downloader_t) :: mock_downloader_t - contains - procedure, nopass :: get_pkg_data, get_file, unpack => unpack_mock_package - end type mock_downloader_t - -contains - - !> Collect all exported unit tests - subroutine collect_package_dependencies(tests) - - !> Collection of tests - type(unittest_t), allocatable, intent(out) :: tests(:) - - tests = [ & - & new_unittest("cache-load-dump", test_cache_load_dump), & - & new_unittest("cache-dump-load", test_cache_dump_load), & - & new_unittest("status-after-load", test_status), & - & new_unittest("add-dependencies", test_add_dependencies), & - & new_unittest("update-dependencies", test_update_dependencies), & - & new_unittest("metapackage-override", test_metapackage_override), & - & new_unittest("do-not-update-dependencies", test_non_updated_dependencies), & - & new_unittest("registry-dir-not-found", registry_dir_not_found, should_fail=.true.), & - & new_unittest("no-versions-in-registry", no_versions_in_registry, should_fail=.true.), & - & new_unittest("local-registry-specified-version-not-found", local_registry_specified_version_not_found, should_fail=.true.), & - & new_unittest("local-registry-specified-no-manifest", local_registry_specified_no_manifest, should_fail=.true.), & - & new_unittest("local-registry-specified-has-manifest", local_registry_specified_has_manifest), & - & new_unittest("local-registry-specified-not-a-dir", local_registry_specified_not_a_dir, should_fail=.true.), & - & new_unittest("local-registry-unspecified-no-versions", local_registry_unspecified_no_versions, should_fail=.true.), & - & new_unittest("local-registry-unspecified-no-manifest", local_registry_unspecified_no_manifest, should_fail=.true.), & - & new_unittest("local-registry-unspecified-has-manifest", local_registry_unspecified_has_manifest), & - & new_unittest("cache-specified-version-found", cache_specified_version_found), & - & new_unittest("specified-version-not-found-in-cache", registry_specified_version_not_found_in_cache), & - & new_unittest("registry-specified-version-not-exists", registry_specified_version_not_exists, should_fail=.true.), & - & new_unittest("registry-specified-version-other-versions-exist", registry_specified_version_other_versions_exist), & - & new_unittest("registry-unspecified-version", registry_unspecified_version), & - & new_unittest("registry-unspecified-version_exists_in_cache", registry_unspecified_version_exists_in_cache), & - & new_unittest("pkg-data-no-code", pkg_data_no_code, should_fail=.true.), & - & new_unittest("pkg-data-corrupt-code", pkg_data_corrupt_code, should_fail=.true.), & - & new_unittest("pkg-data-missing-error-message", pkg_data_missing_error_msg, should_fail=.true.), & - & new_unittest("pkg-data-error-reading-message", pkg_data_error_reading_msg, should_fail=.true.), & - & new_unittest("pkg-data-error-has-message", pkg_data_error_has_msg, should_fail=.true.), & - & new_unittest("pkg-data-error-no-data", pkg_data_no_data, should_fail=.true.), & - & new_unittest("pkg-data-error-reading-data", pkg_data_error_reading_data, should_fail=.true.), & - & new_unittest("pkg-data-requested-version-wrong-key", pkg_data_requested_version_wrong_key, should_fail=.true.), & - & new_unittest("pkg-data-no-version-requested-wrong-key", pkg_data_no_version_requested_wrong_key, should_fail=.true.), & - & new_unittest("pkg-data-error-reading-latest-version", pkg_data_error_reading_latest_version, should_fail=.true.), & - & new_unittest("pkg-data-no-download-url", pkg_data_no_download_url, should_fail=.true.), & - & new_unittest("pkg-data-error-reading-donwload-url", pkg_data_error_reading_download_url, should_fail=.true.), & - & new_unittest("pkg-data-no-version", pkg_data_no_version, should_fail=.true.), & - & new_unittest("pkg-data-error-reading-version", pkg_data_error_reading_version, should_fail=.true.), & - & new_unittest("pkg-data-invalid-version", pkg_data_invalid_version, should_fail=.true.) & - & ] - - end subroutine collect_package_dependencies - - !> Round trip of the dependency cache from a dependency tree to a TOML document - !> to a dependency tree - subroutine test_cache_dump_load(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(dependency_tree_t) :: deps - type(dependency_config_t) :: dep - integer :: unit - - call new_dependency_tree(deps) - call resize(deps%dep, 5) - deps%ndep = 3 - dep%name = "dep1" - dep%path = "fpm-tmp1-dir" - call new_dependency_node(deps%dep(1), dep, proj_dir=dep%path) - dep%name = "dep2" - dep%path = "fpm-tmp2-dir" - call new_dependency_node(deps%dep(2), dep, proj_dir=dep%path) - dep%name = "dep3" - dep%path = "fpm-tmp3-dir" - call new_dependency_node(deps%dep(3), dep, proj_dir=dep%path) - - open (newunit=unit, status='scratch') - call deps%dump_cache(unit, error) - if (.not. allocated(error)) then - rewind (unit) - - call new_dependency_tree(deps) - call resize(deps%dep, 2) - call deps%load_cache(unit, error) - close (unit) - end if - if (allocated(error)) return - - if (deps%ndep /= 3) then - call test_failed(error, "Expected three dependencies in loaded cache") - return - end if - - end subroutine test_cache_dump_load - - !> Round trip of the dependency cache from a TOML data structure to - !> a dependency tree to a TOML data structure - subroutine test_cache_load_dump(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(toml_table), pointer :: ptr - type(toml_key), allocatable :: list(:) - type(dependency_tree_t) :: deps - - table = toml_table() - call add_table(table, "dep1", ptr) - call set_value(ptr, "version", "1.1.0") - call set_value(ptr, "proj-dir", "fpm-tmp1-dir") - call add_table(table, "dep2", ptr) - call set_value(ptr, "version", "0.55.3") - call set_value(ptr, "proj-dir", "fpm-tmp2-dir") - call set_value(ptr, "git", "https://github.com/fortran-lang/dep2") - call add_table(table, "dep3", ptr) - call set_value(ptr, "version", "20.1.15") - call set_value(ptr, "proj-dir", "fpm-tmp3-dir") - call set_value(ptr, "git", "https://gitlab.com/fortran-lang/dep3") - call set_value(ptr, "rev", "c0ffee") - call add_table(table, "dep4", ptr) - call set_value(ptr, "proj-dir", "fpm-tmp4-dir") - - call new_dependency_tree(deps) - call deps%load_cache(table, error) - if (allocated(error)) return - - if (deps%ndep /= 4) then - call test_failed(error, "Expected four dependencies in loaded cache") - return - end if - - call table%destroy - table = toml_table() - - call deps%dump_cache(table, error) - if (allocated(error)) return - - call table%get_keys(list) - - if (size(list) /= 4) then - call test_failed(error, "Expected four dependencies in dumped cache") - return - end if - - end subroutine test_cache_load_dump - - subroutine test_status(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(toml_table), pointer :: ptr - type(dependency_tree_t) :: deps - - table = toml_table() - call add_table(table, "dep1", ptr) - call set_value(ptr, "version", "1.1.0") - call set_value(ptr, "proj-dir", "fpm-tmp1-dir") - call add_table(table, "dep2", ptr) - call set_value(ptr, "version", "0.55.3") - call set_value(ptr, "proj-dir", "fpm-tmp2-dir") - call set_value(ptr, "git", "https://github.com/fortran-lang/dep2") - - call new_dependency_tree(deps) - call deps%load_cache(table, error) - if (allocated(error)) return - - if (deps%finished()) then - call test_failed(error, "Newly initialized dependency tree cannot be reolved") - return - end if - - end subroutine test_status - - subroutine test_add_dependencies(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(toml_table), pointer :: ptr - type(mock_dependency_tree_t) :: deps - type(dependency_config_t), allocatable :: nodes(:) - - table = toml_table() - call add_table(table, "sub1", ptr) - call set_value(ptr, "path", "external") - call add_table(table, "lin2", ptr) - call set_value(ptr, "git", "https://github.com/fortran-lang/lin2") - call add_table(table, "pkg3", ptr) - call set_value(ptr, "git", "https://gitlab.com/fortran-lang/pkg3") - call set_value(ptr, "rev", "c0ffee") - call add_table(table, "proj4", ptr) - call set_value(ptr, "path", "vendor") - - call new_dependencies(nodes, table, error=error) - if (allocated(error)) return - - call new_dependencies(nodes, table, root='.', error=error) - if (allocated(error)) return - - call new_dependency_tree(deps%dependency_tree_t) - call deps%add(nodes, error) - if (allocated(error)) return - - if (deps%finished()) then - call test_failed(error, "Newly added nodes cannot be already resolved") - return - end if - - if (deps%ndep /= 4) then - call test_failed(error, "Expected for dependencies in tree") - return - end if - - ! Do not use polymorphic version due to Ifort issue - call resolve_dependencies(deps, ".", error) - if (allocated(error)) return - - if (.not. deps%finished()) then - call test_failed(error, "Mocked dependency tree must resolve in one step") - return - end if - - end subroutine test_add_dependencies - - subroutine test_non_updated_dependencies(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: cache, manifest - type(toml_table), pointer :: ptr - type(toml_key), allocatable :: list(:) - type(dependency_tree_t) :: cached, manifest_deps - integer :: ii - - ! Create a dummy cache - cache = toml_table() - call add_table(cache, "dep1", ptr) - call set_value(ptr, "version", "1.1.0") - call set_value(ptr, "proj-dir", "fpm-tmp1-dir") - call add_table(cache, "dep2", ptr) - call set_value(ptr, "git", "https://gitlab.com/fortran-lang/lin2") - call set_value(ptr, "rev", "c0ffee") - call set_value(ptr, "proj-dir", "fpm-tmp1-dir") - call add_table(cache, "dep3", ptr) - call set_value(ptr, "git", "https://gitlab.com/fortran-lang/pkg3") - call set_value(ptr, "rev", "t4a") - call set_value(ptr, "proj-dir", "fpm-tmp1-dir") - call add_table(cache, "dep4", ptr) - call set_value(ptr, "version", "1.0.0") - call set_value(ptr, "proj-dir", "fpm-tmp1-dir") - - ! Load into a dependency tree - call new_dependency_tree(cached) - call cached%load_cache(cache, error) - if (allocated(error)) return - ! Mark all dependencies as "cached" - do ii=1,cached%ndep - cached%dep(ii)%cached = .true. - end do - call cache%destroy() - - ! Create a dummy manifest, with different version - manifest = toml_table() - call add_table(manifest, "dep1", ptr) - call set_value(ptr, "version", "1.1.1") - call set_value(ptr, "proj-dir", "fpm-tmp1-dir") - call add_table(manifest, "dep2", ptr) - call set_value(ptr, "git", "https://gitlab.com/fortran-lang/lin4") - call set_value(ptr, "rev", "c0ffee") - call set_value(ptr, "proj-dir", "fpm-tmp1-dir") - call add_table(manifest, "dep3", ptr) - call set_value(ptr, "git", "https://gitlab.com/fortran-lang/pkg3") - call set_value(ptr, "rev", "t4a") - call set_value(ptr, "proj-dir", "fpm-tmp1-dir") - - ! Load dependencies from manifest - call new_dependency_tree(manifest_deps) - call manifest_deps%load_cache(manifest, error) - call manifest%destroy() - if (allocated(error)) return - - ! Add cached dependencies afterwards; will flag those that need udpate - do ii=1,cached%ndep - cached%dep(ii)%cached = .true. - call manifest_deps%add(cached%dep(ii), error) - if (allocated(error)) return - end do - - ! Test that dependencies 1-2 are flagged as "update" - if (.not. manifest_deps%dep(1)%update) then - call test_failed(error, "Updated dependency (different version) not detected") - return - end if - if (.not. manifest_deps%dep(2)%update) then - call test_failed(error, "Updated dependency (git address) not detected") - return - end if - - ! Test that dependency 3 is flagged as "not update" - if (manifest_deps%dep(3)%update) then - call test_failed(error, "Updated dependency (git rev) detected, should not be") - return - end if - - end subroutine test_non_updated_dependencies - - subroutine test_update_dependencies(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: cache, manifest - type(toml_table), pointer :: ptr - type(toml_key), allocatable :: list(:) - type(dependency_tree_t) :: cached, manifest_deps - integer :: ii - - ! Create a dummy cache - cache = toml_table() - call add_table(cache, "dep1", ptr) - call set_value(ptr, "version", "1.1.0") - call set_value(ptr, "proj-dir", "fpm-tmp1-dir") - call add_table(cache, "dep2", ptr) - call set_value(ptr, "git", "https://gitlab.com/fortran-lang/lin2") - call set_value(ptr, "rev", "c0ffee") - call set_value(ptr, "proj-dir", "fpm-tmp1-dir") - call add_table(cache, "dep3", ptr) - call set_value(ptr, "git", "https://gitlab.com/fortran-lang/pkg3") - call set_value(ptr, "rev", "t4a") - call set_value(ptr, "proj-dir", "fpm-tmp1-dir") - call add_table(cache, "dep4", ptr) - call set_value(ptr, "version", "1.0.0") - call set_value(ptr, "proj-dir", "fpm-tmp1-dir") - - ! Load into a dependency tree - call new_dependency_tree(cached) - call cached%load_cache(cache, error) - if (allocated(error)) return - ! Mark all dependencies as "cached" - do ii=1,cached%ndep - cached%dep(ii)%cached = .true. - end do - call cache%destroy() - - ! Create a dummy manifest, with different version - manifest = toml_table() - call add_table(manifest, "dep1", ptr) - call set_value(ptr, "version", "1.1.1") - call set_value(ptr, "proj-dir", "fpm-tmp1-dir") - call add_table(manifest, "dep2", ptr) - call set_value(ptr, "git", "https://gitlab.com/fortran-lang/lin4") - call set_value(ptr, "rev", "c0ffee") - call set_value(ptr, "proj-dir", "fpm-tmp1-dir") - call add_table(manifest, "dep3", ptr) - call set_value(ptr, "git", "https://gitlab.com/fortran-lang/pkg3") - call set_value(ptr, "rev", "l4tte") - call set_value(ptr, "proj-dir", "fpm-tmp1-dir") - - ! Load dependencies from manifest - call new_dependency_tree(manifest_deps) - call manifest_deps%load_cache(manifest, error) - call manifest%destroy() - if (allocated(error)) return - - ! Add cached dependencies afterwards; will flag those that need udpate - do ii=1,cached%ndep - cached%dep(ii)%cached = .true. - call manifest_deps%add(cached%dep(ii), error) - if (allocated(error)) return - end do - - ! Test that all dependencies are flagged as "update" - if (.not. manifest_deps%dep(1)%update) then - call test_failed(error, "Updated dependency (different version) not detected") - return - end if - if (.not. manifest_deps%dep(2)%update) then - call test_failed(error, "Updated dependency (git address) not detected") - return - end if - if (.not. manifest_deps%dep(3)%update) then - call test_failed(error, "Updated dependency (git rev) not detected") - return - end if - - end subroutine test_update_dependencies - - - !> Test that a metapackage is overridden if a regular dependency is provided - subroutine test_metapackage_override(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: manifest - type(toml_table), pointer :: ptr - type(dependency_config_t), allocatable :: deps(:) - type(metapackage_config_t) :: meta - logical :: found - integer :: i - - ! Create a dummy manifest, with a standard git dependency for stdlib - manifest = toml_table() - call add_table(manifest, "stdlib", ptr) - call set_value(ptr, "git", "https://github.com/fortran-lang/stdlib") - call set_value(ptr, "branch", "stdlib-fpm") - - ! Load dependencies from manifest - call new_dependencies(deps, manifest, meta=meta, error=error) - if (allocated(error)) return - - ! Check that stdlib is in the regular dependency list - found = .false. - do i=1,size(deps) - if (deps(i)%name=="stdlib") found = .true. - end do - - if (.not.found) then - call test_failed(error,"standard git-based dependency for stdlib not recognized") - return - end if - call manifest%destroy() - - - ! Create a dummy manifest, with a version-based metapackage dependency for stdlib - manifest = toml_table() - call set_value(manifest, "stdlib", "*") - - ! Load dependencies from manifest - call new_dependencies(deps, manifest, meta=meta, error=error) - if (allocated(error)) return - - ! Check that stdlib is in the metapackage config and not the standard dependencies - found = .false. - do i=1,size(deps) - if (deps(i)%name=="stdlib") found = .true. - end do - - if (found) then - call test_failed(error,"metapackage dependency for stdlib should not be in the tree") - return - end if - call manifest%destroy() - - if (.not.meta%stdlib%on) then - call test_failed(error,"metapackage dependency for stdlib should be in the metapackage config") - return - end if - - end subroutine test_metapackage_override - - !> Directories for namespace and package name not found in path registry. - subroutine registry_dir_not_found(error) - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(dependency_node_t) :: node - type(fpm_global_settings) :: global_settings - character(len=:), allocatable :: target_dir - type(toml_table), pointer :: child - - call new_table(table) - table%key = 'test-dep' - call set_value(table, 'namespace', 'test-org') - - call new_dependency(node%dependency_config_t, table, error=error) - if (allocated(error)) return - - call delete_tmp_folder - call mkdir(join_path(tmp_folder, 'cache')) ! Missing directories for namesapce and package name - - call new_table(table) - call add_table(table, 'registry', child) - call set_value(child, 'path', 'cache') - - call setup_global_settings(global_settings, error) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - call get_registry_settings(child, global_settings, error) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - call node%get_from_registry(target_dir, global_settings, error) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - call delete_tmp_folder - - end subroutine registry_dir_not_found - - !> No versions found in path registry. - subroutine no_versions_in_registry(error) - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(dependency_node_t) :: node - type(fpm_global_settings) :: global_settings - character(len=:), allocatable :: target_dir - type(toml_table), pointer :: child - - call new_table(table) - table%key = 'test-dep' - call set_value(table, 'namespace', 'test-org') - - call new_dependency(node%dependency_config_t, table, error=error) - if (allocated(error)) return - - call delete_tmp_folder - call mkdir(join_path(tmp_folder, 'cache', 'test-org', 'test-dep')) - - call new_table(table) - call add_table(table, 'registry', child) - call set_value(child, 'path', 'cache') - - call setup_global_settings(global_settings, error) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - call get_registry_settings(child, global_settings, error) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - call node%get_from_registry(target_dir, global_settings, error) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - call delete_tmp_folder - - end subroutine no_versions_in_registry - - !> Specific version not found in the local registry. - subroutine local_registry_specified_version_not_found(error) - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(dependency_node_t) :: node - type(fpm_global_settings) :: global_settings - character(len=:), allocatable :: target_dir - type(toml_table), pointer :: child - - call new_table(table) - table%key = 'test-dep' - call set_value(table, 'namespace', 'test-org') - call set_value(table, 'v', '0.1.0') - - call new_dependency(node%dependency_config_t, table, error=error) - if (allocated(error)) return - - call delete_tmp_folder - call mkdir(join_path(tmp_folder, 'cache', 'test-org', 'test-dep', '0.0.9')) - call mkdir(join_path(tmp_folder, 'cache', 'test-org', 'test-dep', '0.1.1')) - - call new_table(table) - call add_table(table, 'registry', child) - call set_value(child, 'path', 'cache') - - call setup_global_settings(global_settings, error) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - call get_registry_settings(child, global_settings, error) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - call node%get_from_registry(target_dir, global_settings, error) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - call delete_tmp_folder - - end subroutine local_registry_specified_version_not_found - - !> Target package in path registry does not contain manifest. - subroutine local_registry_specified_no_manifest(error) - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(dependency_node_t) :: node - type(fpm_global_settings) :: global_settings - character(len=:), allocatable :: target_dir - type(toml_table), pointer :: child - - call new_table(table) - table%key = 'test-dep' - call set_value(table, 'namespace', 'test-org') - call set_value(table, 'v', '0.1.0') - - call new_dependency(node%dependency_config_t, table, error=error) - if (allocated(error)) return - - call delete_tmp_folder - call mkdir(join_path(tmp_folder, 'cache', 'test-org', 'test-dep', '0.0.9')) - call mkdir(join_path(tmp_folder, 'cache', 'test-org', 'test-dep', '0.1.0')) - call mkdir(join_path(tmp_folder, 'cache', 'test-org', 'test-dep', '0.1.1')) - - call new_table(table) - call add_table(table, 'registry', child) - call set_value(child, 'path', 'cache') - - call setup_global_settings(global_settings, error) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - call get_registry_settings(child, global_settings, error) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - call node%get_from_registry(target_dir, global_settings, error) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - call delete_tmp_folder - - end subroutine local_registry_specified_no_manifest - - !> Target package in path registry contains manifest. - subroutine local_registry_specified_has_manifest(error) - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(dependency_node_t) :: node - type(fpm_global_settings) :: global_settings - character(len=:), allocatable :: target_dir, cwd - type(toml_table), pointer :: child - - call new_table(table) - table%key = 'test-dep' - call set_value(table, 'namespace', 'test-org') - call set_value(table, 'v', '0.1.0') - - call new_dependency(node%dependency_config_t, table, error=error) - if (allocated(error)) return - - call delete_tmp_folder - call mkdir(join_path(tmp_folder, 'cache', 'test-org', 'test-dep', '0.0.0')) - call mkdir(join_path(tmp_folder, 'cache', 'test-org', 'test-dep', '0.1.0')) - call filewrite(join_path(join_path(tmp_folder, 'cache', 'test-org', 'test-dep', '0.1.0'), 'fpm.toml'), ['']) - call mkdir(join_path(tmp_folder, 'cache', 'test-org', 'test-dep', '0.2.0')) - - call new_table(table) - call add_table(table, 'registry', child) - call set_value(child, 'path', 'cache') - - call setup_global_settings(global_settings, error) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - call get_registry_settings(child, global_settings, error) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - call node%get_from_registry(target_dir, global_settings, error) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - call get_current_directory(cwd, error) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - if (target_dir /= join_path(cwd, join_path(tmp_folder, 'cache', 'test-org', 'test-dep', '0.1.0'))) then - call test_failed(error, 'target_dir not set correctly') - call delete_tmp_folder; return - end if - - call delete_tmp_folder - - end subroutine local_registry_specified_has_manifest - - !> Target is a file, not a directory. - subroutine local_registry_specified_not_a_dir(error) - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(dependency_node_t) :: node - type(fpm_global_settings) :: global_settings - character(len=:), allocatable :: target_dir - type(toml_table), pointer :: child - - call new_table(table) - table%key = 'test-dep' - call set_value(table, 'namespace', 'test-org') - - call new_dependency(node%dependency_config_t, table, error=error) - if (allocated(error)) return - - call delete_tmp_folder - call mkdir(join_path(tmp_folder, 'cache', 'test-org', 'test-dep')) - call filewrite(join_path(tmp_folder, 'cache', 'test-org', 'test-dep', '0.1.0'), ['']) ! File, not directory - - call new_table(table) - call add_table(table, 'registry', child) - call set_value(child, 'path', 'cache') - - call setup_global_settings(global_settings, error) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - call get_registry_settings(child, global_settings, error) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - call node%get_from_registry(target_dir, global_settings, error) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - call delete_tmp_folder - - end subroutine local_registry_specified_not_a_dir - - !> Try fetching the latest version in the local registry, but none are found. - !> Compared to no-versions-in-registry, we aren't requesting a specific version here. - subroutine local_registry_unspecified_no_versions(error) - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(dependency_node_t) :: node - type(fpm_global_settings) :: global_settings - character(len=:), allocatable :: target_dir - type(toml_table), pointer :: child - - call new_table(table) - table%key = 'test-dep' - call set_value(table, 'namespace', 'test-org') - - call new_dependency(node%dependency_config_t, table, error=error) - if (allocated(error)) return - - call delete_tmp_folder - call mkdir(join_path(tmp_folder, 'cache', 'test-org', 'test-dep')) - - call new_table(table) - call add_table(table, 'registry', child) - call set_value(child, 'path', 'cache') - - call setup_global_settings(global_settings, error) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - call get_registry_settings(child, global_settings, error) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - call node%get_from_registry(target_dir, global_settings, error) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - call delete_tmp_folder - - end subroutine local_registry_unspecified_no_versions - - !> Latest version in the local registry does not have a manifest. - subroutine local_registry_unspecified_no_manifest(error) - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(dependency_node_t) :: node - type(fpm_global_settings) :: global_settings - character(len=:), allocatable :: target_dir, cwd - type(toml_table), pointer :: child - - call new_table(table) - table%key = 'test-dep' - call set_value(table, 'namespace', 'test-org') - - call new_dependency(node%dependency_config_t, table, error=error) - if (allocated(error)) return - - call delete_tmp_folder - call mkdir(join_path(tmp_folder, 'cache', 'test-org', 'test-dep', '0.0.0')) - call mkdir(join_path(tmp_folder, 'cache', 'test-org', 'test-dep', '1.3.0')) - call mkdir(join_path(tmp_folder, 'cache', 'test-org', 'test-dep', '1.2.1')) - - call new_table(table) - call add_table(table, 'registry', child) - call set_value(child, 'path', 'cache') - - call setup_global_settings(global_settings, error) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - call get_registry_settings(child, global_settings, error) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - call node%get_from_registry(target_dir, global_settings, error) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - call get_current_directory(cwd, error) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - if (target_dir /= join_path(cwd, join_path(tmp_folder, 'cache', 'test-org', 'test-dep', '1.3.0'))) then - call test_failed(error, 'target_dir not set correctly: '//target_dir//"'") - call delete_tmp_folder; return - end if - - call delete_tmp_folder - - end subroutine local_registry_unspecified_no_manifest - - !> Latest version in the local registry has a manifest. - subroutine local_registry_unspecified_has_manifest(error) - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(dependency_node_t) :: node - type(fpm_global_settings) :: global_settings - character(len=:), allocatable :: target_dir, cwd - type(toml_table), pointer :: child - - call new_table(table) - table%key = 'test-dep' - call set_value(table, 'namespace', 'test-org') - - call new_dependency(node%dependency_config_t, table, error=error) - if (allocated(error)) return - - call delete_tmp_folder - call mkdir(join_path(tmp_folder, 'cache', 'test-org', 'test-dep', '0.0.0')) - call mkdir(join_path(tmp_folder, 'cache', 'test-org', 'test-dep', '1.3.0')) - call filewrite(join_path(join_path(tmp_folder, 'cache', 'test-org', 'test-dep', '1.3.0'), 'fpm.toml'), ['']) - call mkdir(join_path(tmp_folder, 'cache', 'test-org', 'test-dep', '1.2.1')) - - call new_table(table) - call add_table(table, 'registry', child) - call set_value(child, 'path', 'cache') - - call setup_global_settings(global_settings, error) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - call get_registry_settings(child, global_settings, error) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - call node%get_from_registry(target_dir, global_settings, error) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - call get_current_directory(cwd, error) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - if (target_dir /= join_path(cwd, join_path(tmp_folder, 'cache', 'test-org', 'test-dep', '1.3.0'))) then - call test_failed(error, 'target_dir not set correctly: '//target_dir//"'") - call delete_tmp_folder; return - end if - - call delete_tmp_folder - - end subroutine local_registry_unspecified_has_manifest - - !> Version specified in manifest, version found in cache. - subroutine cache_specified_version_found(error) - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(dependency_node_t) :: node - type(fpm_global_settings) :: global_settings - character(len=:), allocatable :: target_dir, cwd, path - type(toml_table), pointer :: child - - call new_table(table) - table%key = 'test-dep' - call set_value(table, 'namespace', 'test-org') - call set_value(table, 'v', '2.3.0') - - call new_dependency(node%dependency_config_t, table, error=error) - if (allocated(error)) return - - call delete_tmp_folder - path = join_path(tmp_folder, 'dependencies', 'test-org', 'test-dep', '2.3.0') - call mkdir(path) - call filewrite(join_path(path, 'fpm.toml'), ['']) - - call new_table(table) - call add_table(table, 'registry', child) ! No cache_path specified, use default - - call setup_global_settings(global_settings, error) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - call get_registry_settings(child, global_settings, error) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - call node%get_from_registry(target_dir, global_settings, error) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - call get_current_directory(cwd, error) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - if (target_dir /= join_path(cwd, join_path(tmp_folder, 'dependencies', 'test-org', 'test-dep', '2.3.0'))) then - call test_failed(error, "Target directory not set correctly: '"//target_dir//"'") - call delete_tmp_folder; return - end if - - call delete_tmp_folder - - end subroutine cache_specified_version_found - - !> Version specified in manifest, but not found in cache. Therefore download dependency. - subroutine registry_specified_version_not_found_in_cache(error) - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(dependency_node_t) :: node - type(fpm_global_settings) :: global_settings - character(len=:), allocatable :: target_dir, cwd - type(toml_table), pointer :: child - type(mock_downloader_t) :: mock_downloader - - call new_table(table) - table%key = 'test-dep' - call set_value(table, 'namespace', 'test-org') - call set_value(table, 'v', '0.1.0') - - call new_dependency(node%dependency_config_t, table, error=error) - if (allocated(error)) return - - call delete_tmp_folder - call mkdir(tmp_folder) ! Dependencies folder doesn't exist - - call new_table(table) - call add_table(table, 'registry', child) - - call setup_global_settings(global_settings, error) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - call get_registry_settings(child, global_settings, error) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - call node%get_from_registry(target_dir, global_settings, error, mock_downloader) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - call get_current_directory(cwd, error) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - if (target_dir /= join_path(cwd, join_path(tmp_folder, 'dependencies', 'test-org', 'test-dep', '0.1.0'))) then - call test_failed(error, "Target directory not set correctly: '"//target_dir//"'") - call delete_tmp_folder; return - end if - - call delete_tmp_folder - - end subroutine registry_specified_version_not_found_in_cache - - !> Version specified in manifest, but not found in cache or registry. - subroutine registry_specified_version_not_exists(error) - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(dependency_node_t) :: node - type(fpm_global_settings) :: global_settings - character(len=:), allocatable :: target_dir - type(toml_table), pointer :: child - type(mock_downloader_t) :: mock_downloader - - call new_table(table) - table%key = 'test-dep' - call set_value(table, 'namespace', 'test-org') - call set_value(table, 'v', '9.9.9') - - call new_dependency(node%dependency_config_t, table, error=error) - if (allocated(error)) return - - call delete_tmp_folder - call mkdir(tmp_folder) - - call new_table(table) - call add_table(table, 'registry', child) - - call setup_global_settings(global_settings, error) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - call get_registry_settings(child, global_settings, error) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - call node%get_from_registry(target_dir, global_settings, error, mock_downloader) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - call delete_tmp_folder - - end subroutine registry_specified_version_not_exists - - subroutine registry_specified_version_other_versions_exist(error) - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(dependency_node_t) :: node - type(fpm_global_settings) :: global_settings - character(len=:), allocatable :: target_dir - type(toml_table), pointer :: child - type(mock_downloader_t) :: mock_downloader - - call new_table(table) - table%key = 'test-dep' - call set_value(table, 'namespace', 'test-org') - call set_value(table, 'v', '0.1.0') - - call new_dependency(node%dependency_config_t, table, error=error) - if (allocated(error)) return - - call delete_tmp_folder - call mkdir(join_path(tmp_folder, 'dependencies', 'test-org', 'test-dep', '2.1.0')) - call mkdir(join_path(tmp_folder, 'dependencies', 'test-org', 'test-dep', '9.1.0')) - - call new_table(table) - call add_table(table, 'registry', child) - - call setup_global_settings(global_settings, error) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - call get_registry_settings(child, global_settings, error) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - call node%get_from_registry(target_dir, global_settings, error, mock_downloader) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - call delete_tmp_folder - - end subroutine registry_specified_version_other_versions_exist - - !> No version specified, get the newest version from the registry. - subroutine registry_unspecified_version(error) - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(dependency_node_t) :: node - type(fpm_global_settings) :: global_settings - character(len=:), allocatable :: target_dir, cwd - type(toml_table), pointer :: child - type(mock_downloader_t) :: mock_downloader - - call new_table(table) - table%key = 'test-dep' - call set_value(table, 'namespace', 'test-org') - - call new_dependency(node%dependency_config_t, table, error=error) - if (allocated(error)) return - - call delete_tmp_folder - call mkdir(tmp_folder) - - call new_table(table) - call add_table(table, 'registry', child) - - call setup_global_settings(global_settings, error) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - call get_registry_settings(child, global_settings, error) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - call node%get_from_registry(target_dir, global_settings, error, mock_downloader) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - call get_current_directory(cwd, error) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - if (target_dir /= join_path(cwd, join_path(tmp_folder, 'dependencies', 'test-org', 'test-dep', '0.1.0'))) then - call test_failed(error, "Target directory not set correctly: '"//target_dir//"'") - call delete_tmp_folder; return - end if - - call delete_tmp_folder - - end subroutine registry_unspecified_version - - !> No version specified, therefore load package data from the registry. Find out that there is a cached version of - !> the latest package. - subroutine registry_unspecified_version_exists_in_cache(error) - type(error_t), allocatable, intent(out) :: error - - type(toml_table) :: table - type(dependency_node_t) :: node - type(fpm_global_settings) :: global_settings - character(len=:), allocatable :: target_dir, cwd - type(toml_table), pointer :: child - type(mock_downloader_t) :: mock_downloader - - call new_table(table) - table%key = 'test-dep' - call set_value(table, 'namespace', 'test-org') - - call new_dependency(node%dependency_config_t, table, error=error) - if (allocated(error)) return - - call delete_tmp_folder - call mkdir(join_path(tmp_folder, 'cache', 'test-org', 'test-dep', '0.0.0')) - call mkdir(join_path(tmp_folder, 'cache', 'test-org', 'test-dep', '0.1.0')) - call filewrite(join_path(join_path(tmp_folder, 'cache', 'test-org', 'test-dep', '0.1.0'), 'fpm.toml'), ['']) - call mkdir(join_path(tmp_folder, 'cache', 'test-org', 'test-dep', '1.2.1')) - - call new_table(table) - call add_table(table, 'registry', child) - - call setup_global_settings(global_settings, error) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - call get_registry_settings(child, global_settings, error) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - call node%get_from_registry(target_dir, global_settings, error, mock_downloader) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - call get_current_directory(cwd, error) - if (allocated(error)) then - call delete_tmp_folder; return - end if - - if (target_dir /= join_path(cwd, join_path(tmp_folder, 'dependencies', 'test-org', 'test-dep', '0.1.0'))) then - call test_failed(error, "Target directory not set correctly: '"//target_dir//"'") - call delete_tmp_folder; return - end if - - call delete_tmp_folder - - end subroutine registry_unspecified_version_exists_in_cache - - !> Package data returned from the registry does not contain a code field. - subroutine pkg_data_no_code(error) - type(error_t), allocatable, intent(out) :: error - - type(dependency_node_t) :: node - character(:), allocatable :: url - type(version_t) :: version - type(json_object) :: json - class(json_value), allocatable :: j_value - - call json_loads(j_value, '{}') - json = cast_to_object(j_value) - - call check_and_read_pkg_data(json, node, url, version, error) - - end subroutine pkg_data_no_code - - !> Error reading status code from package data. - subroutine pkg_data_corrupt_code(error) - type(error_t), allocatable, intent(out) :: error - - type(dependency_node_t) :: node - character(:), allocatable :: url - type(version_t) :: version - type(json_object) :: json - class(json_value), allocatable :: j_value - - call json_loads(j_value, '{"code": "integer expected"}') - json = cast_to_object(j_value) - - call check_and_read_pkg_data(json, node, url, version, error) - - end subroutine pkg_data_corrupt_code - - subroutine pkg_data_missing_error_msg(error) - type(error_t), allocatable, intent(out) :: error - - type(dependency_node_t) :: node - character(:), allocatable :: url - type(version_t) :: version - type(json_object) :: json - class(json_value), allocatable :: j_value - - call json_loads(j_value, '{"code": 123}') - json = cast_to_object(j_value) - - call check_and_read_pkg_data(json, node, url, version, error) - - end subroutine pkg_data_missing_error_msg - - subroutine pkg_data_error_reading_msg(error) - type(error_t), allocatable, intent(out) :: error - - type(dependency_node_t) :: node - character(:), allocatable :: url - type(version_t) :: version - type(json_object) :: json - class(json_value), allocatable :: j_value - - call json_loads(j_value, '{"code": 123, "message": 123}') - json = cast_to_object(j_value) - - call check_and_read_pkg_data(json, node, url, version, error) - - end subroutine pkg_data_error_reading_msg - - subroutine pkg_data_error_has_msg(error) - type(error_t), allocatable, intent(out) :: error - - type(dependency_node_t) :: node - character(:), allocatable :: url - type(version_t) :: version - type(json_object) :: json - class(json_value), allocatable :: j_value - - call json_loads(j_value, '{"code": 123, "message": "Really bad error message"}') - json = cast_to_object(j_value) - - call check_and_read_pkg_data(json, node, url, version, error) - - end subroutine pkg_data_error_has_msg - - subroutine pkg_data_no_data(error) - type(error_t), allocatable, intent(out) :: error - - type(dependency_node_t) :: node - character(:), allocatable :: url - type(version_t) :: version - type(json_object) :: json - class(json_value), allocatable :: j_value - - call json_loads(j_value, '{"code": 200}') - json = cast_to_object(j_value) - - call check_and_read_pkg_data(json, node, url, version, error) - - end subroutine pkg_data_no_data - - subroutine pkg_data_error_reading_data(error) - type(error_t), allocatable, intent(out) :: error - - type(dependency_node_t) :: node - character(:), allocatable :: url - type(version_t) :: version - type(json_object) :: json - class(json_value), allocatable :: j_value - - call json_loads(j_value, '{"code": 200, "data": 123}') - json = cast_to_object(j_value) - - call check_and_read_pkg_data(json, node, url, version, error) - - end subroutine pkg_data_error_reading_data - - subroutine pkg_data_requested_version_wrong_key(error) - type(error_t), allocatable, intent(out) :: error - - type(dependency_node_t) :: node - character(:), allocatable :: url - type(version_t) :: version - type(json_object) :: json - class(json_value), allocatable :: j_value - - allocate (node%requested_version) - call json_loads(j_value, '{"code": 200, "data": {"latest_version_data": 123}}') ! Expected key: "version_data" - json = cast_to_object(j_value) - - call check_and_read_pkg_data(json, node, url, version, error) - - end subroutine pkg_data_requested_version_wrong_key - - subroutine pkg_data_no_version_requested_wrong_key(error) - type(error_t), allocatable, intent(out) :: error - - type(dependency_node_t) :: node - character(:), allocatable :: url - type(version_t) :: version - type(json_object) :: json - class(json_value), allocatable :: j_value - - call json_loads(j_value, '{"code": 200, "data": {"version_data": 123}}') ! Expected key: "latest_version_data" - json = cast_to_object(j_value) - - call check_and_read_pkg_data(json, node, url, version, error) - - end subroutine pkg_data_no_version_requested_wrong_key - - subroutine pkg_data_error_reading_latest_version(error) - type(error_t), allocatable, intent(out) :: error - - type(dependency_node_t) :: node - character(:), allocatable :: url - type(version_t) :: version - type(json_object) :: json - class(json_value), allocatable :: j_value - - call json_loads(j_value, '{"code": 200, "data": {"latest_version_data": 123}}') - json = cast_to_object(j_value) - - call check_and_read_pkg_data(json, node, url, version, error) - - end subroutine pkg_data_error_reading_latest_version - - subroutine pkg_data_no_download_url(error) - type(error_t), allocatable, intent(out) :: error - - type(dependency_node_t) :: node - character(:), allocatable :: url - type(version_t) :: version - type(json_object) :: json - class(json_value), allocatable :: j_value - - call json_loads(j_value, '{"code": 200, "data": {"latest_version_data": {}}}') - json = cast_to_object(j_value) - - call check_and_read_pkg_data(json, node, url, version, error) - - end subroutine pkg_data_no_download_url - - subroutine pkg_data_error_reading_download_url(error) - type(error_t), allocatable, intent(out) :: error - - type(dependency_node_t) :: node - character(:), allocatable :: url - type(version_t) :: version - type(json_object) :: json - class(json_value), allocatable :: j_value - - call json_loads(j_value, '{"code": 200, "data": {"latest_version_data": {"download_url": 123}}}') - json = cast_to_object(j_value) - - call check_and_read_pkg_data(json, node, url, version, error) - - end subroutine pkg_data_error_reading_download_url - - subroutine pkg_data_no_version(error) - type(error_t), allocatable, intent(out) :: error - - type(dependency_node_t) :: node - character(:), allocatable :: url - type(version_t) :: version - type(json_object) :: json - class(json_value), allocatable :: j_value - - call json_loads(j_value, '{"code": 200, "data": {"latest_version_data": {"download_url": "abc"}}}') - json = cast_to_object(j_value) - - call check_and_read_pkg_data(json, node, url, version, error) - - end subroutine pkg_data_no_version - - subroutine pkg_data_error_reading_version(error) - type(error_t), allocatable, intent(out) :: error - - type(dependency_node_t) :: node - character(:), allocatable :: url - type(version_t) :: version - type(json_object) :: json - class(json_value), allocatable :: j_value - - call json_loads(j_value, '{"code": 200, "data": {"latest_version_data": {"download_url": "abc", "version": 123}}}') - json = cast_to_object(j_value) - - call check_and_read_pkg_data(json, node, url, version, error) - - end subroutine pkg_data_error_reading_version - - subroutine pkg_data_invalid_version(error) - type(error_t), allocatable, intent(out) :: error - - type(dependency_node_t) :: node - character(:), allocatable :: url - type(version_t) :: version - type(json_object) :: json - class(json_value), allocatable :: j_value - - call json_loads(j_value, '{"code": 200, "data": {"latest_version_data": {"download_url": "abc", "version": "abc"}}}') - json = cast_to_object(j_value) - - call check_and_read_pkg_data(json, node, url, version, error) - - end subroutine pkg_data_invalid_version - - !> Resolve a single dependency node - subroutine resolve_dependency_once(self, dependency, global_settings, root, error) - !> Mock instance of the dependency tree - class(mock_dependency_tree_t), intent(inout) :: self - !> Dependency configuration to add - type(dependency_node_t), intent(inout) :: dependency - !> Global configuration settings. - type(fpm_global_settings), intent(in) :: global_settings - !> Current installation prefix - character(len=*), intent(in) :: root - !> Error handling - type(error_t), allocatable, intent(out) :: error - - if (dependency%done) then - call test_failed(error, "Should only visit this node once") - return - end if - - dependency%done = .true. - - end subroutine resolve_dependency_once - - !> Resolve all dependencies in the tree - subroutine resolve_dependencies(self, root, error) - !> Instance of the dependency tree - type(mock_dependency_tree_t), intent(inout) :: self - !> Current installation prefix - character(len=*), intent(in) :: root - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(fpm_global_settings) :: global_settings - integer :: ii - - call get_global_settings(global_settings, error) - if (allocated(error)) return - - do ii = 1, self%ndep - call resolve_dependency_once(self, self%dep(ii), global_settings, root, error) - if (allocated(error)) exit - end do - - if (allocated(error)) return - - end subroutine resolve_dependencies - - subroutine delete_tmp_folder - if (is_dir(tmp_folder)) call os_delete_dir(os_is_unix(), tmp_folder) - end - - subroutine setup_global_settings(global_settings, error) - type(fpm_global_settings), intent(out) :: global_settings - type(error_t), allocatable, intent(out) :: error - - character(:), allocatable :: cwd - - call get_current_directory(cwd, error) - if (allocated(error)) return - - global_settings%path_to_config_folder = join_path(cwd, tmp_folder) - global_settings%config_file_name = config_file_name - end - - subroutine get_pkg_data(url, version, tmp_pkg_file, json, error) - character(*), intent(in) :: url - type(version_t), allocatable, intent(in) :: version - character(*), intent(in) :: tmp_pkg_file - type(json_object), intent(out) :: json - type(error_t), allocatable, intent(out) :: error - - class(json_value), allocatable :: j_value - - if (allocated(version)) then - if (version%s() == '9.9.9') then - call json_loads(j_value, '{"code": 404, "message": "Package not found"}') - else - call json_loads(j_value, '{"code": 200, "data": {"version_data": {"version": "0.1.0", "download_url": "abc"}}}') - end if - else - call json_loads(j_value, '{"code": 200, "data": {"latest_version_data": {"version": "0.1.0", "download_url": "abc"}}}') - end if - - json = cast_to_object(j_value) - end - - subroutine get_file(url, tmp_pkg_file, error) - character(*), intent(in) :: url - character(*), intent(in) :: tmp_pkg_file - type(error_t), allocatable, intent(out) :: error - end - - subroutine unpack_mock_package(tmp_pkg_file, destination, error) - character(*), intent(in) :: tmp_pkg_file - character(*), intent(in) :: destination - type(error_t), allocatable, intent(out) :: error - - integer :: stat - - call execute_command_line('cp '//tmp_pkg_file//' '//destination, exitstat=stat) - - if (stat /= 0) then - call test_failed(error, "Failed to create mock package"); return - end if - end - -end module test_package_dependencies diff --git a/test/fpm_test/test_settings.f90 b/test/fpm_test/test_settings.f90 deleted file mode 100644 index ba8c09e003..0000000000 --- a/test/fpm_test/test_settings.f90 +++ /dev/null @@ -1,677 +0,0 @@ -module test_settings - use testsuite, only: new_unittest, unittest_t, error_t, test_failed - use fpm_settings, only: fpm_global_settings, get_global_settings, get_registry_settings, official_registry_base_url - use fpm_filesystem, only: is_dir, join_path, mkdir, filewrite, os_delete_dir, exists, get_local_prefix - use fpm_environment, only: os_is_unix - use tomlf, only: toml_table, new_table - use fpm_toml, only: add_table, set_value - use fpm_os, only: get_absolute_path, get_current_directory - - implicit none - private - public :: collect_settings - - character(len=*), parameter :: tmp_folder = 'tmp' - character(len=*), parameter :: config_file_name = 'config.toml' - -contains - - !> Collect unit tests. - subroutine collect_settings(tests) - - !> Unit tests to collect. - type(unittest_t), allocatable, intent(out) :: tests(:) - - tests = [ & - & new_unittest('no-folder', no_folder, should_fail=.true.), & - & new_unittest('no-file', no_file, should_fail=.true.), & - & new_unittest('empty-file', empty_file), & - & new_unittest('default-config-settings', default_config_settings), & - & new_unittest('error-reading-table', error_reading_table, should_fail=.true.), & - & new_unittest('empty-registry-table', empty_registry_table), & - & new_unittest('invalid-key', invalid_key, should_fail=.true.), & - & new_unittest('invalid-type', invalid_type, should_fail=.true.), & - & new_unittest('has-non-existent-path-to-registry', has_non_existent_path_to_registry, should_fail=.true.), & - & new_unittest('has-existent-path-to-registry', has_existent_path_to_registry), & - & new_unittest('absolute-path-to-registry', absolute_path_to_registry), & - & new_unittest('relative-path-to-registry', relative_path_to_registry), & - & new_unittest('relative-path-to-registry-file-read', relative_path_to_registry_file_read), & - & new_unittest('canonical-path-to-registry', canonical_path_to_registry), & - & new_unittest('has-url-to-registry', has_url_to_registry), & - & new_unittest('has-both-path-and-url-to-registry', has_both_path_and_url_to_registry, should_fail=.true.), & - & new_unittest('has-both-path-and-cache-path', has_both_path_and_cache_path, should_fail=.true.), & - & new_unittest('abs-cache-path-no-dir', abs_cache_path_no_dir), & - & new_unittest('abs-cache-path-has-dir', abs_cache_path_has_dir), & - & new_unittest('rel-cache-path-no-dir', rel_cache_path_no_dir), & - & new_unittest('rel-cache-path-has-dir', rel_cache_path_has_dir) & - ] - - end subroutine collect_settings - - subroutine delete_tmp_folder - if (is_dir(tmp_folder)) call os_delete_dir(os_is_unix(), tmp_folder) - end subroutine - - subroutine setup_global_settings(global_settings, error) - type(fpm_global_settings), intent(out) :: global_settings - type(error_t), allocatable, intent(out) :: error - - character(:), allocatable :: cwd - - call get_current_directory(cwd, error) - if (allocated(error)) return - - global_settings%path_to_config_folder = join_path(cwd, tmp_folder) - global_settings%config_file_name = config_file_name - end subroutine - - !> Throw error when custom path to config file was entered but no folder exists. - subroutine no_folder(error) - type(error_t), allocatable, intent(out) :: error - type(fpm_global_settings) :: global_settings - - call delete_tmp_folder - - call setup_global_settings(global_settings, error) - if (allocated(error)) return - - call get_global_settings(global_settings, error) - end subroutine - - !> Throw error when custom path to config file was entered but no file exists. - subroutine no_file(error) - type(error_t), allocatable, intent(out) :: error - type(fpm_global_settings) :: global_settings - - call delete_tmp_folder - call mkdir(tmp_folder) - - call setup_global_settings(global_settings, error) - if (allocated(error)) return - - call get_global_settings(global_settings, error) - end subroutine - - !> No custom path and config file specified, use default path and file name. - subroutine default_config_settings(error) - type(error_t), allocatable, intent(out) :: error - type(fpm_global_settings) :: global_settings - - character(:), allocatable :: default_path - - call delete_tmp_folder - - call get_global_settings(global_settings, error) - if (allocated(error)) return - - if (os_is_unix()) then - default_path = join_path(get_local_prefix(), 'share', 'fpm') - else - default_path = join_path(get_local_prefix(), 'fpm') - end if - - if (global_settings%path_to_config_folder /= default_path) then - call test_failed(error, "Path to config folder not set correctly :'"//global_settings%config_file_name//"'") - return - end if - - if (global_settings%config_file_name /= 'config.toml') then - call test_failed(error, "Config file name not set correctly :'"//global_settings%config_file_name//"'") - return - end if - end subroutine - - !> Config file exists and the path to that file is set. - subroutine empty_file(error) - type(error_t), allocatable, intent(out) :: error - type(fpm_global_settings) :: global_settings - - character(:), allocatable :: cwd - - call delete_tmp_folder - call mkdir(tmp_folder) - - call filewrite(join_path(tmp_folder, config_file_name), ['']) - - call setup_global_settings(global_settings, error) - if (allocated(error)) return - - call get_global_settings(global_settings, error) - - call delete_tmp_folder - - if (allocated(error)) return - - call get_current_directory(cwd, error) - if (allocated(error)) return - - if (global_settings%path_to_config_folder /= join_path(cwd, tmp_folder)) then - call test_failed(error, "global_settings%path_to_config_folder not set correctly :'" & - & //global_settings%path_to_config_folder//"'"); return - end if - - if (.not. allocated(global_settings%registry_settings)) then - call test_failed(error, 'global_settings%registry_settings not be allocated'); return - end if - - if (global_settings%registry_settings%url /= official_registry_base_url) then - call test_failed(error, 'Wrong default url'); return - end if - - if (global_settings%registry_settings%cache_path /= join_path(global_settings%path_to_config_folder, & - & 'dependencies')) then - call test_failed(error, 'Wrong default cache_path'); return - end if - end subroutine - - !> Invalid TOML file. - subroutine error_reading_table(error) - type(error_t), allocatable, intent(out) :: error - type(fpm_global_settings) :: global_settings - - call delete_tmp_folder - call mkdir(tmp_folder) - - call filewrite(join_path(tmp_folder, config_file_name), ['[']) - - call setup_global_settings(global_settings, error) - if (allocated(error)) return - - call get_global_settings(global_settings, error) - - call delete_tmp_folder - - if (allocated(global_settings%registry_settings)) then - call test_failed(error, 'Registry settings should not be allocated'); return - end if - end subroutine - - subroutine empty_registry_table(error) - type(error_t), allocatable, intent(out) :: error - type(fpm_global_settings) :: global_settings - type(toml_table) :: table - type(toml_table), pointer :: child - - call new_table(table) - call add_table(table, 'registry', child) - - call get_registry_settings(child, global_settings, error) - if (allocated(error)) return - - if (.not. allocated(global_settings%registry_settings)) then - call test_failed(error, 'Registry settings not allocated'); return - end if - - if (allocated(global_settings%registry_settings%path)) then - call test_failed(error, "Path shouldn't be allocated"); return - end if - - if (global_settings%registry_settings%url /= official_registry_base_url) then - call test_failed(error, "Url not be allocated"); return - end if - end subroutine - - subroutine invalid_key(error) - type(error_t), allocatable, intent(out) :: error - type(fpm_global_settings) :: global_settings - type(toml_table) :: table - type(toml_table), pointer :: child - - call new_table(table) - call add_table(table, 'registry', child) - call set_value(child, 'invalid_key', 'abc') - - call get_registry_settings(child, global_settings, error) - end subroutine - - subroutine invalid_type(error) - type(error_t), allocatable, intent(out) :: error - type(fpm_global_settings) :: global_settings - type(toml_table) :: table - type(toml_table), pointer :: child - - call new_table(table) - call add_table(table, 'registry', child) - call set_value(child, 'path', 42) - - call get_registry_settings(child, global_settings, error) - end subroutine - - subroutine has_non_existent_path_to_registry(error) - type(error_t), allocatable, intent(out) :: error - type(fpm_global_settings) :: global_settings - type(toml_table) :: table - type(toml_table), pointer :: child - - call new_table(table) - call add_table(table, 'registry', child) - call set_value(child, 'path', 'nonexistent_path') - - call get_registry_settings(child, global_settings, error) - end subroutine - - subroutine has_existent_path_to_registry(error) - type(error_t), allocatable, intent(out) :: error - type(fpm_global_settings) :: global_settings - type(toml_table) :: table - type(toml_table), pointer :: child - character(:), allocatable :: cwd - - call delete_tmp_folder - call mkdir(tmp_folder) - - call setup_global_settings(global_settings, error) - if (allocated(error)) return - - call new_table(table) - call add_table(table, 'registry', child) - call set_value(child, 'path', '.') - - call get_registry_settings(child, global_settings, error) - - if (.not. allocated(global_settings%registry_settings%path)) then - call test_failed(error, 'Path not allocated') - return - end if - - call delete_tmp_folder - - call get_current_directory(cwd, error) - if (allocated(error)) return - - if (global_settings%registry_settings%path /= join_path(cwd, tmp_folder)) then - call test_failed(error, "Path not set correctly: '"//global_settings%registry_settings%path//"'") - return - end if - - if (allocated(global_settings%registry_settings%url)) then - call test_failed(error, "Url shouldn't be allocated") - return - end if - - end subroutine - - subroutine absolute_path_to_registry(error) - type(error_t), allocatable, intent(out) :: error - type(fpm_global_settings) :: global_settings - character(len=:), allocatable :: abs_path - type(toml_table) :: table - type(toml_table), pointer :: child - - call delete_tmp_folder - call mkdir(tmp_folder) - - call get_absolute_path(tmp_folder, abs_path, error) - if (allocated(error)) return - - call setup_global_settings(global_settings, error) - if (allocated(error)) return - - call new_table(table) - call add_table(table, 'registry', child) - call set_value(child, 'path', abs_path) - - call get_registry_settings(child, global_settings, error) - - call delete_tmp_folder - - if (allocated(error)) return - - if (.not. allocated(global_settings%registry_settings)) then - call test_failed(error, 'Registry settings not allocated') - return - end if - - if (.not. allocated(global_settings%registry_settings%path)) then - call test_failed(error, 'Path not allocated') - return - end if - - if (global_settings%registry_settings%path /= abs_path) then - call test_failed(error, "Path not set correctly: '"//global_settings%registry_settings%path//"'") - return - end if - end subroutine - - subroutine relative_path_to_registry(error) - type(error_t), allocatable, intent(out) :: error - type(fpm_global_settings) :: global_settings - character(len=:), allocatable :: abs_path - type(toml_table) :: table - type(toml_table), pointer :: child - - call delete_tmp_folder - call mkdir(join_path(tmp_folder, 'abc')) - - call setup_global_settings(global_settings, error) - if (allocated(error)) return - - call new_table(table) - call add_table(table, 'registry', child) - call set_value(child, 'path', 'abc') - - call get_registry_settings(child, global_settings, error) - - call get_absolute_path(tmp_folder, abs_path, error) - - call delete_tmp_folder - - if (allocated(error)) return - - if (.not. allocated(global_settings%registry_settings)) then - call test_failed(error, 'Registry settings not allocated') - return - end if - - if (global_settings%registry_settings%path /= join_path(abs_path, 'abc')) then - call test_failed(error, "Path not set correctly: '"//global_settings%registry_settings%path//"'") - return - end if - end subroutine - - ! Test that the registry path is set correctly when the path is written to and read from a config file. - subroutine relative_path_to_registry_file_read(error) - type(error_t), allocatable, intent(out) :: error - type(fpm_global_settings) :: global_settings - character(len=:), allocatable :: abs_path - - call delete_tmp_folder - call mkdir(join_path(tmp_folder, 'abc')) - - call filewrite(join_path(tmp_folder, config_file_name), ['[registry]', 'path="abc"']) - - call setup_global_settings(global_settings, error) - if (allocated(error)) return - - call get_global_settings(global_settings, error) - - call get_absolute_path(tmp_folder, abs_path, error) - - call delete_tmp_folder - - if (allocated(error)) return - - if (.not. allocated(global_settings%registry_settings)) then - call test_failed(error, 'Registry settings not allocated') - return - end if - - if (global_settings%registry_settings%path /= join_path(abs_path, 'abc')) then - call test_failed(error, "Path not set correctly: '"//global_settings%registry_settings%path//"'") - return - end if - end subroutine - - subroutine canonical_path_to_registry(error) - type(error_t), allocatable, intent(out) :: error - type(fpm_global_settings) :: global_settings - character(len=:), allocatable :: abs_path - type(toml_table) :: table - type(toml_table), pointer :: child - - call delete_tmp_folder - call mkdir(tmp_folder) - - call setup_global_settings(global_settings, error) - if (allocated(error)) return - - call new_table(table) - call add_table(table, 'registry', child) - call set_value(child, 'path', join_path('..', tmp_folder)) - - call get_registry_settings(child, global_settings, error) - - call get_absolute_path(tmp_folder, abs_path, error) - - call delete_tmp_folder - - if (allocated(error)) return - - if (.not. allocated(global_settings%registry_settings)) then - call test_failed(error, 'Registry settings not allocated') - return - end if - - if (global_settings%registry_settings%path /= abs_path) then - call test_failed(error, "Path not set correctly: '"//global_settings%registry_settings%path//"'") - return - end if - end subroutine - - subroutine has_url_to_registry(error) - type(error_t), allocatable, intent(out) :: error - type(fpm_global_settings) :: global_settings - type(toml_table) :: table - type(toml_table), pointer :: child - - call delete_tmp_folder - call mkdir(tmp_folder) - - call setup_global_settings(global_settings, error) - if (allocated(error)) return - - call new_table(table) - call add_table(table, 'registry', child) - call set_value(child, 'url', 'http') - - call get_registry_settings(child, global_settings, error) - - call delete_tmp_folder - - if (.not. allocated(global_settings%registry_settings)) then - call test_failed(error, 'Registry settings not allocated') - return - end if - - if (allocated(global_settings%registry_settings%path)) then - call test_failed(error, "Path shouldn't be allocated: '" & - & //global_settings%registry_settings%path//"'") - return - end if - - if (.not. allocated(global_settings%registry_settings%url)) then - call test_failed(error, 'Url not allocated') - return - end if - - if (global_settings%registry_settings%url /= 'http') then - call test_failed(error, 'Failed to parse url') - return - end if - end subroutine - - subroutine has_both_path_and_url_to_registry(error) - type(error_t), allocatable, intent(out) :: error - type(fpm_global_settings) :: global_settings - type(toml_table) :: table - type(toml_table), pointer :: child - - call delete_tmp_folder - call mkdir(tmp_folder) - - call setup_global_settings(global_settings, error) - if (allocated(error)) return - - call new_table(table) - call add_table(table, 'registry', child) - call set_value(child, 'path', '.') - call set_value(child, 'url', 'http') - - call get_registry_settings(child, global_settings, error) - - call delete_tmp_folder - end subroutine - - subroutine has_both_path_and_cache_path(error) - type(error_t), allocatable, intent(out) :: error - type(fpm_global_settings) :: global_settings - type(toml_table) :: table - type(toml_table), pointer :: child - - call delete_tmp_folder - call mkdir(tmp_folder) - - call setup_global_settings(global_settings, error) - if (allocated(error)) return - - call new_table(table) - call add_table(table, 'registry', child) - call set_value(child, 'path', '.') - call set_value(child, 'cache_path', 'cache') - - call get_registry_settings(child, global_settings, error) - - call delete_tmp_folder - end subroutine - - ! Custom cache location defined via absolute path but directory doesn't exist. Create it. - subroutine abs_cache_path_no_dir(error) - type(error_t), allocatable, intent(out) :: error - type(fpm_global_settings) :: global_settings - character(len=:), allocatable :: abs_path, abs_path_to_cache - type(toml_table) :: table - type(toml_table), pointer :: child - - call delete_tmp_folder - call mkdir(tmp_folder) - - call get_absolute_path(tmp_folder, abs_path, error) - if (allocated(error)) return - - abs_path_to_cache = join_path(abs_path, 'cache') - - call setup_global_settings(global_settings, error) - if (allocated(error)) return - - call new_table(table) - call add_table(table, 'registry', child) - call set_value(child, 'cache_path', abs_path_to_cache) - - call get_registry_settings(child, global_settings, error) - - if (.not. exists(abs_path_to_cache)) then - call test_failed(error, "Cache directory '"//abs_path_to_cache//"' not created.") - return - end if - - if (global_settings%registry_settings%cache_path /= abs_path_to_cache) then - call test_failed(error, "Cache path '"//abs_path_to_cache//"' not registered.") - return - end if - - call delete_tmp_folder - end subroutine - - ! Custom cache location defined via absolute path for existing directory. - subroutine abs_cache_path_has_dir(error) - type(error_t), allocatable, intent(out) :: error - type(fpm_global_settings) :: global_settings - character(len=:), allocatable :: abs_path - type(toml_table) :: table - type(toml_table), pointer :: child - - call delete_tmp_folder - call mkdir(join_path(tmp_folder, 'cache')) - - call get_absolute_path(join_path(tmp_folder, 'cache'), abs_path, error) - if (allocated(error)) return - - call setup_global_settings(global_settings, error) - if (allocated(error)) return - - call new_table(table) - call add_table(table, 'registry', child) - call set_value(child, 'cache_path', abs_path) - - call get_registry_settings(child, global_settings, error) - - if (.not. exists(abs_path)) then - call test_failed(error, "Cache directory '"//abs_path//"' not created.") - return - end if - - if (global_settings%registry_settings%cache_path /= abs_path) then - call test_failed(error, "Cache path '"//abs_path//"' not registered.") - return - end if - - call delete_tmp_folder - end subroutine - - ! Custom cache location defined via relative path but directory doesn't exist. Create it. - subroutine rel_cache_path_no_dir(error) - type(error_t), allocatable, intent(out) :: error - type(fpm_global_settings) :: global_settings - character(:), allocatable :: cache_path, abs_path - type(toml_table) :: table - type(toml_table), pointer :: child - - call delete_tmp_folder - call mkdir(tmp_folder) - - call setup_global_settings(global_settings, error) - if (allocated(error)) return - - call new_table(table) - call add_table(table, 'registry', child) - call set_value(child, 'cache_path', 'cache') - - call get_registry_settings(child, global_settings, error) - - cache_path = join_path(tmp_folder, 'cache') - - if (.not. exists(cache_path)) then - call test_failed(error, "Cache directory '"//cache_path//"' not created.") - return - end if - - call get_absolute_path(cache_path, abs_path, error) - if (allocated(error)) return - - if (global_settings%registry_settings%cache_path /= abs_path) then - call test_failed(error, "Cache path '"//cache_path//"' not registered.") - return - end if - - call delete_tmp_folder - end subroutine - - ! Custom cache location defined via relative path for existing directory. - subroutine rel_cache_path_has_dir(error) - type(error_t), allocatable, intent(out) :: error - type(fpm_global_settings) :: global_settings - character(len=:), allocatable :: cache_path, abs_path - type(toml_table) :: table - type(toml_table), pointer :: child - - call delete_tmp_folder - - cache_path = join_path(tmp_folder, 'cache') - call mkdir(cache_path) - - call setup_global_settings(global_settings, error) - if (allocated(error)) return - - call new_table(table) - call add_table(table, 'registry', child) - call set_value(child, 'cache_path', 'cache') - - call get_registry_settings(child, global_settings, error) - - if (.not. exists(cache_path)) then - call test_failed(error, "Cache directory '"//cache_path//"' not created.") - return - end if - - call get_absolute_path(cache_path, abs_path, error) - if (allocated(error)) return - - if (global_settings%registry_settings%cache_path /= abs_path) then - call test_failed(error, "Cache path '"//cache_path//"' not registered.") - return - end if - - call delete_tmp_folder - end subroutine - -end module test_settings diff --git a/test/fpm_test/test_source_parsing.f90 b/test/fpm_test/test_source_parsing.f90 deleted file mode 100644 index b4947c2b7d..0000000000 --- a/test/fpm_test/test_source_parsing.f90 +++ /dev/null @@ -1,1292 +0,0 @@ -!> Define tests for the `fpm_sources` module (parsing routines) -module test_source_parsing - use testsuite, only : new_unittest, unittest_t, error_t, test_failed - use fpm_filesystem, only: get_temp_filename - use fpm_source_parsing, only: parse_f_source, parse_c_source, parse_use_statement - use fpm_model, only: srcfile_t, FPM_UNIT_PROGRAM, FPM_UNIT_MODULE, & - FPM_UNIT_SUBMODULE, FPM_UNIT_SUBPROGRAM, FPM_UNIT_CSOURCE, & - FPM_UNIT_CPPSOURCE, FPM_UNIT_NAME - use fpm_strings, only: operator(.in.), lower - use fpm_error, only: file_parse_error, fatal_error - implicit none - private - - public :: collect_source_parsing - -contains - - !> Collect all exported unit tests - subroutine collect_source_parsing(testsuite) - - !> Collection of tests - type(unittest_t), allocatable, intent(out) :: testsuite(:) - - testsuite = [ & - & new_unittest("modules-used", test_modules_used), & - & new_unittest("intrinsic-modules-used", test_intrinsic_modules_used), & - & new_unittest("nonintrinsic-modules-used", test_nonintrinsic_modules_used), & - & new_unittest("include-stmt", test_include_stmt), & - & new_unittest("program", test_program), & - & new_unittest("program-noheader", test_program_noheader), & - & new_unittest("program-noheader-2", test_program_noheader_2), & - & new_unittest("module", test_module), & - & new_unittest("module-with-subprogram", test_module_with_subprogram), & - & new_unittest("module-with-c-api", test_module_with_c_api), & - & new_unittest("module-with-abstract-interface",test_module_with_abstract_interface), & - & new_unittest("module-end-stmt", test_module_end_stmt), & - & new_unittest("program-with-module", test_program_with_module), & - & new_unittest("program-with-abstract-interface", test_program_with_abstract_interface), & - & new_unittest("submodule", test_submodule), & - & new_unittest("submodule-ancestor", test_submodule_ancestor), & - & new_unittest("subprogram", test_subprogram), & - & new_unittest("csource", test_csource), & - & new_unittest("invalid-use-stmt", & - test_invalid_use_stmt, should_fail=.true.), & - & new_unittest("invalid-include-stmt", & - test_invalid_include_stmt, should_fail=.true.), & - & new_unittest("invalid-module", & - test_invalid_module, should_fail=.true.), & - & new_unittest("invalid-submodule", & - test_invalid_submodule, should_fail=.true.), & - & new_unittest("use-statement",test_use_statement) & - ] - - end subroutine collect_source_parsing - - - !> Check parsing of module 'USE' statements - subroutine test_modules_used(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - integer :: unit - character(:), allocatable :: temp_file - type(srcfile_t), allocatable :: f_source - - allocate(temp_file, source=get_temp_filename()) - - open(file=temp_file, newunit=unit) - write(unit, '(a)') & - & 'program test', & - & ' use module_one', & - & ' use :: module_two', & - & ' use module_three, only: a, b, c', & - & ' use :: module_four, only: a => b', & - & '! use module_not_used', & - & ' implicit none', & - & 'end program test' - close(unit) - - f_source = parse_f_source(temp_file,error) - if (allocated(error)) then - return - end if - - if (f_source%unit_type /= FPM_UNIT_PROGRAM) then - call test_failed(error,'Wrong unit type detected - expecting FPM_UNIT_PROGRAM') - return - end if - - if (size(f_source%modules_provided) /= 0) then - call test_failed(error,'Unexpected modules_provided - expecting zero') - return - end if - - if (size(f_source%modules_used) /= 4) then - call test_failed(error,'Incorrect number of modules_used - expecting four') - return - end if - - if (.not.('module_one' .in. f_source%modules_used)) then - call test_failed(error,'Missing module in modules_used') - return - end if - - if (.not.('module_two' .in. f_source%modules_used)) then - call test_failed(error,'Missing module in modules_used') - return - end if - - if (.not.('module_three' .in. f_source%modules_used)) then - call test_failed(error,'Missing module in modules_used') - return - end if - - if (.not.('module_four' .in. f_source%modules_used)) then - call test_failed(error,'Missing module in modules_used') - return - end if - - if ('module_not_used' .in. f_source%modules_used) then - call test_failed(error,'Commented module found in modules_used') - return - end if - - call f_source%test_serialization('srcfile_t: serialization', error) - - end subroutine test_modules_used - - - !> Check that intrinsic modules are properly ignore - subroutine test_intrinsic_modules_used(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - integer :: unit - character(:), allocatable :: temp_file - type(srcfile_t), allocatable :: f_source - - allocate(temp_file, source=get_temp_filename()) - - open(file=temp_file, newunit=unit) - write(unit, '(a)') & - & 'program test', & - & ' use iso_c_binding', & - & ' use iso_fortran_env', & - & ' use ieee_arithmetic', & - & ' use ieee_exceptions', & - & ' use ieee_features', & - & ' implicit none', & - & 'end program test' - close(unit) - - f_source = parse_f_source(temp_file,error) - if (allocated(error)) then - return - end if - - if (size(f_source%modules_provided) /= 0) then - call test_failed(error,'Unexpected modules_provided - expecting zero') - return - end if - - if (size(f_source%modules_used) /= 0) then - call test_failed(error,'Incorrect number of modules_used - expecting zero') - return - end if - - if ('iso_c_binding' .in. f_source%modules_used) then - call test_failed(error,'Intrinsic module found in modules_used') - return - end if - - if ('iso_fortran_env' .in. f_source%modules_used) then - call test_failed(error,'Intrinsic module found in modules_used') - return - end if - - if ('ieee_arithmetic' .in. f_source%modules_used) then - call test_failed(error,'Intrinsic module found in modules_used') - return - end if - - if ('ieee_exceptions' .in. f_source%modules_used) then - call test_failed(error,'Intrinsic module found in modules_used') - return - end if - - if ('ieee_features' .in. f_source%modules_used) then - call test_failed(error,'Intrinsic module found in modules_used') - return - end if - - call f_source%test_serialization('srcfile_t: serialization', error) - - end subroutine test_intrinsic_modules_used - - - !> Check that intrinsic module names are not ignored if declared non_intrinsic - subroutine test_nonintrinsic_modules_used(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - integer :: unit - character(:), allocatable :: temp_file - type(srcfile_t), allocatable :: f_source - - allocate(temp_file, source=get_temp_filename()) - - open(file=temp_file, newunit=unit) - write(unit, '(a)') & - & 'program test', & - & ' use, non_intrinsic :: iso_c_binding', & - & ' use, intrinsic :: iso_fortran_env', & - & ' use, non_intrinsic :: ieee_arithmetic', & - & ' use, non_intrinsic :: ieee_exceptions', & - & ' use, non_intrinsic :: ieee_features', & - & ' use, non_intrinsic :: my_module', & - & ' implicit none', & - & 'end program test' - close(unit) - - f_source = parse_f_source(temp_file,error) - if (allocated(error)) then - return - end if - - if (size(f_source%modules_provided) /= 0) then - call test_failed(error,'Unexpected modules_provided - expecting zero') - return - end if - - if (size(f_source%modules_used) /= 5) then - call test_failed(error,'Incorrect number of modules_used - expecting five') - return - end if - - if (.not. ('iso_c_binding' .in. f_source%modules_used)) then - call test_failed(error,'Non-Intrinsic module found in modules_used') - return - end if - - if ('iso_fortran_env' .in. f_source%modules_used) then - call test_failed(error,'Intrinsic module found in modules_used') - return - end if - - if (.not. ('ieee_arithmetic' .in. f_source%modules_used)) then - call test_failed(error,'Non-Intrinsic module not found in modules_used') - return - end if - - if (.not. ('ieee_exceptions' .in. f_source%modules_used)) then - call test_failed(error,'Non-Intrinsic module not found in modules_used') - return - end if - - if (.not. ('ieee_features' .in. f_source%modules_used)) then - call test_failed(error,'Non-Intrinsic module not found in modules_used') - return - end if - - if (.not. ('my_module' .in. f_source%modules_used)) then - call test_failed(error,'Non-Intrinsic module not found in modules_used') - return - end if - - end subroutine test_nonintrinsic_modules_used - - !> Check parsing of include statements - subroutine test_include_stmt(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - integer :: unit - character(:), allocatable :: temp_file - type(srcfile_t), allocatable :: f_source - - allocate(temp_file, source=get_temp_filename()) - - open(file=temp_file, newunit=unit) - write(unit, '(a)') & - & 'program test', & - & ' implicit none', & - & ' include "included_file.f90"', & - & ' character(*) :: include_comments', & - & ' include_comments = "some comments"', & - & ' contains ', & - & ' include"second_include.f90"', & - & 'end program test' - close(unit) - - f_source = parse_f_source(temp_file,error) - if (allocated(error)) then - return - end if - - if (size(f_source%modules_provided) /= 0) then - call test_failed(error,'Unexpected modules_provided - expecting zero') - return - end if - - if (size(f_source%modules_used) /= 0) then - call test_failed(error,'Incorrect number of modules_used - expecting zero') - return - end if - - if (size(f_source%include_dependencies) /= 2) then - call test_failed(error,'Incorrect number of include_dependencies - expecting two') - return - end if - - if (.not.('included_file.f90' .in. f_source%include_dependencies)) then - call test_failed(error,'Missing include file in include_dependencies') - return - end if - - if (.not.('second_include.f90' .in. f_source%include_dependencies)) then - call test_failed(error,'Missing include file in include_dependencies') - return - end if - - call f_source%test_serialization('srcfile_t: serialization', error) - - end subroutine test_include_stmt - - !> Try to parse a simple fortran program - subroutine test_program(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - integer :: unit - character(:), allocatable :: temp_file - type(srcfile_t), allocatable :: f_source - - allocate(temp_file, source=get_temp_filename()) - - open(file=temp_file, newunit=unit) - write(unit, '(a)') & - & 'program my_program', & - & 'use module_one', & - & 'implicit none', & - & 'integer :: module', & - & 'module = 1', & - & 'module= 1', & - & 'module =1', & - & 'module (i) =1', & - & 'contains', & - & 'subroutine f()', & - & 'end subroutine f', & - & 'end program my_program' - close(unit) - - f_source = parse_f_source(temp_file,error) - if (allocated(error)) then - return - end if - - if (f_source%unit_type /= FPM_UNIT_PROGRAM) then - call test_failed(error,'Wrong unit type detected - expecting FPM_UNIT_PROGRAM') - return - end if - - if (size(f_source%modules_provided) /= 0) then - call test_failed(error,'Unexpected modules_provided - expecting zero') - return - end if - - if (size(f_source%modules_used) /= 1) then - call test_failed(error,'Incorrect number of modules_used - expecting one') - return - end if - - if (.not.('module_one' .in. f_source%modules_used)) then - call test_failed(error,'Missing module in modules_used') - return - end if - - call f_source%test_serialization('srcfile_t: serialization', error) - - end subroutine test_program - - !> Try to parse a simple fortran program with no "program" header - subroutine test_program_noheader(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - integer :: unit - character(:), allocatable :: temp_file - type(srcfile_t), allocatable :: f_source - - allocate(temp_file, source=get_temp_filename()) - - open(file=temp_file, newunit=unit) - write(unit, '(a)') & - & 'use program_one', & - & 'implicit none', & - & 'integer :: module, program', & - & 'module = 1', & - & 'module= 1', & - & 'module =1', & - & 'module (i) =1', & - & 'program = 123', & - & 'contains', & - & 'subroutine f()', & - & 'end subroutine f', & - & 'end program' - close(unit) - - f_source = parse_f_source(temp_file,error) - if (allocated(error)) then - return - end if - - if (f_source%unit_type /= FPM_UNIT_PROGRAM) then - call test_failed(error,'Wrong unit type detected - expecting FPM_UNIT_PROGRAM, found '//& - FPM_UNIT_NAME(f_source%unit_type)) - return - end if - - if (size(f_source%modules_provided) /= 0) then - call test_failed(error,'Unexpected modules_provided - expecting zero') - return - end if - - if (size(f_source%modules_used) /= 1) then - call test_failed(error,'Incorrect number of modules_used - expecting one') - return - end if - - if (.not.('program_one' .in. f_source%modules_used)) then - call test_failed(error,'Missing module in modules_used') - return - end if - - call f_source%test_serialization('srcfile_t: serialization', error) - - end subroutine test_program_noheader - - !> Try to parse a simple fortran program with no "program" header - subroutine test_program_noheader_2(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - integer :: unit - character(:), allocatable :: temp_file - type(srcfile_t), allocatable :: f_source - - allocate(temp_file, source=get_temp_filename()) - - open(file=temp_file, newunit=unit) - write(unit, '(a)') & - & 'print *, "Hello World"', & - & 'end program' - close(unit) - - f_source = parse_f_source(temp_file,error) - if (allocated(error)) then - return - end if - - if (f_source%unit_type /= FPM_UNIT_PROGRAM) then - call test_failed(error,'Wrong unit type detected - expecting FPM_UNIT_PROGRAM, found '//& - FPM_UNIT_NAME(f_source%unit_type)) - return - end if - - call f_source%test_serialization('srcfile_t: serialization', error) - - end subroutine test_program_noheader_2 - - !> Try to parse fortran module - subroutine test_module(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - integer :: unit - character(:), allocatable :: temp_file - type(srcfile_t), allocatable :: f_source - - allocate(temp_file, source=get_temp_filename()) - - open(file=temp_file, newunit=unit) - write(unit, '(a)') & - & '#define preprocesor_line_outside', & - & 'module my_mod ! A trailing comment', & - & 'use module_one', & - & 'interface', & - & ' module subroutine f() bind(C)', & - & 'end interface', & - & 'integer :: program', & - & 'program = 1', & - & 'program= 1', & - & 'program =1', & - & 'program (i) =1', & - & 'contains', & - & 'module subroutine&', & - & ' e()', & - & ' integer, parameter :: c = 1', & - & ' integer :: & ', & - & ' bind(c)', & - & ' bind(c) = 1', & - & 'end subroutine e', & - & 'module subroutine f()', & - & 'end subroutine f', & - & 'module function g()', & - & 'end function g', & - & 'module integer function h()', & - & 'end function h', & - & 'module real function i()', & - & 'string = " &', & - & 'module name"', & - & 'string = " &', & - & 'module name !"', & - & 'end function i', & - & 'end module test', & - & '! A trailing comment outside of module' - close(unit) - - f_source = parse_f_source(temp_file,error) - if (allocated(error)) then - return - end if - - if (f_source%unit_type /= FPM_UNIT_MODULE) then - call test_failed(error,'Wrong unit type detected - expecting FPM_UNIT_MODULE') - return - end if - - if (size(f_source%modules_provided) /= 1) then - call test_failed(error,'Unexpected modules_provided - expecting one') - return - end if - - if (size(f_source%modules_used) /= 1) then - call test_failed(error,'Incorrect number of modules_used - expecting one') - return - end if - - if (.not.('my_mod' .in. f_source%modules_provided)) then - call test_failed(error,'Missing module in modules_provided') - return - end if - - if (.not.('module_one' .in. f_source%modules_used)) then - call test_failed(error,'Missing module in modules_used') - return - end if - - call f_source%test_serialization('srcfile_t: serialization', error) - - end subroutine test_module - - - !> Try to parse fortran module with subroutine outside of module - !> (this should be detected as FPM_UNIT_SUBPROGRAM not FPM_UNIT_MODULE) - subroutine test_module_with_subprogram(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - integer :: unit - character(:), allocatable :: temp_file - type(srcfile_t), allocatable :: f_source - - allocate(temp_file, source=get_temp_filename()) - - open(file=temp_file, newunit=unit) - write(unit, '(a)') & - & 'module my_mod', & - & 'contains', & - & 'module subroutine f()', & - & 'end subroutine f', & - & 'module function g()', & - & 'end function g', & - & 'end module test',& - & 'function h()', & - & 'end function' - close(unit) - - f_source = parse_f_source(temp_file,error) - if (allocated(error)) then - return - end if - - if (f_source%unit_type /= FPM_UNIT_SUBPROGRAM) then - call test_failed(error,'Wrong unit type detected - expecting FPM_UNIT_SUBPROGRAM') - return - end if - - if (size(f_source%modules_provided) /= 1) then - call test_failed(error,'Unexpected modules_provided - expecting one') - return - end if - - if (size(f_source%modules_used) /= 0) then - call test_failed(error,'Incorrect number of modules_used - expecting zero') - return - end if - - call f_source%test_serialization('srcfile_t: serialization', error) - - end subroutine test_module_with_subprogram - - - !> Try to parse fortran modules without the full end module statement - !> This should be detected as FPM_UNIT_SUBPROGRAM not FPM_UNIT_MODULE - !> because we cannot guarantee if non-module subprograms are present - subroutine test_module_end_stmt(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - integer :: unit - character(:), allocatable :: temp_file - type(srcfile_t), allocatable :: f_source - - allocate(temp_file, source=get_temp_filename()) - - open(file=temp_file, newunit=unit) - write(unit, '(a)') & - & 'module mod1', & - & 'contains', & - & 'module subroutine f()', & - & 'end subroutine f', & - & 'module function g()', & - & 'end function g', & - & 'end', & - & 'module mod2', & - & 'contains', & - & 'module subroutine f()', & - & 'end subroutine f', & - & 'module function g()', & - & 'end function g', & - & 'end module mod2' - close(unit) - - f_source = parse_f_source(temp_file,error) - if (allocated(error)) then - return - end if - - if (f_source%unit_type /= FPM_UNIT_SUBPROGRAM) then - call test_failed(error,'Wrong unit type detected - expecting FPM_UNIT_SUBPROGRAM') - return - end if - - if (size(f_source%modules_provided) /= 2) then - call test_failed(error,'Unexpected modules_provided - expecting two') - return - end if - - if (size(f_source%modules_used) /= 0) then - call test_failed(error,'Incorrect number of modules_used - expecting zero') - return - end if - - if (.not.('mod1' .in. f_source%modules_provided)) then - call test_failed(error,'Missing module in modules_provided') - return - end if - - if (.not.('mod2' .in. f_source%modules_provided)) then - call test_failed(error,'Missing module in modules_provided') - return - end if - - call f_source%test_serialization('srcfile_t: serialization', error) - - end subroutine test_module_end_stmt - - - !> Try to parse fortran module with exported C-API via bind(c) - !> (this should be detected as FPM_UNIT_SUBPROGRAM not FPM_UNIT_MODULE to prevent pruning) - subroutine test_module_with_c_api(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - integer :: unit - character(:), allocatable :: temp_file - type(srcfile_t), allocatable :: f_source - - allocate(temp_file, source=get_temp_filename()) - - open(file=temp_file, newunit=unit) - write(unit, '(a)') & - & 'module my_mod', & - & 'contains', & - & 'subroutine f() &', & - & ' bind(C)', & - & 'end subroutine f', & - & 'module function g()', & - & 'end function g', & - & 'end module test' - close(unit) - - f_source = parse_f_source(temp_file,error) - if (allocated(error)) then - return - end if - - if (f_source%unit_type /= FPM_UNIT_SUBPROGRAM) then - call test_failed(error,'Wrong unit type detected - expecting FPM_UNIT_SUBPROGRAM') - return - end if - - if (size(f_source%modules_provided) /= 1) then - call test_failed(error,'Unexpected modules_provided - expecting one') - return - end if - - if (size(f_source%modules_used) /= 0) then - call test_failed(error,'Incorrect number of modules_used - expecting zero') - return - end if - - call f_source%test_serialization('srcfile_t: serialization', error) - - end subroutine test_module_with_c_api - - !> Check parsing of module exporting an abstract interface - !> See also https://github.com/fortran-lang/fpm/issues/1073 - subroutine test_module_with_abstract_interface(error) - type(error_t), allocatable, intent(out) :: error - - integer :: unit - character(:), allocatable :: temp_file - type(srcfile_t) :: f_source - - allocate(temp_file,source=get_temp_filename()) - open(file=temp_file,newunit=unit) - write(unit, '(A)') & - & 'module foo', & - & 'abstract interface', & - & ' subroutine bar1()', & - & ' end subroutine', & - & ' subroutine bar2() bind(c)', & - & ' end subroutine', & - & 'end interface', & - & 'end module foo' - close(unit) - - f_source = parse_f_source(temp_file,error) - if (allocated(error)) return - if (f_source%unit_type /= FPM_UNIT_MODULE) then - call test_failed(error,'Wrong unit type detected - expecting FPM_UNIT_MODULE') - return - end if - call f_source%test_serialization('srcfile_t: serialization', error) - end subroutine test_module_with_abstract_interface - - - !> Try to parse combined fortran module and program - !> Check that parsed unit type is FPM_UNIT_PROGRAM - subroutine test_program_with_module(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - integer :: unit - character(:), allocatable :: temp_file - type(srcfile_t), allocatable :: f_source - - allocate(temp_file, source=get_temp_filename()) - - open(file=temp_file, newunit=unit) - write(unit, '(a)') & - & 'module my_mod', & - & 'use module_one', & - & 'interface', & - & ' module subroutine f()', & - & 'end interface', & - & 'contains', & - & 'module procedure f()', & - & 'end procedure f', & - & 'end module test', & - & 'program my_program', & - & 'use my_mod', & - & 'implicit none', & - & 'end my_program' - close(unit) - - f_source = parse_f_source(temp_file,error) - if (allocated(error)) then - return - end if - - if (f_source%unit_type /= FPM_UNIT_PROGRAM) then - call test_failed(error,'Wrong unit type detected - expecting FPM_UNIT_PROGRAM') - return - end if - - if (size(f_source%modules_provided) /= 1) then - call test_failed(error,'Unexpected modules_provided - expecting one') - return - end if - - if (.not.('my_mod' .in. f_source%modules_provided)) then - call test_failed(error,'Missing module in modules_provided') - return - end if - - if (.not.('module_one' .in. f_source%modules_used)) then - call test_failed(error,'Missing module in modules_used') - return - end if - - if (.not.('my_mod' .in. f_source%modules_used)) then - call test_failed(error,'Missing module in modules_used') - return - end if - - call f_source%test_serialization('srcfile_t: serialization', error) - - end subroutine test_program_with_module - - !> Check parsing of interfaces within program unit - !> See also https://github.com/fortran-lang/fpm/issues/1073 - subroutine test_program_with_abstract_interface(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - integer :: unit - character(:), allocatable :: temp_file - type(srcfile_t), allocatable :: f_source - - allocate(temp_file, source=get_temp_filename()) - - open(file=temp_file, newunit=unit) - write(unit, '(a)') & - & 'program my_program', & - & 'implicit none', & - & 'abstract interface', & - & ' function cmpfunc(a,b) bind(c)', & - & ' use, intrinsic :: iso_c_binding', & - & ' type(c_ptr), intent(in), value :: a, b', & - & ' integer(c_int) :: cmpfunc', & - & ' end function', & - & 'end interface', & - & 'interface', & - & ' subroutine qsort(ptr,count,size,comp) bind(c,name="qsort")', & - & ' use, intrinsic :: iso_c_binding', & - & ' type(c_ptr), value :: ptr', & - & ' integer(c_size_t), value :: count, size', & - & ' type(c_funptr), value :: comp', & - & 'end interface', & - & 'end program my_program' - close(unit) - - f_source = parse_f_source(temp_file,error) - if (allocated(error)) then - return - end if - - if (f_source%unit_type /= FPM_UNIT_PROGRAM) then - call test_failed(error,'Wrong unit type detected - expecting FPM_UNIT_PROGRAM') - return - end if - - if (size(f_source%modules_provided) /= 0) then - call test_failed(error,'Unexpected modules_provided - expecting zero') - return - end if - - ! Intrinsic modules are not counted in `modules_used` (!) - if (size(f_source%modules_used) /= 0) then - call test_failed(error,'Incorrect number of modules_used - expecting zero') - return - end if - - call f_source%test_serialization('srcfile_t: serialization', error) - - end subroutine test_program_with_abstract_interface - - !> Try to parse fortran submodule for ancestry - subroutine test_submodule(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - integer :: unit - character(:), allocatable :: temp_file - type(srcfile_t), allocatable :: f_source - - allocate(temp_file, source=get_temp_filename()) - - open(file=temp_file, newunit=unit) - write(unit, '(a)') & - & 'submodule (parent) child', & - & 'use module_one', & - & 'end submodule test' - close(unit) - - f_source = parse_f_source(temp_file,error) - if (allocated(error)) then - return - end if - - if (f_source%unit_type /= FPM_UNIT_SUBMODULE) then - call test_failed(error,'Wrong unit type detected - expecting FPM_UNIT_SUBMODULE') - return - end if - - if (size(f_source%modules_provided) /= 1) then - call test_failed(error,'Unexpected modules_provided - expecting one') - return - end if - - if (size(f_source%modules_used) /= 2) then - call test_failed(error,'Incorrect number of modules_used - expecting two') - return - end if - - if (.not.('child' .in. f_source%modules_provided)) then - call test_failed(error,'Missing module in modules_provided') - return - end if - - if (.not.('module_one' .in. f_source%modules_used)) then - call test_failed(error,'Missing module in modules_used') - return - end if - - if (.not.('parent' .in. f_source%modules_used)) then - call test_failed(error,'Missing parent module in modules_used') - return - end if - - call f_source%test_serialization('srcfile_t: serialization', error) - - end subroutine test_submodule - - - !> Try to parse fortran multi-level submodule for ancestry - subroutine test_submodule_ancestor(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - integer :: unit - character(:), allocatable :: temp_file - type(srcfile_t), allocatable :: f_source - - allocate(temp_file, source=get_temp_filename()) - - open(file=temp_file, newunit=unit) - write(unit, '(a)') & - & 'submodule (ancestor:parent) child', & - & 'use module_one', & - & 'end submodule test' - close(unit) - - f_source = parse_f_source(temp_file,error) - if (allocated(error)) then - return - end if - - if (f_source%unit_type /= FPM_UNIT_SUBMODULE) then - call test_failed(error,'Wrong unit type detected - expecting FPM_UNIT_SUBMODULE') - return - end if - - if (size(f_source%modules_provided) /= 1) then - call test_failed(error,'Unexpected modules_provided - expecting one') - return - end if - - if (size(f_source%modules_used) /= 2) then - call test_failed(error,'Incorrect number of modules_used - expecting two') - return - end if - - if (.not.('child' .in. f_source%modules_provided)) then - call test_failed(error,'Missing module in modules_provided') - return - end if - - if (.not.('module_one' .in. f_source%modules_used)) then - call test_failed(error,'Missing module in modules_used') - return - end if - - if (.not.('parent' .in. f_source%modules_used)) then - call test_failed(error,'Missing parent module in modules_used') - return - end if - - call f_source%test_serialization('srcfile_t: serialization', error) - - end subroutine test_submodule_ancestor - - - !> Try to parse standard fortran sub-program (non-module) source - subroutine test_subprogram(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - integer :: unit - character(:), allocatable :: temp_file - type(srcfile_t), allocatable :: f_source - - allocate(temp_file, source=get_temp_filename()) - - open(file=temp_file, newunit=unit) - write(unit, '(a)') & - & 'subroutine my_sub(a)', & - & ' use module_one', & - & ' integer, intent(in) :: a', & - & 'end subroutine my_sub' - close(unit) - - f_source = parse_f_source(temp_file,error) - if (allocated(error)) then - return - end if - - if (f_source%unit_type /= FPM_UNIT_SUBPROGRAM) then - call test_failed(error,'Wrong unit type detected - expecting FPM_UNIT_SUBPROGRAM') - return - end if - - if (size(f_source%modules_provided) /= 0) then - call test_failed(error,'Unexpected modules_provided - expecting zero') - return - end if - - if (size(f_source%modules_used) /= 1) then - call test_failed(error,'Incorrect number of modules_used - expecting one') - return - end if - - if (.not.('module_one' .in. f_source%modules_used)) then - call test_failed(error,'Missing module in modules_used') - return - end if - - call f_source%test_serialization('srcfile_t: serialization', error) - - end subroutine test_subprogram - - - !> Try to parse standard c source for includes - subroutine test_csource(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - integer :: unit - character(:), allocatable :: temp_file - type(srcfile_t), allocatable :: f_source - - allocate(temp_file, source=get_temp_filename()) - temp_file = temp_file//'.c' - - open(file=temp_file, newunit=unit) - write(unit, '(a)') & - & '#include "proto.h"', & - & 'void c_func(int a) {', & - & ' #include "function_body.c"', & - & ' return', & - & '}' - close(unit) - - f_source = parse_c_source(temp_file,error) - if (allocated(error)) then - return - end if - - if (f_source%unit_type /= FPM_UNIT_CSOURCE) then - call test_failed(error,'Wrong unit type detected - expecting FPM_UNIT_CSOURCE') - return - end if - - if (size(f_source%modules_provided) /= 0) then - call test_failed(error,'Unexpected modules_provided - expecting zero') - return - end if - - if (size(f_source%modules_used) /= 0) then - call test_failed(error,'Incorrect number of modules_used - expecting zero') - return - end if - - if (size(f_source%include_dependencies) /= 2) then - call test_failed(error,'Incorrect number of include_dependencies - expecting two') - return - end if - - if (allocated(f_source%link_libraries)) then - call test_failed(error,'Unexpected link_libraries - expecting unallocated') - return - end if - - if (size(f_source%parent_modules) /= 0) then - call test_failed(error,'Incorrect number of parent_modules - expecting zero') - return - end if - - if (.not.('proto.h' .in. f_source%include_dependencies)) then - call test_failed(error,'Missing file in include_dependencies') - return - end if - - if (.not.('function_body.c' .in. f_source%include_dependencies)) then - call test_failed(error,'Missing file in include_dependencies') - return - end if - - call f_source%test_serialization('srcfile_t: serialization', error) - - end subroutine test_csource - - !> Try to parse fortran program with invalid use statement - subroutine test_invalid_use_stmt(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - integer :: unit - character(:), allocatable :: temp_file - type(srcfile_t), allocatable :: f_source - - allocate(temp_file, source=get_temp_filename()) - - open(file=temp_file, newunit=unit) - write(unit, '(a)') & - & 'program test', & - & 'use module_one', & - & 'use :: ', & - & 'end program test' - close(unit) - - f_source = parse_f_source(temp_file,error) - if (allocated(error)) then - return - end if - - end subroutine test_invalid_use_stmt - - - !> Try to parse fortran program with invalid use statement - subroutine test_invalid_include_stmt(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - integer :: unit - character(:), allocatable :: temp_file - type(srcfile_t), allocatable :: f_source - - allocate(temp_file, source=get_temp_filename()) - - open(file=temp_file, newunit=unit) - write(unit, '(a)') & - & 'program test', & - & ' include "', & - & 'end program test' - close(unit) - - f_source = parse_f_source(temp_file,error) - if (allocated(error)) then - return - end if - - end subroutine test_invalid_include_stmt - - - !> Try to parse incorrect fortran module syntax - subroutine test_invalid_module(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - integer :: unit - character(:), allocatable :: temp_file - type(srcfile_t), allocatable :: f_source - - allocate(temp_file, source=get_temp_filename()) - - open(file=temp_file, newunit=unit) - write(unit, '(a)') & - & 'module ::my_mod', & - & 'end module test' - close(unit) - - f_source = parse_f_source(temp_file,error) - if (allocated(error)) then - return - end if - - end subroutine test_invalid_module - - - !> Try to parse incorrect fortran submodule syntax - subroutine test_invalid_submodule(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - integer :: unit - character(:), allocatable :: temp_file - type(srcfile_t), allocatable :: f_source - - allocate(temp_file, source=get_temp_filename()) - - open(file=temp_file, newunit=unit) - write(unit, '(a)') & - & 'submodule :: child', & - & 'end submodule test' - close(unit) - - f_source = parse_f_source(temp_file,error) - if (allocated(error)) then - return - end if - - write(*,*) '"',f_source%modules_used(1)%s,'"' - - end subroutine test_invalid_submodule - - !> Parse several USE statements - subroutine test_use_statement(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - character(*), parameter :: filename='test_use_statement' - character(:), allocatable :: line,module_name - - logical :: used,is_intrinsic - - line = 'use, intrinsic:: iso_fortran_env' - call parse_use_statement(filename,0,line,used,is_intrinsic,module_name,error) - if (allocated(error)) return - - if (.not. (used .and. & - is_intrinsic .and. & - module_name=='iso_fortran_env' .and. & - used)) then - call fatal_error(error,'USE statement failed parsing <'//line//'>') - return - endif - - line = 'use, non_intrinsic :: iso_fortran_env' - call parse_use_statement(filename,0,line,used,is_intrinsic,module_name,error) - if (allocated(error)) return - - if (.not. (used .and. & - (.not.is_intrinsic) .and. & - module_name=='iso_fortran_env' .and. & - used)) then - call fatal_error(error,'USE statement failed parsing <'//line//'>') - return - endif - - line = 'use, non_intrinsic :: my_fortran_module' - call parse_use_statement(filename,0,line,used,is_intrinsic,module_name,error) - if (allocated(error)) return - - if (.not. (used .and. & - (.not.is_intrinsic) .and. & - module_name=='my_fortran_module' .and. & - used)) then - call fatal_error(error,'USE statement failed parsing <'//line//'>') - return - endif - - line = 'use, intrinsic :: my_fortran_module' - call parse_use_statement(filename,0,line,used,is_intrinsic,module_name,error) - - ! This is not an intrinsic module: should detect an error - if (.not. allocated(error)) then - call fatal_error(error,'Did not catch invalid intrinsic module in <'//line//'>') - return - else - deallocate(error) - endif - - end subroutine test_use_statement - - -end module test_source_parsing diff --git a/test/fpm_test/test_toml.f90 b/test/fpm_test/test_toml.f90 deleted file mode 100644 index 8fd28dfbf3..0000000000 --- a/test/fpm_test/test_toml.f90 +++ /dev/null @@ -1,1299 +0,0 @@ -!> Define tests for the `fpm_toml` modules -module test_toml - use testsuite, only : new_unittest, unittest_t, error_t - use tomlf, only: toml_table, toml_load - use fpm_toml, only: read_package_file, toml_array, toml_key, toml_stat, & - get_value, set_value, get_list, new_table, add_table, add_array, len, & - toml_error, toml_serialize, check_keys, set_list, set_string, & - name_is_json - use tomlf_constants, only: tf_i8 - use fpm_git, only: git_target_t, git_target_revision, git_target_branch, & - & git_target_tag - use fpm_dependency, only: dependency_node_t, destroy_dependency_node, dependency_tree_t, & - & new_dependency_node, new_dependency_tree, resize - use fpm_manifest_dependency, only: dependency_config_t, dependency_destroy - use fpm_manifest_install, only: install_config_t - use fpm_manifest_fortran, only: fortran_config_t - use fpm_manifest_library, only: library_config_t - use fpm_manifest_executable, only: executable_config_t - use fpm_manifest_preprocess, only: preprocess_config_t - use fpm_manifest_profile, only: file_scope_flag - use fpm_versioning, only: new_version - use fpm_strings, only: string_t, operator(==), split - use fpm_model, only: fortran_features_t, package_t, FPM_SCOPE_LIB, FPM_UNIT_MODULE, fpm_model_t, & - & srcfile_t - use fpm_compiler, only: archiver_t, compiler_t, id_gcc - use fpm_error, only: fatal_error - - - implicit none - private - - public :: collect_toml - - character, parameter :: NL = new_line('a') - -contains - - - !> Collect all exported unit tests - subroutine collect_toml(testsuite) - - !> Collection of tests - type(unittest_t), allocatable, intent(out) :: testsuite(:) - - testsuite = [ & - & new_unittest("valid-toml", test_valid_toml), & - & new_unittest("invalid-toml", test_invalid_toml, should_fail=.true.), & - & new_unittest("missing-file", test_missing_file, should_fail=.true.), & - & new_unittest("serialize-git-target", git_target_roundtrip), & - & new_unittest("serialize-git-invalid", git_target_invalid, should_fail=.true.), & - & new_unittest("serialize-dependency-config", dependency_config_roundtrip), & - & new_unittest("serialize-dependency-node", dependency_node_roundtrip), & - & new_unittest("serialize-dependency-invalid", dependency_node_invalid, should_fail=.true.), & - & new_unittest("serialize-dependency-invalid2", dependency_node_invalid_2, should_fail=.true.), & - & new_unittest("serialize-dependency-tree", dependency_tree_roundtrip), & - & new_unittest("serialize-dependency-tree-invalid", dependency_tree_invalid, should_fail=.true.), & - & new_unittest("serialize-dependency-tree-invalid2", dependency_tree_invalid2, should_fail=.true.), & - & new_unittest("serialize-install-config", install_config_roundtrip), & - & new_unittest("serialize-fortran-config", fortran_features_roundtrip), & - & new_unittest("serialize-library-config", library_config_roundtrip), & - & new_unittest("serialize-executable-config", executable_config_roundtrip), & - & new_unittest("serialize-preprocess-config", preprocess_config_roundtrip), & - & new_unittest("serialize-file-scope-flag", file_scope_flag_roundtrip), & - & new_unittest("serialize-string-array", string_array_roundtrip), & - & new_unittest("serialize-fortran-features", fft_roundtrip), & - & new_unittest("serialize-fortran-invalid", fft_invalid, should_fail=.true.), & - & new_unittest("serialize-package", package_roundtrip), & - & new_unittest("serialize-package-invalid", package_invalid, should_fail=.true.), & - & new_unittest("serialize-srcfile-invalid", source_invalid, should_fail=.true.), & - & new_unittest("serialize-archiver", ar_roundtrip), & - & new_unittest("serialize-archiver-invalid", ar_invalid, should_fail=.true.), & - & new_unittest("serialize-compiler", compiler_roundtrip), & - & new_unittest("serialize-compiler-invalid", compiler_invalid, should_fail=.true.), & - & new_unittest("serialize-model", fpm_model_roundtrip), & - & new_unittest("serialize-model-invalid", fpm_model_invalid, should_fail=.true.)] - - end subroutine collect_toml - - - !> Try to read some unnecessary obscure and convoluted but not invalid package file - subroutine test_valid_toml(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table), allocatable :: table - character(len=*), parameter :: manifest = 'fpm-valid-toml.toml' - integer :: unit - - open(file=manifest, newunit=unit) - write(unit, '(a)') & - & 'name = "example"', & - & '[dependencies.fpm]', & - & 'git = "https://github.com/fortran-lang/fpm"', & - & '[[executable]]', & - & 'name = "example-1" # comment', & - & 'source-dir = "prog"', & - & '[dependencies]', & - & 'toml-f.git = "git@github.com:toml-f/toml-f.git"', & - & '"toml..f" = { path = ".." }', & - & '[["executable"]]', & - & 'name = "example-2"', & - & 'source-dir = "prog"', & - & '[executable.dependencies]', & - & '[''library'']', & - & 'source-dir = """', & - & 'lib""" # comment' - close(unit) - - call read_package_file(table, manifest, error) - - open(file=manifest, newunit=unit) - close(unit, status='delete') - - end subroutine test_valid_toml - - - !> Try to read an invalid TOML document - subroutine test_invalid_toml(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table), allocatable :: table - character(len=*), parameter :: manifest = 'fpm-invalid-toml.toml' - integer :: unit - - open(file=manifest, newunit=unit) - write(unit, '(a)') & - & '# INVALID TOML DOC', & - & 'name = "example"', & - & 'dependencies.fpm.git = "https://github.com/fortran-lang/fpm"', & - & '[dependencies]', & - & 'toml-f.git = "git@github.com:toml-f/toml-f.git"', & - & '"toml..f" = { path = ".." }' - close(unit) - - call read_package_file(table, manifest, error) - - open(file=manifest, newunit=unit) - close(unit, status='delete') - - end subroutine test_invalid_toml - - - !> Try to read configuration from a non-existing file - subroutine test_missing_file(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table), allocatable :: table - - call read_package_file(table, 'low+chance+of+existing.toml', error) - - end subroutine test_missing_file - - !> Test git_target_t serialization - subroutine git_target_roundtrip(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(git_target_t) :: git - - ! Revision type - git = git_target_revision(url="https://github.com/urbanjost/M_CLI2.git", & - sha1="7264878cdb1baff7323cc48596d829ccfe7751b8") - call git%test_serialization("revision git type",error) - if (allocated(error)) return - - ! Branch type - git = git_target_branch(url="https://github.com/urbanjost/M_CLI2.git", & - branch="main") - call git%test_serialization("branch git type",error) - if (allocated(error)) return - - ! Tag type - git = git_target_tag(url="https://github.com/urbanjost/M_CLI2.git", & - tag="1.0.0") - call git%test_serialization("target git type",error) - if (allocated(error)) return - - ! Incomplete type - if (allocated(git%object)) deallocate(git%object) - call git%test_serialization("incomplete git type 1/2",error) - if (allocated(error)) return - - ! Incomplete type - if (allocated(git%url)) deallocate(git%url) - call git%test_serialization("incomplete git type 2/2",error) - if (allocated(error)) return - - end subroutine git_target_roundtrip - - - !> Test invalid git_target_t serialization - subroutine git_target_invalid(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(git_target_t) :: git - type(toml_table), allocatable :: table - - character(*), parameter :: toml = 'descriptor = ""'//NL//& ! invalid descriptor ID - 'url = "https://github.com/toml-f/toml-f"'//NL//& - 'object = "54686e45993f3a9a1d05d5c7419f39e7d5a4eb3f"' - - - call string_to_toml(toml, table) - - call git%load(table, error) - - end subroutine git_target_invalid - - !> Test git_target_t serialization - subroutine dependency_config_roundtrip(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(dependency_config_t) :: dep - - call dependency_destroy(dep) - - dep%name = "M_CLI2" - dep%path = "~/./some/dummy/path" - dep%namespace = "urbanjost" - allocate(dep%requested_version) - call new_version(dep%requested_version, "3.2.0",error); if (allocated(error)) return - - allocate(dep%git) - dep%git = git_target_revision(url="https://github.com/urbanjost/M_CLI2.git", & - sha1="7264878cdb1baff7323cc48596d829ccfe7751b8") - - ! Test full object - call dep%test_serialization("full object",error) - if (allocated(error)) return - - ! Remove namespace - deallocate(dep%namespace) - call dep%test_serialization("no namespace",error) - if (allocated(error)) return - - ! Remove git - deallocate(dep%git) - call dep%test_serialization("no git",error) - if (allocated(error)) return - - ! Remove version - deallocate(dep%requested_version) - call dep%test_serialization("no requested_version",error) - if (allocated(error)) return - - ! Remove name - deallocate(dep%name) - call dep%test_serialization("no name",error) - if (allocated(error)) return - - ! Remove path - deallocate(dep%path) - call dep%test_serialization("no path",error) - if (allocated(error)) return - - end subroutine dependency_config_roundtrip - - !> Test dependency_node_t serialization - subroutine dependency_node_roundtrip(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(dependency_node_t) :: dep - - call destroy_dependency_node(dep) - - dep%name = "M_CLI2" - dep%path = "~/./some/dummy/path" - dep%proj_dir = "~/./" - dep%namespace = "urbanjost" - dep%revision = "7264878cdb1baff7323cc48596d829ccfe7751b8" - dep%cached = .true. - dep%done = .false. - dep%update = .true. - allocate(dep%requested_version) - call new_version(dep%requested_version, "3.2.0",error); if (allocated(error)) return - allocate(dep%version) - call new_version(dep%version, "4.53.2",error); if (allocated(error)) return - - allocate(dep%git) - dep%git = git_target_revision(url="https://github.com/urbanjost/M_CLI2.git", & - sha1="7264878cdb1baff7323cc48596d829ccfe7751b8") - - ! Test full object - call dep%test_serialization("full object",error) - if (allocated(error)) return - - ! Remove namespace - deallocate(dep%namespace) - call dep%test_serialization("no namespace",error) - if (allocated(error)) return - - ! Remove git - deallocate(dep%git) - call dep%test_serialization("no git",error) - if (allocated(error)) return - - ! Remove version - deallocate(dep%requested_version) - call dep%test_serialization("no requested_version",error) - if (allocated(error)) return - - ! Remove name - deallocate(dep%name) - call dep%test_serialization("no name",error) - if (allocated(error)) return - - ! Remove path - deallocate(dep%path) - call dep%test_serialization("no path",error) - if (allocated(error)) return - - ! Remove revision - deallocate(dep%revision) - call dep%test_serialization("no revision",error) - if (allocated(error)) return - - ! Remove proj_dir - deallocate(dep%proj_dir) - call dep%test_serialization("no proj_dir",error) - if (allocated(error)) return - - ! Remove version - deallocate(dep%version) - call dep%test_serialization("no version",error) - if (allocated(error)) return - - end subroutine dependency_node_roundtrip - - !> Test loading invalid dependency node - subroutine dependency_node_invalid(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(dependency_node_t) :: dep - type(toml_table), allocatable :: table - - character(*), parameter :: toml = 'name = "jonquil" '//NL//& - & 'version = "h0.2.0"'//NL//& ! invalid version - & 'proj-dir = "build/dependencies/jonquil"'//NL//& - & 'revision = "05d30818bb12fb877226ce284b9a3a41b971a889"'//NL//& - & 'done = true'//NL//& - & 'update = false'//NL//& - & 'cached = true' - - call string_to_toml(toml, table) - - call dep%load(table, error) - - end subroutine dependency_node_invalid - - !> Test loading invalid dependency node - subroutine dependency_node_invalid_2(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(dependency_node_t) :: dep - type(toml_table), allocatable :: table - - character(*), parameter :: toml = 'name = "jonquil" '//NL//& - & 'version = "0.2.0"'//NL//& - & 'proj-dir = "build/dependencies/jonquil"'//NL//& - & 'revision = "05d30818bb12fb877226ce284b9a3a41b971a889"'//NL//& - & 'done = 123'//NL//& ! not a boolean - & 'update = false'//NL//& - & 'cached = true' - - call string_to_toml(toml, table) - call dep%load(table, error) - - end subroutine dependency_node_invalid_2 - - !> Test dependency_tree_t serialization - subroutine dependency_tree_roundtrip(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(dependency_tree_t) :: deps - type(dependency_config_t) :: dep - - integer, parameter :: ALLOCATED_DEPS = 5 - character(36) :: msg - integer :: ii - - ! Generate dummy tree with ndep=3 but 5 allocated dependencies - call new_dependency_tree(deps) - call resize(deps%dep, ALLOCATED_DEPS) - deps%ndep = 3 - dep%name = "dep1" - dep%path = "fpm-tmp1-dir" - call new_dependency_node(deps%dep(1), dep, proj_dir=dep%path) - dep%name = "dep2" - dep%path = "fpm-tmp2-dir" - call new_dependency_node(deps%dep(2), dep, proj_dir=dep%path) - deps%dep(3)%name = "M_CLI2" - deps%dep(3)%path = "~/./some/dummy/path" - deps%dep(3)%proj_dir = "~/./" - deps%dep(3)%namespace = "urbanjost" - deps%dep(3)%revision = "7264878cdb1baff7323cc48596d829ccfe7751b8" - deps%dep(3)%cached = .true. - deps%dep(3)%done = .false. - deps%dep(3)%update = .true. - allocate(deps%dep(3)%requested_version) - call new_version(deps%dep(3)%requested_version, "3.2.0",error); if (allocated(error)) return - allocate(deps%dep(3)%version) - call new_version(deps%dep(3)%version, "4.53.2",error); if (allocated(error)) return - allocate(deps%dep(3)%git) - deps%dep(3)%git = git_target_revision(url="https://github.com/urbanjost/M_CLI2.git", & - sha1="7264878cdb1baff7323cc48596d829ccfe7751b8") - - call deps%test_serialization("full dependency tree", error) - if (allocated(error)) return - - ! Remove dependencies (including all them) - do ii = 1, ALLOCATED_DEPS - write(msg,1) ii - call resize(deps%dep, size(deps%dep) - 1) - call deps%test_serialization(trim(msg), error) - if (allocated(error)) return - end do - - ! deallocate dependencies - deallocate(deps%dep) - call deps%test_serialization("unallocated deps(:)", error) - if (allocated(error)) return - - ! Remove deps dir - deallocate(deps%dep_dir) - call deps%test_serialization("no deps dir", error) - if (allocated(error)) return - - 1 format('removed ',i0,' dependencies') - - end subroutine dependency_tree_roundtrip - - !> Test invalid dependency tree loading - subroutine dependency_tree_invalid(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table), allocatable :: table - type(dependency_tree_t) :: dep - - character(len=*), parameter :: toml = & - & 'unit = 6 '//NL//& - & 'verbosity = true'//NL//& ! not a number - & 'dep-dir = "build/dependencies"'//NL//& - & 'ndep = 3'//NL//& ! consistency is not checked: - & '[dependencies]'//NL//& - & '[dependencies.dep1]'//NL//& - & 'name = "dep1"'//NL//& - & 'path = "fpm-tmp1-dir"'//NL//& - & 'proj-dir = "fpm-tmp1-dir"'//NL//& - & 'done = false'//NL//& - & 'update = false'//NL//& - & 'cached = false' - - call string_to_toml(toml, table) - call dep%load(table, error) - - end subroutine dependency_tree_invalid - - !> Test invalid dependency tree loading - subroutine dependency_tree_invalid2(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(toml_table), allocatable :: table - type(dependency_tree_t) :: dep - - character(len=*), parameter :: toml = & - & 'unit = "" '//NL//& ! not provided - & 'verbosity = 1'//NL//& - & 'dep-dir = "build/dependencies"'//NL//& - & 'ndep = 3'//NL//& ! consistency is not checked: - & '[dependencies.M_CLI2]'//NL//& - & 'name = "M_CLI2"'//NL//& - & 'path = "~/./some/dummy/path"'//NL//& - & 'namespace = "urbanjost"'//NL//& - & 'requested_version = "3.2.0"'//NL//& - & 'version = "4.53.2"'//NL//& - & 'proj-dir = "~/./"'//NL//& - & 'revision = "7264878cdb1baff7323cc48596d829ccfe7751b8"'//NL//& - & 'done = false'//NL//& - & 'update = true'//NL//& - & 'cached = true'//NL//& - & '[dependencies.M_CLI2.git]'//NL//& - & 'descriptor = "revision"'//NL//& - & 'url = "https://github.com/urbanjost/M_CLI2.git"'//NL//& - & 'object = "7264878cdb1baff7323cc48596d829ccfe7751b8"' - - call string_to_toml(toml, table) - call dep%load(table, error) - - end subroutine dependency_tree_invalid2 - - !> Test serialization/deserialization of a string array - subroutine string_array_roundtrip(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - character(len=*), parameter :: lorem = "Lorem ipsum dolor sit amet, consectetur adipiscing " & - & //"elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad " & - & //"minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo " & - & //"consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum " & - & //"dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt " & - & //"in culpa qui officia deserunt mollit anim id est laborum" - - integer :: ii, nword - character(len=:), allocatable :: tokens(:) - type(string_t), allocatable :: list(:),copy(:) - type(toml_table) :: table - character(len=16) :: key - - call split(lorem, tokens) - nword = size(tokens) - - !> Convert to string_t array - allocate(list(nword)) - do ii = 1, nword - list(ii) = string_t(trim(tokens(ii))) - end do - - ! Test list with any length - do ii = nword, 1, -1 - - ! Shorten list - list = list(1:ii) - - ! Set list to table - table = toml_table() - - call set_list(table, key="lorem-ipsum", list=list, error=error) - if (allocated(error)) return - - ! Load list from table - call get_list(table, key="lorem-ipsum", list=copy, error=error) - if (allocated(error)) return - - if (.not.(list==copy)) then - call fatal_error(error,'string_array is not equal after TOML roundtrip') - return - end if - - end do - - ! Test empty list - deallocate(list) - allocate(list(0)) - ! Set list to table - table = toml_table() - - call set_list(table, key="lorem-ipsum", list=list, error=error) - if (allocated(error)) return - - ! Load list from table - call get_list(table, key="lorem-ipsum", list=copy, error=error) - if (allocated(error)) return - - if (.not.(list==copy)) then - call fatal_error(error,'empty string_array is not equal after TOML roundtrip') - return - end if - - ! Test unallocated list - deallocate(list) - table = toml_table() - - call set_list(table, key="lorem-ipsum", list=list, error=error) - if (allocated(error)) return - - ! Load list from table - call get_list(table, key="lorem-ipsum", list=copy, error=error) - if (allocated(error)) return - - if (.not.(list==copy)) then - call fatal_error(error,'deallocated string_array is not equal after TOML roundtrip') - return - end if - - 1 format('word_',i0) - - end subroutine string_array_roundtrip - - !> Test serialization/deserialization of a fortran-features structure - subroutine fft_roundtrip(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(fortran_features_t) :: fortran - - !> Default object - call fortran%test_serialization('fortran_features_t: default object',error) - if (allocated(error)) return - - !> Set form - fortran%source_form = "free" - call fortran%test_serialization('fortran_features_t: with form',error) - if (allocated(error)) return - - end subroutine fft_roundtrip - - !> Test deserialization of an invalid fortran-features structure - subroutine fft_invalid(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(fortran_features_t) :: fortran - type(toml_table), allocatable :: table - - character(len=*), parameter :: toml = 'implicit-typing = false '//NL//& - & 'implicit-external = 0 '//NL//& ! not a boolean - & 'source-form = "free" ' - - call string_to_toml(toml, table) - - !> Default object - call fortran%load(table,error) - - end subroutine fft_invalid - - !> Test serialization/deserialization of a package_t structure - subroutine package_roundtrip(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(package_t) :: pkg - integer :: ierr - - !> Default object - call pkg%test_serialization('package_t: default object',error) - if (allocated(error)) return - - !> Create a dummy package - pkg%name = "orderpack" - pkg%version = "0.1.0" - pkg%enforce_module_names = .false. - pkg%module_prefix = string_t("") - pkg%features%source_form = "free" - - if (allocated(pkg%sources)) deallocate(pkg%sources) - allocate(pkg%sources(4)) - - pkg%sources(1)%file_name = "build/dependencies/orderpack/src/M_valnth.f90" - pkg%sources(1)%digest = 2662523002405134329_tf_i8 - pkg%sources(1)%unit_scope = FPM_SCOPE_LIB - pkg%sources(1)%unit_type = FPM_UNIT_MODULE - pkg%sources(1)%modules_provided = [string_t("m_valnth")] - deallocate(pkg%sources(1)%parent_modules, stat=ierr) - deallocate(pkg%sources(1)%modules_used, stat=ierr) - deallocate(pkg%sources(1)%include_dependencies, stat=ierr) - deallocate(pkg%sources(1)%link_libraries, stat=ierr) - - pkg%sources(2)%file_name = "build/dependencies/orderpack/src/M_mrgrnk.f90" - pkg%sources(2)%digest = 7985690966656622651_tf_i8 - pkg%sources(2)%unit_scope = FPM_SCOPE_LIB - pkg%sources(2)%unit_type = FPM_UNIT_MODULE - pkg%sources(2)%modules_provided = [string_t("m_mrgrnk")] - pkg%sources(2)%link_libraries = [string_t("netcdf"),string_t("hdf-5")] - deallocate(pkg%sources(2)%parent_modules, stat=ierr) - deallocate(pkg%sources(2)%modules_used, stat=ierr) - deallocate(pkg%sources(2)%include_dependencies, stat=ierr) - deallocate(pkg%sources(2)%link_libraries, stat=ierr) - - pkg%sources(3)%file_name = "build/dependencies/orderpack/src/M_median.f90" - pkg%sources(3)%digest = 7985690966656622651_tf_i8 - pkg%sources(3)%unit_scope = FPM_SCOPE_LIB - pkg%sources(3)%unit_type = FPM_UNIT_MODULE - pkg%sources(3)%modules_provided = [string_t("m_median")] - deallocate(pkg%sources(3)%parent_modules, stat=ierr) - deallocate(pkg%sources(3)%modules_used, stat=ierr) - deallocate(pkg%sources(3)%include_dependencies, stat=ierr) - deallocate(pkg%sources(3)%link_libraries, stat=ierr) - - pkg%sources(4)%file_name = "build/dependencies/orderpack/src/M_unista.f90" - pkg%sources(4)%digest = -7512253540457404792_tf_i8 - pkg%sources(4)%unit_scope = FPM_SCOPE_LIB - pkg%sources(4)%unit_type = FPM_UNIT_MODULE - pkg%sources(4)%modules_provided = [string_t("m_unista")] - pkg%sources(4)%modules_used = [string_t("m_uniinv")] - deallocate(pkg%sources(4)%parent_modules, stat=ierr) - deallocate(pkg%sources(4)%include_dependencies, stat=ierr) - deallocate(pkg%sources(4)%link_libraries, stat=ierr) - - !> Package mock - call pkg%test_serialization('package_t: orderpack',error) - if (allocated(error)) return - - !> Remove some entries - pkg%sources(1)%file_name = "" - pkg%sources(3)%digest = 0 - pkg%sources = pkg%sources(1:3) - call pkg%test_serialization('package_t: orderpack (reduced)',error) - if (allocated(error)) return - - !> Remove all sources - deallocate(pkg%sources,stat=ierr) - call pkg%test_serialization('package_t: no sources',error) - if (allocated(error)) return - - end subroutine package_roundtrip - - !> Test deserialization of an invalid package TOML file - subroutine package_invalid(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - character(len=*), parameter :: toml = & - & 'name = "toml-f" '//NL//& - & 'version = "0.8.0" '//NL//& - & 'module-naming = "prefix" '//NL//& ! this should be boolean - & 'module-prefix = "" ' - - type(package_t) :: pkg - type(toml_table), allocatable :: table - - call string_to_toml(toml, table) - - !> Default object - call pkg%load(table,error) - - end subroutine package_invalid - - !> Test deserialization of an invalid source file - subroutine source_invalid(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - character(len=*), parameter :: toml = & - & 'file-name = "build/dependencies/toml-f/src/tomlf.f90" '//NL//& - & 'digest = "abcde" '//NL//& ! not a number - & 'unit-scope = "FPM_SCOPE_MODULE" '//NL//& - & 'unit-type = "FPM_UNIT_MODULE" '//NL//& - & 'modules-provided = "tomlf" '//NL//& - & 'parent-modules = [ ] '//NL//& - & 'modules-used = [ "tomlf_build", "tomlf_datetime" ] '//NL//& - & 'include-dependencies = [ ] '//NL//& - & 'link-libraries = [ ] ' - - type(srcfile_t) :: src - type(toml_table), allocatable :: table - - call string_to_toml(toml, table) - - !> Default object - call src%load(table,error) - - end subroutine source_invalid - - !> Test serialization/deserialization of an archiver_t structure - subroutine ar_roundtrip(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(archiver_t) :: ar - integer :: ierr - - !> Default object - call ar%test_serialization('archiver_t: default object',error) - if (allocated(error)) return - - !> change a few items - ar%ar = "ar" - ar%echo = .true. - ar%use_response_file = .false. - - call ar%test_serialization('archiver_t: ar',error) - - end subroutine ar_roundtrip - - !> Test deserialization of an invalid archiver_t structure - subroutine ar_invalid(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - character(len=*), parameter :: toml = & - & 'ar = "ar -rs " '//NL//& - & 'use-response-file = false '//NL//& - & 'echo = 123 '//NL//& ! not a boolean - & 'verbose = false ' - - type(archiver_t) :: ar - type(toml_table), allocatable :: table - - call string_to_toml(toml, table) - - !> Default object - call ar%load(table,error) - - end subroutine ar_invalid - - !> Test serialization/deserialization of a compiler_t structure - subroutine compiler_roundtrip(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(compiler_t) :: compiler - - !> Default object - call compiler%test_serialization('compiler_t: default object',error) - if (allocated(error)) return - - !> change a few items - compiler%id = id_gcc - compiler%fc = "gfortran -ffree-line-length-none -fdefault-real-8 -O3" - compiler%cc = "" - compiler%cxx = "g++ -O3 -std=c++11" - compiler%echo = .false. - - call compiler%test_serialization('compiler_t: gcc',error) - - end subroutine compiler_roundtrip - - !> Test deserialization of an invalid compiler_t TOML structure - subroutine compiler_invalid(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - character(len=*), parameter :: toml = & - & 'id = "gfortran" '//NL//& ! not an integer identifier - & 'fc = "gfortran" '//NL//& - & 'cc = "gcc" '//NL//& - & 'cxx = "g++" '//NL//& - & 'echo = false '//NL//& - & 'verbose = false ' - - type(compiler_t) :: cc - type(toml_table), allocatable :: table - - call string_to_toml(toml, table) - - !> Default object - call cc%load(table,error) - - end subroutine compiler_invalid - - !> Get a shortened TOML representation of the fpm v0.8.1 model - subroutine fpm_081_table(table) - - !> TOML representation of the fpm v0.8.1 model - type(toml_table), allocatable, intent(out) :: table - - !> simplified TOML representation of the fpm v0.8.1 model - character(len=:), allocatable :: fpm - - integer :: iunit - - allocate(character(len=0) :: fpm) - fpm = fpm//NL//'package-name = "fpm"' - fpm = fpm//NL//'fortran-flags = " -Wall -Wextra -fPIC -fmax-errors=1 -g "' - fpm = fpm//NL//'c-flags = ""' - fpm = fpm//NL//'cxx-flags = ""' - fpm = fpm//NL//'link-flags = ""' - fpm = fpm//NL//'build-prefix = "build/gfortran"' - fpm = fpm//NL//'include-dirs = [ ]' - fpm = fpm//NL//'link-libraries = [ ]' - fpm = fpm//NL//'external-modules = [ ]' - fpm = fpm//NL//'include-tests = false' - fpm = fpm//NL//'module-naming = false' - fpm = fpm//NL//'module-prefix = ""' - fpm = fpm//NL//'[compiler]' - fpm = fpm//NL//'id = 1' - fpm = fpm//NL//'fc = "gfortran"' - fpm = fpm//NL//'cc = "gcc"' - fpm = fpm//NL//'cxx = "g++"' - fpm = fpm//NL//'echo = false' - fpm = fpm//NL//'verbose = false' - fpm = fpm//NL//'[archiver]' - fpm = fpm//NL//'ar = "ar -rs "' - fpm = fpm//NL//'use-response-file = false' - fpm = fpm//NL//'echo = false' - fpm = fpm//NL//'verbose = false' - fpm = fpm//NL//'[deps]' - fpm = fpm//NL//'unit = 6' - fpm = fpm//NL//'verbosity = 1' - fpm = fpm//NL//'dep-dir = "build/dependencies"' - fpm = fpm//NL//'cache = "build/cache.toml"' - fpm = fpm//NL//'ndep = 4' - fpm = fpm//NL//'[deps.dependencies]' - fpm = fpm//NL//'[deps.dependencies.fpm]' - fpm = fpm//NL//'name = "fpm"' - fpm = fpm//NL//'path = "."' - fpm = fpm//NL//'version = "0.8.0"' - fpm = fpm//NL//'proj-dir = "./."' - fpm = fpm//NL//'done = true' - fpm = fpm//NL//'update = false' - fpm = fpm//NL//'cached = false' - fpm = fpm//NL//'[deps.dependencies.toml-f]' - fpm = fpm//NL//'name = "toml-f"' - fpm = fpm//NL//'version = "0.4.0"' - fpm = fpm//NL//'proj-dir = "build/dependencies/toml-f"' - fpm = fpm//NL//'revision = "54686e45993f3a9a1d05d5c7419f39e7d5a4eb3f"' - fpm = fpm//NL//'done = true' - fpm = fpm//NL//'update = false' - fpm = fpm//NL//'cached = true' - fpm = fpm//NL//'[deps.dependencies.toml-f.git]' - fpm = fpm//NL//'descriptor = "revision"' - fpm = fpm//NL//'url = "https://github.com/toml-f/toml-f"' - fpm = fpm//NL//'object = "54686e45993f3a9a1d05d5c7419f39e7d5a4eb3f"' - fpm = fpm//NL//'[deps.dependencies.UNNAMED_DEPENDENCY_5]' - fpm = fpm//NL//'done = false' - fpm = fpm//NL//'update = false' - fpm = fpm//NL//'cached = false' - fpm = fpm//NL//'[packages]' - fpm = fpm//NL//'[packages.fpm]' - fpm = fpm//NL//'name = "fpm"' - fpm = fpm//NL//'version = "0.8.0"' - fpm = fpm//NL//'module-naming = false' - fpm = fpm//NL//'module-prefix = ""' - fpm = fpm//NL//'[packages.fpm.fortran]' - fpm = fpm//NL//'implicit-typing = false' - fpm = fpm//NL//'implicit-external = false' - fpm = fpm//NL//'source-form = "free"' - fpm = fpm//NL//'[packages.fpm.sources]' - fpm = fpm//NL//'[packages.fpm.sources.src_1]' - fpm = fpm//NL//'file-name = "././src/fpm.f90"' - fpm = fpm//NL//'digest = 4322290725857190613' - fpm = fpm//NL//'unit-scope = "FPM_SCOPE_LIB"' - fpm = fpm//NL//'unit-type = "FPM_UNIT_MODULE"' - fpm = fpm//NL//'modules-provided = "fpm"' - fpm = fpm//NL//'parent-modules = [ ]' - fpm = fpm//NL//'modules-used = [ "fpm_strings", "fpm_backend", "fpm_compiler", "fpm_error" ]' - fpm = fpm//NL//'include-dependencies = [ ]' - fpm = fpm//NL//'link-libraries = [ ]' - fpm = fpm//NL//'[packages.fpm.sources.src_2]' - fpm = fpm//NL//'file-name = "././src/fpm_backend.F90"' - fpm = fpm//NL//'digest = -3210121688944515946' - fpm = fpm//NL//'unit-scope = "FPM_SCOPE_LIB"' - fpm = fpm//NL//'unit-type = "FPM_UNIT_MODULE"' - fpm = fpm//NL//'modules-provided = "fpm_backend"' - fpm = fpm//NL//'parent-modules = [ ]' - fpm = fpm//NL//'modules-used = [ "fpm_error", "fpm_filesystem", "fpm_backend_output" ]' - fpm = fpm//NL//'include-dependencies = [ ]' - fpm = fpm//NL//'link-libraries = [ ]' - fpm = fpm//NL//'[packages.fpm.sources.src_3]' - fpm = fpm//NL//'file-name = "././src/fpm_environment.f90"' - fpm = fpm//NL//'digest = 2235607720245152632' - fpm = fpm//NL//'unit-scope = "FPM_SCOPE_LIB"' - fpm = fpm//NL//'unit-type = "FPM_UNIT_MODULE"' - fpm = fpm//NL//'modules-provided = "fpm_environment"' - fpm = fpm//NL//'parent-modules = [ ]' - fpm = fpm//NL//'modules-used = "fpm_error"' - fpm = fpm//NL//'include-dependencies = [ ]' - fpm = fpm//NL//'link-libraries = [ ]' - fpm = fpm//NL//'[packages.fpm.sources.src_4]' - fpm = fpm//NL//'file-name = "././src/fpm_model.f90"' - fpm = fpm//NL//'digest = -6774177234665080583' - fpm = fpm//NL//'unit-scope = "FPM_SCOPE_LIB"' - fpm = fpm//NL//'unit-type = "FPM_UNIT_MODULE"' - fpm = fpm//NL//'modules-provided = "fpm_model"' - fpm = fpm//NL//'parent-modules = [ ]' - fpm = fpm//NL//'modules-used = [ "fpm_compiler", "fpm_dependency" ]' - fpm = fpm//NL//'include-dependencies = [ ]' - fpm = fpm//NL//'link-libraries = [ ]' - fpm = fpm//NL//'[packages.fpm.sources.src_5]' - fpm = fpm//NL//'file-name = "././src/filesystem_utilities.c"' - fpm = fpm//NL//'digest = 4957633104775755438' - fpm = fpm//NL//'unit-scope = "FPM_SCOPE_LIB"' - fpm = fpm//NL//'unit-type = "FPM_UNIT_CSOURCE"' - fpm = fpm//NL//'modules-provided = [ ]' - fpm = fpm//NL//'parent-modules = [ ]' - fpm = fpm//NL//'modules-used = [ ]' - fpm = fpm//NL//'include-dependencies = [ ]' - fpm = fpm//NL//'link-libraries = [ ]' - fpm = fpm//NL//'[packages.fpm.sources.src_59]' - fpm = fpm//NL//'file-name = "test/new_test/new_test.f90"' - fpm = fpm//NL//'exe-name = "new-test"' - fpm = fpm//NL//'digest = 4683353150944180202' - fpm = fpm//NL//'unit-scope = "FPM_SCOPE_TEST"' - fpm = fpm//NL//'unit-type = "FPM_UNIT_PROGRAM"' - fpm = fpm//NL//'modules-provided = [ ]' - fpm = fpm//NL//'parent-modules = [ ]' - fpm = fpm//NL//'modules-used = [ "fpm_filesystem", "fpm_strings", "fpm_environment" ]' - fpm = fpm//NL//'include-dependencies = [ ]' - fpm = fpm//NL//'link-libraries = [ ]' - fpm = fpm//NL//'[packages.toml-f]' - fpm = fpm//NL//'name = "toml-f"' - fpm = fpm//NL//'version = "0.8.0"' - fpm = fpm//NL//'module-naming = false' - fpm = fpm//NL//'module-prefix = ""' - fpm = fpm//NL//'[packages.toml-f.fortran]' - fpm = fpm//NL//'implicit-typing = false' - fpm = fpm//NL//'implicit-external = false' - fpm = fpm//NL//'source-form = "free"' - fpm = fpm//NL//'[packages.toml-f.sources]' - fpm = fpm//NL//'[packages.toml-f.sources.src_1]' - fpm = fpm//NL//'file-name = "build/dependencies/toml-f/src/tomlf.f90"' - fpm = fpm//NL//'digest = -8299830903248890534' - fpm = fpm//NL//'unit-scope = "FPM_SCOPE_LIB"' - fpm = fpm//NL//'unit-type = "FPM_UNIT_MODULE"' - fpm = fpm//NL//'modules-provided = "tomlf"' - fpm = fpm//NL//'parent-modules = [ ]' - fpm = fpm//NL//'modules-used = [ "tomlf_build", "tomlf_datetime" ]' - fpm = fpm//NL//'include-dependencies = [ ]' - fpm = fpm//NL//'link-libraries = [ ]' - fpm = fpm//NL//'[packages.toml-f.sources.src_2]' - fpm = fpm//NL//'file-name = "build/dependencies/toml-f/src/tomlf/constants.f90"' - fpm = fpm//NL//'digest = 7170350792708576173' - fpm = fpm//NL//'unit-scope = "FPM_SCOPE_LIB"' - fpm = fpm//NL//'unit-type = "FPM_UNIT_MODULE"' - fpm = fpm//NL//'modules-provided = "tomlf_constants"' - fpm = fpm//NL//'parent-modules = [ ]' - fpm = fpm//NL//'modules-used = [ ]' - fpm = fpm//NL//'include-dependencies = [ ]' - fpm = fpm//NL//'link-libraries = [ ]' - fpm = fpm//NL//'[packages.M_CLI2]' - fpm = fpm//NL//'name = "M_CLI2"' - fpm = fpm//NL//'version = "0.8.0"' - fpm = fpm//NL//'module-naming = false' - fpm = fpm//NL//'module-prefix = ""' - fpm = fpm//NL//'[packages.M_CLI2.fortran]' - fpm = fpm//NL//'implicit-typing = false' - fpm = fpm//NL//'implicit-external = false' - fpm = fpm//NL//'source-form = "free"' - fpm = fpm//NL//'[packages.M_CLI2.sources]' - fpm = fpm//NL//'[packages.M_CLI2.sources.src_1]' - fpm = fpm//NL//'file-name = "build/dependencies/M_CLI2/src/M_CLI2.F90"' - fpm = fpm//NL//'digest = -6169834068995303802' - fpm = fpm//NL//'unit-scope = "FPM_SCOPE_LIB"' - fpm = fpm//NL//'unit-type = "FPM_UNIT_MODULE"' - fpm = fpm//NL//'modules-provided = "m_cli2"' - fpm = fpm//NL//'parent-modules = [ ]' - fpm = fpm//NL//'modules-used = [ ]' - fpm = fpm//NL//'include-dependencies = [ ]' - fpm = fpm//NL//'link-libraries = [ ]' - fpm = fpm//NL//'[packages.jonquil]' - fpm = fpm//NL//'name = "jonquil"' - fpm = fpm//NL//'version = "0.8.0"' - fpm = fpm//NL//'module-naming = false' - fpm = fpm//NL//'module-prefix = ""' - fpm = fpm//NL//'[packages.jonquil.fortran]' - fpm = fpm//NL//'implicit-typing = false' - fpm = fpm//NL//'implicit-external = false' - fpm = fpm//NL//'source-form = "free"' - fpm = fpm//NL//'[packages.jonquil.sources]' - fpm = fpm//NL//'[packages.jonquil.sources.src_1]' - fpm = fpm//NL//'file-name = "build/dependencies/jonquil/src/jonquil.f90"' - fpm = fpm//NL//'digest = 5552073973512025871' - fpm = fpm//NL//'unit-scope = "FPM_SCOPE_LIB"' - fpm = fpm//NL//'unit-type = "FPM_UNIT_MODULE"' - fpm = fpm//NL//'modules-provided = "jonquil"' - fpm = fpm//NL//'parent-modules = [ ]' - fpm = fpm//NL//'modules-used = [ "tomlf", "tomlf_type", "jonquil_ser" ]' - fpm = fpm//NL//'include-dependencies = [ ]' - fpm = fpm//NL//'link-libraries = [ ]' - fpm = fpm//NL//'[packages.jonquil.sources.src_2]' - fpm = fpm//NL//'file-name = "build/dependencies/jonquil/src/jonquil/version.f90"' - fpm = fpm//NL//'digest = -2934903401983932826' - fpm = fpm//NL//'unit-scope = "FPM_SCOPE_LIB"' - fpm = fpm//NL//'unit-type = "FPM_UNIT_MODULE"' - fpm = fpm//NL//'modules-provided = "jonquil_version"' - fpm = fpm//NL//'parent-modules = [ ]' - fpm = fpm//NL//'modules-used = [ ]' - fpm = fpm//NL//'include-dependencies = [ ]' - fpm = fpm//NL//'link-libraries = [ ]' - - call string_to_toml(fpm, table) - - end subroutine fpm_081_table - - !> Convert a character string to a TOML table - subroutine string_to_toml(string, table) - - !> The input TOML as a string - character(*), intent(in) :: string - - !> The TOML table - type(toml_table), allocatable, intent(out) :: table - - integer :: iunit - - ! Write - open(newunit=iunit,form='formatted',status='scratch',action='readwrite',recl=1073741824) - - !> Dump to scratch file - write(iunit,*) string - - !> Load from scratch file - rewind(iunit) - call toml_load(table, iunit) - - close(iunit) - - end subroutine string_to_toml - - subroutine fpm_model_roundtrip(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - type(fpm_model_t) :: model - type(toml_table), allocatable :: table - - call model%test_serialization('fpm_model_t: default object', error) - if (allocated(error)) return - - !> Now init form fpm 0.8.1 table - call fpm_081_table(table) - - call model%load(table, error) - if (allocated(error)) then - call fatal_error(error, 'fpm_model_t: cannot load model from fpm v0.8.1 TOML') - return - end if - - call model%test_serialization('fpm_model_t: fpm v0.8.1 model test', error) - - end subroutine fpm_model_roundtrip - - - subroutine fpm_model_invalid(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(fpm_model_t) :: model - type(toml_table), allocatable :: table - character(len=:), allocatable :: fpm - - allocate(character(len=0) :: fpm) - fpm = fpm//NL//'package-name = "fpm"' - fpm = fpm//NL//'fortran-flags = " -Wall -Wextra -fPIC -fmax-errors=1 -g "' - fpm = fpm//NL//'c-flags = ""' - fpm = fpm//NL//'cxx-flags = ""' - fpm = fpm//NL//'link-flags = ""' - fpm = fpm//NL//'build-prefix = "build/gfortran"' - fpm = fpm//NL//'include-dirs = [ ]' - fpm = fpm//NL//'link-libraries = [ ]' - fpm = fpm//NL//'external-modules = "" ' - fpm = fpm//NL//'include-tests = "my_test"' ! not a boolean - fpm = fpm//NL//'module-naming = false' - fpm = fpm//NL//'module-prefix = ""' - - call string_to_toml(fpm, table) - call model%load(table,error) - - end subroutine fpm_model_invalid - - subroutine install_config_roundtrip(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(install_config_t) :: install - - integer :: loop - - do loop=1,2 - - install % library = mod(loop,2)==0 - - ! Test full object - call install%test_serialization('install_config_roundtrip',error) - if (allocated(error)) return - - end do - - end subroutine install_config_roundtrip - - subroutine fortran_features_roundtrip(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(fortran_config_t) :: fortran - - fortran%implicit_external = .true. - fortran%implicit_typing = .false. - fortran%source_form = 'free' - - call fortran%test_serialization('fortran_features_roundtrip',error) - if (allocated(error)) return - - deallocate(fortran%source_form) - call fortran%test_serialization('fortran_features_roundtrip 2',error) - - end subroutine fortran_features_roundtrip - - subroutine library_config_roundtrip(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(library_config_t) :: lib - - lib%source_dir = 'lib' - lib%include_dir = [string_t('a'),string_t('b')] - - call lib%test_serialization('library_config: 1',error) - if (allocated(error)) return - - lib%build_script = 'install.sh' - - call lib%test_serialization('library_config: 2',error) - if (allocated(error)) return - - deallocate(lib%include_dir) - call lib%test_serialization('library_config: 3',error) - - end subroutine library_config_roundtrip - - - subroutine executable_config_roundtrip(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(executable_config_t) :: exe - type(dependency_config_t) :: dep - - exe%name = "my_executable" - exe%source_dir = 'app' - - call exe%test_serialization('executable_config: 1',error) - if (allocated(error)) return - - exe%main = 'main_program.F90' - - call exe%test_serialization('executable_config: 2',error) - if (allocated(error)) return - - exe%link = [string_t('netcdf'),string_t('hdf5')] - call exe%test_serialization('executable_config: 3',error) - - call dependency_destroy(dep) - - dep%name = "M_CLI2" - dep%path = "~/./some/dummy/path" - dep%namespace = "urbanjost" - allocate(dep%requested_version) - call new_version(dep%requested_version, "3.2.0",error); if (allocated(error)) return - - allocate(dep%git) - dep%git = git_target_revision(url="https://github.com/urbanjost/M_CLI2.git", & - sha1="7264878cdb1baff7323cc48596d829ccfe7751b8") - - allocate(exe%dependency(1),source=dep) - call exe%test_serialization('executable_config: 4',error) - - end subroutine executable_config_roundtrip - - - subroutine preprocess_config_roundtrip(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(preprocess_config_t) :: prep - - prep%name = "preprocessor config" - prep%macros = [string_t('Whatever'),string_t('FPM_BOOTSTRAP')] - - call prep%test_serialization('preprocess_config', error) - - end subroutine preprocess_config_roundtrip - - subroutine file_scope_flag_roundtrip(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(file_scope_flag) :: ff - - call ff%test_serialization('file_scope_flag: empty', error) - if (allocated(error)) return - - ff%file_name = "preprocessor config" - ff%flags = "-1 -f -2 -g" - - call ff%test_serialization('file_scope_flag: non-empty', error) - - end subroutine file_scope_flag_roundtrip - -end module test_toml diff --git a/test/fpm_test/test_versioning.f90 b/test/fpm_test/test_versioning.f90 deleted file mode 100644 index 36ef7b9caf..0000000000 --- a/test/fpm_test/test_versioning.f90 +++ /dev/null @@ -1,507 +0,0 @@ -!> Test implementation of version data type -module test_versioning - use testsuite, only : new_unittest, unittest_t, error_t, test_failed - use fpm_versioning - use fpm_release, only: fpm_version - implicit none - private - - public :: collect_versioning - - -contains - - - !> Collect all exported unit tests - subroutine collect_versioning(tests) - - !> Collection of tests - type(unittest_t), allocatable, intent(out) :: tests(:) - - tests = [ & - & new_unittest("fpm-version", test_fpm_version), & - & new_unittest("valid-version", test_valid_version), & - & new_unittest("valid-equals", test_valid_equals), & - & new_unittest("valid-notequals", test_valid_notequals), & - & new_unittest("valid-compare", test_valid_compare), & - & new_unittest("valid-match", test_valid_match), & - & new_unittest("valid-string", test_valid_string), & - & new_unittest("invalid-empty", test_invalid_empty, should_fail=.true.), & - & new_unittest("invalid-version1", test_invalid_version1, should_fail=.true.), & - & new_unittest("invalid-version2", test_invalid_version2, should_fail=.true.), & - & new_unittest("invalid-version3", test_invalid_version3, should_fail=.true.), & - & new_unittest("invalid-overflow", test_invalid_overflow, should_fail=.true.)] - - end subroutine collect_versioning - - !> Test fpm self-version query - subroutine test_fpm_version(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(version_t) :: self_version - - self_version = fpm_version() - - end subroutine test_fpm_version - - !> Read valid version strings - subroutine test_valid_version(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(version_t) :: version - - call new_version(version, "8.9.0", error) - if (allocated(error)) return - - call new_version(version, "2020.10.003", error) - - end subroutine test_valid_version - - - !> Compare versions for equality - subroutine test_valid_equals(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(version_t) :: v1, v2 - type(version_t) :: varray(4) - - call new_version(v1, [1, 2, 0]) - call new_version(v2, [1, 2]) - - if (.not. v1 == v2) then - call test_failed(error, "Version comparison failed") - return - end if - - if (.not. v2 == v1) then - call test_failed(error, "Version comparison failed") - return - end if - - call new_version(v1, [0, 9, 0]) - call new_version(v2, [0, 9]) - - if (.not. v1==v2) then - call test_failed(error, "Version comparison failed") - return - end if - - if (.not. v2==v1) then - call test_failed(error, "Version comparison failed") - return - end if - - call new_version(v1, [2020]) - call new_version(v2, [2020, 0]) - - if (.not. v1 == v2) then - call test_failed(error, "Version comparison failed") - return - end if - - if (.not. v2 == v1) then - call test_failed(error, "Version comparison failed") - return - end if - - call new_version(v1, [20, 1]) - call new_version(varray(1), [19]) - call new_version(varray(2), [18, 2]) - call new_version(varray(3), [20, 1]) - call new_version(varray(4), [1, 3, 1]) - - if (.not. any(v1 == varray)) then - call test_failed(error, "Version comparison failed") - return - end if - - end subroutine test_valid_equals - - - !> Compare versions for mismatch - subroutine test_valid_notequals(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(version_t) :: v1, v2 - type(version_t) :: varray(4) - - call new_version(v1, [2020, 3, 1]) - call new_version(v2, [2020, 3]) - - if (.not. v1 /= v2) then - call test_failed(error, "Version comparison failed") - return - end if - - if (.not. v2 /= v1) then - call test_failed(error, "Version comparison failed") - return - end if - - call new_version(v1, [0, 9, 1]) - call new_version(v2, [0, 9]) - - if (.not. v1/=v2) then - call test_failed(error, "Version comparison failed") - return - end if - - if (.not. v2/=v1) then - call test_failed(error, "Version comparison failed") - return - end if - - call new_version(v1, [2020]) - call new_version(v2, [0, 2020]) - - if (.not. v2 /= v1) then - call test_failed(error, "Version comparison failed") - return - end if - - if (.not. v1 /= v2) then - call test_failed(error, "Version comparison failed") - return - end if - - call new_version(v1, [20, 1]) - call new_version(varray(1), [19]) - call new_version(varray(2), [18, 2]) - call new_version(varray(3), [18, 1]) - call new_version(varray(4), [1, 3, 1]) - - if (.not. any(v1 /= varray)) then - call test_failed(error, "Version comparison failed") - return - end if - - end subroutine test_valid_notequals - - - !> Relative comparison of versions - subroutine test_valid_compare(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(version_t) :: v1, v2 - type(version_t) :: varray(4) - - call new_version(v1, [10]) - call new_version(v2, [1]) - - if (.not. v1 > v2) then - call test_failed(error, "Version comparison failed (gt)") - return - end if - - if (.not. v1 >= v2) then - call test_failed(error, "Version comparison failed (ge)") - return - end if - - if (.not. v2 < v1) then - call test_failed(error, "Version comparison failed (lt)") - return - end if - - if (.not. v2 <= v1) then - call test_failed(error, "Version comparison failed (le)") - return - end if - - call new_version(v1, [1, 0, 8]) - call new_version(v2, [1, 0]) - - if (.not. v1 > v2) then - call test_failed(error, "Version comparison failed (gt)") - return - end if - - if (.not. v1 >= v2) then - call test_failed(error, "Version comparison failed (ge)") - return - end if - - if (.not. v2 < v1) then - call test_failed(error, "Version comparison failed (lt)") - return - end if - - if (.not. v2 <= v1) then - call test_failed(error, "Version comparison failed (le)") - return - end if - - call new_version(v1, [1, 2]) - call new_version(v2, [1, 2, 0]) - - if (v1 > v2) then - call test_failed(error, "Version comparison failed (gt)") - return - end if - - if (.not. v1 >= v2) then - call test_failed(error, "Version comparison failed (ge)") - return - end if - - if (v2 < v1) then - call test_failed(error, "Version comparison failed (lt)") - return - end if - - if (.not. v2 <= v1) then - call test_failed(error, "Version comparison failed (le)") - return - end if - - call new_version(v1, [20, 1]) - call new_version(varray(1), [19]) - call new_version(varray(2), [18, 2]) - call new_version(varray(3), [18, 1]) - call new_version(varray(4), [1, 3, 1]) - - if (.not. all(v1 > varray)) then - call test_failed(error, "Version comparison failed (gt)") - return - end if - - call new_version(v1, [1, 2, 3]) - call new_version(v2, [2, 0, 0]) - - if (v1 > v2) then - call test_failed(error, "Version comparison failed (gt)") - return - end if - - if (v1 >= v2) then - call test_failed(error, "Version comparison failed (ge)") - return - end if - - if (v2 < v1) then - call test_failed(error, "Version comparison failed (lt)") - return - end if - - if (v2 <= v1) then - call test_failed(error, "Version comparison failed (le)") - return - end if - - call new_version(v1, [1, 2, 3]) - call new_version(v2, [1, 0, 4]) - - if (v2 > v1) then - call test_failed(error, "Version comparison failed (gt)") - return - end if - - if (v2 >= v1) then - call test_failed(error, "Version comparison failed (ge)") - return - end if - - if (v1 < v2) then - call test_failed(error, "Version comparison failed (lt)") - return - end if - - if (v1 <= v2) then - call test_failed(error, "Version comparison failed (le)") - return - end if - - call new_version(v1, [1, 0, 8]) - call new_version(v2, [1]) - - if (.not. v1 > v2) then - call test_failed(error, "Version comparison failed (gt)") - return - end if - - if (.not. v1 >= v2) then - call test_failed(error, "Version comparison failed (ge)") - return - end if - - if (.not. v2 < v1) then - call test_failed(error, "Version comparison failed (lt)") - return - end if - - if (.not. v2 <= v1) then - call test_failed(error, "Version comparison failed (le)") - return - end if - - call new_version(v1, [1]) - call new_version(v2, [1, 0, 8]) - - if (v1 > v2) then - call test_failed(error, "Version comparison failed (gt)") - return - end if - - if (v1 >= v2) then - call test_failed(error, "Version comparison failed (ge)") - return - end if - - if (v2 < v1) then - call test_failed(error, "Version comparison failed (lt)") - return - end if - - if (v2 <= v1) then - call test_failed(error, "Version comparison failed (le)") - return - end if - - end subroutine test_valid_compare - - - !> Semantic version matching - subroutine test_valid_match(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(version_t) :: v1, v2 - - call new_version(v1, [1, 1, 0]) - call new_version(v2, [1]) - - if (.not. (v1 .match. v2)) then - call test_failed(error, "Version comparison failed (match)") - return - end if - - if (v2 .match. v1) then - call test_failed(error, "Version comparison failed (match)") - return - end if - - call new_version(v1, [0, 5, 8]) - call new_version(v2, [0, 5]) - - if (.not. (v1 .match. v2)) then - call test_failed(error, "Version comparison failed (match)") - return - end if - - if (v2 .match. v1) then - call test_failed(error, "Version comparison failed (match)") - return - end if - - call new_version(v1, [1, 2]) - call new_version(v2, [1, 2, 0]) - - if (.not. (v1 .match. v2)) then - call test_failed(error, "Version comparison failed (match)") - return - end if - - if (.not. (v2 .match. v1)) then - call test_failed(error, "Version comparison failed (match)") - return - end if - - end subroutine test_valid_match - - - !> Test if version string is preserved - subroutine test_valid_string(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - character(len=*), parameter :: str_in = "20.1.100" - type(version_t) :: version - - call new_version(version, str_in, error) - if (allocated(error)) return - - if (str_in /= version%s()) then - call test_failed(error, "Expected "//str_in//" but got "//version%s()) - end if - - end subroutine test_valid_string - - - !> Empty string does not represent a version - subroutine test_invalid_empty(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(version_t) :: version - - call new_version(version, "", error) - - end subroutine test_invalid_empty - - - !> Version is invalid with trailing dots - subroutine test_invalid_version1(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(version_t) :: version - - call new_version(version, "1.", error) - - end subroutine test_invalid_version1 - - - !> Version is invalid with multiple dots - subroutine test_invalid_version2(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(version_t) :: version - - call new_version(version, "1..1", error) - - end subroutine test_invalid_version2 - - - !> Version is invalid if it is not a version - subroutine test_invalid_version3(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(version_t) :: version - - call new_version(version, "one", error) - - end subroutine test_invalid_version3 - - - !> Check if overflows of the internal size constraint are handled gracefully - subroutine test_invalid_overflow(error) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - type(version_t) :: version - - call new_version(version, "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0", error) - - end subroutine test_invalid_overflow - - -end module test_versioning diff --git a/test/fpm_test/testsuite.f90 b/test/fpm_test/testsuite.f90 deleted file mode 100644 index 124d19a5b4..0000000000 --- a/test/fpm_test/testsuite.f90 +++ /dev/null @@ -1,286 +0,0 @@ -!> Define some procedures to automate collecting and launching of tests -module testsuite - use fpm_error, only : error_t, test_failed => fatal_error - implicit none - private - - public :: run_testsuite, run_selected, new_unittest, new_testsuite, test_failed - public :: select_test, select_suite - public :: check_string - public :: unittest_t, testsuite_t, error_t - - - abstract interface - !> Entry point for tests - subroutine test_interface(error) - import :: error_t - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - end subroutine test_interface - end interface - - - !> Declaration of a unit test - type :: unittest_t - - !> Name of the test - character(len=:), allocatable :: name - - !> Entry point of the test - procedure(test_interface), pointer, nopass :: test => null() - - !> Whether test is supposed to fail - logical :: should_fail = .false. - - end type unittest_t - - - abstract interface - !> Collect all tests - subroutine collect_interface(testsuite) - import :: unittest_t - - !> Collection of tests - type(unittest_t), allocatable, intent(out) :: testsuite(:) - - end subroutine collect_interface - end interface - - - !> Collection of unit tests - type :: testsuite_t - - !> Name of the testsuite - character(len=:), allocatable :: name - - !> Entry point of the test - procedure(collect_interface), pointer, nopass :: collect => null() - - end type testsuite_t - - - character(len=*), parameter :: fmt = '("#", *(1x, a))' - character(len=*), parameter :: indent = repeat(" ", 5) // repeat(".", 3) - - -contains - - - !> Driver for testsuite - subroutine run_testsuite(collect, unit, stat) - - !> Collect tests - procedure(collect_interface) :: collect - - !> Unit for IO - integer, intent(in) :: unit - - !> Number of failed tests - integer, intent(inout) :: stat - - type(unittest_t), allocatable :: testsuite(:) - integer :: ii - - call collect(testsuite) - - do ii = 1, size(testsuite) - write(unit, '("#", 3(1x, a), 1x, "(", i0, "/", i0, ")")') & - & "Starting", testsuite(ii)%name, "...", ii, size(testsuite) - call run_unittest(testsuite(ii), unit, stat) - end do - - end subroutine run_testsuite - - - !> Driver for selective testing - subroutine run_selected(collect, name, unit, stat) - - !> Collect tests - procedure(collect_interface) :: collect - - !> Name of the selected test - character(len=*), intent(in) :: name - - !> Unit for IO - integer, intent(in) :: unit - - !> Number of failed tests - integer, intent(inout) :: stat - - type(unittest_t), allocatable :: testsuite(:) - integer :: ii - - call collect(testsuite) - - ii = select_test(testsuite, name) - - if (ii > 0 .and. ii <= size(testsuite)) then - call run_unittest(testsuite(ii), unit, stat) - else - write(unit, fmt) "Available tests:" - do ii = 1, size(testsuite) - write(unit, fmt) "-", testsuite(ii)%name - end do - stat = -huge(ii) - end if - - end subroutine run_selected - - - !> Run a selected unit test - subroutine run_unittest(test, unit, stat) - - !> Unit test - type(unittest_t), intent(in) :: test - - !> Unit for IO - integer, intent(in) :: unit - - !> Number of failed tests - integer, intent(inout) :: stat - - type(error_t), allocatable :: error - - call test%test(error) - if (allocated(error) .neqv. test%should_fail) then - if (test%should_fail) then - write(unit, fmt) indent, test%name, "[UNEXPECTED PASS]" - else - write(unit, fmt) indent, test%name, "[FAILED]" - end if - stat = stat + 1 - else - if (test%should_fail) then - write(unit, fmt) indent, test%name, "[EXPECTED FAIL]" - else - write(unit, fmt) indent, test%name, "[PASSED]" - end if - end if - if (allocated(error)) then - write(unit, fmt) "Message:", error%message - end if - - end subroutine run_unittest - - - !> Select a unit test from all available tests - function select_test(tests, name) result(pos) - - !> Name identifying the test suite - character(len=*), intent(in) :: name - - !> Available unit tests - type(unittest_t) :: tests(:) - - !> Selected test suite - integer :: pos - - integer :: it - - pos = 0 - do it = 1, size(tests) - if (name == tests(it)%name) then - pos = it - exit - end if - end do - - end function select_test - - - !> Select a test suite from all available suites - function select_suite(suites, name) result(pos) - - !> Name identifying the test suite - character(len=*), intent(in) :: name - - !> Available test suites - type(testsuite_t) :: suites(:) - - !> Selected test suite - integer :: pos - - integer :: it - - pos = 0 - do it = 1, size(suites) - if (name == suites(it)%name) then - pos = it - exit - end if - end do - - end function select_suite - - - !> Register a new unit test - function new_unittest(name, test, should_fail) result(self) - - !> Name of the test - character(len=*), intent(in) :: name - - !> Entry point for the test - procedure(test_interface) :: test - - !> Whether test is supposed to error or not - logical, intent(in), optional :: should_fail - - !> Newly registered test - type(unittest_t) :: self - - self%name = name - self%test => test - if (present(should_fail)) self%should_fail = should_fail - - end function new_unittest - - - !> Register a new testsuite - function new_testsuite(name, collect) result(self) - - !> Name of the testsuite - character(len=*), intent(in) :: name - - !> Entry point to collect tests - procedure(collect_interface) :: collect - - !> Newly registered testsuite - type(testsuite_t) :: self - - self%name = name - self%collect => collect - - end function new_testsuite - - - !> Check a deferred length character variable against a reference value - subroutine check_string(error, actual, expected, name) - - !> Error handling - type(error_t), allocatable, intent(out) :: error - - !> Actual string value - character(len=:), allocatable, intent(in) :: actual - - !> Expected string value - character(len=*), intent(in) :: expected - - !> Name of the string to check - character(len=*), intent(in) :: name - - if (.not.allocated(actual)) then - call test_failed(error, name//" is not set correctly") - return - end if - - if (actual /= expected) then - call test_failed(error, name//" is "//actual// & - & " but should be "//expected) - end if - - end subroutine check_string - - -end module testsuite diff --git a/test/help_test/help_test.f90 b/test/help_test/help_test.f90 deleted file mode 100644 index 8112b81a37..0000000000 --- a/test/help_test/help_test.f90 +++ /dev/null @@ -1,294 +0,0 @@ -program help_test -! note hardcoded len=k1 instead of len=: in this test is a work-around a gfortran bug in old -! pre-v8.3 versions -use,intrinsic :: iso_fortran_env, only : stdin=>input_unit, stdout=>output_unit, stderr=>error_unit -use fpm_filesystem, only : dirname, join_path, exists -use fpm_environment, only : get_os_type, OS_WINDOWS -implicit none -integer :: i -integer :: be, af -character(len=:),allocatable :: path -integer :: estat, cstat -integer,parameter :: k1=132 -character(len=k1) :: message -logical,allocatable :: tally(:) -!intel-bug!character(len=:),allocatable :: book1(:), book2(:) -character(len=k1),allocatable :: book1(:), book2(:) -!intel-bug!character(len=:),allocatable :: page1(:) -character(len=k1),allocatable :: page1(:) -integer :: lines -integer :: chars -! run a variety of "fpm help" variations and verify expected files are generated -character(len=*),parameter :: cmds(*) = [character(len=80) :: & -! build manual as pieces using various help commands -! debug version -'--version ',& ! verify fpm version being used -'--help > fpm_scratch_help.txt',& -'help new >> fpm_scratch_help.txt',& -'help update >> fpm_scratch_help.txt',& -'build --help >> fpm_scratch_help.txt',& -'help run >> fpm_scratch_help.txt',& -'help test >> fpm_scratch_help.txt',& -'help runner >> fpm_scratch_help.txt',& -'help install >> fpm_scratch_help.txt',& -'help list >> fpm_scratch_help.txt',& -'help help >> fpm_scratch_help.txt',& -'help clean >> fpm_scratch_help.txt',& -'help publish >> fpm_scratch_help.txt',& -'--version >> fpm_scratch_help.txt',& -! generate manual -' help manual > fpm_scratch_manual.txt'] - -!'fpm run >> fpm_scratch_help.txt',& -!'fpm run -- --list >> fpm_scratch_help.txt',& -!'fpm run -- list --list >> fpm_scratch_help.txt',& -character(len=*),parameter :: names(*)=[character(len=10) ::& - 'fpm','new','update','build','run','test','runner','install','list','help','clean'] -character(len=:), allocatable :: prog -integer :: length - - ! FIXME: Super hacky way to get the name of the fpm executable, - ! it works better than invoking fpm again but should be replaced ASAP. - call get_command_argument(0, length=length) - allocate(character(len=length) :: prog) - call get_command_argument(0, prog) - path = dirname(prog) - if (get_os_type() == OS_WINDOWS) then - prog = join_path(path, "..", "app", "fpm.exe") - if (.not.exists(prog)) then - prog = join_path(path, "..", "..", "app", "fpm.exe") - end if - else - prog = join_path(path, "..", "app", "fpm") - if (.not.exists(prog)) then - prog = join_path(path, "..", "..", "app", "fpm") - end if - end if - - write(*,'(g0:,1x)')'TEST help SUBCOMMAND STARTED' - if(allocated(tally))deallocate(tally) - allocate(tally(0)) - call wipe('fpm_scratch_help.txt') - call wipe('fpm_scratch_manual.txt') - - ! check that output has NAME SYNOPSIS DESCRIPTION - do i=1,size(names) - write(*,*)'check '//names(i)//' for NAME SYNOPSIS DESCRIPTION' - path= prog // ' help '//names(i)//' >fpm_scratch_help.txt' - message='' - call execute_command_line(path,exitstat=estat,cmdstat=cstat,cmdmsg=message) - write(*,'(*(g0))')'CMD=',path,' EXITSTAT=',estat,' CMDSTAT=',cstat,' MESSAGE=',trim(message) - tally=[tally,all([estat==0,cstat==0])] - call swallow('fpm_scratch_help.txt',page1) - if(size(page1)<3)then - write(*,*)'help for '//names(i)//' ridiculiously small' - tally=[tally,.false.] - exit - endif - !!write(*,*)findloc(page1,'NAME')==1 - be=count(.not.tally) - tally=[tally,count(page1=='NAME')==1] - tally=[tally,count(page1=='SYNOPSIS')==1] - tally=[tally,count(page1=='DESCRIPTION')==1] - af=count(.not.tally) - if(be/=af)then - write(*,*)'missing expected sections in ',names(i) - write(*,*)page1(1) ! assuming at least size 1 for debugging mingw - write(*,*)count(page1=='NAME') - write(*,*)count(page1=='SYNOPSIS') - write(*,*)count(page1=='DESCRIPTION') - write(*,'(a)')page1 - endif - write(*,*)'have completed ',count(tally),' tests' - call wipe('fpm_scratch_help.txt') - enddo - - - ! execute the fpm(1) commands - do i=1,size(cmds) - message='' - path= prog //' '//cmds(i) - call execute_command_line(path,exitstat=estat,cmdstat=cstat,cmdmsg=message) - write(*,'(*(g0))')'CMD=',path,' EXITSTAT=',estat,' CMDSTAT=',cstat,' MESSAGE=',trim(message) - tally=[tally,all([estat==0,cstat==0])] - enddo - - ! compare book written in fragments with manual - call swallow('fpm_scratch_help.txt',book1) - call swallow('fpm_scratch_manual.txt',book2) - ! get rid of lines from run() which is not on stderr at the moment - book1=pack(book1,index(book1,' + build/')==0) - book2=pack(book1,index(book2,' + build/')==0) - write(*,*)'book1 ',size(book1), len(book1) - write(*,*)'book2 ',size(book2), len(book2) - if(size(book1)/=size(book2))then - write(*,*)'manual and "debug" appended pages are not the same size' - tally=[tally,.false.] - else - if(all(book1/=book2))then - tally=[tally,.false.] - write(*,*)'manual and "debug" appended pages are not the same' - else - write(*,*)'manual and "debug" appended pages are the same' - tally=[tally,.true.] - endif - endif - - ! overall size of manual - !chars=size(book2) - !lines=max(count(char(10)==book2),count(char(13)==book2)) - chars=sum(len_trim(book2)) ! SUM TRIMMED LENGTH - lines=size(book2) - if( (chars<12000) .or. (lines<350) )then - write(*,*)'"debug" manual is suspiciously small, bytes=',chars,' lines=',lines - tally=[tally,.false.] - else - write(*,*)'"debug" manual size in bytes=',chars,' lines=',lines - tally=[tally,.true.] - endif - - write(*,'("HELP TEST TALLY=",*(g0))')tally - call wipe('fpm_scratch_help.txt') - call wipe('fpm_scratch_manual.txt') - if(all(tally))then - write(*,'(*(g0))')'PASSED: all ',count(tally),' tests passed ' - else - write(*,*)'FAILED: PASSED=',count(tally),' FAILED=',count(.not.tally) - stop 5 - endif - write(*,'(g0:,1x)')'TEST help SUBCOMMAND COMPLETE' -contains - -subroutine wipe(filename) -character(len=*),intent(in) :: filename -integer :: ios -integer :: lun -character(len=k1) :: message -open(file=filename,newunit=lun,iostat=ios,iomsg=message) -if(ios==0)then - close(unit=lun,iostat=ios,status='delete',iomsg=message) - if(ios/=0)then - write(*,*)''//trim(message) - endif -else - write(*,*)''//trim(message) -endif -end subroutine wipe - -subroutine slurp(filename,text) -implicit none -!$@(#) M_io::slurp(3f): allocate text array and read file filename into it -character(*),intent(in) :: filename ! filename to shlep -character(len=1),allocatable,intent(out) :: text(:) ! array to hold file -integer :: nchars, igetunit, ios -character(len=k1) :: message -character(len=4096) :: local_filename - ios=0 - nchars=0 - message='' - open(newunit=igetunit, file=trim(filename), action="read", iomsg=message,& - &form="unformatted", access="stream",status='old',iostat=ios) - local_filename=filename - if(ios==0)then ! if file was successfully opened - inquire(unit=igetunit, size=nchars) - if(nchars<=0)then - call stderr_local( '*slurp* empty file '//trim(local_filename) ) - return - endif - ! read file into text array - if(allocated(text))deallocate(text) ! make sure text array not allocated - allocate ( text(nchars) ) ! make enough storage to hold file - read(igetunit,iostat=ios,iomsg=message) text ! load input file -> text array - if(ios/=0)then - call stderr_local( '*slurp* bad read of '//trim(local_filename)//':'//trim(message) ) - endif - else - call stderr_local('*slurp* '//message) - allocate ( text(0) ) ! make enough storage to hold file - endif - close(iostat=ios,unit=igetunit) ! close if opened successfully or not -end subroutine slurp - -subroutine stderr_local(message) -character(len=*) :: message - write(*,'(a)')trim(message) ! write message to standard error -end subroutine stderr_local - -subroutine swallow(FILENAME,pageout) -implicit none -character(len=*),intent(in) :: FILENAME ! file to read -!intel-bug!character(len=:),allocatable,intent(out) :: pageout(:) ! page to hold file in memory -character(len=k1),allocatable,intent(out) :: pageout(:) ! page to hold file in memory -character(len=1),allocatable :: text(:) ! array to hold file in memory - - call slurp(FILENAME,text) ! allocate character array and copy file into it - - if(.not.allocated(text))then - write(*,*)'*swallow* failed to load file '//FILENAME - else ! convert array of characters to array of lines - pageout=page(text) - deallocate(text) ! release memory - endif -end subroutine swallow - -function page(array) result (table) - -!$@(#) M_strings::page(3fp): function to copy char array to page of text - -character(len=1),intent(in) :: array(:) -!intel-bug!character(len=:),allocatable :: table(:) -character(len=k1),allocatable :: table(:) -integer :: i -integer :: linelength -integer :: length -integer :: lines -integer :: linecount -integer :: position -integer :: sz -!!character(len=1),parameter :: nl=new_line('A') -character(len=1),parameter :: nl=char(10) -character(len=1),parameter :: cr=char(13) - lines=0 - linelength=0 - length=0 - sz=size(array) - do i=1,sz - if(array(i)==nl)then - linelength=max(linelength,length) - lines=lines+1 - length=0 - else - length=length+1 - endif - enddo - if(sz>0)then - if(array(sz)/=nl)then - lines=lines+1 - endif - endif - - if(allocated(table))deallocate(table) - !intel-bug!allocate(character(len=linelength) :: table(lines)) - allocate(character(len=k1) :: table(lines)) - table=' ' - linecount=1 - position=1 - do i=1,sz - if(array(i)==nl)then - linecount=linecount+1 - position=1 - elseif(array(i)==cr)then - elseif(linelength/=0)then - if(position>len(table))then - write(*,*)' adding character past edge of text',table(linecount),array(i) - elseif(linecount>size(table))then - write(*,*)' adding line past end of text',linecount,size(table) - else - table(linecount)(position:position)=array(i) - endif - position=position+1 - endif - enddo -end function page - -end program help_test diff --git a/test/new_test/new_test.f90 b/test/new_test/new_test.f90 deleted file mode 100644 index edf2975613..0000000000 --- a/test/new_test/new_test.f90 +++ /dev/null @@ -1,198 +0,0 @@ -program new_test -use,intrinsic :: iso_fortran_env, only : stdin=>input_unit, stdout=>output_unit, stderr=>error_unit -use fpm_filesystem, only : is_dir, list_files, exists, windows_path, join_path, & - dirname, run -use fpm_strings, only : string_t, operator(.in.) -use fpm_environment, only : get_os_type -use fpm_environment, only : OS_UNKNOWN, OS_LINUX, OS_MACOS, OS_CYGWIN, OS_SOLARIS, OS_FREEBSD, OS_OPENBSD, OS_WINDOWS -implicit none -type(string_t), allocatable :: file_names(:) -integer :: i, j, k -character(len=:),allocatable :: cmdpath -character(len=:),allocatable :: path -character(len=*),parameter :: scr = 'fpm_scratch_' -character(len=*),parameter :: cmds(*) = [character(len=80) :: & -! run a variety of "fpm new" variations and verify expected files are generated -'new', & -'new name-with-hyphens', & -'new '//scr//'A', & -'new '//scr//'B --lib', & -'new '//scr//'C --app', & -'new '//scr//'D --test', & -'new '//scr//'E --lib --test ', & -'new '//scr//'F --lib --app', & -'new '//scr//'G --test --app', & -'new '//scr//'H --example', & -'new '//scr//'BB --lib', & -'new '//scr//'BB --test ', & -'new '//scr//'BB --backfill --test', & -'new '//scr//'CC --test --src --app', & -'new --version', & -'new --help'] -integer :: estat, cstat -character(len=256) :: message -character(len=:),allocatable :: directories(:) -character(len=:),allocatable :: shortdirs(:) -character(len=:),allocatable :: expected(:) -logical,allocatable :: tally(:) -logical :: IS_OS_WINDOWS -character(len=*),parameter :: dirs_to_be_removed = 'fpm_scratch_* name-with-hyphens' -character(len=:),allocatable :: rm_command - write(*,'(g0:,1x)')'TEST new SUBCOMMAND (draft):' - - cmdpath = get_command_path() - allocate(tally(0)) - shortdirs=[character(len=80) :: 'A','B','C','D','E','F','G','H','BB','CC'] - allocate(character(len=80) :: directories(size(shortdirs))) - - !! SEE IF EXPECTED FILES ARE GENERATED - !! Issues: - !! o assuming fpm command is in expected path and the new version - !! o DOS versus POSIX filenames - is_os_windows=.false. - select case (get_os_type()) - case (OS_UNKNOWN, OS_LINUX, OS_MACOS, OS_CYGWIN, OS_SOLARIS, OS_FREEBSD, OS_OPENBSD) - call execute_command_line('rm -rf fpm_scratch_*',exitstat=estat,cmdstat=cstat,cmdmsg=message) - path=cmdpath - case (OS_WINDOWS) - path=windows_path(cmdpath) - is_os_windows=.true. - do i=1,size(directories) - call execute_command_line('rmdir /s /q fpm_scratch_'//trim(shortdirs(i)),exitstat=estat,& - cmdstat=cstat,cmdmsg=message) - end do - case default - write(*,*)'ERROR: unknown OS. Stopping test' - stop 2 - end select - do i=1,size(directories) - directories(i)=scr//trim(shortdirs(i)) - if( is_dir(trim(directories(i))) ) then - write(*,*)'ERROR:',trim( directories(i) ),' already exists' - write(*,*)' you must remove scratch directories before performing this test' - write(*,'(*(g0:,1x))')'directories:',(trim(directories(j)),j=1,size(directories)),'name-with-hyphens' - stop - endif - enddo - ! execute the fpm(1) commands - do i=1,size(cmds) - message='' - write(*,*)path//' '//cmds(i) - call execute_command_line(path//' '//cmds(i),exitstat=estat,cmdstat=cstat,cmdmsg=message) - write(*,'(*(g0))')'CMD=',trim(cmds(i)),' EXITSTAT=',estat,' CMDSTAT=',cstat,' MESSAGE=',trim(message) - enddo - - if( is_dir('name-with-hyphens') ) then - tally=[tally,.true.] - - else - write(*,*)'ERROR: directory name-with-hyphens/ exists' - tally=[tally,.false.] - endif - - ! assuming hidden files in .git and .gitignore are ignored for now - TESTS: do i=1,size(directories) - ! test if expected directory exists - if( .not. is_dir(trim( directories(i))) ) then - tally=[tally,.false.] - write(*,*)'ERROR:',trim( directories(i) ),' is not a directory' - else - select case(shortdirs(i)) - case('A'); expected=[ character(len=80)::& - &'A/app','A/fpm.toml','A/README.md','A/src','A/test','A/app/main.f90','A/src/'//scr//'A.f90','A/test/check.f90'] - case('B'); expected=[ character(len=80)::& - &'B/fpm.toml','B/README.md','B/src','B/src/'//scr//'B.f90'] - case('C'); expected=[ character(len=80)::& - &'C/app','C/fpm.toml','C/README.md','C/app/main.f90'] - case('D'); expected=[ character(len=80)::& - &'D/fpm.toml','D/README.md','D/test','D/test/check.f90'] - case('E'); expected=[ character(len=80)::& - &'E/fpm.toml','E/README.md','E/src','E/test','E/src/'//scr//'E.f90','E/test/check.f90'] - case('F'); expected=[ character(len=80)::& - &'F/app','F/fpm.toml','F/README.md','F/src','F/app/main.f90','F/src/'//scr//'F.f90'] - case('G'); expected=[ character(len=80)::& - &'G/app','G/fpm.toml','G/README.md','G/test','G/app/main.f90','G/test/check.f90'] - case('H'); expected=[ character(len=80)::& - &'H/example','H/fpm.toml','H/README.md','H/example/demo.f90'] - case('BB'); expected=[ character(len=80)::& - &'BB/fpm.toml','BB/README.md','BB/src','BB/test','BB/src/'//scr//'BB.f90','BB/test/check.f90'] - case('CC'); expected=[ character(len=80)::& - &'CC/app','CC/fpm.toml','CC/README.md','CC/src','CC/test','CC/app/main.f90','CC/src/'//scr//'CC.f90','CC/test/check.f90'] - case default - write(*,*)'ERROR: internal error. unknown directory name ',trim(shortdirs(i)) - stop 4 - end select - !! MSwindows has hidden files in it - !! Warning: This only looks for expected files. If there are more files than expected it does not fail - call list_files(trim(directories(i)), file_names,recurse=.true.) - - if(size(expected)/=size(file_names))then - write(*,*)'WARNING: unexpected number of files in file list=',size(file_names),' expected ',size(expected) - write(*,'("EXPECTED: ",*(g0:,","))')(scr//trim(expected(j)),j=1,size(expected)) - write(*,'("FOUND: ",*(g0:,","))')(trim(file_names(j)%s),j=1,size(file_names)) - endif - - do j=1,size(expected) - - expected(j)=scr//expected(j) - if(is_os_windows) expected(j)=windows_path(expected(j)) - if( .not.(trim(expected(j)).in.file_names) )then - tally=[tally,.false.] - write(*,'("ERROR: FOUND ",*(g0:,", "))')( trim(file_names(k)%s), k=1,size(file_names) ) - write(*,'(*(g0))')' BUT NO MATCH FOR ',expected(j) - tally=[tally,.false.] - cycle TESTS - endif - enddo - tally=[tally,.true.] - endif - enddo TESTS - - ! clean up scratch files; might want an option to leave them for inspection - select case (get_os_type()) - case (OS_UNKNOWN, OS_LINUX, OS_MACOS, OS_CYGWIN, OS_SOLARIS, OS_FREEBSD, OS_OPENBSD) - rm_command = 'rm -rf ' // dirs_to_be_removed - case (OS_WINDOWS) - do i=1,size(directories) - rm_command = 'rmdir /s /q fpm_scratch_'//trim(shortdirs(i)) - call execute_command_line('rmdir /s /q fpm_scratch_'//trim(shortdirs(i)),exitstat=estat,& - cmdstat=cstat,cmdmsg=message) - end do - rm_command = 'rmdir /s /q name-with-hyphens' - end select - call execute_command_line(rm_command, exitstat=estat,cmdstat=cstat,cmdmsg=message) - - write(*,'("new TEST TALLY=",*(g0))')tally - if(all(tally))then - write(*,'(*(g0))')'PASSED: all ',count(tally),' tests passed ' - else - write(*,*)'FAILED: PASSED=',count(tally),' FAILED=',count(.not.tally) - stop 5 - endif -contains - function get_command_path() result(prog) - character(len=:), allocatable :: prog - - character(len=:), allocatable :: path - integer :: length - - ! FIXME: Super hacky way to get the name of the fpm executable, - ! it works better than invoking fpm again but should be replaced ASAP. - call get_command_argument(0, length=length) - allocate(character(len=length) :: prog) - call get_command_argument(0, prog) - path = dirname(prog) - if (get_os_type() == OS_WINDOWS) then - prog = join_path(path, "..", "app", "fpm.exe") - if (.not.exists(prog)) then - prog = join_path(path, "..", "..", "app", "fpm.exe") - end if - else - prog = join_path(path, "..", "app", "fpm") - if (.not.exists(prog)) then - prog = join_path(path, "..", "..", "app", "fpm") - end if - end if - - end function -end program new_test diff --git a/type/archiver_t.html b/type/archiver_t.html new file mode 100644 index 0000000000..9b48ffaa43 --- /dev/null +++ b/type/archiver_t.html @@ -0,0 +1,1387 @@ + + + + + + + + + + + + + archiver_t – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      archiver_t + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public, extends(serializable_t) :: archiver_t

      +

      Definition of archiver object

      +
      + +
      +

      Components

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      TypeVisibility AttributesNameInitial
      + + character(len=:), + public, + allocatable + ::ar +

      Path to archiver

      +
      + + logical, + public + + ::echo =.true. +

      Print all command

      +
      + + logical, + public + + ::use_response_file =.false. +

      Use response files to pass arguments

      +
      + + logical, + public + + ::verbose =.true. +

      Verbose output of command

      +
      + +
      +
      + + + +
      +

      Type-Bound Procedures

      +
      +
      +
      + +

      + generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_dump_to_toml(self, table, error) +

        + +

        Dump dependency to toml table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine dump_to_file(self, file, error, json) +

        + +

        Write serializable object to file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine dump_to_unit(self, unit, error, json) +

        + +

        Write serializable object to a formatted Fortran unit

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        Formatted unit

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format requested?

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + dump_to_toml + +

      +
      +
        +
      • +

        + public subroutine dump_to_toml(self, table, error) +

        + + +

        Dump dependency to toml table

        Read more… + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(archiver_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + load => load_from_toml, load_from_file, load_from_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_load_from_toml(self, table, error) +

        + +

        Read dependency from toml table (no checks made at this stage)

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine load_from_file(self, file, error, json) +

        + +

        Read dependency tree from file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine load_from_unit(self, unit, error, json) +

        + +

        Read dependency tree from file +init JSON interpreter +Read object from TOML table

        +

        use default TOML parser

        +

        Read object from TOML table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + load_from_toml + +

      +
      +
        +
      • +

        + public subroutine load_from_toml(self, table, error) +

        + + +

        Read dependency from toml table (no checks made at this stage)

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(archiver_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + make_archive + +

      +
      +
      + +

      Create static archive

      +
      +
        +
      • +

        + public subroutine make_archive(self, output, args, log_file, stat, dry_run) +

        + + +

        Create an archive

        Read more… + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(archiver_t), + intent(in) + + ::self +

        Instance of the archiver object

        +
        + + character(len=*), + intent(in) + + ::output +

        Name of the archive to generate

        +
        + + type(string_t), + intent(in) + + ::args(:) +

        Object files to include into the archive

        +
        + + character(len=*), + intent(in) + + ::log_file +

        Compiler output log file

        +
        + + integer, + intent(out) + + ::stat +

        Status flag

        +
        + + logical, + intent(in),optional + + ::dry_run +

        Optional mocking

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + operator(==) => serializable_is_same + +

      +
      +
        +
      • +

        + private function srcfile_is_same(this, that) +

        + +

        Check that two source files are equal +All checks passed!

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + serializable_is_same => ar_is_same + +

      +
      +
      + +

      Serialization interface

      +
      +
        +
      • +

        + public function ar_is_same(this, that) +

        + + +

        Check that two archiver_t objects are equal +All checks passed!

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(archiver_t), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public, non_overridable :: + test_serialization + +

      +
      +
      + +

      Test load/write roundtrip

      +
      +
        +
      • +

        + private subroutine test_serialization(self, message, error) +

        + +

        Test serialization of a serializable object +Dump to scratch file +Load from scratch file +Check same

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self + +
        + + character(len=*), + intent(in) + + ::message + +
        + + type(error_t), + intent(out), + allocatable + ::error + +
        + + +
      • +
      +
      + +
      +
      + +
      +

      Source Code

      +
      type, extends(serializable_t) :: archiver_t
      +    !> Path to archiver
      +    character(len=:), allocatable :: ar
      +    !> Use response files to pass arguments
      +    logical :: use_response_file = .false.
      +    !> Print all command
      +    logical :: echo = .true.
      +    !> Verbose output of command
      +    logical :: verbose = .true.
      +contains
      +    !> Create static archive
      +    procedure :: make_archive
      +
      +    !> Serialization interface
      +    procedure :: serializable_is_same => ar_is_same
      +    procedure :: dump_to_toml
      +    procedure :: load_from_toml
      +
      +end type archiver_t
      +
      + +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/type/build_config_t.html b/type/build_config_t.html new file mode 100644 index 0000000000..f92ee74c64 --- /dev/null +++ b/type/build_config_t.html @@ -0,0 +1,1407 @@ + + + + + + + + + + + + + build_config_t – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      build_config_t + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public, extends(serializable_t) :: build_config_t

      +

      Configuration data for build

      +
      + +
      +

      Components

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      TypeVisibility AttributesNameInitial
      + + logical, + public + + ::auto_examples =.true. +

      Automatic discovery of examples

      +
      + + logical, + public + + ::auto_executables =.true. +

      Automatic discovery of executables

      +
      + + logical, + public + + ::auto_tests =.true. +

      Automatic discovery of tests

      +
      + + type(string_t), + public, + allocatable + ::external_modules(:) +

      External modules to use

      +
      + + type(string_t), + public, + allocatable + ::link(:) +

      Libraries to link against

      +
      + + logical, + public + + ::module_naming =.false. +

      Enforcing of package module names

      +
      + + type(string_t), + public + + ::module_prefix + +
      + +
      +
      + + + +
      +

      Type-Bound Procedures

      +
      +
      +
      + +

      + generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_dump_to_toml(self, table, error) +

        + +

        Dump dependency to toml table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine dump_to_file(self, file, error, json) +

        + +

        Write serializable object to file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine dump_to_unit(self, unit, error, json) +

        + +

        Write serializable object to a formatted Fortran unit

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        Formatted unit

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format requested?

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + dump_to_toml + +

      +
      +
        +
      • +

        + private subroutine dump_to_toml(self, table, error) +

        + +

        Dump build config to toml table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(build_config_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + info + +

      +
      +
      + +

      Print information on this instance

      +
      +
        +
      • +

        + private subroutine info(self, unit, verbosity) +

        + +

        Write information on build configuration instance

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(build_config_t), + intent(in) + + ::self +

        Instance of the build configuration

        +
        + + integer, + intent(in) + + ::unit +

        Unit for IO

        +
        + + integer, + intent(in),optional + + ::verbosity +

        Verbosity of the printout

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + load => load_from_toml, load_from_file, load_from_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_load_from_toml(self, table, error) +

        + +

        Read dependency from toml table (no checks made at this stage)

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine load_from_file(self, file, error, json) +

        + +

        Read dependency tree from file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine load_from_unit(self, unit, error, json) +

        + +

        Read dependency tree from file +init JSON interpreter +Read object from TOML table

        +

        use default TOML parser

        +

        Read object from TOML table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + load_from_toml + +

      +
      +
        +
      • +

        + private subroutine load_from_toml(self, table, error) +

        + +

        Read build config from toml table (no checks made at this stage)

        +

        Module naming: fist, attempt boolean value first +Value found, but not a boolean. Attempt to read a prefix string

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(build_config_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + operator(==) => serializable_is_same + +

      +
      +
        +
      • +

        + private function srcfile_is_same(this, that) +

        + +

        Check that two source files are equal +All checks passed!

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + serializable_is_same => build_conf_is_same + +

      +
      +
      + +

      Serialization interface

      +
      +
        +
      • +

        + private function build_conf_is_same(this, that) +

        + +

        Check that two dependency trees are equal +All checks passed!

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(build_config_t), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public, non_overridable :: + test_serialization + +

      +
      +
      + +

      Test load/write roundtrip

      +
      +
        +
      • +

        + private subroutine test_serialization(self, message, error) +

        + +

        Test serialization of a serializable object +Dump to scratch file +Load from scratch file +Check same

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self + +
        + + character(len=*), + intent(in) + + ::message + +
        + + type(error_t), + intent(out), + allocatable + ::error + +
        + + +
      • +
      +
      + +
      +
      + +
      +

      Source Code

      +
          type, extends(serializable_t) :: build_config_t
      +
      +        !> Automatic discovery of executables
      +        logical :: auto_executables = .true.
      +
      +        !> Automatic discovery of examples
      +        logical :: auto_examples = .true.
      +
      +        !> Automatic discovery of tests
      +        logical :: auto_tests = .true.
      +
      +        !> Enforcing of package module names
      +        logical :: module_naming = .false.
      +        type(string_t) :: module_prefix
      +
      +        !> Libraries to link against
      +        type(string_t), allocatable :: link(:)
      +
      +        !> External modules to use
      +        type(string_t), allocatable :: external_modules(:)
      +
      +    contains
      +
      +        !> Print information on this instance
      +        procedure :: info
      +
      +        !> Serialization interface
      +        procedure :: serializable_is_same => build_conf_is_same
      +        procedure :: dump_to_toml
      +        procedure :: load_from_toml
      +
      +    end type build_config_t
      +
      + +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/type/build_progress_t.html b/type/build_progress_t.html new file mode 100644 index 0000000000..e19da3367f --- /dev/null +++ b/type/build_progress_t.html @@ -0,0 +1,771 @@ + + + + + + + + + + + + + build_progress_t – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      build_progress_t + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public :: build_progress_t

      +

      Build progress object

      +
      + +
      +

      Components

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      TypeVisibility AttributesNameInitial
      + + type(compile_command_table_t), + public + + ::compile_commands +

      The compile_commands.json table

      +
      + + type(console_t), + public + + ::console +

      Console object for updating console lines

      +
      + + integer, + public + + ::n_complete +

      Number of completed targets

      +
      + + integer, + public + + ::n_target +

      Total number of targets scheduled

      +
      + + integer, + public, + allocatable + ::output_lines(:) +

      Store needed when updating previous console lines

      +
      + + logical, + public + + ::plain_mode =.true. +

      ‘Plain’ output (no colors or updating)

      +
      + + type(build_target_ptr), + public, + pointer + ::target_queue(:) +

      Queue of scheduled build targets

      +
      + +
      +
      + +
      +

      Constructor

      +
      +
      + +

      public interface build_progress_t +

      +
      +
      +

      Constructor for build_progress_t

      +
      +
        +
      • +

        + private function new_build_progress(target_queue, plain_mode) result(progress) + +

        +

        Initialise a new build progress object

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + type(build_target_ptr), + intent(in), + target + ::target_queue(:) +

        The queue of scheduled targets

        +
        + + logical, + intent(in),optional + + ::plain_mode +

        Enable ‘plain’ output for progress object

        +
        + +

        + Return Value + type(build_progress_t) +

        +

        Progress object to initialise

        + +
      • +
      +
      + +
      +
      + + +
      +

      Type-Bound Procedures

      +
      +
      +
      + +

      + procedure, public :: + compiling_status => output_status_compiling + +

      +
      +
      + +

      Output ‘compiling’ status for build target

      +
      +
        +
      • +

        + private subroutine output_status_compiling(progress, queue_index) +

        + +

        Output ‘compiling’ status for build target and overall percentage progress

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(build_progress_t), + intent(inout) + + ::progress +

        Progress object

        +
        + + integer, + intent(in) + + ::queue_index +

        Index of build target in the target queue

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + completed_status => output_status_complete + +

      +
      +
      + +

      Output ‘complete’ status for build target

      +
      +
        +
      • +

        + private subroutine output_status_complete(progress, queue_index, build_stat) +

        + +

        Output ‘complete’ status for build target and update overall percentage progress

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(build_progress_t), + intent(inout) + + ::progress +

        Progress object

        +
        + + integer, + intent(in) + + ::queue_index +

        Index of build target in the target queue

        +
        + + integer, + intent(in) + + ::build_stat +

        Build status flag

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + dump_commands => output_write_compile_commands + +

      +
      +
      + +

      Output ‘compile_commands.json’ to build/ folder

      +
      +
        +
      • +

        + private subroutine output_write_compile_commands(progress, error) +

        + +

        Write compile commands table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(build_progress_t), + intent(inout) + + ::progress + +
        + + type(error_t), + + allocatable + ::error + +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + success => output_progress_success + +

      +
      +
      + +

      Output finished status for whole package

      +
      +
        +
      • +

        + private subroutine output_progress_success(progress) +

        + +

        Output finished status for whole package

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(build_progress_t), + intent(inout) + + ::progress + +
        + + +
      • +
      +
      + +
      +
      + +
      +

      Source Code

      +
      type build_progress_t
      +    !> Console object for updating console lines
      +    type(console_t) :: console
      +    !> Number of completed targets
      +    integer :: n_complete
      +    !> Total number of targets scheduled
      +    integer :: n_target
      +    !> 'Plain' output (no colors or updating)
      +    logical :: plain_mode = .true.
      +    !> Store needed when updating previous console lines
      +    integer, allocatable :: output_lines(:)
      +    !> Queue of scheduled build targets
      +    type(build_target_ptr), pointer :: target_queue(:)
      +    !> The compile_commands.json table
      +    type(compile_command_table_t) :: compile_commands
      +contains
      +    !> Output 'compiling' status for build target
      +    procedure :: compiling_status => output_status_compiling
      +    !> Output 'complete' status for build target
      +    procedure :: completed_status => output_status_complete
      +    !> Output finished status for whole package
      +    procedure :: success => output_progress_success
      +    !> Output 'compile_commands.json' to build/ folder
      +    procedure :: dump_commands => output_write_compile_commands
      +end type build_progress_t
      +
      + +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/type/build_target_ptr.html b/type/build_target_ptr.html new file mode 100644 index 0000000000..e4ff0ea6e8 --- /dev/null +++ b/type/build_target_ptr.html @@ -0,0 +1,252 @@ + + + + + + + + + + + + + build_target_ptr – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      build_target_ptr + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public :: build_target_ptr

      +

      Wrapper type for constructing arrays of [[build_target_t]] pointers

      +
      + +
      +

      Components

      + + + + + + + + + + + + + + + + + + + + + +
      TypeVisibility AttributesNameInitial
      + + type(build_target_t), + public, + pointer + ::ptr=> null() + +
      + +
      +
      + + + + +
      +

      Source Code

      +
      type build_target_ptr
      +
      +    type(build_target_t), pointer :: ptr => null()
      +
      +end type build_target_ptr
      +
      + +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/type/build_target_t.html b/type/build_target_t.html new file mode 100644 index 0000000000..ab090e41ea --- /dev/null +++ b/type/build_target_t.html @@ -0,0 +1,910 @@ + + + + + + + + + + + + + build_target_t – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      build_target_t + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public :: build_target_t

      +

      Type describing a generated build target

      +
      + +
      +

      Components

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      TypeVisibility AttributesNameInitial
      + + character(len=:), + public, + allocatable + ::compile_flags +

      Compile flags for this build target

      +
      + + type(build_target_ptr), + public, + allocatable + ::dependencies(:) +

      Resolved build dependencies

      +
      + + integer(kind=int64), + public, + allocatable + ::digest_cached +

      Previous source file hash

      +
      + + type(fortran_features_t), + public + + ::features +

      Language features

      +
      + + character(len=:), + public, + allocatable + ::link_flags +

      Link flags for this build target

      +
      + + type(string_t), + public, + allocatable + ::link_libraries(:) +

      Native libraries to link against

      +
      + + type(string_t), + public, + allocatable + ::link_objects(:) +

      Objects needed to link this target

      +
      + + type(string_t), + public, + allocatable + ::macros(:) +

      List of macros

      +
      + + character(len=:), + public, + allocatable + ::output_dir +

      File path of output directory

      +
      + + character(len=:), + public, + allocatable + ::output_file +

      File path of build target object relative to cwd

      +
      + + character(len=:), + public, + allocatable + ::output_log_file +

      File path of build log file relative to cwd

      +
      + + character(len=:), + public, + allocatable + ::output_name +

      File path of build target object relative to output_dir

      +
      + + character(len=:), + public, + allocatable + ::package_name +

      Name of parent package

      +
      + + integer, + public + + ::schedule =-1 +

      Targets in the same schedule group are guaranteed to be independent

      +
      + + logical, + public + + ::skip =.false. +

      Flag set if build target will be skipped (not built)

      +
      + + logical, + public + + ::sorted =.false. +

      Flag set if build target is sorted for building

      +
      + + type(srcfile_t), + public, + allocatable + ::source +

      Primary source for this build target

      +
      + + integer, + public + + ::target_type =FPM_TARGET_UNKNOWN +

      Target type

      +
      + + logical, + public + + ::touched =.false. +

      Flag set when first visited to check for circular dependencies

      +
      + + character(len=:), + public, + allocatable + ::version +

      Version number

      +
      + +
      +
      + + + +
      +

      Type-Bound Procedures

      +
      +
      +
      + +

      + procedure, public :: + info + +

      +
      +
      + +

      Print information on this instance

      +
      +
        +
      • +

        + private subroutine info(self, unit, verbosity) +

        + +

        Write information on a build target

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(build_target_t), + intent(in) + + ::self + +
        + + integer, + intent(in) + + ::unit + +
        + + integer, + intent(in),optional + + ::verbosity + +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + is_executable_target + +

      +
      +
        +
      • +

        + private elemental function is_executable_target(target_ptr, scope) result(is_exe) +

        + + + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(build_target_t), + intent(in) + + ::target_ptr + +
        + + integer, + intent(in) + + ::scope + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + set_output_dir + +

      +
      +
      + +

      Set output directory

      +
      +
        +
      • +

        + private subroutine set_output_dir(self, output_dir) +

        + +

        Helper function: update output directory of a target

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(build_target_t), + intent(inout) + + ::self + +
        + + character(len=*), + intent(in),optional + + ::output_dir + +
        + + +
      • +
      +
      + +
      +
      + +
      +

      Source Code

      +
      type build_target_t
      +
      +    !> File path of build target object relative to cwd
      +    character(:), allocatable :: output_file
      +
      +    !> File path of build target object relative to output_dir
      +    character(:), allocatable :: output_name
      +
      +    !> File path of output directory
      +    character(:), allocatable :: output_dir
      +
      +    !> File path of build log file relative to cwd
      +    character(:), allocatable :: output_log_file
      +
      +    !> Name of parent package
      +    character(:), allocatable :: package_name
      +
      +    !> Primary source for this build target
      +    type(srcfile_t), allocatable :: source
      +
      +    !> Resolved build dependencies
      +    type(build_target_ptr), allocatable :: dependencies(:)
      +
      +    !> Target type
      +    integer :: target_type = FPM_TARGET_UNKNOWN
      +
      +    !> Native libraries to link against
      +    type(string_t), allocatable :: link_libraries(:)
      +
      +    !> Objects needed to link this target
      +    type(string_t), allocatable :: link_objects(:)
      +
      +    !> Link flags for this build target
      +    character(:), allocatable :: link_flags
      +
      +    !> Compile flags for this build target
      +    character(:), allocatable :: compile_flags
      +
      +    !> Flag set when first visited to check for circular dependencies
      +    logical :: touched = .false.
      +
      +    !> Flag set if build target is sorted for building
      +    logical :: sorted = .false.
      +
      +    !> Flag set if build target will be skipped (not built)
      +    logical :: skip = .false.
      +
      +    !> Language features
      +    type(fortran_features_t) :: features
      +
      +    !> Targets in the same schedule group are guaranteed to be independent
      +    integer :: schedule = -1
      +
      +    !> Previous source file hash
      +    integer(int64), allocatable :: digest_cached
      +
      +    !> List of macros
      +    type(string_t), allocatable :: macros(:)
      +
      +    !> Version number
      +    character(:), allocatable :: version
      +    
      +    contains
      +    
      +        !> Print information on this instance
      +        procedure :: info    
      +        
      +        !> Set output directory
      +        procedure :: set_output_dir
      +         
      +        procedure :: is_executable_target
      +
      +end type build_target_t
      +
      + +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/type/compile_command_t.html b/type/compile_command_t.html new file mode 100644 index 0000000000..ef7facce73 --- /dev/null +++ b/type/compile_command_t.html @@ -0,0 +1,1393 @@ + + + + + + + + + + + + + compile_command_t – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      compile_command_t + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public, extends(serializable_t) :: compile_command_t

      +

      Definition of a build command

      +
      + +
      +

      Components

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      TypeVisibility AttributesNameInitial
      + + type(string_t), + public, + allocatable + ::arguments(:) + +
      + + type(string_t), + public + + ::directory + +
      + + type(string_t), + public + + ::file + +
      + +
      +
      + +
      +

      Constructor

      +
      +
      + +

      public interface compile_command_t +

      +
      +
        +
      • +

        + public function cct_new(directory, arguments, file) result(cct) + +

        + +

        Override default initializer (GCC 15 bug)

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + character(len=*), + intent(in) + + ::directory + +
        + + character(len=*), + intent(in),optional + + ::arguments(:) + +
        + + character(len=*), + intent(in) + + ::file + +
        + +

        + Return Value + type(compile_command_t) +

        + + +
      • +
      +
      + +
      +
      + + +
      +

      Type-Bound Procedures

      +
      +
      +
      + +

      + procedure, public :: + destroy => compile_command_destroy + +

      +
      +
      + +

      Operation

      +
      +
        +
      • +

        + public elemental subroutine compile_command_destroy(self) +

        + + +

        Cleanup compile command

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(compile_command_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_dump_to_toml(self, table, error) +

        + +

        Dump dependency to toml table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine dump_to_file(self, file, error, json) +

        + +

        Write serializable object to file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine dump_to_unit(self, unit, error, json) +

        + +

        Write serializable object to a formatted Fortran unit

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        Formatted unit

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format requested?

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + dump_to_toml => compile_command_dump_toml + +

      +
      +
        +
      • +

        + public subroutine compile_command_dump_toml(self, table, error) +

        + + +

        Dump compile_command_t to toml table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(compile_command_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + load => load_from_toml, load_from_file, load_from_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_load_from_toml(self, table, error) +

        + +

        Read dependency from toml table (no checks made at this stage)

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine load_from_file(self, file, error, json) +

        + +

        Read dependency tree from file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine load_from_unit(self, unit, error, json) +

        + +

        Read dependency tree from file +init JSON interpreter +Read object from TOML table

        +

        use default TOML parser

        +

        Read object from TOML table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + load_from_toml => compile_command_load_toml + +

      +
      +
        +
      • +

        + public subroutine compile_command_load_toml(self, table, error) +

        + + +

        Read compile_command_t from toml table (no checks made at this stage)

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(compile_command_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + operator(==) => serializable_is_same + +

      +
      +
        +
      • +

        + private function srcfile_is_same(this, that) +

        + +

        Check that two source files are equal +All checks passed!

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + serializable_is_same => compile_command_is_same + +

      +
      +
      + +

      Serialization interface

      +
      +
        +
      • +

        + public function compile_command_is_same(this, that) +

        + + +

        Check that two compile_command_t objects are equal +All checks passed!

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(compile_command_t), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public, non_overridable :: + test_serialization + +

      +
      +
      + +

      Test load/write roundtrip

      +
      +
        +
      • +

        + private subroutine test_serialization(self, message, error) +

        + +

        Test serialization of a serializable object +Dump to scratch file +Load from scratch file +Check same

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self + +
        + + character(len=*), + intent(in) + + ::message + +
        + + type(error_t), + intent(out), + allocatable + ::error + +
        + + +
      • +
      +
      + +
      +
      + +
      +

      Source Code

      +
          type, extends(serializable_t) :: compile_command_t
      +        
      +        type(string_t) :: directory
      +        
      +        type(string_t), allocatable :: arguments(:)
      +        
      +        type(string_t) :: file
      +        
      +        contains
      +        
      +        !> Operation
      +        procedure :: destroy              => compile_command_destroy
      +        
      +        !> Serialization interface
      +        procedure :: serializable_is_same => compile_command_is_same
      +        procedure :: dump_to_toml         => compile_command_dump_toml
      +        procedure :: load_from_toml       => compile_command_load_toml
      +        
      +    end type compile_command_t    
      +
      + +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/type/compile_command_table_t.html b/type/compile_command_table_t.html new file mode 100644 index 0000000000..aa0a554fd7 --- /dev/null +++ b/type/compile_command_table_t.html @@ -0,0 +1,1516 @@ + + + + + + + + + + + + + compile_command_table_t – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      compile_command_table_t + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public, extends(serializable_t) :: compile_command_table_t

      + +
      + +
      +

      Components

      + + + + + + + + + + + + + + + + + + + + + +
      TypeVisibility AttributesNameInitial
      + + type(compile_command_t), + public, + allocatable + ::command(:) + +
      + +
      +
      + + + +
      +

      Type-Bound Procedures

      +
      +
      +
      + +

      + procedure, public :: + destroy => cct_destroy + +

      +
      +
      + +

      Operation

      +
      +
        +
      • +

        + public elemental subroutine cct_destroy(self) +

        + + +

        Cleanup a compile command table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(compile_command_table_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_dump_to_toml(self, table, error) +

        + +

        Dump dependency to toml table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine dump_to_file(self, file, error, json) +

        + +

        Write serializable object to file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine dump_to_unit(self, unit, error, json) +

        + +

        Write serializable object to a formatted Fortran unit

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        Formatted unit

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format requested?

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + dump_to_toml => cct_dump_toml + +

      +
      +
        +
      • +

        + public subroutine cct_dump_toml(self, table, error) +

        + + +

        Dump compile_command_table_t to toml table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(compile_command_table_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + load => load_from_toml, load_from_file, load_from_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_load_from_toml(self, table, error) +

        + +

        Read dependency from toml table (no checks made at this stage)

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine load_from_file(self, file, error, json) +

        + +

        Read dependency tree from file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine load_from_unit(self, unit, error, json) +

        + +

        Read dependency tree from file +init JSON interpreter +Read object from TOML table

        +

        use default TOML parser

        +

        Read object from TOML table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + load_from_toml => cct_load_toml + +

      +
      +
        +
      • +

        + public subroutine cct_load_toml(self, table, error) +

        + + +

        Read compile_command_table_t from toml table (no checks made at this stage)

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(compile_command_table_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + operator(==) => serializable_is_same + +

      +
      +
        +
      • +

        + private function srcfile_is_same(this, that) +

        + +

        Check that two source files are equal +All checks passed!

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + register => cct_register, cct_register_object + +

      +
      +
        +
      • +

        + public subroutine cct_register(self, command, target_os, error) +

        + + +

        Register a new compile command

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(compile_command_table_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + character(len=*), + intent(in) + + ::command +

        Data structure

        +
        + + integer, + intent(in) + + ::target_os +

        The target OS of the compile_commands.json (may be cross-compiling)

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + public pure subroutine cct_register_object(self, command, error) +

        + + + + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(compile_command_table_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(compile_command_t), + intent(in) + + ::command +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + serializable_is_same => cct_is_same + +

      +
      +
      + +

      Serialization interface

      +
      +
        +
      • +

        + public function cct_is_same(this, that) +

        + + +

        Check that two compile_command_table_t objects are equal +All checks passed!

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(compile_command_table_t), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public, non_overridable :: + test_serialization + +

      +
      +
      + +

      Test load/write roundtrip

      +
      +
        +
      • +

        + private subroutine test_serialization(self, message, error) +

        + +

        Test serialization of a serializable object +Dump to scratch file +Load from scratch file +Check same

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self + +
        + + character(len=*), + intent(in) + + ::message + +
        + + type(error_t), + intent(out), + allocatable + ::error + +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + write => cct_write + +

      +
      +
        +
      • +

        + public subroutine cct_write(self, filename, error) +

        + + +

        Write compile_commands.json file. Because Jonquil does not support non-named arrays, +create a custom json here.

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(compile_command_table_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + character(len=*), + intent(in) + + ::filename +

        The file name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      + +
      +

      Source Code

      +
          type, extends(serializable_t) :: compile_command_table_t
      +        
      +        type(compile_command_t), allocatable :: command(:)
      +        
      +        contains
      +        
      +        !> Operation
      +        procedure :: destroy              => cct_destroy        
      +        procedure :: write                => cct_write
      +        
      +        procedure, private :: cct_register
      +        procedure, private :: cct_register_object
      +        generic   :: register             => cct_register, &
      +                                             cct_register_object
      +        
      +        !> Serialization interface
      +        procedure :: serializable_is_same => cct_is_same
      +        procedure :: dump_to_toml         => cct_dump_toml
      +        procedure :: load_from_toml       => cct_load_toml
      +        
      +        
      +    end type compile_command_table_t    
      +
      + +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/type/compiler_t.html b/type/compiler_t.html new file mode 100644 index 0000000000..439ca600d7 --- /dev/null +++ b/type/compiler_t.html @@ -0,0 +1,3426 @@ + + + + + + + + + + + + + compiler_t – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      compiler_t + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public, extends(serializable_t) :: compiler_t

      +

      Definition of compiler object

      +
      + +
      +

      Components

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      TypeVisibility AttributesNameInitial
      + + character(len=:), + public, + allocatable + ::cc +

      Path to the C compiler

      +
      + + character(len=:), + public, + allocatable + ::cxx +

      Path to the C++ compiler

      +
      + + logical, + public + + ::echo =.true. +

      Print all commands

      +
      + + character(len=:), + public, + allocatable + ::fc +

      Path to the Fortran compiler

      +
      + + integer(kind=compiler_enum), + public + + ::id =id_unknown +

      Identifier of the compiler

      +
      + + logical, + public + + ::verbose =.true. +

      Verbose output of command

      +
      + +
      +
      + + + +
      +

      Type-Bound Procedures

      +
      +
      +
      + +

      + procedure, public :: + check_flags_supported + +

      +
      +
        +
      • +

        + public function check_flags_supported(self, compile_flags, link_flags) +

        + + +

        Check if the given compile and/or link flags are accepted by the compiler

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(compiler_t), + intent(in) + + ::self + +
        + + character(len=*), + intent(in),optional + + ::compile_flags + +
        + + character(len=*), + intent(in),optional + + ::link_flags + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + check_fortran_source_runs + +

      +
      +
      + +

      Fortran feature support

      +
      +
        +
      • +

        + public function check_fortran_source_runs(self, input, compile_flags, link_flags) result(success) +

        + + +

        Run a single-source Fortran program using the current compiler +Compile a Fortran object +Create temporary source file +Write contents +Get flags +Intel: Needs -warn last for error on unknown command line arguments to work +Compile and link program +Run and retrieve exit code

        Read more… + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(compiler_t), + intent(in) + + ::self +

        Instance of the compiler object

        +
        + + character(len=*), + intent(in) + + ::input +

        Program Source

        +
        + + character(len=*), + intent(in),optional + + ::compile_flags +

        Optional build and link flags

        +
        + + character(len=*), + intent(in),optional + + ::link_flags +

        Optional build and link flags

        +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + compile_c + +

      +
      +
      + +

      Compile a C object

      +
      +
        +
      • +

        + public subroutine compile_c(self, input, output, args, log_file, stat, table, dry_run) +

        + + +

        Compile a C object

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(compiler_t), + intent(in) + + ::self +

        Instance of the compiler object

        +
        + + character(len=*), + intent(in) + + ::input +

        Source file input

        +
        + + character(len=*), + intent(in) + + ::output +

        Output file of object

        +
        + + character(len=*), + intent(in) + + ::args +

        Arguments for compiler

        +
        + + character(len=*), + intent(in) + + ::log_file +

        Compiler output log file

        +
        + + integer, + intent(out) + + ::stat +

        Status flag

        +
        + + type(compile_command_table_t), + intent(inout),optional + + ::table +

        Optional compile_commands table

        +
        + + logical, + intent(in),optional + + ::dry_run +

        Optional mocking

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + compile_cpp + +

      +
      +
      + +

      Compile a CPP object

      +
      +
        +
      • +

        + public subroutine compile_cpp(self, input, output, args, log_file, stat, table, dry_run) +

        + + +

        Compile a CPP object

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(compiler_t), + intent(in) + + ::self +

        Instance of the compiler object

        +
        + + character(len=*), + intent(in) + + ::input +

        Source file input

        +
        + + character(len=*), + intent(in) + + ::output +

        Output file of object

        +
        + + character(len=*), + intent(in) + + ::args +

        Arguments for compiler

        +
        + + character(len=*), + intent(in) + + ::log_file +

        Compiler output log file

        +
        + + integer, + intent(out) + + ::stat +

        Status flag

        +
        + + type(compile_command_table_t), + intent(inout),optional + + ::table +

        Optional compile_commands table

        +
        + + logical, + intent(in),optional + + ::dry_run +

        Optional mocking

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + compile_fortran + +

      +
      +
      + +

      Compile a Fortran object

      +
      +
        +
      • +

        + public subroutine compile_fortran(self, input, output, args, log_file, stat, table, dry_run) +

        + + +

        Compile a Fortran object

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(compiler_t), + intent(in) + + ::self +

        Instance of the compiler object

        +
        + + character(len=*), + intent(in) + + ::input +

        Source file input

        +
        + + character(len=*), + intent(in) + + ::output +

        Output file of object

        +
        + + character(len=*), + intent(in) + + ::args +

        Arguments for compiler

        +
        + + character(len=*), + intent(in) + + ::log_file +

        Compiler output log file

        +
        + + integer, + intent(out) + + ::stat +

        Status flag

        +
        + + type(compile_command_table_t), + intent(inout),optional + + ::table +

        Optional compile_commands table

        +
        + + logical, + intent(in),optional + + ::dry_run +

        Optional mocking

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_dump_to_toml(self, table, error) +

        + +

        Dump dependency to toml table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine dump_to_file(self, file, error, json) +

        + +

        Write serializable object to file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine dump_to_unit(self, unit, error, json) +

        + +

        Write serializable object to a formatted Fortran unit

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        Formatted unit

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format requested?

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + dump_to_toml => compiler_dump + +

      +
      +
        +
      • +

        + public subroutine compiler_dump(self, table, error) +

        + + +

        Dump dependency to toml table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(compiler_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + enumerate_libraries + +

      +
      +
      + +

      Enumerate libraries, based on compiler and platform

      +
      +
        +
      • +

        + public function enumerate_libraries(self, prefix, libs) result(r) +

        + + +

        Enumerate libraries, based on compiler and platform

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(compiler_t), + intent(in) + + ::self + +
        + + character(len=*), + intent(in) + + ::prefix + +
        + + type(string_t), + intent(in) + + ::libs(:) + +
        + +

        + Return Value + character(len=:), allocatable +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + get_default_flags + +

      +
      +
      + +

      Get default compiler flags

      +
      +
        +
      • +

        + public function get_default_flags(self, release) result(flags) +

        + + + + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(compiler_t), + intent(in) + + ::self + +
        + + logical, + intent(in) + + ::release + +
        + +

        + Return Value + character(len=:), allocatable +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + get_export_flags + +

      +
      +
      + +

      Get library export flags

      +
      +
        +
      • +

        + public function get_export_flags(self, target_dir, target_name) result(export_flags) +

        + + +

        Generate library export flags for a shared library build

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(compiler_t), + intent(in) + + ::self +

        Instance of the compiler

        +
        + + character(len=*), + intent(in) + + ::target_dir +

        Path and package name

        +
        + + character(len=*), + intent(in) + + ::target_name +

        Path and package name

        +
        + +

        + Return Value + character(len=:), allocatable +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + get_feature_flag + +

      +
      +
      + +

      Get feature flag

      +
      +
        +
      • +

        + public function get_feature_flag(self, feature) result(flags) +

        + + + + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(compiler_t), + intent(in) + + ::self + +
        + + character(len=*), + intent(in) + + ::feature + +
        + +

        + Return Value + character(len=:), allocatable +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + get_headerpad_flags + +

      +
      +
      + +

      Generate header padding flags for macOS executables

      +
      +
        +
      • +

        + public function get_headerpad_flags(self) result(flags) +

        + + +

        Generate header padding flags for install_name_tool compatibility on macOS

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(compiler_t), + intent(in) + + ::self + +
        + +

        + Return Value + character(len=:), allocatable +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + get_include_flag + +

      +
      +
      + +

      Get flag for include directories

      +
      +
        +
      • +

        + public function get_include_flag(self, path) result(flags) +

        + + + + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(compiler_t), + intent(in) + + ::self + +
        + + character(len=*), + intent(in) + + ::path + +
        + +

        + Return Value + character(len=:), allocatable +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + get_install_name_flags + +

      +
      +
      + +

      Get library install name flags

      +
      +
        +
      • +

        + public function get_install_name_flags(self, target_dir, target_name) result(flags) +

        + + +

        Generate install_name flag for a shared library build on macOS

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(compiler_t), + intent(in) + + ::self + +
        + + character(len=*), + intent(in) + + ::target_dir + +
        + + character(len=*), + intent(in) + + ::target_name + +
        + +

        + Return Value + character(len=:), allocatable +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + get_main_flags + +

      +
      +
      + +

      Get flags for the main linking command

      +
      +
        +
      • +

        + public subroutine get_main_flags(self, language, flags) +

        + + +

        Get special flags for the main linker

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(compiler_t), + intent(in) + + ::self + +
        + + character(len=*), + intent(in) + + ::language + +
        + + character(len=:), + intent(out), + allocatable + ::flags + +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + get_module_flag + +

      +
      +
      + +

      Get flag for module output directories

      +
      +
        +
      • +

        + public function get_module_flag(self, path) result(flags) +

        + + + + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(compiler_t), + intent(in) + + ::self + +
        + + character(len=*), + intent(in) + + ::path + +
        + +

        + Return Value + character(len=:), allocatable +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + is_gnu + +

      +
      +
      + +

      Check whether this is a GNU compiler

      +
      +
        +
      • +

        + public pure function is_gnu(self) +

        + + + + +

        Arguments

        + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(compiler_t), + intent(in) + + ::self + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + is_intel + +

      +
      +
      + +

      Check whether this is an Intel compiler

      +
      +
        +
      • +

        + public pure function is_intel(self) +

        + + + + +

        Arguments

        + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(compiler_t), + intent(in) + + ::self + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + is_unknown + +

      +
      +
      + +

      Check whether compiler is recognized

      +
      +
        +
      • +

        + public pure function is_unknown(self) +

        + + + + +

        Arguments

        + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(compiler_t), + intent(in) + + ::self + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + link => link_executable + +

      +
      +
      + +

      Link executable

      +
      +
        +
      • +

        + public subroutine link_executable(self, output, args, log_file, stat, dry_run) +

        + + +

        Link an executable

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(compiler_t), + intent(in) + + ::self +

        Instance of the compiler object

        +
        + + character(len=*), + intent(in) + + ::output +

        Output file of object

        +
        + + character(len=*), + intent(in) + + ::args +

        Arguments for compiler

        +
        + + character(len=*), + intent(in) + + ::log_file +

        Compiler output log file

        +
        + + integer, + intent(out) + + ::stat +

        Status flag

        +
        + + logical, + intent(in),optional + + ::dry_run +

        Optional mocking

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + link_shared + +

      +
      +
      + +

      Link a shared library

      +
      +
        +
      • +

        + public subroutine link_shared(self, output, args, log_file, stat, dry_run) +

        + + +

        Link a shared library

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(compiler_t), + intent(in) + + ::self +

        Instance of the compiler object

        +
        + + character(len=*), + intent(in) + + ::output +

        Output file of shared library object

        +
        + + character(len=*), + intent(in) + + ::args +

        Arguments for the compiler

        +
        + + character(len=*), + intent(in) + + ::log_file +

        Compiler output log file

        +
        + + integer, + intent(out) + + ::stat +

        Status flag

        +
        + + logical, + intent(in),optional + + ::dry_run +

        Optional mocking

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + load => load_from_toml, load_from_file, load_from_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_load_from_toml(self, table, error) +

        + +

        Read dependency from toml table (no checks made at this stage)

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine load_from_file(self, file, error, json) +

        + +

        Read dependency tree from file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine load_from_unit(self, unit, error, json) +

        + +

        Read dependency tree from file +init JSON interpreter +Read object from TOML table

        +

        use default TOML parser

        +

        Read object from TOML table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + load_from_toml => compiler_load + +

      +
      +
        +
      • +

        + public subroutine compiler_load(self, table, error) +

        + + +

        Read dependency from toml table (no checks made at this stage)

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(compiler_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + name => compiler_name + +

      +
      +
      + +

      Return compiler name

      +
      +
        +
      • +

        + public pure function compiler_name(self) result(name) +

        + + +

        Return a compiler name string

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(compiler_t), + intent(in) + + ::self +

        Instance of the compiler object

        +
        + +

        + Return Value + character(len=:), allocatable +

        +

        Representation as string

        + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + operator(==) => serializable_is_same + +

      +
      +
        +
      • +

        + private function srcfile_is_same(this, that) +

        + +

        Check that two source files are equal +All checks passed!

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + serializable_is_same => compiler_is_same + +

      +
      +
      + +

      Serialization interface

      +
      +
        +
      • +

        + public function compiler_is_same(this, that) +

        + + +

        Check that two compiler_t objects are equal +All checks passed!

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(compiler_t), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public, non_overridable :: + test_serialization + +

      +
      +
      + +

      Test load/write roundtrip

      +
      +
        +
      • +

        + private subroutine test_serialization(self, message, error) +

        + +

        Test serialization of a serializable object +Dump to scratch file +Load from scratch file +Check same

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self + +
        + + character(len=*), + intent(in) + + ::message + +
        + + type(error_t), + intent(out), + allocatable + ::error + +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + with_qp + +

      +
      +
        +
      • +

        + public function with_qp(self) +

        + + +

        Check if the current compiler supports 128-bit real precision

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(compiler_t), + intent(in) + + ::self +

        Instance of the compiler object

        +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + with_xdp + +

      +
      +
        +
      • +

        + public function with_xdp(self) +

        + + +

        Check if the current compiler supports 80-bit “extended” real precision

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(compiler_t), + intent(in) + + ::self +

        Instance of the compiler object

        +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      + +
      +

      Source Code

      +
      type, extends(serializable_t) :: compiler_t
      +    !> Identifier of the compiler
      +    integer(compiler_enum) :: id = id_unknown
      +    !> Path to the Fortran compiler
      +    character(len=:), allocatable :: fc
      +    !> Path to the C compiler
      +    character(len=:), allocatable :: cc
      +    !> Path to the C++ compiler
      +    character(len=:), allocatable :: cxx
      +    !> Print all commands
      +    logical :: echo = .true.
      +    !> Verbose output of command
      +    logical :: verbose = .true.
      +contains
      +    !> Get default compiler flags
      +    procedure :: get_default_flags
      +    !> Get flag for module output directories
      +    procedure :: get_module_flag
      +    !> Get flag for include directories
      +    procedure :: get_include_flag
      +    !> Get feature flag
      +    procedure :: get_feature_flag
      +    !> Get flags for the main linking command
      +    procedure :: get_main_flags
      +    !> Get library export flags
      +    procedure :: get_export_flags    
      +    !> Get library install name flags
      +    procedure :: get_install_name_flags
      +    !> Generate header padding flags for macOS executables
      +    procedure :: get_headerpad_flags
      +    !> Compile a Fortran object
      +    procedure :: compile_fortran
      +    !> Compile a C object
      +    procedure :: compile_c
      +    !> Compile a CPP object
      +    procedure :: compile_cpp
      +    !> Link a shared library
      +    procedure :: link_shared
      +    !> Link executable
      +    procedure :: link => link_executable
      +    !> Check whether compiler is recognized
      +    procedure :: is_unknown
      +    !> Check whether this is an Intel compiler
      +    procedure :: is_intel
      +    !> Check whether this is a GNU compiler
      +    procedure :: is_gnu
      +    !> Enumerate libraries, based on compiler and platform
      +    procedure :: enumerate_libraries
      +
      +
      +    !> Serialization interface
      +    procedure :: serializable_is_same => compiler_is_same
      +    procedure :: dump_to_toml => compiler_dump
      +    procedure :: load_from_toml => compiler_load
      +    !> Fortran feature support
      +    procedure :: check_fortran_source_runs
      +    procedure :: check_flags_supported
      +    procedure :: with_xdp
      +    procedure :: with_qp
      +    !> Return compiler name
      +    procedure :: name => compiler_name
      +
      +end type compiler_t
      +
      + +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/type/console_t.html b/type/console_t.html new file mode 100644 index 0000000000..4715525099 --- /dev/null +++ b/type/console_t.html @@ -0,0 +1,461 @@ + + + + + + + + + + + + + console_t – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      console_t + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public :: console_t

      +

      Console object

      +
      + +
      +

      Components

      + + + + + + + + + + + + + + + + + + + + + +
      TypeVisibility AttributesNameInitial
      + + integer, + public + + ::n_line =1 +

      Number of lines printed

      +
      + +
      +
      + + + +
      +

      Type-Bound Procedures

      +
      +
      +
      + +

      + procedure, public :: + update_line => console_update_line + +

      +
      +
      + +

      Update a previously-written console line

      +
      +
        +
      • +

        + private subroutine console_update_line(console, line_no, str) +

        + +

        Overwrite a previously-written line in standard output

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(console_t), + intent(in) + + ::console +

        Console object

        +
        + + integer, + intent(in) + + ::line_no +

        Integer output from [[console_write_line]]

        +
        + + character(len=*), + intent(in) + + ::str +

        New string to overwrite line

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + write_line => console_write_line + +

      +
      +
      + +

      Write a single line to the console

      +
      +
        +
      • +

        + private subroutine console_write_line(console, str, line, advance) +

        + +

        Write a single line to the standard output

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(console_t), + intent(inout) + + ::console +

        Console object

        +
        + + character(len=*), + intent(in) + + ::str +

        String to write

        +
        + + integer, + intent(out),optional + + ::line +

        Integer needed to later update console line

        +
        + + logical, + intent(in),optional + + ::advance +

        Advancing output (print newline?)

        +
        + + +
      • +
      +
      + +
      +
      + +
      +

      Source Code

      +
      type console_t
      +    !> Number of lines printed
      +    integer :: n_line = 1
      +
      +contains
      +    !> Write a single line to the console
      +    procedure :: write_line => console_write_line
      +    !> Update a previously-written console line
      +    procedure :: update_line => console_update_line
      +end type console_t
      +
      + +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/type/dependency_config_t.html b/type/dependency_config_t.html new file mode 100644 index 0000000000..f5d0df1da0 --- /dev/null +++ b/type/dependency_config_t.html @@ -0,0 +1,1468 @@ + + + + + + + + + + + + + dependency_config_t – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      dependency_config_t + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public, extends(serializable_t) :: dependency_config_t

      +

      Configuration meta data for a dependency

      +
      + +
      +

      Components

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      TypeVisibility AttributesNameInitial
      + + type(git_target_t), + public, + allocatable + ::git +

      Git descriptor

      +
      + + character(len=:), + public, + allocatable + ::name +

      Name of the dependency

      +
      + + character(len=:), + public, + allocatable + ::namespace +

      Namespace which the dependency belongs to. +Enables multiple dependencies with the same name. +Required for dependencies that are obtained via the official registry.

      +
      + + character(len=:), + public, + allocatable + ::path +

      Local target

      +
      + + type(preprocess_config_t), + public, + allocatable + ::preprocess(:) +

      Requested macros for the dependency

      +
      + + type(version_t), + public, + allocatable + ::requested_version +

      The requested version of the dependency. +The latest version is used if not specified.

      +
      + +
      +
      + + + +
      +

      Type-Bound Procedures

      +
      +
      +
      + +

      + procedure, public :: + add_preprocess + +

      +
      +
      + +

      Add a preprocessor configuration

      +
      +
        +
      • +

        + private subroutine add_preprocess(dep, preprocess) +

        + + + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(dependency_config_t), + intent(inout) + + ::dep +

        Instance of the dependency config

        +
        + + type(preprocess_config_t), + intent(in) + + ::preprocess +

        Instance of the preprocessor configuration

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_dump_to_toml(self, table, error) +

        + +

        Dump dependency to toml table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine dump_to_file(self, file, error, json) +

        + +

        Write serializable object to file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine dump_to_unit(self, unit, error, json) +

        + +

        Write serializable object to a formatted Fortran unit

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        Formatted unit

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format requested?

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + dump_to_toml + +

      +
      +
        +
      • +

        + private subroutine dump_to_toml(self, table, error) +

        + +

        Dump dependency to toml table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(dependency_config_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error + +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + info + +

      +
      +
      + +

      Print information on this instance

      +
      +
        +
      • +

        + private subroutine info(self, unit, verbosity) +

        + +

        Write information on instance

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(dependency_config_t), + intent(in) + + ::self +

        Instance of the dependency configuration

        +
        + + integer, + intent(in) + + ::unit +

        Unit for IO

        +
        + + integer, + intent(in),optional + + ::verbosity +

        Verbosity of the printout

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + load => load_from_toml, load_from_file, load_from_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_load_from_toml(self, table, error) +

        + +

        Read dependency from toml table (no checks made at this stage)

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine load_from_file(self, file, error, json) +

        + +

        Read dependency tree from file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine load_from_unit(self, unit, error, json) +

        + +

        Read dependency tree from file +init JSON interpreter +Read object from TOML table

        +

        use default TOML parser

        +

        Read object from TOML table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + load_from_toml + +

      +
      +
        +
      • +

        + private subroutine load_from_toml(self, table, error) +

        + +

        Read dependency from toml table (no checks made at this stage)

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(dependency_config_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + operator(==) => serializable_is_same + +

      +
      +
        +
      • +

        + private function srcfile_is_same(this, that) +

        + +

        Check that two source files are equal +All checks passed!

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + serializable_is_same => dependency_is_same + +

      +
      +
      + +

      Serialization interface

      +
      +
        +
      • +

        + private function dependency_is_same(this, that) +

        + +

        Check that two dependency configs are equal +All checks passed!

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(dependency_config_t), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public, non_overridable :: + test_serialization + +

      +
      +
      + +

      Test load/write roundtrip

      +
      +
        +
      • +

        + private subroutine test_serialization(self, message, error) +

        + +

        Test serialization of a serializable object +Dump to scratch file +Load from scratch file +Check same

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self + +
        + + character(len=*), + intent(in) + + ::message + +
        + + type(error_t), + intent(out), + allocatable + ::error + +
        + + +
      • +
      +
      + +
      +
      + +
      +

      Source Code

      +
          type, extends(serializable_t) :: dependency_config_t
      +
      +        !> Name of the dependency
      +        character(len=:), allocatable :: name
      +
      +        !> Local target
      +        character(len=:), allocatable :: path
      +
      +        !> Namespace which the dependency belongs to.
      +        !> Enables multiple dependencies with the same name.
      +        !> Required for dependencies that are obtained via the official registry.
      +        character(len=:), allocatable :: namespace
      +
      +        !> The requested version of the dependency.
      +        !> The latest version is used if not specified.
      +        type(version_t), allocatable :: requested_version
      +
      +        !> Requested macros for the dependency
      +        type(preprocess_config_t), allocatable :: preprocess(:)
      +
      +        !> Git descriptor
      +        type(git_target_t), allocatable :: git
      +
      +    contains
      +
      +        !> Print information on this instance
      +        procedure :: info
      +        
      +        !> Add a preprocessor configuration
      +        procedure :: add_preprocess
      +
      +        !> Serialization interface
      +        procedure :: serializable_is_same => dependency_is_same
      +        procedure :: dump_to_toml
      +        procedure :: load_from_toml
      +
      +    end type dependency_config_t
      +
      + +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/type/dependency_node_t.html b/type/dependency_node_t.html new file mode 100644 index 0000000000..1e69acd8c3 --- /dev/null +++ b/type/dependency_node_t.html @@ -0,0 +1,1843 @@ + + + + + + + + + + + + + dependency_node_t – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      dependency_node_t + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public, extends(dependency_config_t) :: dependency_node_t

      +

      Dependency node in the projects dependency tree

      +
      + +
      +

      Components

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      TypeVisibility AttributesNameInitial
      + + logical, + public + + ::cached =.false. +

      Dependency was loaded from a cache

      +
      + + logical, + public + + ::done =.false. +

      Dependency is handled

      +
      + + type(git_target_t), + public, + allocatable + ::git +

      Git descriptor

      +
      + + character(len=:), + public, + allocatable + ::name +

      Name of the dependency

      +
      + + character(len=:), + public, + allocatable + ::namespace +

      Namespace which the dependency belongs to. +Enables multiple dependencies with the same name. +Required for dependencies that are obtained via the official registry.

      +
      + + type(string_t), + public, + allocatable + ::package_dep(:) +

      Package dependencies of this node

      +
      + + character(len=:), + public, + allocatable + ::path +

      Local target

      +
      + + type(preprocess_config_t), + public, + allocatable + ::preprocess(:) +

      Requested macros for the dependency

      +
      + + character(len=:), + public, + allocatable + ::proj_dir +

      Installation prefix of this dependencies

      +
      + + type(version_t), + public, + allocatable + ::requested_version +

      The requested version of the dependency. +The latest version is used if not specified.

      +
      + + character(len=:), + public, + allocatable + ::revision +

      Checked out revision of the version control system

      +
      + + logical, + public + + ::update =.false. +

      Dependency should be updated

      +
      + + type(version_t), + public, + allocatable + ::version +

      Actual version of this dependency

      +
      + +
      +
      + + + +
      +

      Type-Bound Procedures

      +
      +
      +
      + +

      + procedure, public :: + add_preprocess + +

      +
      +
      + +

      Add a preprocessor configuration

      +
      +
        +
      • +

        + private subroutine add_preprocess(dep, preprocess) +

        + + + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(dependency_config_t), + intent(inout) + + ::dep +

        Instance of the dependency config

        +
        + + type(preprocess_config_t), + intent(in) + + ::preprocess +

        Instance of the preprocessor configuration

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_dump_to_toml(self, table, error) +

        + +

        Dump dependency to toml table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine dump_to_file(self, file, error, json) +

        + +

        Write serializable object to file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine dump_to_unit(self, unit, error, json) +

        + +

        Write serializable object to a formatted Fortran unit

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        Formatted unit

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format requested?

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + dump_to_toml => node_dump_to_toml + +

      +
      +
        +
      • +

        + private subroutine node_dump_to_toml(self, table, error) +

        + +

        Dump dependency to toml table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(dependency_node_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + get_from_registry + +

      +
      +
      + +

      Get dependency from the registry.

      +
      +
        +
      • +

        + private subroutine get_from_registry(self, target_dir, global_settings, error, downloader_) +

        + +

        Get a dependency from the registry. Whether the dependency is fetched +from a local, a custom remote or the official registry is determined +by the global configuration settings.

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(dependency_node_t), + intent(in) + + ::self +

        Instance of the dependency configuration.

        +
        + + character(len=:), + intent(out), + allocatable + ::target_dir +

        The target directory of the dependency.

        +
        + + type(fpm_global_settings), + intent(in) + + ::global_settings +

        Global configuration settings.

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling.

        +
        + + class(downloader_t), + intent(in),optional + + ::downloader_ +

        Downloader instance.

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + info + +

      +
      +
      + +

      Print information on this instance

      +
      +
        +
      • +

        + private subroutine info(self, unit, verbosity) +

        + +

        Write information on instance

        +

        Call base object info

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(dependency_node_t), + intent(in) + + ::self +

        Instance of the dependency configuration

        +
        + + integer, + intent(in) + + ::unit +

        Unit for IO

        +
        + + integer, + intent(in),optional + + ::verbosity +

        Verbosity of the printout

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + load => load_from_toml, load_from_file, load_from_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_load_from_toml(self, table, error) +

        + +

        Read dependency from toml table (no checks made at this stage)

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine load_from_file(self, file, error, json) +

        + +

        Read dependency tree from file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine load_from_unit(self, unit, error, json) +

        + +

        Read dependency tree from file +init JSON interpreter +Read object from TOML table

        +

        use default TOML parser

        +

        Read object from TOML table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + load_from_toml => node_load_from_toml + +

      +
      +
        +
      • +

        + private subroutine node_load_from_toml(self, table, error) +

        + +

        Read dependency from toml table (no checks made at this stage)

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(dependency_node_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + operator(==) => serializable_is_same + +

      +
      +
        +
      • +

        + private function srcfile_is_same(this, that) +

        + +

        Check that two source files are equal +All checks passed!

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + register + +

      +
      +
      + +

      Update dependency from project manifest.

      +
      +
        +
      • +

        + private subroutine register(node, package, root, fetch, revision, error) +

        + +

        Update dependency from project manifest

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(dependency_node_t), + intent(inout) + + ::node +

        Instance of the dependency node

        +
        + + type(package_config_t), + intent(in) + + ::package +

        Package configuration data

        +
        + + character(len=*), + intent(in) + + ::root +

        Root directory of the project

        +
        + + logical, + intent(in) + + ::fetch +

        Project has been fetched

        +
        + + character(len=*), + intent(in),optional + + ::revision +

        Git revision of the project

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + serializable_is_same => dependency_node_is_same + +

      +
      +
      + +

      Serialization interface

      +
      +
        +
      • +

        + private function dependency_node_is_same(this, that) +

        + +

        Check that two dependency nodes are equal +All checks passed!

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(dependency_node_t), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public, non_overridable :: + test_serialization + +

      +
      +
      + +

      Test load/write roundtrip

      +
      +
        +
      • +

        + private subroutine test_serialization(self, message, error) +

        + +

        Test serialization of a serializable object +Dump to scratch file +Load from scratch file +Check same

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self + +
        + + character(len=*), + intent(in) + + ::message + +
        + + type(error_t), + intent(out), + allocatable + ::error + +
        + + +
      • +
      +
      + +
      +
      + +
      +

      Source Code

      +
        type, extends(dependency_config_t) :: dependency_node_t
      +    !> Actual version of this dependency
      +    type(version_t), allocatable  :: version
      +    !> Installation prefix of this dependencies
      +    character(len=:), allocatable :: proj_dir
      +    !> Checked out revision of the version control system
      +    character(len=:), allocatable :: revision
      +    !> Dependency is handled
      +    logical :: done = .false.
      +    !> Dependency should be updated
      +    logical :: update = .false.
      +    !> Dependency was loaded from a cache
      +    logical :: cached = .false.
      +    !> Package dependencies of this node 
      +    type(string_t), allocatable :: package_dep(:)    
      +  contains
      +
      +    !> Update dependency from project manifest.
      +    procedure :: register    
      +
      +    !> Get dependency from the registry.
      +    procedure :: get_from_registry
      +    procedure, private :: get_from_local_registry
      +    !> Print information on this instance
      +    procedure :: info
      +
      +    !> Serialization interface
      +    procedure :: serializable_is_same => dependency_node_is_same
      +    procedure :: dump_to_toml         => node_dump_to_toml
      +    procedure :: load_from_toml       => node_load_from_toml
      +
      +  end type dependency_node_t
      +
      + +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/type/dependency_tree_t.html b/type/dependency_tree_t.html new file mode 100644 index 0000000000..cd8c453fbe --- /dev/null +++ b/type/dependency_tree_t.html @@ -0,0 +1,2869 @@ + + + + + + + + + + + + + dependency_tree_t – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      dependency_tree_t + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public, extends(serializable_t) :: dependency_tree_t

      +

      Respresentation of a projects dependencies

      +

      The dependencies are stored in a simple array for now, this can be replaced +with a binary-search tree or a hash table in the future.

      +
      + +
      +

      Components

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      TypeVisibility AttributesNameInitial
      + + character(len=:), + public, + allocatable + ::cache +

      Cache file

      +
      + + type(dependency_node_t), + public, + allocatable + ::dep(:) +

      Flattend list of all dependencies

      +
      + + character(len=:), + public, + allocatable + ::dep_dir +

      Installation prefix for dependencies

      +
      + + integer, + public + + ::ndep =0 +

      Number of currently registered dependencies

      +
      + + character(len=:), + public, + allocatable + ::path_to_config +

      Custom path to the global config file

      +
      + + integer, + public + + ::unit =output_unit +

      Unit for IO

      +
      + + integer, + public + + ::verbosity =1 +

      Verbosity of printout

      +
      + +
      +
      + + + +
      +

      Type-Bound Procedures

      +
      +
      +
      + +

      + generic, public :: + add => add_project, add_project_dependencies, add_dependencies, add_dependency, add_dependency_node + +

      +
      +
      + +

      Overload procedure to add new dependencies to the tree

      +
      +
        +
      • +

        + private subroutine add_project(self, package, error) +

        + +

        Add project dependencies, each depth level after each other.

        +

        We implement this algorithm in an interative rather than a recursive fashion +as a choice of design.

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(dependency_tree_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + type(package_config_t), + intent(in) + + ::package +

        Project configuration to add

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private recursive subroutine add_project_dependencies(self, package, root, main, error) +

        + +

        Add a project and its dependencies to the dependency tree +Ensure allocation fits

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(dependency_tree_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + type(package_config_t), + intent(in) + + ::package +

        Project configuration to add

        +
        + + character(len=*), + intent(in) + + ::root +

        Current project root directory

        +
        + + logical, + intent(in) + + ::main +

        Is the main project

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine add_dependencies(self, dependency, error) +

        + +

        Add a list of dependencies to the dependency tree +Ensure allocation fits ndep

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(dependency_tree_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + type(dependency_config_t), + intent(in) + + ::dependency(:) +

        Dependency configuration to add

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine add_dependency(self, dependency, error) +

        + +

        Add a single dependency to the dependency tree

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(dependency_tree_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + type(dependency_config_t), + intent(in) + + ::dependency +

        Dependency configuration to add

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine add_dependency_node(self, dependency, error) +

        + +

        Add a single dependency node to the dependency tree +Dependency nodes contain additional information (version, git, revision) +Safety: reallocate if necessary

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(dependency_tree_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + type(dependency_node_t), + intent(in) + + ::dependency +

        Dependency configuration to add

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_dump_to_toml(self, table, error) +

        + +

        Dump dependency to toml table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine dump_to_file(self, file, error, json) +

        + +

        Write serializable object to file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine dump_to_unit(self, unit, error, json) +

        + +

        Write serializable object to a formatted Fortran unit

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        Formatted unit

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format requested?

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + dump_cache => dump_cache_to_file, dump_cache_to_unit, dump_cache_to_toml + +

      +
      +
      + +

      Writing of dependency tree

      +
      +
        +
      • +

        + private subroutine dump_cache_to_file(self, file, error) +

        + +

        Write dependency tree to file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(dependency_tree_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine dump_cache_to_unit(self, unit, error) +

        + +

        Write dependency tree to file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(dependency_tree_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        Formatted unit

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine dump_cache_to_toml(self, table, error) +

        + +

        Write dependency tree to TOML datastructure

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(dependency_tree_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + dump_to_toml => tree_dump_to_toml + +

      +
      +
        +
      • +

        + private subroutine tree_dump_to_toml(self, table, error) +

        + +

        Dump dependency to toml table

        +

        Because dependencies are named, fallback if this has no name +So, serialization will work regardless of size(self%dep) == self%ndep

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(dependency_tree_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + find => find_name + +

      +
      +
      + +

      Find a dependency in the tree

      +
      +
        +
      • +

        + private pure function find_name(self, name) result(pos) +

        + +

        Find a dependency in the dependency tree

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(dependency_tree_t), + intent(in) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::name +

        Dependency configuration to add

        +
        + +

        + Return Value + integer +

        +

        Index of the dependency

        + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + finished + +

      +
      +
      + +

      Depedendncy resolution finished

      +
      +
        +
      • +

        + private pure function finished(self) +

        + +

        Check if we are done with the dependency resolution

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(dependency_tree_t), + intent(in) + + ::self +

        Instance of the dependency tree

        +
        + +

        + Return Value + logical +

        +

        All dependencies are updated

        + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + has => has_dependency + +

      +
      +
      + +

      True if entity can be found

      +
      +
        +
      • +

        + private pure function has_dependency(self, dependency) +

        + +

        True if dependency is part of the tree

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(dependency_tree_t), + intent(in) + + ::self +

        Instance of the dependency tree

        +
        + + class(dependency_node_t), + intent(in) + + ::dependency +

        Dependency configuration to check

        +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + load => load_from_toml, load_from_file, load_from_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_load_from_toml(self, table, error) +

        + +

        Read dependency from toml table (no checks made at this stage)

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine load_from_file(self, file, error, json) +

        + +

        Read dependency tree from file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine load_from_unit(self, unit, error, json) +

        + +

        Read dependency tree from file +init JSON interpreter +Read object from TOML table

        +

        use default TOML parser

        +

        Read object from TOML table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + load_cache => load_cache_from_file, load_cache_from_unit, load_cache_from_toml + +

      +
      +
      + +

      Reading of dependency tree

      +
      +
        +
      • +

        + private subroutine load_cache_from_file(self, file, error) +

        + +

        Read dependency tree from file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(dependency_tree_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine load_cache_from_unit(self, unit, error) +

        + +

        Read dependency tree from file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(dependency_tree_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine load_cache_from_toml(self, table, error) +

        + +

        Read dependency tree from TOML data structure

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(dependency_tree_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + load_from_toml => tree_load_from_toml + +

      +
      +
        +
      • +

        + private subroutine tree_load_from_toml(self, table, error) +

        + +

        Read dependency from toml table (no checks made at this stage)

        +

        Read all dependencies

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(dependency_tree_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + local_link_order + +

      +
      +
      + +

      Establish local link order for a node’s package dependencies

      +
      +
        +
      • +

        + private subroutine local_link_order(tree, root_id, order, error) +

        + +

        Build a correct topological link order for a given dependency node.

        +

        This routine returns the list of dependencies required to build root_id, +sorted such that each dependency appears before any node that depends on it. +This is suitable for correct linker ordering: -lA -lB means B can use symbols from A.

        +

        The returned list includes both the transitive dependencies and the node itself. +Example: if node 3 requires [5, 7, 9, 2] and 9 also requires 2, +then the result will ensure that 2 appears before 9, etc. +Depth-First Search from root node +The final link order is the reverse of the DFS post-order

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(dependency_tree_t), + intent(in) + + ::tree +

        The full dependency graph

        +
        + + integer, + intent(in) + + ::root_id +

        Index of the node for which to compute link order (e.g., the target being linked)

        +
        + + integer, + intent(out), + allocatable + ::order(:) +

        Ordered list of dependency indices (subset of tree%dep(:)) in link-safe order

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Optional fatal error if a cycle is detected (not expected)

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + operator(==) => serializable_is_same + +

      +
      +
        +
      • +

        + private function srcfile_is_same(this, that) +

        + +

        Check that two source files are equal +All checks passed!

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + resolve => resolve_dependencies, resolve_dependency + +

      +
      +
      + +

      Resolve dependencies

      +
      +
        +
      • +

        + private subroutine resolve_dependencies(self, root, error) +

        + +

        Resolve all dependencies in the tree

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(dependency_tree_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::root +

        Current installation prefix

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine resolve_dependency(self, dependency, global_settings, root, error) +

        + +

        Resolve a single dependency node

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(dependency_tree_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + type(dependency_node_t), + intent(inout) + + ::dependency +

        Dependency configuration to add

        +
        + + type(fpm_global_settings), + intent(in) + + ::global_settings +

        Global configuration settings.

        +
        + + character(len=*), + intent(in) + + ::root +

        Current installation prefix

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + serializable_is_same => dependency_tree_is_same + +

      +
      +
      + +

      Serialization interface

      +
      +
        +
      • +

        + private function dependency_tree_is_same(this, that) +

        + +

        Check that two dependency trees are equal +All checks passed!

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(dependency_tree_t), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public, non_overridable :: + test_serialization + +

      +
      +
      + +

      Test load/write roundtrip

      +
      +
        +
      • +

        + private subroutine test_serialization(self, message, error) +

        + +

        Test serialization of a serializable object +Dump to scratch file +Load from scratch file +Check same

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self + +
        + + character(len=*), + intent(in) + + ::message + +
        + + type(error_t), + intent(out), + allocatable + ::error + +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + update => update_dependency, update_tree + +

      +
      +
      + +

      Update dependency tree

      +
      +
        +
      • +

        + private subroutine update_dependency(self, name, error) +

        + +

        Update dependency tree

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(dependency_tree_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::name +

        Name of the dependency to update

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine update_tree(self, error) +

        + +

        Update whole dependency tree

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(dependency_tree_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      + +
      +

      Source Code

      +
        type, extends(serializable_t) :: dependency_tree_t
      +    !> Unit for IO
      +    integer :: unit = output_unit
      +    !> Verbosity of printout
      +    integer :: verbosity = 1
      +    !> Installation prefix for dependencies
      +    character(len=:), allocatable :: dep_dir
      +    !> Number of currently registered dependencies
      +    integer :: ndep = 0
      +    !> Flattend list of all dependencies
      +    type(dependency_node_t), allocatable :: dep(:)
      +    !> Cache file
      +    character(len=:), allocatable :: cache
      +    !> Custom path to the global config file
      +    character(len=:), allocatable :: path_to_config
      +
      +  contains
      +
      +    !> Overload procedure to add new dependencies to the tree
      +    generic :: add => add_project, add_project_dependencies, add_dependencies, &
      +      add_dependency, add_dependency_node
      +    !> Main entry point to add a project
      +    procedure, private :: add_project
      +    !> Add a project and its dependencies to the dependency tree
      +    procedure, private :: add_project_dependencies
      +    !> Add a list of dependencies to the dependency tree
      +    procedure, private :: add_dependencies
      +    !> Add a single dependency to the dependency tree
      +    procedure, private :: add_dependency
      +    !> Add a single dependency node to the dependency tree
      +    procedure, private :: add_dependency_node
      +    !> Resolve dependencies
      +    generic :: resolve => resolve_dependencies, resolve_dependency
      +    !> Resolve dependencies
      +    procedure, private :: resolve_dependencies
      +    !> Resolve dependency
      +    procedure, private :: resolve_dependency
      +    !> True if entity can be found
      +    generic :: has => has_dependency
      +    !> True if dependency is part of the tree
      +    procedure, private :: has_dependency
      +    !> Find a dependency in the tree
      +    generic :: find => find_name
      +    !> Find a dependency by its name
      +    procedure, private :: find_name
      +    !> Establish local link order for a node's package dependencies
      +    procedure :: local_link_order
      +    !> Depedendncy resolution finished
      +    procedure :: finished
      +    !> Reading of dependency tree
      +    generic :: load_cache => load_cache_from_file, load_cache_from_unit, load_cache_from_toml
      +    !> Read dependency tree from file
      +    procedure, private :: load_cache_from_file
      +    !> Read dependency tree from formatted unit
      +    procedure, private :: load_cache_from_unit
      +    !> Read dependency tree from TOML data structure
      +    procedure, private :: load_cache_from_toml
      +    !> Writing of dependency tree
      +    generic :: dump_cache => dump_cache_to_file, dump_cache_to_unit, dump_cache_to_toml
      +    !> Write dependency tree to file
      +    procedure, private :: dump_cache_to_file
      +    !> Write dependency tree to formatted unit
      +    procedure, private :: dump_cache_to_unit
      +    !> Write dependency tree to TOML data structure
      +    procedure, private :: dump_cache_to_toml
      +    !> Update dependency tree
      +    generic :: update => update_dependency, update_tree
      +    !> Update a list of dependencies
      +    procedure, private :: update_dependency
      +    !> Update all dependencies in the tree
      +    procedure, private :: update_tree
      +
      +    !> Serialization interface
      +    procedure :: serializable_is_same => dependency_tree_is_same
      +    procedure :: dump_to_toml         => tree_dump_to_toml
      +    procedure :: load_from_toml       => tree_load_from_toml
      +
      +  end type dependency_tree_t
      +
      + +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/type/downloader_t.html b/type/downloader_t.html new file mode 100644 index 0000000000..4b44712915 --- /dev/null +++ b/type/downloader_t.html @@ -0,0 +1,585 @@ + + + + + + + + + + + + + downloader_t – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      downloader_t + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public :: downloader_t

      +

      This type could be entirely avoided but it is quite practical because it can be mocked for testing.

      +
      + + + + +
      +

      Type-Bound Procedures

      +
      +
      +
      + +

      + procedure, public, nopass :: + get_file + +

      +
      +
        +
      • +

        + private subroutine get_file(url, tmp_pkg_file, error) +

        + +

        Download a file from a url using either curl or wget.

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + character(len=*), + intent(in) + + ::url + +
        + + character(len=*), + intent(in) + + ::tmp_pkg_file + +
        + + type(error_t), + intent(out), + allocatable + ::error + +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public, nopass :: + get_pkg_data + +

      +
      +
        +
      • +

        + private subroutine get_pkg_data(url, version, tmp_pkg_file, json, error) +

        + +

        Perform an http get request, save output to file, and parse json.

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + character(len=*), + intent(in) + + ::url + +
        + + type(version_t), + intent(in), + allocatable + ::version + +
        + + character(len=*), + intent(in) + + ::tmp_pkg_file + +
        + + type(json_object), + intent(out) + + ::json + +
        + + type(error_t), + intent(out), + allocatable + ::error + +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public, nopass :: + unpack + +

      +
      +
        +
      • +

        + private subroutine unpack(tmp_pkg_file, destination, error) +

        + +

        Unpack a tarball to a destination.

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + character(len=*), + intent(in) + + ::tmp_pkg_file +

        Path to tarball.

        +
        + + character(len=*), + intent(in) + + ::destination +

        Destination to unpack to.

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling.

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public, nopass :: + upload_form + +

      +
      +
        +
      • +

        + private subroutine upload_form(endpoint, form_data, verbose, error) +

        + +

        Perform an http post request with form data.

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + character(len=*), + intent(in) + + ::endpoint +

        Endpoint to upload to.

        +
        + + type(string_t), + intent(in) + + ::form_data(:) +

        Form data to upload.

        +
        + + logical, + intent(in) + + ::verbose +

        Print additional information if true.

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling.

        +
        + + +
      • +
      +
      + +
      +
      + + +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/type/enum_descriptor.html b/type/enum_descriptor.html new file mode 100644 index 0000000000..d762883cf2 --- /dev/null +++ b/type/enum_descriptor.html @@ -0,0 +1,337 @@ + + + + + + + + + + + + + enum_descriptor – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      enum_descriptor + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public :: enum_descriptor

      +

      Possible git target

      +
      + +
      +

      Components

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      TypeVisibility AttributesNameInitial
      + + integer, + public + + ::branch =201 +

      Branch in git repository

      +
      + + integer, + public + + ::default =200 +

      Default target

      +
      + + integer, + public + + ::error =-999 +

      Invalid descriptor

      +
      + + integer, + public + + ::revision =203 +

      Commit hash

      +
      + + integer, + public + + ::tag =202 +

      Tag in git repository

      +
      + +
      +
      + + + + +
      +

      Source Code

      +
          type :: enum_descriptor
      +
      +        !> Default target
      +        integer :: default = 200
      +
      +        !> Branch in git repository
      +        integer :: branch = 201
      +
      +        !> Tag in git repository
      +        integer :: tag = 202
      +
      +        !> Commit hash
      +        integer :: revision = 203
      +
      +        !> Invalid descriptor
      +        integer :: error = -999
      +
      +    end type enum_descriptor
      +
      + +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/type/error_t.html b/type/error_t.html new file mode 100644 index 0000000000..b9fbc5c441 --- /dev/null +++ b/type/error_t.html @@ -0,0 +1,253 @@ + + + + + + + + + + + + + error_t – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      error_t + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public :: error_t

      +

      Data type defining an error

      +
      + +
      +

      Components

      + + + + + + + + + + + + + + + + + + + + + +
      TypeVisibility AttributesNameInitial
      + + character(len=:), + public, + allocatable + ::message +

      Error message

      +
      + +
      +
      + + + + +
      +

      Source Code

      +
          type :: error_t
      +
      +        !> Error message
      +        character(len=:), allocatable :: message
      +
      +    end type error_t
      +
      + +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/type/example_config_t.html b/type/example_config_t.html new file mode 100644 index 0000000000..2d2a61268b --- /dev/null +++ b/type/example_config_t.html @@ -0,0 +1,1347 @@ + + + + + + + + + + + + + example_config_t – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      example_config_t + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public, extends(executable_config_t) :: example_config_t

      +

      Configuation meta data for an example

      +
      + +
      +

      Components

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      TypeVisibility AttributesNameInitial
      + + type(dependency_config_t), + public, + allocatable + ::dependency(:) +

      Dependency meta data for this executable

      +
      + + type(string_t), + public, + allocatable + ::link(:) +

      Libraries to link against

      +
      + + character(len=:), + public, + allocatable + ::main +

      Name of the source file declaring the main program

      +
      + + character(len=:), + public, + allocatable + ::name +

      Name of the resulting executable

      +
      + + character(len=:), + public, + allocatable + ::source_dir +

      Source directory for collecting the executable

      +
      + +
      +
      + + + +
      +

      Type-Bound Procedures

      +
      +
      +
      + +

      + generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_dump_to_toml(self, table, error) +

        + +

        Dump dependency to toml table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine dump_to_file(self, file, error, json) +

        + +

        Write serializable object to file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine dump_to_unit(self, unit, error, json) +

        + +

        Write serializable object to a formatted Fortran unit

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        Formatted unit

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format requested?

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + dump_to_toml + +

      +
      +
        +
      • +

        + private subroutine dump_to_toml(self, table, error) +

        + +

        Dump install config to toml table

        +

        Because dependencies are named, fallback if this has no name +So, serialization will work regardless of size(self%dep) == self%ndep

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(executable_config_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + info + +

      +
      +
      + +

      Print information on this instance

      +
      +
        +
      • +

        + private subroutine info(self, unit, verbosity) +

        + +

        Write information on instance

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(example_config_t), + intent(in) + + ::self +

        Instance of the example configuration

        +
        + + integer, + intent(in) + + ::unit +

        Unit for IO

        +
        + + integer, + intent(in),optional + + ::verbosity +

        Verbosity of the printout

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + load => load_from_toml, load_from_file, load_from_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_load_from_toml(self, table, error) +

        + +

        Read dependency from toml table (no checks made at this stage)

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine load_from_file(self, file, error, json) +

        + +

        Read dependency tree from file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine load_from_unit(self, unit, error, json) +

        + +

        Read dependency tree from file +init JSON interpreter +Read object from TOML table

        +

        use default TOML parser

        +

        Read object from TOML table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + load_from_toml + +

      +
      +
        +
      • +

        + private subroutine load_from_toml(self, table, error) +

        + +

        Read install config from toml table (no checks made at this stage)

        +

        Read all dependencies

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(executable_config_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + operator(==) => serializable_is_same + +

      +
      +
        +
      • +

        + private function srcfile_is_same(this, that) +

        + +

        Check that two source files are equal +All checks passed!

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + serializable_is_same => exe_is_same + +

      +
      +
      + +

      Serialization interface

      +
      +
        +
      • +

        + private function exe_is_same(this, that) +

        + +

        All checks passed!

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(executable_config_t), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public, non_overridable :: + test_serialization + +

      +
      +
      + +

      Test load/write roundtrip

      +
      +
        +
      • +

        + private subroutine test_serialization(self, message, error) +

        + +

        Test serialization of a serializable object +Dump to scratch file +Load from scratch file +Check same

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self + +
        + + character(len=*), + intent(in) + + ::message + +
        + + type(error_t), + intent(out), + allocatable + ::error + +
        + + +
      • +
      +
      + +
      +
      + +
      +

      Source Code

      +
          type, extends(executable_config_t) :: example_config_t
      +
      +    contains
      +
      +        !> Print information on this instance
      +        procedure :: info
      +
      +    end type example_config_t
      +
      + +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/type/executable_config_t.html b/type/executable_config_t.html new file mode 100644 index 0000000000..2c24942ecc --- /dev/null +++ b/type/executable_config_t.html @@ -0,0 +1,1367 @@ + + + + + + + + + + + + + executable_config_t – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      executable_config_t + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public, extends(serializable_t) :: executable_config_t

      +

      Configuation meta data for an executable

      +
      + +
      +

      Components

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      TypeVisibility AttributesNameInitial
      + + type(dependency_config_t), + public, + allocatable + ::dependency(:) +

      Dependency meta data for this executable

      +
      + + type(string_t), + public, + allocatable + ::link(:) +

      Libraries to link against

      +
      + + character(len=:), + public, + allocatable + ::main +

      Name of the source file declaring the main program

      +
      + + character(len=:), + public, + allocatable + ::name +

      Name of the resulting executable

      +
      + + character(len=:), + public, + allocatable + ::source_dir +

      Source directory for collecting the executable

      +
      + +
      +
      + + + +
      +

      Type-Bound Procedures

      +
      +
      +
      + +

      + generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_dump_to_toml(self, table, error) +

        + +

        Dump dependency to toml table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine dump_to_file(self, file, error, json) +

        + +

        Write serializable object to file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine dump_to_unit(self, unit, error, json) +

        + +

        Write serializable object to a formatted Fortran unit

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        Formatted unit

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format requested?

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + dump_to_toml + +

      +
      +
        +
      • +

        + private subroutine dump_to_toml(self, table, error) +

        + +

        Dump install config to toml table

        +

        Because dependencies are named, fallback if this has no name +So, serialization will work regardless of size(self%dep) == self%ndep

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(executable_config_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + info + +

      +
      +
      + +

      Print information on this instance

      +
      +
        +
      • +

        + private subroutine info(self, unit, verbosity) +

        + +

        Write information on instance

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(executable_config_t), + intent(in) + + ::self +

        Instance of the executable configuration

        +
        + + integer, + intent(in) + + ::unit +

        Unit for IO

        +
        + + integer, + intent(in),optional + + ::verbosity +

        Verbosity of the printout

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + load => load_from_toml, load_from_file, load_from_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_load_from_toml(self, table, error) +

        + +

        Read dependency from toml table (no checks made at this stage)

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine load_from_file(self, file, error, json) +

        + +

        Read dependency tree from file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine load_from_unit(self, unit, error, json) +

        + +

        Read dependency tree from file +init JSON interpreter +Read object from TOML table

        +

        use default TOML parser

        +

        Read object from TOML table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + load_from_toml + +

      +
      +
        +
      • +

        + private subroutine load_from_toml(self, table, error) +

        + +

        Read install config from toml table (no checks made at this stage)

        +

        Read all dependencies

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(executable_config_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + operator(==) => serializable_is_same + +

      +
      +
        +
      • +

        + private function srcfile_is_same(this, that) +

        + +

        Check that two source files are equal +All checks passed!

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + serializable_is_same => exe_is_same + +

      +
      +
      + +

      Serialization interface

      +
      +
        +
      • +

        + private function exe_is_same(this, that) +

        + +

        All checks passed!

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(executable_config_t), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public, non_overridable :: + test_serialization + +

      +
      +
      + +

      Test load/write roundtrip

      +
      +
        +
      • +

        + private subroutine test_serialization(self, message, error) +

        + +

        Test serialization of a serializable object +Dump to scratch file +Load from scratch file +Check same

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self + +
        + + character(len=*), + intent(in) + + ::message + +
        + + type(error_t), + intent(out), + allocatable + ::error + +
        + + +
      • +
      +
      + +
      +
      + +
      +

      Source Code

      +
          type, extends(serializable_t) :: executable_config_t
      +
      +        !> Name of the resulting executable
      +        character(len=:), allocatable :: name
      +
      +        !> Source directory for collecting the executable
      +        character(len=:), allocatable :: source_dir
      +
      +        !> Name of the source file declaring the main program
      +        character(len=:), allocatable :: main
      +
      +        !> Dependency meta data for this executable
      +        type(dependency_config_t), allocatable :: dependency(:)
      +
      +        !> Libraries to link against
      +        type(string_t), allocatable :: link(:)
      +
      +    contains
      +
      +        !> Print information on this instance
      +        procedure :: info
      +
      +        !> Serialization interface
      +        procedure :: serializable_is_same => exe_is_same
      +        procedure :: dump_to_toml
      +        procedure :: load_from_toml
      +
      +    end type executable_config_t
      +
      + +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/type/file_scope_flag.html b/type/file_scope_flag.html new file mode 100644 index 0000000000..a05ea301fb --- /dev/null +++ b/type/file_scope_flag.html @@ -0,0 +1,1213 @@ + + + + + + + + + + + + + file_scope_flag – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      file_scope_flag + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public, extends(serializable_t) :: file_scope_flag

      +

      Type storing file name - file scope compiler flags pairs

      +
      + +
      +

      Components

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      TypeVisibility AttributesNameInitial
      + + character(len=:), + public, + allocatable + ::file_name +

      Name of the file

      +
      + + character(len=:), + public, + allocatable + ::flags +

      File scope flags

      +
      + +
      +
      + + + +
      +

      Type-Bound Procedures

      +
      +
      +
      + +

      + generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_dump_to_toml(self, table, error) +

        + +

        Dump dependency to toml table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine dump_to_file(self, file, error, json) +

        + +

        Write serializable object to file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine dump_to_unit(self, unit, error, json) +

        + +

        Write serializable object to a formatted Fortran unit

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        Formatted unit

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format requested?

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + dump_to_toml => file_scope_dump + +

      +
      +
        +
      • +

        + public subroutine file_scope_dump(self, table, error) +

        + + +

        Dump to toml table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(file_scope_flag), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + load => load_from_toml, load_from_file, load_from_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_load_from_toml(self, table, error) +

        + +

        Read dependency from toml table (no checks made at this stage)

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine load_from_file(self, file, error, json) +

        + +

        Read dependency tree from file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine load_from_unit(self, unit, error, json) +

        + +

        Read dependency tree from file +init JSON interpreter +Read object from TOML table

        +

        use default TOML parser

        +

        Read object from TOML table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + load_from_toml => file_scope_load + +

      +
      +
        +
      • +

        + public subroutine file_scope_load(self, table, error) +

        + + +

        Read from toml table (no checks made at this stage)

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(file_scope_flag), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + operator(==) => serializable_is_same + +

      +
      +
        +
      • +

        + private function srcfile_is_same(this, that) +

        + +

        Check that two source files are equal +All checks passed!

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + serializable_is_same => file_scope_same + +

      +
      +
      + +

      Serialization interface

      +
      +
        +
      • +

        + public function file_scope_same(this, that) +

        + + +

        All checks passed!

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(file_scope_flag), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public, non_overridable :: + test_serialization + +

      +
      +
      + +

      Test load/write roundtrip

      +
      +
        +
      • +

        + private subroutine test_serialization(self, message, error) +

        + +

        Test serialization of a serializable object +Dump to scratch file +Load from scratch file +Check same

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self + +
        + + character(len=*), + intent(in) + + ::message + +
        + + type(error_t), + intent(out), + allocatable + ::error + +
        + + +
      • +
      +
      + +
      +
      + +
      +

      Source Code

      +
          type, extends(serializable_t) :: file_scope_flag
      +
      +      !> Name of the file
      +      character(len=:), allocatable :: file_name
      +
      +      !> File scope flags
      +      character(len=:), allocatable :: flags
      +
      +      contains
      +
      +          !> Serialization interface
      +          procedure :: serializable_is_same => file_scope_same
      +          procedure :: dump_to_toml => file_scope_dump
      +          procedure :: load_from_toml => file_scope_load
      +
      +    end type file_scope_flag
      +
      + +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/type/fortran_config_t.html b/type/fortran_config_t.html new file mode 100644 index 0000000000..786b9e6a82 --- /dev/null +++ b/type/fortran_config_t.html @@ -0,0 +1,1231 @@ + + + + + + + + + + + + + fortran_config_t – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      fortran_config_t + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public, extends(serializable_t) :: fortran_config_t

      +

      Configuration data for Fortran

      +
      + +
      +

      Components

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      TypeVisibility AttributesNameInitial
      + + logical, + public + + ::implicit_external =.false. +

      Enable implicit external interfaces

      +
      + + logical, + public + + ::implicit_typing =.false. +

      Enable default implicit typing

      +
      + + character(len=:), + public, + allocatable + ::source_form +

      Form to use for all Fortran sources

      +
      + +
      +
      + + + +
      +

      Type-Bound Procedures

      +
      +
      +
      + +

      + generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_dump_to_toml(self, table, error) +

        + +

        Dump dependency to toml table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine dump_to_file(self, file, error, json) +

        + +

        Write serializable object to file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine dump_to_unit(self, unit, error, json) +

        + +

        Write serializable object to a formatted Fortran unit

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        Formatted unit

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format requested?

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + dump_to_toml + +

      +
      +
        +
      • +

        + private subroutine dump_to_toml(self, table, error) +

        + +

        Dump install config to toml table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(fortran_config_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + load => load_from_toml, load_from_file, load_from_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_load_from_toml(self, table, error) +

        + +

        Read dependency from toml table (no checks made at this stage)

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine load_from_file(self, file, error, json) +

        + +

        Read dependency tree from file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine load_from_unit(self, unit, error, json) +

        + +

        Read dependency tree from file +init JSON interpreter +Read object from TOML table

        +

        use default TOML parser

        +

        Read object from TOML table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + load_from_toml + +

      +
      +
        +
      • +

        + private subroutine load_from_toml(self, table, error) +

        + +

        Read install config from toml table (no checks made at this stage)

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(fortran_config_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + operator(==) => serializable_is_same + +

      +
      +
        +
      • +

        + private function srcfile_is_same(this, that) +

        + +

        Check that two source files are equal +All checks passed!

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + serializable_is_same => fortran_is_same + +

      +
      +
      + +

      Serialization interface

      +
      +
        +
      • +

        + private function fortran_is_same(this, that) +

        + +

        All checks passed!

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(fortran_config_t), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public, non_overridable :: + test_serialization + +

      +
      +
      + +

      Test load/write roundtrip

      +
      +
        +
      • +

        + private subroutine test_serialization(self, message, error) +

        + +

        Test serialization of a serializable object +Dump to scratch file +Load from scratch file +Check same

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self + +
        + + character(len=*), + intent(in) + + ::message + +
        + + type(error_t), + intent(out), + allocatable + ::error + +
        + + +
      • +
      +
      + +
      +
      + +
      +

      Source Code

      +
          type, extends(serializable_t) :: fortran_config_t
      +
      +        !> Enable default implicit typing
      +        logical :: implicit_typing = .false.
      +
      +        !> Enable implicit external interfaces
      +        logical :: implicit_external = .false.
      +
      +        !> Form to use for all Fortran sources
      +        character(:), allocatable :: source_form
      +
      +        contains
      +
      +            !> Serialization interface
      +            procedure :: serializable_is_same => fortran_is_same
      +            procedure :: dump_to_toml
      +            procedure :: load_from_toml
      +
      +    end type fortran_config_t
      +
      + +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/type/fortran_features_t.html b/type/fortran_features_t.html new file mode 100644 index 0000000000..4a71d90dec --- /dev/null +++ b/type/fortran_features_t.html @@ -0,0 +1,1232 @@ + + + + + + + + + + + + + fortran_features_t – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      fortran_features_t + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public, extends(serializable_t) :: fortran_features_t

      +

      Enabled Fortran language features

      +
      + +
      +

      Components

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      TypeVisibility AttributesNameInitial
      + + logical, + public + + ::implicit_external =.false. +

      Use implicit external interface

      +
      + + logical, + public + + ::implicit_typing =.false. +

      Use default implicit typing

      +
      + + character(len=:), + public, + allocatable + ::source_form +

      Form to use for all Fortran sources

      +
      + +
      +
      + + + +
      +

      Type-Bound Procedures

      +
      +
      +
      + +

      + generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_dump_to_toml(self, table, error) +

        + +

        Dump dependency to toml table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine dump_to_file(self, file, error, json) +

        + +

        Write serializable object to file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine dump_to_unit(self, unit, error, json) +

        + +

        Write serializable object to a formatted Fortran unit

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        Formatted unit

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format requested?

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + dump_to_toml => fft_dump_to_toml + +

      +
      +
        +
      • +

        + private subroutine fft_dump_to_toml(self, table, error) +

        + +

        Dump fortran features to toml table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(fortran_features_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + load => load_from_toml, load_from_file, load_from_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_load_from_toml(self, table, error) +

        + +

        Read dependency from toml table (no checks made at this stage)

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine load_from_file(self, file, error, json) +

        + +

        Read dependency tree from file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine load_from_unit(self, unit, error, json) +

        + +

        Read dependency tree from file +init JSON interpreter +Read object from TOML table

        +

        use default TOML parser

        +

        Read object from TOML table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + load_from_toml => fft_load_from_toml + +

      +
      +
        +
      • +

        + private subroutine fft_load_from_toml(self, table, error) +

        + +

        Read dependency from toml table (no checks made at this stage)

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(fortran_features_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + operator(==) => serializable_is_same + +

      +
      +
        +
      • +

        + private function srcfile_is_same(this, that) +

        + +

        Check that two source files are equal +All checks passed!

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + serializable_is_same => fft_is_same + +

      +
      +
      + +

      Serialization interface

      +
      +
        +
      • +

        + private function fft_is_same(this, that) +

        + +

        Check that two fortran feature objects are equal +All checks passed!

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(fortran_features_t), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public, non_overridable :: + test_serialization + +

      +
      +
      + +

      Test load/write roundtrip

      +
      +
        +
      • +

        + private subroutine test_serialization(self, message, error) +

        + +

        Test serialization of a serializable object +Dump to scratch file +Load from scratch file +Check same

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self + +
        + + character(len=*), + intent(in) + + ::message + +
        + + type(error_t), + intent(out), + allocatable + ::error + +
        + + +
      • +
      +
      + +
      +
      + +
      +

      Source Code

      +
      type, extends(serializable_t) :: fortran_features_t
      +
      +    !> Use default implicit typing
      +    logical :: implicit_typing = .false.
      +
      +    !> Use implicit external interface
      +    logical :: implicit_external = .false.
      +
      +    !> Form to use for all Fortran sources
      +    character(:), allocatable :: source_form
      +
      +    contains
      +
      +        !> Serialization interface
      +        procedure :: serializable_is_same => fft_is_same
      +        procedure :: dump_to_toml   => fft_dump_to_toml
      +        procedure :: load_from_toml => fft_load_from_toml
      +
      +end type fortran_features_t
      +
      + +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/type/fpm_build_settings.html b/type/fpm_build_settings.html new file mode 100644 index 0000000000..8d8f72af9d --- /dev/null +++ b/type/fpm_build_settings.html @@ -0,0 +1,524 @@ + + + + + + + + + + + + + fpm_build_settings – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      fpm_build_settings + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public, extends(fpm_cmd_settings) :: fpm_build_settings

      + +
      + +
      +

      Components

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      TypeVisibility AttributesNameInitial
      + + character(len=:), + public, + allocatable + ::archiver + +
      + + logical, + public + + ::build_tests =.false. + +
      + + character(len=:), + public, + allocatable + ::c_compiler + +
      + + character(len=:), + public, + allocatable + ::cflag + +
      + + character(len=:), + public, + allocatable + ::compiler + +
      + + character(len=:), + public, + allocatable + ::cxx_compiler + +
      + + character(len=:), + public, + allocatable + ::cxxflag + +
      + + character(len=:), + public, + allocatable + ::dump + +
      + + character(len=:), + public, + allocatable + ::flag + +
      + + character(len=:), + public, + allocatable + ::ldflag + +
      + + logical, + public + + ::list =.false. + +
      + + character(len=:), + public, + allocatable + ::path_to_config + +
      + + character(len=:), + public, + allocatable + ::profile + +
      + + logical, + public + + ::prune =.true. + +
      + + logical, + public + + ::show_model =.false. + +
      + + logical, + public + + ::verbose =.true. + +
      + + character(len=:), + public, + allocatable + ::working_dir + +
      + +
      +
      + + + + + +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/type/fpm_clean_settings.html b/type/fpm_clean_settings.html new file mode 100644 index 0000000000..d74642e136 --- /dev/null +++ b/type/fpm_clean_settings.html @@ -0,0 +1,326 @@ + + + + + + + + + + + + + fpm_clean_settings – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      fpm_clean_settings + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public, extends(fpm_cmd_settings) :: fpm_clean_settings

      + +
      + +
      +

      Components

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      TypeVisibility AttributesNameInitial
      + + logical, + public + + ::clean_all =.false. + +
      + + logical, + public + + ::clean_skip =.false. + +
      + + character(len=:), + public, + allocatable + ::path_to_config + +
      + + logical, + public + + ::registry_cache =.false. + +
      + + logical, + public + + ::verbose =.true. + +
      + + character(len=:), + public, + allocatable + ::working_dir + +
      + +
      +
      + + + + + +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/type/fpm_cmd_settings.html b/type/fpm_cmd_settings.html new file mode 100644 index 0000000000..5db6e65866 --- /dev/null +++ b/type/fpm_cmd_settings.html @@ -0,0 +1,272 @@ + + + + + + + + + + + + + fpm_cmd_settings – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      fpm_cmd_settings + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public, abstract :: fpm_cmd_settings

      + +
      + +
      +

      Components

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      TypeVisibility AttributesNameInitial
      + + character(len=:), + public, + allocatable + ::path_to_config + +
      + + logical, + public + + ::verbose =.true. + +
      + + character(len=:), + public, + allocatable + ::working_dir + +
      + +
      +
      + + + + + +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/type/fpm_export_settings.html b/type/fpm_export_settings.html new file mode 100644 index 0000000000..ca080af1a1 --- /dev/null +++ b/type/fpm_export_settings.html @@ -0,0 +1,578 @@ + + + + + + + + + + + + + fpm_export_settings – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      fpm_export_settings + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public, extends(fpm_build_settings) :: fpm_export_settings

      +

      Settings for exporting model data

      +
      + +
      +

      Components

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      TypeVisibility AttributesNameInitial
      + + character(len=:), + public, + allocatable + ::archiver + +
      + + logical, + public + + ::build_tests =.false. + +
      + + character(len=:), + public, + allocatable + ::c_compiler + +
      + + character(len=:), + public, + allocatable + ::cflag + +
      + + character(len=:), + public, + allocatable + ::compiler + +
      + + character(len=:), + public, + allocatable + ::cxx_compiler + +
      + + character(len=:), + public, + allocatable + ::cxxflag + +
      + + character(len=:), + public, + allocatable + ::dump + +
      + + character(len=:), + public, + allocatable + ::dump_dependencies + +
      + + character(len=:), + public, + allocatable + ::dump_manifest + +
      + + character(len=:), + public, + allocatable + ::dump_model + +
      + + character(len=:), + public, + allocatable + ::flag + +
      + + character(len=:), + public, + allocatable + ::ldflag + +
      + + logical, + public + + ::list =.false. + +
      + + character(len=:), + public, + allocatable + ::path_to_config + +
      + + character(len=:), + public, + allocatable + ::profile + +
      + + logical, + public + + ::prune =.true. + +
      + + logical, + public + + ::show_model =.false. + +
      + + logical, + public + + ::verbose =.true. + +
      + + character(len=:), + public, + allocatable + ::working_dir + +
      + +
      +
      + + + + + +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/type/fpm_global_settings.html b/type/fpm_global_settings.html new file mode 100644 index 0000000000..242baa2ca4 --- /dev/null +++ b/type/fpm_global_settings.html @@ -0,0 +1,462 @@ + + + + + + + + + + + + + fpm_global_settings – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      fpm_global_settings + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public :: fpm_global_settings

      + +
      + +
      +

      Components

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      TypeVisibility AttributesNameInitial
      + + character(len=:), + public, + allocatable + ::config_file_name +

      Name of the global config file. The default is config.toml.

      +
      + + character(len=:), + public, + allocatable + ::path_to_config_folder +

      Path to the global config file excluding the file name.

      +
      + + type(fpm_registry_settings), + public, + allocatable + ::registry_settings +

      Registry configs.

      +
      + +
      +
      + + + +
      +

      Type-Bound Procedures

      +
      +
      +
      + +

      + procedure, public :: + full_path + +

      +
      +
        +
      • +

        + private function full_path(self) result(result) +

        + +

        The full path to the global config file.

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(fpm_global_settings), + intent(in) + + ::self + +
        + +

        + Return Value + character(len=:), allocatable +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + has_custom_location + +

      +
      +
        +
      • +

        + private elemental function has_custom_location(self) +

        + +

        True if the global config file is not at the default location.

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(fpm_global_settings), + intent(in) + + ::self + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + path_to_config_folder_or_empty + +

      +
      +
        +
      • +

        + private pure function path_to_config_folder_or_empty(self) +

        + +

        The path to the global config directory.

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(fpm_global_settings), + intent(in) + + ::self + +
        + +

        + Return Value + character(len=:), allocatable +

        + + +
      • +
      +
      + +
      +
      + + +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/type/fpm_install_settings.html b/type/fpm_install_settings.html new file mode 100644 index 0000000000..0c6b091df6 --- /dev/null +++ b/type/fpm_install_settings.html @@ -0,0 +1,632 @@ + + + + + + + + + + + + + fpm_install_settings – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      fpm_install_settings + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public, extends(fpm_build_settings) :: fpm_install_settings

      + +
      + +
      +

      Components

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      TypeVisibility AttributesNameInitial
      + + character(len=:), + public, + allocatable + ::archiver + +
      + + character(len=:), + public, + allocatable + ::bindir + +
      + + logical, + public + + ::build_tests =.false. + +
      + + character(len=:), + public, + allocatable + ::c_compiler + +
      + + character(len=:), + public, + allocatable + ::cflag + +
      + + character(len=:), + public, + allocatable + ::compiler + +
      + + character(len=:), + public, + allocatable + ::cxx_compiler + +
      + + character(len=:), + public, + allocatable + ::cxxflag + +
      + + character(len=:), + public, + allocatable + ::dump + +
      + + character(len=:), + public, + allocatable + ::flag + +
      + + character(len=:), + public, + allocatable + ::includedir + +
      + + character(len=:), + public, + allocatable + ::ldflag + +
      + + character(len=:), + public, + allocatable + ::libdir + +
      + + logical, + public + + ::list =.false. + +
      + + logical, + public + + ::no_rebuild + +
      + + character(len=:), + public, + allocatable + ::path_to_config + +
      + + character(len=:), + public, + allocatable + ::prefix + +
      + + character(len=:), + public, + allocatable + ::profile + +
      + + logical, + public + + ::prune =.true. + +
      + + logical, + public + + ::show_model =.false. + +
      + + character(len=:), + public, + allocatable + ::testdir + +
      + + logical, + public + + ::verbose =.true. + +
      + + character(len=:), + public, + allocatable + ::working_dir + +
      + +
      +
      + + + + + +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/type/fpm_model_t.html b/type/fpm_model_t.html new file mode 100644 index 0000000000..d7b93dcb84 --- /dev/null +++ b/type/fpm_model_t.html @@ -0,0 +1,1651 @@ + + + + + + + + + + + + + fpm_model_t – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      fpm_model_t + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public, extends(serializable_t) :: fpm_model_t

      +

      Type describing everything required to build + the root package and its dependencies.

      +
      + +
      +

      Components

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      TypeVisibility AttributesNameInitial
      + + type(archiver_t), + public + + ::archiver +

      Archiver object

      +
      + + character(len=:), + public, + allocatable + ::build_prefix +

      Base directory for build

      +
      + + character(len=:), + public, + allocatable + ::c_compile_flags +

      Command line flags passed to C for compilation

      +
      + + type(compiler_t), + public + + ::compiler +

      Compiler object

      +
      + + character(len=:), + public, + allocatable + ::cxx_compile_flags +

      Command line flags passed to C++ for compilation

      +
      + + type(dependency_tree_t), + public + + ::deps +

      Project dependencies

      +
      + + logical, + public + + ::enforce_module_names =.false. +

      Whether module names should be prefixed with the package name

      +
      + + type(string_t), + public, + allocatable + ::external_modules(:) +

      External modules used

      +
      + + character(len=:), + public, + allocatable + ::fortran_compile_flags +

      Command line flags passed to fortran for compilation

      +
      + + type(string_t), + public, + allocatable + ::include_dirs(:) +

      Include directories

      +
      + + logical, + public + + ::include_tests =.true. +

      Whether tests should be added to the build list

      +
      + + character(len=:), + public, + allocatable + ::link_flags +

      Command line flags passed to the linker

      +
      + + type(string_t), + public, + allocatable + ::link_libraries(:) +

      Native libraries to link against

      +
      + + type(string_t), + public + + ::module_prefix +

      Prefix for all module names

      +
      + + character(len=:), + public, + allocatable + ::package_name +

      Name of root package

      +
      + + type(package_t), + public, + allocatable + ::packages(:) +

      Array of packages (including the root package)

      +
      + +
      +
      + + + +
      +

      Type-Bound Procedures

      +
      +
      +
      + +

      + generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_dump_to_toml(self, table, error) +

        + +

        Dump dependency to toml table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine dump_to_file(self, file, error, json) +

        + +

        Write serializable object to file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine dump_to_unit(self, unit, error, json) +

        + +

        Write serializable object to a formatted Fortran unit

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        Formatted unit

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format requested?

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + dump_to_toml => model_dump_to_toml + +

      +
      +
        +
      • +

        + private subroutine model_dump_to_toml(self, table, error) +

        + +

        Dump dependency to toml table

        +

        Array of packages (including the root package)

        +

        Because dependencies are named, fallback if this has no name +So, serialization will work regardless of size(self%dep) == self%ndep

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(fpm_model_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + get_package_libraries_link + +

      +
      +
      + +

      Get target link flags

      +
      +
        +
      • +

        + private function get_package_libraries_link(model, package_name, prefix, exclude_self, dep_IDs, error) result(r) +

        + + + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(fpm_model_t), + intent(in) + + ::model + +
        + + character(len=*), + intent(in) + + ::package_name + +
        + + character(len=*), + intent(in) + + ::prefix + +
        + + logical, + intent(in),optional + + ::exclude_self +

        Option to exclude linking to the given package (needed building it as a library)

        +
        + + integer, + intent(out),optional, + allocatable + ::dep_IDs(:) +

        Optionally export the list of dependency IDs

        +
        + + type(error_t), + intent(out), + allocatable + ::error + +
        + +

        + Return Value + character(len=:), allocatable +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + load => load_from_toml, load_from_file, load_from_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_load_from_toml(self, table, error) +

        + +

        Read dependency from toml table (no checks made at this stage)

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine load_from_file(self, file, error, json) +

        + +

        Read dependency tree from file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine load_from_unit(self, unit, error, json) +

        + +

        Read dependency tree from file +init JSON interpreter +Read object from TOML table

        +

        use default TOML parser

        +

        Read object from TOML table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + load_from_toml => model_load_from_toml + +

      +
      +
        +
      • +

        + private subroutine model_load_from_toml(self, table, error) +

        + +

        Read dependency from toml table (no checks made at this stage)

        +

        Read all packages

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(fpm_model_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + operator(==) => serializable_is_same + +

      +
      +
        +
      • +

        + private function srcfile_is_same(this, that) +

        + +

        Check that two source files are equal +All checks passed!

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + serializable_is_same => model_is_same + +

      +
      +
      + +

      Serialization interface

      +
      +
        +
      • +

        + private function model_is_same(this, that) +

        + +

        Check that two model objects are equal +All checks passed!

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(fpm_model_t), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public, non_overridable :: + test_serialization + +

      +
      +
      + +

      Test load/write roundtrip

      +
      +
        +
      • +

        + private subroutine test_serialization(self, message, error) +

        + +

        Test serialization of a serializable object +Dump to scratch file +Load from scratch file +Check same

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self + +
        + + character(len=*), + intent(in) + + ::message + +
        + + type(error_t), + intent(out), + allocatable + ::error + +
        + + +
      • +
      +
      + +
      +
      + +
      +

      Source Code

      +
      type, extends(serializable_t) :: fpm_model_t
      +
      +    !> Name of root package
      +    character(:), allocatable :: package_name
      +
      +    !> Array of packages (including the root package)
      +    type(package_t), allocatable :: packages(:)
      +
      +    !> Compiler object
      +    type(compiler_t) :: compiler
      +
      +    !> Archiver object
      +    type(archiver_t) :: archiver
      +
      +    !> Command line flags passed to fortran for compilation
      +    character(:), allocatable :: fortran_compile_flags
      +
      +    !> Command line flags passed to C for compilation
      +    character(:), allocatable :: c_compile_flags
      +
      +    !> Command line flags passed to C++ for compilation
      +    character(:), allocatable :: cxx_compile_flags
      +
      +    !> Command line flags passed to the linker
      +    character(:), allocatable :: link_flags
      +
      +    !> Base directory for build
      +    character(:), allocatable :: build_prefix
      +
      +    !> Include directories
      +    type(string_t), allocatable :: include_dirs(:)
      +
      +    !> Native libraries to link against
      +    type(string_t), allocatable :: link_libraries(:)
      +
      +    !> External modules used
      +    type(string_t), allocatable :: external_modules(:)
      +
      +    !> Project dependencies
      +    type(dependency_tree_t) :: deps
      +
      +    !> Whether tests should be added to the build list
      +    logical :: include_tests = .true.
      +
      +    !> Whether module names should be prefixed with the package name
      +    logical :: enforce_module_names = .false.
      +
      +    !> Prefix for all module names
      +    type(string_t) :: module_prefix
      +
      +    contains
      +    
      +        !> Get target link flags
      +        procedure :: get_package_libraries_link
      +    
      +        !> Serialization interface
      +        procedure :: serializable_is_same => model_is_same
      +        procedure :: dump_to_toml   => model_dump_to_toml
      +        procedure :: load_from_toml => model_load_from_toml
      +
      +end type fpm_model_t
      +
      + +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/type/fpm_new_settings.html b/type/fpm_new_settings.html new file mode 100644 index 0000000000..517257114d --- /dev/null +++ b/type/fpm_new_settings.html @@ -0,0 +1,416 @@ + + + + + + + + + + + + + fpm_new_settings – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      fpm_new_settings + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public, extends(fpm_cmd_settings) :: fpm_new_settings

      + +
      + +
      +

      Components

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      TypeVisibility AttributesNameInitial
      + + logical, + public + + ::backfill =.true. + +
      + + character(len=:), + public, + allocatable + ::name + +
      + + character(len=:), + public, + allocatable + ::path_to_config + +
      + + logical, + public + + ::verbose =.true. + +
      + + logical, + public + + ::with_bare =.false. + +
      + + logical, + public + + ::with_example =.false. + +
      + + logical, + public + + ::with_executable =.false. + +
      + + logical, + public + + ::with_full =.false. + +
      + + logical, + public + + ::with_lib =.true. + +
      + + logical, + public + + ::with_test =.false. + +
      + + character(len=:), + public, + allocatable + ::working_dir + +
      + +
      +
      + + + + + +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/type/fpm_publish_settings.html b/type/fpm_publish_settings.html new file mode 100644 index 0000000000..254f493839 --- /dev/null +++ b/type/fpm_publish_settings.html @@ -0,0 +1,596 @@ + + + + + + + + + + + + + fpm_publish_settings – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      fpm_publish_settings + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public, extends(fpm_build_settings) :: fpm_publish_settings

      + +
      + +
      +

      Components

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      TypeVisibility AttributesNameInitial
      + + character(len=:), + public, + allocatable + ::archiver + +
      + + logical, + public + + ::build_tests =.false. + +
      + + character(len=:), + public, + allocatable + ::c_compiler + +
      + + character(len=:), + public, + allocatable + ::cflag + +
      + + character(len=:), + public, + allocatable + ::compiler + +
      + + character(len=:), + public, + allocatable + ::cxx_compiler + +
      + + character(len=:), + public, + allocatable + ::cxxflag + +
      + + character(len=:), + public, + allocatable + ::dump + +
      + + character(len=:), + public, + allocatable + ::flag + +
      + + logical, + public + + ::is_dry_run =.false. + +
      + + character(len=:), + public, + allocatable + ::ldflag + +
      + + logical, + public + + ::list =.false. + +
      + + character(len=:), + public, + allocatable + ::path_to_config + +
      + + character(len=:), + public, + allocatable + ::profile + +
      + + logical, + public + + ::prune =.true. + +
      + + logical, + public + + ::show_model =.false. + +
      + + logical, + public + + ::show_package_version =.false. + +
      + + logical, + public + + ::show_upload_data =.false. + +
      + + character(len=:), + public, + allocatable + ::token + +
      + + logical, + public + + ::verbose =.true. + +
      + + character(len=:), + public, + allocatable + ::working_dir + +
      + +
      +
      + + + + + +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/type/fpm_run_settings.html b/type/fpm_run_settings.html new file mode 100644 index 0000000000..f432459a3f --- /dev/null +++ b/type/fpm_run_settings.html @@ -0,0 +1,763 @@ + + + + + + + + + + + + + fpm_run_settings – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      fpm_run_settings + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public, extends(fpm_build_settings) :: fpm_run_settings

      + +
      + +
      +

      Components

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      TypeVisibility AttributesNameInitial
      + + character(len=:), + public, + allocatable + ::archiver + +
      + + character(len=:), + public, + allocatable + ::args + +
      + + logical, + public + + ::build_tests =.false. + +
      + + character(len=:), + public, + allocatable + ::c_compiler + +
      + + character(len=:), + public, + allocatable + ::cflag + +
      + + character(len=:), + public, + allocatable + ::compiler + +
      + + character(len=:), + public, + allocatable + ::cxx_compiler + +
      + + character(len=:), + public, + allocatable + ::cxxflag + +
      + + character(len=:), + public, + allocatable + ::dump + +
      + + logical, + public + + ::example + +
      + + character(len=:), + public, + allocatable + ::flag + +
      + + character(len=:), + public, + allocatable + ::ldflag + +
      + + logical, + public + + ::list =.false. + +
      + + character(len=ibug), + public, + allocatable + ::name(:) + +
      + + character(len=:), + public, + allocatable + ::path_to_config + +
      + + character(len=:), + public, + allocatable + ::profile + +
      + + logical, + public + + ::prune =.true. + +
      + + character(len=:), + public, + allocatable + ::runner + +
      + + character(len=:), + public, + allocatable + ::runner_args + +
      + + logical, + public + + ::show_model =.false. + +
      + + logical, + public + + ::verbose =.true. + +
      + + character(len=:), + public, + allocatable + ::working_dir + +
      + +
      +
      + + + +
      +

      Type-Bound Procedures

      +
      +
      +
      + +

      + procedure, public :: + name_ID + +

      +
      +
        +
      • +

        + private function name_ID(cmd, name) +

        + +

        Check name in list ID. return 0 if not found +Default: not found

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(fpm_run_settings), + intent(in) + + ::cmd + +
        + + character(len=*), + intent(in) + + ::name + +
        + +

        + Return Value + integer +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + runner_command + +

      +
      +
        +
      • +

        + private function runner_command(cmd) result(run_cmd) +

        + +

        Build a full runner command (executable + command-line arguments) +Get executable +Append command-line arguments

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(fpm_run_settings), + intent(in) + + ::cmd + +
        + +

        + Return Value + character(len=:), allocatable +

        + + +
      • +
      +
      + +
      +
      + + +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/type/fpm_test_settings.html b/type/fpm_test_settings.html new file mode 100644 index 0000000000..5b69918046 --- /dev/null +++ b/type/fpm_test_settings.html @@ -0,0 +1,763 @@ + + + + + + + + + + + + + fpm_test_settings – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      fpm_test_settings + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public, extends(fpm_run_settings) :: fpm_test_settings

      + +
      + +
      +

      Components

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      TypeVisibility AttributesNameInitial
      + + character(len=:), + public, + allocatable + ::archiver + +
      + + character(len=:), + public, + allocatable + ::args + +
      + + logical, + public + + ::build_tests =.false. + +
      + + character(len=:), + public, + allocatable + ::c_compiler + +
      + + character(len=:), + public, + allocatable + ::cflag + +
      + + character(len=:), + public, + allocatable + ::compiler + +
      + + character(len=:), + public, + allocatable + ::cxx_compiler + +
      + + character(len=:), + public, + allocatable + ::cxxflag + +
      + + character(len=:), + public, + allocatable + ::dump + +
      + + logical, + public + + ::example + +
      + + character(len=:), + public, + allocatable + ::flag + +
      + + character(len=:), + public, + allocatable + ::ldflag + +
      + + logical, + public + + ::list =.false. + +
      + + character(len=ibug), + public, + allocatable + ::name(:) + +
      + + character(len=:), + public, + allocatable + ::path_to_config + +
      + + character(len=:), + public, + allocatable + ::profile + +
      + + logical, + public + + ::prune =.true. + +
      + + character(len=:), + public, + allocatable + ::runner + +
      + + character(len=:), + public, + allocatable + ::runner_args + +
      + + logical, + public + + ::show_model =.false. + +
      + + logical, + public + + ::verbose =.true. + +
      + + character(len=:), + public, + allocatable + ::working_dir + +
      + +
      +
      + + + +
      +

      Type-Bound Procedures

      +
      +
      +
      + +

      + procedure, public :: + name_ID + +

      +
      +
        +
      • +

        + private function name_ID(cmd, name) +

        + +

        Check name in list ID. return 0 if not found +Default: not found

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(fpm_run_settings), + intent(in) + + ::cmd + +
        + + character(len=*), + intent(in) + + ::name + +
        + +

        + Return Value + integer +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + runner_command + +

      +
      +
        +
      • +

        + private function runner_command(cmd) result(run_cmd) +

        + +

        Build a full runner command (executable + command-line arguments) +Get executable +Append command-line arguments

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(fpm_run_settings), + intent(in) + + ::cmd + +
        + +

        + Return Value + character(len=:), allocatable +

        + + +
      • +
      +
      + +
      +
      + + +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/type/fpm_update_settings.html b/type/fpm_update_settings.html new file mode 100644 index 0000000000..3185de0818 --- /dev/null +++ b/type/fpm_update_settings.html @@ -0,0 +1,344 @@ + + + + + + + + + + + + + fpm_update_settings – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      fpm_update_settings + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public, extends(fpm_cmd_settings) :: fpm_update_settings

      +

      Settings for interacting and updating with project dependencies

      +
      + +
      +

      Components

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      TypeVisibility AttributesNameInitial
      + + logical, + public + + ::clean + +
      + + character(len=:), + public, + allocatable + ::dump + +
      + + logical, + public + + ::fetch_only + +
      + + character(len=ibug), + public, + allocatable + ::name(:) + +
      + + character(len=:), + public, + allocatable + ::path_to_config + +
      + + logical, + public + + ::verbose =.true. + +
      + + character(len=:), + public, + allocatable + ::working_dir + +
      + +
      +
      + + + + + +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/type/git_target_t.html b/type/git_target_t.html new file mode 100644 index 0000000000..2c29c1259c --- /dev/null +++ b/type/git_target_t.html @@ -0,0 +1,1419 @@ + + + + + + + + + + + + + git_target_t – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      git_target_t + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public, extends(serializable_t) :: git_target_t

      +

      Description of an git target

      +
      + +
      +

      Components

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      TypeVisibility AttributesNameInitial
      + + integer, + public + + ::descriptor =git_descriptor%default +

      Kind of the git target

      +
      + + character(len=:), + public, + allocatable + ::object +

      Additional descriptor of the git object

      +
      + + character(len=:), + public, + allocatable + ::url +

      Target URL of the git repository

      +
      + +
      +
      + + + +
      +

      Type-Bound Procedures

      +
      +
      +
      + +

      + procedure, public :: + checkout + +

      +
      +
      + +

      Fetch and checkout in local directory

      +
      +
        +
      • +

        + public subroutine checkout(self, local_path, error) +

        + + + + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(git_target_t), + intent(in) + + ::self +

        Instance of the git target

        +
        + + character(len=*), + intent(in) + + ::local_path +

        Local path to checkout in

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_dump_to_toml(self, table, error) +

        + +

        Dump dependency to toml table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine dump_to_file(self, file, error, json) +

        + +

        Write serializable object to file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine dump_to_unit(self, unit, error, json) +

        + +

        Write serializable object to a formatted Fortran unit

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        Formatted unit

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format requested?

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + dump_to_toml + +

      +
      +
        +
      • +

        + public subroutine dump_to_toml(self, table, error) +

        + + +

        Dump dependency to toml table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(git_target_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + info + +

      +
      +
      + +

      Show information on instance

      +
      +
        +
      • +

        + public subroutine info(self, unit, verbosity) +

        + + +

        Show information on git target

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(git_target_t), + intent(in) + + ::self +

        Instance of the git target

        +
        + + integer, + intent(in) + + ::unit +

        Unit for IO

        +
        + + integer, + intent(in),optional + + ::verbosity +

        Verbosity of the printout

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + load => load_from_toml, load_from_file, load_from_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_load_from_toml(self, table, error) +

        + +

        Read dependency from toml table (no checks made at this stage)

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine load_from_file(self, file, error, json) +

        + +

        Read dependency tree from file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine load_from_unit(self, unit, error, json) +

        + +

        Read dependency tree from file +init JSON interpreter +Read object from TOML table

        +

        use default TOML parser

        +

        Read object from TOML table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + load_from_toml + +

      +
      +
        +
      • +

        + public subroutine load_from_toml(self, table, error) +

        + + +

        Read dependency from toml table (no checks made at this stage)

        Read more… + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(git_target_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + operator(==) => serializable_is_same + +

      +
      +
        +
      • +

        + private function srcfile_is_same(this, that) +

        + +

        Check that two source files are equal +All checks passed!

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + serializable_is_same => git_is_same + +

      +
      +
      + +

      Serialization interface

      +
      +
        +
      • +

        + public function git_is_same(this, that) +

        + + +

        Check that two git targets are equal +All checks passed!

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(git_target_t), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public, non_overridable :: + test_serialization + +

      +
      +
      + +

      Test load/write roundtrip

      +
      +
        +
      • +

        + private subroutine test_serialization(self, message, error) +

        + +

        Test serialization of a serializable object +Dump to scratch file +Load from scratch file +Check same

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self + +
        + + character(len=*), + intent(in) + + ::message + +
        + + type(error_t), + intent(out), + allocatable + ::error + +
        + + +
      • +
      +
      + +
      +
      + +
      +

      Source Code

      +
          type, extends(serializable_t) :: git_target_t
      +
      +        !> Kind of the git target
      +        integer :: descriptor = git_descriptor%default
      +
      +        !> Target URL of the git repository
      +        character(len=:), allocatable :: url
      +
      +        !> Additional descriptor of the git object
      +        character(len=:), allocatable :: object
      +
      +    contains
      +
      +        !> Fetch and checkout in local directory
      +        procedure :: checkout
      +
      +        !> Show information on instance
      +        procedure :: info
      +
      +        !> Serialization interface
      +        procedure :: serializable_is_same => git_is_same
      +        procedure :: dump_to_toml
      +        procedure :: load_from_toml
      +
      +    end type git_target_t
      +
      + +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/type/install_config_t.html b/type/install_config_t.html new file mode 100644 index 0000000000..efbda43275 --- /dev/null +++ b/type/install_config_t.html @@ -0,0 +1,1301 @@ + + + + + + + + + + + + + install_config_t – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      install_config_t + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public, extends(serializable_t) :: install_config_t

      +

      Configuration data for installation

      +
      + +
      +

      Components

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      TypeVisibility AttributesNameInitial
      + + logical, + public + + ::library =.false. +

      Install library with this project

      +
      + + logical, + public + + ::test =.false. +

      Install tests with this project

      +
      + +
      +
      + + + +
      +

      Type-Bound Procedures

      +
      +
      +
      + +

      + generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_dump_to_toml(self, table, error) +

        + +

        Dump dependency to toml table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine dump_to_file(self, file, error, json) +

        + +

        Write serializable object to file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine dump_to_unit(self, unit, error, json) +

        + +

        Write serializable object to a formatted Fortran unit

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        Formatted unit

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format requested?

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + dump_to_toml + +

      +
      +
        +
      • +

        + private subroutine dump_to_toml(self, table, error) +

        + +

        Dump install config to toml table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(install_config_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + info + +

      +
      +
      + +

      Print information on this instance

      +
      +
        +
      • +

        + private subroutine info(self, unit, verbosity) +

        + +

        Write information on install configuration instance

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(install_config_t), + intent(in) + + ::self +

        Instance of the build configuration

        +
        + + integer, + intent(in) + + ::unit +

        Unit for IO

        +
        + + integer, + intent(in),optional + + ::verbosity +

        Verbosity of the printout

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + load => load_from_toml, load_from_file, load_from_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_load_from_toml(self, table, error) +

        + +

        Read dependency from toml table (no checks made at this stage)

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine load_from_file(self, file, error, json) +

        + +

        Read dependency tree from file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine load_from_unit(self, unit, error, json) +

        + +

        Read dependency tree from file +init JSON interpreter +Read object from TOML table

        +

        use default TOML parser

        +

        Read object from TOML table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + load_from_toml + +

      +
      +
        +
      • +

        + private subroutine load_from_toml(self, table, error) +

        + +

        Read install config from toml table (no checks made at this stage)

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(install_config_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + operator(==) => serializable_is_same + +

      +
      +
        +
      • +

        + private function srcfile_is_same(this, that) +

        + +

        Check that two source files are equal +All checks passed!

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + serializable_is_same => install_conf_same + +

      +
      +
      + +

      Serialization interface

      +
      +
        +
      • +

        + private function install_conf_same(this, that) +

        + +

        All checks passed!

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(install_config_t), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public, non_overridable :: + test_serialization + +

      +
      +
      + +

      Test load/write roundtrip

      +
      +
        +
      • +

        + private subroutine test_serialization(self, message, error) +

        + +

        Test serialization of a serializable object +Dump to scratch file +Load from scratch file +Check same

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self + +
        + + character(len=*), + intent(in) + + ::message + +
        + + type(error_t), + intent(out), + allocatable + ::error + +
        + + +
      • +
      +
      + +
      +
      + +
      +

      Source Code

      +
        type, extends(serializable_t) :: install_config_t
      +
      +    !> Install library with this project
      +    logical :: library = .false.
      +
      +    !> Install tests with this project
      +    logical :: test = .false.
      +
      +  contains
      +
      +    !> Print information on this instance
      +    procedure :: info
      +
      +    !> Serialization interface
      +    procedure :: serializable_is_same => install_conf_same
      +    procedure :: dump_to_toml
      +    procedure :: load_from_toml
      +
      +  end type install_config_t
      +
      + +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/type/installer_t.html b/type/installer_t.html new file mode 100644 index 0000000000..648a3d3796 --- /dev/null +++ b/type/installer_t.html @@ -0,0 +1,1171 @@ + + + + + + + + + + + + + installer_t – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      installer_t + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public :: installer_t

      +

      Declaration of the installer type

      +
      + +
      +

      Components

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      TypeVisibility AttributesNameInitial
      + + character(len=:), + public, + allocatable + ::bindir +

      Binary dir relative to the installation prefix

      +
      + + character(len=:), + public, + allocatable + ::copy +

      Command to copy objects into the installation prefix

      +
      + + character(len=:), + public, + allocatable + ::includedir +

      Include directory relative to the installation prefix

      +
      + + character(len=:), + public, + allocatable + ::libdir +

      Library directory relative to the installation prefix

      +
      + + character(len=:), + public, + allocatable + ::move +

      Command to move objects into the installation prefix

      +
      + + integer, + public + + ::os +

      Cached operating system

      +
      + + character(len=:), + public, + allocatable + ::prefix +

      Path to installation directory

      +
      + + character(len=:), + public, + allocatable + ::testdir +

      Test program directory relative to the installation prefix

      +
      + + integer, + public + + ::unit =output_unit +

      Output unit for informative printout

      +
      + + integer, + public + + ::verbosity =1 +

      Verbosity of the installer

      +
      + +
      +
      + + + +
      +

      Type-Bound Procedures

      +
      +
      +
      + +

      + procedure, public :: + install + +

      +
      +
      + +

      Install a generic file into a subdirectory in the installation prefix

      +
      +
        +
      • +

        + private subroutine install(self, source, destination, error) +

        + +

        Install a generic file into a subdirectory in the installation prefix

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(installer_t), + intent(inout) + + ::self +

        Instance of the installer

        +
        + + character(len=*), + intent(in) + + ::source +

        Path to the original file

        +
        + + character(len=*), + intent(in) + + ::destination +

        Path to the destination inside the prefix

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + install_destination + +

      +
      +
      + +

      Evaluate the installation path

      +
      +
        +
      • +

        + private function install_destination(self, destination) result(install_dest) +

        + +

        Evaluate the installation path

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(installer_t), + intent(inout) + + ::self +

        Instance of the installer

        +
        + + character(len=*), + intent(in) + + ::destination +

        Path to the destination inside the prefix

        +
        + +

        + Return Value + character(len=:), allocatable +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + install_executable + +

      +
      +
      + +

      Install an executable in its correct subdirectory

      +
      +
        +
      • +

        + private subroutine install_executable(self, executable, error) +

        + +

        Install an executable in its correct subdirectory

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(installer_t), + intent(inout) + + ::self +

        Instance of the installer

        +
        + + character(len=*), + intent(in) + + ::executable +

        Path to the executable

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + install_header + +

      +
      +
      + +

      Install a header/module in its correct subdirectory

      +
      +
        +
      • +

        + private subroutine install_header(self, header, error) +

        + +

        Install a header/module in its correct subdirectory

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(installer_t), + intent(inout) + + ::self +

        Instance of the installer

        +
        + + character(len=*), + intent(in) + + ::header +

        Path to the header

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + install_library + +

      +
      +
      + +

      Install a library in its correct subdirectory

      +
      +
        +
      • +

        + private subroutine install_library(self, library, error) +

        + +

        Install a library in its correct subdirectory

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(installer_t), + intent(inout) + + ::self +

        Instance of the installer

        +
        + + type(build_target_t), + intent(in) + + ::library +

        Library target

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + install_test + +

      +
      +
      + +

      Install a test program in its correct subdirectory

      +
      +
        +
      • +

        + private subroutine install_test(self, test, error) +

        + +

        Install a test program in its correct subdirectory

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(installer_t), + intent(inout) + + ::self +

        Instance of the installer

        +
        + + character(len=*), + intent(in) + + ::test +

        Path to the test executable

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + make_dir + +

      +
      +
      + +

      Create a new directory in the prefix, type-bound for unit testing purposes

      +
      +
        +
      • +

        + private subroutine make_dir(self, dir, error) +

        + +

        Create a new directory in the prefix

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(installer_t), + intent(inout) + + ::self +

        Instance of the installer

        +
        + + character(len=*), + intent(in) + + ::dir +

        Directory to be created

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + run + +

      +
      +
      + +

      Run an installation command, type-bound for unit testing purposes

      +
      +
        +
      • +

        + private subroutine run(self, command, error) +

        + +

        Run an installation command

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(installer_t), + intent(inout) + + ::self +

        Instance of the installer

        +
        + + character(len=*), + intent(in) + + ::command +

        Command to be launched

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      + +
      +

      Source Code

      +
        type :: installer_t
      +    !> Path to installation directory
      +    character(len=:), allocatable :: prefix
      +    !> Binary dir relative to the installation prefix
      +    character(len=:), allocatable :: bindir
      +    !> Library directory relative to the installation prefix
      +    character(len=:), allocatable :: libdir
      +    !> Test program directory relative to the installation prefix
      +    character(len=:), allocatable :: testdir
      +    !> Include directory relative to the installation prefix
      +    character(len=:), allocatable :: includedir
      +    !> Output unit for informative printout
      +    integer :: unit = output_unit
      +    !> Verbosity of the installer
      +    integer :: verbosity = 1
      +    !> Command to copy objects into the installation prefix
      +    character(len=:), allocatable :: copy
      +    !> Command to move objects into the installation prefix
      +    character(len=:), allocatable :: move
      +    !> Cached operating system
      +    integer :: os
      +  contains
      +    !> Evaluate the installation path
      +    procedure :: install_destination  
      +    !> Install an executable in its correct subdirectory
      +    procedure :: install_executable
      +    !> Install a library in its correct subdirectory
      +    procedure :: install_library
      +    !> Install a header/module in its correct subdirectory
      +    procedure :: install_header
      +    !> Install a test program in its correct subdirectory
      +    procedure :: install_test
      +    !> Install a generic file into a subdirectory in the installation prefix
      +    procedure :: install
      +    !> Run an installation command, type-bound for unit testing purposes
      +    procedure :: run
      +    !> Create a new directory in the prefix, type-bound for unit testing purposes
      +    procedure :: make_dir
      +
      +  end type installer_t
      +
      + +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/type/library_config_t.html b/type/library_config_t.html new file mode 100644 index 0000000000..b019e1c3f5 --- /dev/null +++ b/type/library_config_t.html @@ -0,0 +1,1532 @@ + + + + + + + + + + + + + library_config_t – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      library_config_t + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public, extends(serializable_t) :: library_config_t

      +

      Configuration meta data for a library

      +
      + +
      +

      Components

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      TypeVisibility AttributesNameInitial
      + + character(len=:), + public, + allocatable + ::build_script +

      Alternative build script to be invoked

      +
      + + type(string_t), + public, + allocatable + ::include_dir(:) +

      Include path prefix

      +
      + + character(len=:), + public, + allocatable + ::lib_type +

      Shared / Static / Monolithic library

      +
      + + character(len=:), + public, + allocatable + ::source_dir +

      Source path prefix

      +
      + +
      +
      + + + +
      +

      Type-Bound Procedures

      +
      +
      +
      + +

      + generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_dump_to_toml(self, table, error) +

        + +

        Dump dependency to toml table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine dump_to_file(self, file, error, json) +

        + +

        Write serializable object to file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine dump_to_unit(self, unit, error, json) +

        + +

        Write serializable object to a formatted Fortran unit

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        Formatted unit

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format requested?

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + dump_to_toml + +

      +
      +
        +
      • +

        + private subroutine dump_to_toml(self, table, error) +

        + +

        Dump install config to toml table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(library_config_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + info + +

      +
      +
      + +

      Print information on this instance

      +
      +
        +
      • +

        + private subroutine info(self, unit, verbosity) +

        + +

        Write information on instance

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(library_config_t), + intent(in) + + ::self +

        Instance of the library configuration

        +
        + + integer, + intent(in) + + ::unit +

        Unit for IO

        +
        + + integer, + intent(in),optional + + ::verbosity +

        Verbosity of the printout

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + load => load_from_toml, load_from_file, load_from_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_load_from_toml(self, table, error) +

        + +

        Read dependency from toml table (no checks made at this stage)

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine load_from_file(self, file, error, json) +

        + +

        Read dependency tree from file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine load_from_unit(self, unit, error, json) +

        + +

        Read dependency tree from file +init JSON interpreter +Read object from TOML table

        +

        use default TOML parser

        +

        Read object from TOML table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + load_from_toml + +

      +
      +
        +
      • +

        + private subroutine load_from_toml(self, table, error) +

        + +

        Read install config from toml table (no checks made at this stage)

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(library_config_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public, non_overridable :: + monolithic + +

      +
      +
      + +

      Check library types

      +
      +
        +
      • +

        + private elemental function monolithic(self) +

        + +

        Check if this is a monolithic library config +(single monolithic archive with all objects used by this project)

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(library_config_t), + intent(in) + + ::self +

        Instance of the library configuration

        +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + operator(==) => serializable_is_same + +

      +
      +
        +
      • +

        + private function srcfile_is_same(this, that) +

        + +

        Check that two source files are equal +All checks passed!

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + serializable_is_same => library_is_same + +

      +
      +
      + +

      Serialization interface

      +
      +
        +
      • +

        + private function library_is_same(this, that) +

        + +

        All checks passed!

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(library_config_t), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public, non_overridable :: + shared + +

      +
      +
        +
      • +

        + private elemental function shared(self) +

        + +

        Check if this is a shared library config +(full packages built as shared libs)

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(library_config_t), + intent(in) + + ::self +

        Instance of the library configuration

        +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public, non_overridable :: + static + +

      +
      +
        +
      • +

        + private elemental function static(self) +

        + +

        Check if this is a static library config +(full packages built as static libs)

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(library_config_t), + intent(in) + + ::self +

        Instance of the library configuration

        +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public, non_overridable :: + test_serialization + +

      +
      +
      + +

      Test load/write roundtrip

      +
      +
        +
      • +

        + private subroutine test_serialization(self, message, error) +

        + +

        Test serialization of a serializable object +Dump to scratch file +Load from scratch file +Check same

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self + +
        + + character(len=*), + intent(in) + + ::message + +
        + + type(error_t), + intent(out), + allocatable + ::error + +
        + + +
      • +
      +
      + +
      +
      + +
      +

      Source Code

      +
          type, extends(serializable_t) :: library_config_t
      +
      +        !> Source path prefix
      +        character(len=:), allocatable :: source_dir
      +
      +        !> Include path prefix
      +        type(string_t), allocatable :: include_dir(:)
      +
      +        !> Alternative build script to be invoked
      +        character(len=:), allocatable :: build_script
      +        
      +        !> Shared / Static / Monolithic library 
      +        character(:), allocatable :: lib_type
      +
      +    contains
      +
      +        !> Print information on this instance
      +        procedure :: info
      +
      +        !> Serialization interface
      +        procedure :: serializable_is_same => library_is_same
      +        procedure :: dump_to_toml
      +        procedure :: load_from_toml
      +        
      +        !> Check library types
      +        procedure, non_overridable :: monolithic
      +        procedure, non_overridable :: shared
      +        procedure, non_overridable :: static
      +
      +    end type library_config_t
      +
      + +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/type/metapackage_config_t.html b/type/metapackage_config_t.html new file mode 100644 index 0000000000..4f3366a95e --- /dev/null +++ b/type/metapackage_config_t.html @@ -0,0 +1,457 @@ + + + + + + + + + + + + + metapackage_config_t – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      metapackage_config_t + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public :: metapackage_config_t

      +

      Configuration data for metapackages

      +
      + +
      +

      Components

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      TypeVisibility AttributesNameInitial
      + + type(metapackage_request_t), + public + + ::blas +

      BLAS

      +
      + + type(metapackage_request_t), + public + + ::hdf5 +

      HDF5

      +
      + + type(metapackage_request_t), + public + + ::minpack +

      fortran-lang minpack

      +
      + + type(metapackage_request_t), + public + + ::mpi +

      Request MPI support

      +
      + + type(metapackage_request_t), + public + + ::netcdf +

      NetCDF

      +
      + + type(metapackage_request_t), + public + + ::openmp +

      Request OpenMP support

      +
      + + type(metapackage_request_t), + public + + ::stdlib +

      Request stdlib support

      +
      + +
      +
      + + + +
      +

      Type-Bound Procedures

      +
      +
      +
      + +

      + procedure, public :: + get_requests + +

      +
      +
        +
      • +

        + private function get_requests(meta) result(requests) +

        + +

        Return a list of metapackages requested for the current build

        +

        Count requests +Prepare requests

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(metapackage_config_t), + intent(in) + + ::meta +

        Instance of the build configuration

        +
        + +

        + Return Value + type(metapackage_request_t), allocatable, (:) +

        +

        The list of requested metapackages (always allocated)

        + +
      • +
      +
      + +
      +
      + +
      +

      Source Code

      +
          type :: metapackage_config_t
      +
      +        !> Request MPI support
      +        type(metapackage_request_t) :: mpi
      +
      +        !> Request OpenMP support
      +        type(metapackage_request_t) :: openmp
      +
      +        !> Request stdlib support
      +        type(metapackage_request_t) :: stdlib
      +
      +        !> fortran-lang minpack
      +        type(metapackage_request_t) :: minpack
      +
      +        !> HDF5
      +        type(metapackage_request_t) :: hdf5
      +
      +        !> NetCDF
      +        type(metapackage_request_t) :: netcdf
      +
      +        !> BLAS
      +        type(metapackage_request_t) :: blas
      +        
      +        contains
      +        
      +           procedure :: get_requests
      +
      +    end type metapackage_config_t
      +
      + +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/type/metapackage_request_t.html b/type/metapackage_request_t.html new file mode 100644 index 0000000000..1af8739ebf --- /dev/null +++ b/type/metapackage_request_t.html @@ -0,0 +1,295 @@ + + + + + + + + + + + + + metapackage_request_t – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      metapackage_request_t + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public :: metapackage_request_t

      +

      Configuration data for a single metapackage request

      +
      + +
      +

      Components

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      TypeVisibility AttributesNameInitial
      + + character(len=:), + public, + allocatable + ::name +

      Metapackage name

      +
      + + logical, + public + + ::on =.false. +

      Request flag

      +
      + + character(len=:), + public, + allocatable + ::version +

      Version Specification string

      +
      + +
      +
      + + + + +
      +

      Source Code

      +
          type :: metapackage_request_t
      +
      +        !> Request flag
      +        logical :: on = .false.
      +
      +        !> Metapackage name
      +        character(len=:), allocatable :: name
      +
      +        !> Version Specification string
      +        character(len=:), allocatable :: version
      +
      +    end type metapackage_request_t
      +
      + +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/type/metapackage_t.html b/type/metapackage_t.html new file mode 100644 index 0000000000..e9056165cd --- /dev/null +++ b/type/metapackage_t.html @@ -0,0 +1,1006 @@ + + + + + + + + + + + + + metapackage_t – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      metapackage_t + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public :: metapackage_t

      +

      Type for describing a source file

      +
      + +
      +

      Components

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      TypeVisibility AttributesNameInitial
      + + type(string_t), + public + + ::cflags + +
      + + type(string_t), + public + + ::cxxflags + +
      + + type(dependency_config_t), + public, + allocatable + ::dependency(:) +

      List of Development dependency meta data. +Metapackage dependencies are never exported from the model

      +
      + + type(string_t), + public, + allocatable + ::external_modules(:) + +
      + + type(string_t), + public + + ::fflags + +
      + + type(string_t), + public + + ::flags +

      List of compiler flags and options to be added

      +
      + + type(fortran_features_t), + public, + allocatable + ::fortran +

      Special fortran features

      +
      + + logical, + public + + ::has_build_flags =.false. + +
      + + logical, + public + + ::has_c_flags =.false. + +
      + + logical, + public + + ::has_cxx_flags =.false. + +
      + + logical, + public + + ::has_dependencies =.false. + +
      + + logical, + public + + ::has_external_modules =.false. + +
      + + logical, + public + + ::has_fortran_flags =.false. + +
      + + logical, + public + + ::has_include_dirs =.false. + +
      + + logical, + public + + ::has_link_flags =.false. + +
      + + logical, + public + + ::has_link_libraries =.false. + +
      + + logical, + public + + ::has_run_command =.false. + +
      + + type(string_t), + public, + allocatable + ::incl_dirs(:) + +
      + + type(string_t), + public + + ::link_flags + +
      + + type(string_t), + public, + allocatable + ::link_libs(:) + +
      + + character(len=:), + public, + allocatable + ::name +

      Package name

      +
      + + type(preprocess_config_t), + public, + allocatable + ::preprocess +

      Preprocessor configuration

      +
      + + type(string_t), + public + + ::run_command + +
      + + type(version_t), + public, + allocatable + ::version +

      Package version (if supported)

      +
      + +
      +
      + + + +
      +

      Type-Bound Procedures

      +
      +
      +
      + +

      + procedure, public :: + destroy + +

      +
      +
      + +

      Clean metapackage structure

      +
      +
        +
      • +

        + public elemental subroutine destroy(this) +

        + + + + +

        Arguments

        + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(metapackage_t), + intent(inout) + + ::this + +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + resolve => resolve_cmd, resolve_model, resolve_package_config + +

      +
      +
        +
      • +

        + private subroutine resolve_cmd(self, settings, error) +

        + +

        Resolve metapackage dependencies into the command line settings

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(metapackage_t), + intent(in) + + ::self + +
        + + class(fpm_cmd_settings), + intent(inout) + + ::settings + +
        + + type(error_t), + intent(out), + allocatable + ::error + +
        + + +
      • +
      • +

        + private subroutine resolve_model(self, model, error) +

        + +

        Resolve metapackage dependencies into the model

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(metapackage_t), + intent(in) + + ::self + +
        + + type(fpm_model_t), + intent(inout) + + ::model + +
        + + type(error_t), + intent(out), + allocatable + ::error + +
        + + +
      • +
      • +

        + private subroutine resolve_package_config(self, package, error) +

        + + + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(metapackage_t), + intent(in) + + ::self + +
        + + type(package_config_t), + intent(inout) + + ::package + +
        + + type(error_t), + intent(out), + allocatable + ::error + +
        + + +
      • +
      +
      + +
      +
      + +
      +

      Source Code

      +
          type, public :: metapackage_t
      +        
      +        !> Package name
      +        character(:), allocatable :: name
      +
      +        !> Package version (if supported)
      +        type(version_t), allocatable :: version
      +
      +        logical :: has_link_libraries   = .false.
      +        logical :: has_link_flags       = .false.
      +        logical :: has_build_flags      = .false.
      +        logical :: has_fortran_flags    = .false.
      +        logical :: has_c_flags          = .false.
      +        logical :: has_cxx_flags        = .false.
      +        logical :: has_include_dirs     = .false.
      +        logical :: has_dependencies     = .false.
      +        logical :: has_run_command      = .false.
      +        logical :: has_external_modules = .false.
      +
      +        !> List of compiler flags and options to be added
      +        type(string_t) :: flags
      +        type(string_t) :: fflags
      +        type(string_t) :: cflags
      +        type(string_t) :: cxxflags
      +        type(string_t) :: link_flags
      +        type(string_t) :: run_command
      +        type(string_t), allocatable :: incl_dirs(:)
      +        type(string_t), allocatable :: link_libs(:)
      +        type(string_t), allocatable :: external_modules(:)
      +
      +        !> Special fortran features
      +        type(fortran_features_t), allocatable :: fortran
      +        
      +        !> Preprocessor configuration
      +        type(preprocess_config_t), allocatable :: preprocess
      +
      +        !> List of Development dependency meta data.
      +        !> Metapackage dependencies are never exported from the model
      +        type(dependency_config_t), allocatable :: dependency(:)
      +
      +        contains
      +
      +            !> Clean metapackage structure
      +            procedure :: destroy
      +
      +            !> Add metapackage dependencies to the model
      +            procedure, private :: resolve_cmd
      +            procedure, private :: resolve_model
      +            procedure, private :: resolve_package_config
      +            generic :: resolve => resolve_cmd,resolve_model,resolve_package_config
      +
      +    end type metapackage_t
      +
      + +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/type/package_config_t.html b/type/package_config_t.html new file mode 100644 index 0000000000..7fcb7ae27e --- /dev/null +++ b/type/package_config_t.html @@ -0,0 +1,1658 @@ + + + + + + + + + + + + + package_config_t – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      package_config_t + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public, extends(serializable_t) :: package_config_t

      +

      Package meta data

      +
      + +
      +

      Components

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      TypeVisibility AttributesNameInitial
      + + character(len=:), + public, + allocatable + ::author +

      Author meta data

      +
      + + type(build_config_t), + public + + ::build +

      Build configuration data

      +
      + + character(len=:), + public, + allocatable + ::copyright +

      Copyright meta data

      +
      + + type(dependency_config_t), + public, + allocatable + ::dependency(:) +

      Dependency meta data

      +
      + + type(dependency_config_t), + public, + allocatable + ::dev_dependency(:) +

      Development dependency meta data

      +
      + + type(example_config_t), + public, + allocatable + ::example(:) +

      Example meta data

      +
      + + type(executable_config_t), + public, + allocatable + ::executable(:) +

      Executable meta data

      +
      + + type(fortran_config_t), + public + + ::fortran +

      Fortran meta data

      +
      + + type(install_config_t), + public + + ::install +

      Installation configuration data

      +
      + + type(library_config_t), + public, + allocatable + ::library +

      Library meta data

      +
      + + character(len=:), + public, + allocatable + ::license +

      License meta data

      +
      + + character(len=:), + public, + allocatable + ::maintainer +

      Maintainer meta data

      +
      + + type(metapackage_config_t), + public + + ::meta +

      Metapackage data

      +
      + + character(len=:), + public, + allocatable + ::name +

      Name of the package

      +
      + + type(preprocess_config_t), + public, + allocatable + ::preprocess(:) +

      Preprocess meta data

      +
      + + type(profile_config_t), + public, + allocatable + ::profiles(:) +

      Profiles meta data

      +
      + + type(test_config_t), + public, + allocatable + ::test(:) +

      Test meta data

      +
      + + type(version_t), + public + + ::version +

      Package version

      +
      + +
      +
      + + + +
      +

      Type-Bound Procedures

      +
      +
      +
      + +

      + generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_dump_to_toml(self, table, error) +

        + +

        Dump dependency to toml table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine dump_to_file(self, file, error, json) +

        + +

        Write serializable object to file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine dump_to_unit(self, unit, error, json) +

        + +

        Write serializable object to a formatted Fortran unit

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        Formatted unit

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format requested?

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + dump_to_toml + +

      +
      +
        +
      • +

        + private subroutine dump_to_toml(self, table, error) +

        + +

        Dump manifest to toml table

        +

        Because dependencies are named, fallback if this has no name +So, serialization will work regardless of size(self%dep) == self%ndep +Because dependencies are named, fallback if this has no name +So, serialization will work regardless of size(self%dep) == self%ndep +Because dependencies are named, fallback if this has no name +So, serialization will work regardless of size(self%dep) == self%ndep +Duplicate profile names are possible, as multiple profiles are possible with the +same name, same compiler, etc. So, use a unique name here +Because dependencies are named, fallback if this has no name +So, serialization will work regardless of size(self%dep) == self%ndep +Because dependencies are named, fallback if this has no name +So, serialization will work regardless of size(self%dep) == self%ndep +Because dependencies are named, fallback if this has no name +So, serialization will work regardless of size(self%dep) == self%ndep

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(package_config_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + info + +

      +
      +
      + +

      Print information on this instance

      +
      +
        +
      • +

        + private subroutine info(self, unit, verbosity) +

        + +

        Write information on instance

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(package_config_t), + intent(in) + + ::self +

        Instance of the package configuration

        +
        + + integer, + intent(in) + + ::unit +

        Unit for IO

        +
        + + integer, + intent(in),optional + + ::verbosity +

        Verbosity of the printout

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + load => load_from_toml, load_from_file, load_from_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_load_from_toml(self, table, error) +

        + +

        Read dependency from toml table (no checks made at this stage)

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine load_from_file(self, file, error, json) +

        + +

        Read dependency tree from file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine load_from_unit(self, unit, error, json) +

        + +

        Read dependency tree from file +init JSON interpreter +Read object from TOML table

        +

        use default TOML parser

        +

        Read object from TOML table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + load_from_toml + +

      +
      +
        +
      • +

        + private subroutine load_from_toml(self, table, error) +

        + +

        Read manifest from toml table (no checks made at this stage)

        +

        Read all packages +Read all packages +Read all packages +Read all packages +Read all packages +Read all packages +Read all packages

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(package_config_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + operator(==) => serializable_is_same + +

      +
      +
        +
      • +

        + private function srcfile_is_same(this, that) +

        + +

        Check that two source files are equal +All checks passed!

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + serializable_is_same => manifest_is_same + +

      +
      +
      + +

      Serialization interface

      +
      +
        +
      • +

        + private function manifest_is_same(this, that) +

        + +

        All checks passed!

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(package_config_t), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public, non_overridable :: + test_serialization + +

      +
      +
      + +

      Test load/write roundtrip

      +
      +
        +
      • +

        + private subroutine test_serialization(self, message, error) +

        + +

        Test serialization of a serializable object +Dump to scratch file +Load from scratch file +Check same

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self + +
        + + character(len=*), + intent(in) + + ::message + +
        + + type(error_t), + intent(out), + allocatable + ::error + +
        + + +
      • +
      +
      + +
      +
      + +
      +

      Source Code

      +
          type, extends(serializable_t) :: package_config_t
      +
      +        !> Name of the package
      +        character(len=:), allocatable :: name
      +
      +        !> Package version
      +        type(version_t) :: version
      +
      +        !> Build configuration data
      +        type(build_config_t) :: build
      +
      +        !> Metapackage data
      +        type(metapackage_config_t) :: meta
      +
      +        !> Installation configuration data
      +        type(install_config_t) :: install
      +
      +        !> Fortran meta data
      +        type(fortran_config_t) :: fortran
      +
      +        !> License meta data
      +        character(len=:), allocatable :: license
      +
      +        !> Author meta data
      +        character(len=:), allocatable :: author
      +
      +        !> Maintainer meta data
      +        character(len=:), allocatable :: maintainer
      +
      +        !> Copyright meta data
      +        character(len=:), allocatable :: copyright
      +
      +        !> Library meta data
      +        type(library_config_t), allocatable :: library
      +
      +        !> Executable meta data
      +        type(executable_config_t), allocatable :: executable(:)
      +
      +        !> Dependency meta data
      +        type(dependency_config_t), allocatable :: dependency(:)
      +
      +        !> Development dependency meta data
      +        type(dependency_config_t), allocatable :: dev_dependency(:)
      +
      +        !> Profiles meta data
      +        type(profile_config_t), allocatable :: profiles(:)
      +
      +        !> Example meta data
      +        type(example_config_t), allocatable :: example(:)
      +
      +        !> Test meta data
      +        type(test_config_t), allocatable :: test(:)
      +
      +        !> Preprocess meta data
      +        type(preprocess_config_t), allocatable :: preprocess(:)
      +
      +    contains
      +
      +        !> Print information on this instance
      +        procedure :: info
      +
      +        !> Serialization interface
      +        procedure :: serializable_is_same => manifest_is_same
      +        procedure :: dump_to_toml
      +        procedure :: load_from_toml
      +
      +    end type package_config_t
      +
      + +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/type/package_t.html b/type/package_t.html new file mode 100644 index 0000000000..7a33715b52 --- /dev/null +++ b/type/package_t.html @@ -0,0 +1,1388 @@ + + + + + + + + + + + + + package_t – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      package_t + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public, extends(serializable_t) :: package_t

      +

      Type for describing a single package

      +
      + +
      +

      Components

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      TypeVisibility AttributesNameInitial
      + + logical, + public + + ::enforce_module_names =.false. +

      Module naming conventions

      +
      + + type(fortran_features_t), + public + + ::features +

      Language features

      +
      + + type(string_t), + public + + ::module_prefix +

      Prefix for all module names

      +
      + + character(len=:), + public, + allocatable + ::name +

      Name of package

      +
      + + type(preprocess_config_t), + public + + ::preprocess +

      List of macros.

      +
      + + type(srcfile_t), + public, + allocatable + ::sources(:) +

      Array of sources

      +
      + + character(len=:), + public, + allocatable + ::version +

      Package version number.

      +
      + +
      +
      + + + +
      +

      Type-Bound Procedures

      +
      +
      +
      + +

      + generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_dump_to_toml(self, table, error) +

        + +

        Dump dependency to toml table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine dump_to_file(self, file, error, json) +

        + +

        Write serializable object to file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine dump_to_unit(self, unit, error, json) +

        + +

        Write serializable object to a formatted Fortran unit

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        Formatted unit

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format requested?

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + dump_to_toml => package_dump_to_toml + +

      +
      +
        +
      • +

        + private subroutine package_dump_to_toml(self, table, error) +

        + +

        Dump dependency to toml table

        +

        Create a preprocessor table +Create a fortran table +Create a sources table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(package_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + has_library => package_has_library + +

      +
      +
      + +

      Check if a package will create a library

      +
      +
        +
      • +

        + private elemental function package_has_library(self) result(has_library) +

        + +

        Check whether a package has an object library

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(package_t), + intent(in) + + ::self + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + load => load_from_toml, load_from_file, load_from_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_load_from_toml(self, table, error) +

        + +

        Read dependency from toml table (no checks made at this stage)

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine load_from_file(self, file, error, json) +

        + +

        Read dependency tree from file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine load_from_unit(self, unit, error, json) +

        + +

        Read dependency tree from file +init JSON interpreter +Read object from TOML table

        +

        use default TOML parser

        +

        Read object from TOML table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + load_from_toml => package_load_from_toml + +

      +
      +
        +
      • +

        + private subroutine package_load_from_toml(self, table, error) +

        + +

        Read dependency from toml table (no checks made at this stage)

        +

        Read all dependencies

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(package_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + operator(==) => serializable_is_same + +

      +
      +
        +
      • +

        + private function srcfile_is_same(this, that) +

        + +

        Check that two source files are equal +All checks passed!

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + serializable_is_same => package_is_same + +

      +
      +
      + +

      Serialization interface

      +
      +
        +
      • +

        + private function package_is_same(this, that) +

        + +

        Check that two package objects are equal +Module naming +Fortran features

        +

        All checks passed!

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(package_t), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public, non_overridable :: + test_serialization + +

      +
      +
      + +

      Test load/write roundtrip

      +
      +
        +
      • +

        + private subroutine test_serialization(self, message, error) +

        + +

        Test serialization of a serializable object +Dump to scratch file +Load from scratch file +Check same

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self + +
        + + character(len=*), + intent(in) + + ::message + +
        + + type(error_t), + intent(out), + allocatable + ::error + +
        + + +
      • +
      +
      + +
      +
      + +
      +

      Source Code

      +
      type, extends(serializable_t) :: package_t
      +
      +    !> Name of package
      +    character(:), allocatable :: name
      +
      +    !> Array of sources
      +    type(srcfile_t), allocatable :: sources(:)
      +
      +    !> List of macros.
      +    type(preprocess_config_t) :: preprocess
      +
      +    !> Package version number.
      +    character(:), allocatable :: version
      +
      +    !> Module naming conventions
      +    logical :: enforce_module_names = .false.
      +
      +    !> Prefix for all module names
      +    type(string_t) :: module_prefix
      +
      +    !> Language features
      +    type(fortran_features_t) :: features
      +
      +    contains
      +    
      +        !> Check if a package will create a library
      +        procedure :: has_library => package_has_library
      +    
      +        !> Serialization interface
      +        procedure :: serializable_is_same => package_is_same
      +        procedure :: dump_to_toml   => package_dump_to_toml
      +        procedure :: load_from_toml => package_load_from_toml
      +
      +end type package_t
      +
      + +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/type/preprocess_config_t.html b/type/preprocess_config_t.html new file mode 100644 index 0000000000..5f213a5411 --- /dev/null +++ b/type/preprocess_config_t.html @@ -0,0 +1,1744 @@ + + + + + + + + + + + + + preprocess_config_t – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      preprocess_config_t + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public, extends(serializable_t) :: preprocess_config_t

      +

      Configuration meta data for a preprocessor

      +
      + +
      +

      Components

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      TypeVisibility AttributesNameInitial
      + + type(string_t), + public, + allocatable + ::directories(:) +

      Directories to search for files to be preprocessed

      +
      + + type(string_t), + public, + allocatable + ::macros(:) +

      Macros to be defined for the preprocessor

      +
      + + character(len=:), + public, + allocatable + ::name +

      Name of the preprocessor

      +
      + + type(string_t), + public, + allocatable + ::suffixes(:) +

      Suffixes of the files to be preprocessed

      +
      + +
      +
      + + + +
      +

      Type-Bound Procedures

      +
      +
      +
      + +

      + procedure, public :: + add_config + +

      +
      +
        +
      • +

        + private subroutine add_config(this, that) +

        + +

        Add preprocessor settings

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(preprocess_config_t), + intent(inout) + + ::this + +
        + + type(preprocess_config_t), + intent(in) + + ::that + +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + destroy + +

      +
      +
      + +

      Operations

      +
      +
        +
      • +

        + private elemental subroutine destroy(this) +

        + +

        Clean preprocessor structure

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(preprocess_config_t), + intent(inout) + + ::this + +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_dump_to_toml(self, table, error) +

        + +

        Dump dependency to toml table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine dump_to_file(self, file, error, json) +

        + +

        Write serializable object to file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine dump_to_unit(self, unit, error, json) +

        + +

        Write serializable object to a formatted Fortran unit

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        Formatted unit

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format requested?

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + dump_to_toml + +

      +
      +
        +
      • +

        + private subroutine dump_to_toml(self, table, error) +

        + +

        Dump install config to toml table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(preprocess_config_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + info + +

      +
      +
      + +

      Print information on this instance

      +
      +
        +
      • +

        + private subroutine info(self, unit, verbosity) +

        + +

        Write information on this instance

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(preprocess_config_t), + intent(in) + + ::self +

        Instance of the preprocess configuration

        +
        + + integer, + intent(in) + + ::unit +

        Unit for IO

        +
        + + integer, + intent(in),optional + + ::verbosity +

        Verbosity of the printout

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + is_cpp + +

      +
      +
      + +

      Properties

      +
      +
        +
      • +

        + private function is_cpp(this) +

        + + + +

        Arguments

        + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(preprocess_config_t), + intent(in) + + ::this + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + is_fypp + +

      +
      +
        +
      • +

        + private function is_fypp(this) +

        + + + +

        Arguments

        + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(preprocess_config_t), + intent(in) + + ::this + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + load => load_from_toml, load_from_file, load_from_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_load_from_toml(self, table, error) +

        + +

        Read dependency from toml table (no checks made at this stage)

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine load_from_file(self, file, error, json) +

        + +

        Read dependency tree from file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine load_from_unit(self, unit, error, json) +

        + +

        Read dependency tree from file +init JSON interpreter +Read object from TOML table

        +

        use default TOML parser

        +

        Read object from TOML table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + load_from_toml + +

      +
      +
        +
      • +

        + private subroutine load_from_toml(self, table, error) +

        + +

        Read install config from toml table (no checks made at this stage)

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(preprocess_config_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + new => new_cpp_config_with_macros, new_preprocess_config + +

      +
      +
        +
      • +

        + private subroutine new_cpp_config_with_macros(self, macros) +

        + +

        Construct a new cpp preprocessor configuration with a list of macros

        +

        Set cpp

        +

        Set macros

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(preprocess_config_t), + intent(out) + + ::self +

        Instance of the preprocess configuration

        +
        + + type(string_t), + intent(in) + + ::macros(:) +

        List of macros

        +
        + + +
      • +
      • +

        + private subroutine new_preprocess_config(self, table, error) +

        + +

        Construct a new preprocess configuration from TOML data structure

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(preprocess_config_t), + intent(out) + + ::self +

        Instance of the preprocess configuration

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Instance of the TOML data structure.

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + operator(==) => serializable_is_same + +

      +
      +
        +
      • +

        + private function srcfile_is_same(this, that) +

        + +

        Check that two source files are equal +All checks passed!

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + serializable_is_same => preprocess_is_same + +

      +
      +
      + +

      Serialization interface

      +
      +
        +
      • +

        + private function preprocess_is_same(this, that) +

        + +

        All checks passed!

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(preprocess_config_t), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public, non_overridable :: + test_serialization + +

      +
      +
      + +

      Test load/write roundtrip

      +
      +
        +
      • +

        + private subroutine test_serialization(self, message, error) +

        + +

        Test serialization of a serializable object +Dump to scratch file +Load from scratch file +Check same

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self + +
        + + character(len=*), + intent(in) + + ::message + +
        + + type(error_t), + intent(out), + allocatable + ::error + +
        + + +
      • +
      +
      + +
      +
      + +
      +

      Source Code

      +
         type, extends(serializable_t) :: preprocess_config_t
      +
      +      !> Name of the preprocessor
      +      character(len=:), allocatable :: name
      +
      +      !> Suffixes of the files to be preprocessed
      +      type(string_t), allocatable :: suffixes(:)
      +
      +      !> Directories to search for files to be preprocessed
      +      type(string_t), allocatable :: directories(:)
      +
      +      !> Macros to be defined for the preprocessor
      +      type(string_t), allocatable :: macros(:)
      +
      +   contains
      +
      +      !> Print information on this instance
      +      procedure :: info
      +      
      +      !> Initialization
      +      procedure, private :: new_cpp_config_with_macros
      +      procedure, private :: new_preprocess_config
      +      generic   :: new => new_cpp_config_with_macros, new_preprocess_config
      +
      +      !> Serialization interface
      +      procedure :: serializable_is_same => preprocess_is_same
      +      procedure :: dump_to_toml
      +      procedure :: load_from_toml
      +
      +      !> Operations
      +      procedure :: destroy
      +      procedure :: add_config
      +
      +      !> Properties
      +      procedure :: is_cpp
      +      procedure :: is_fypp
      +
      +   end type preprocess_config_t
      +
      + +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/type/profile_config_t.html b/type/profile_config_t.html new file mode 100644 index 0000000000..7dd57f0118 --- /dev/null +++ b/type/profile_config_t.html @@ -0,0 +1,1451 @@ + + + + + + + + + + + + + profile_config_t – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      profile_config_t + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public, extends(serializable_t) :: profile_config_t

      +

      Configuration meta data for a profile

      +
      + +
      +

      Components

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      TypeVisibility AttributesNameInitial
      + + character(len=:), + public, + allocatable + ::c_flags +

      C compiler flags

      +
      + + character(len=:), + public, + allocatable + ::compiler +

      Name of the compiler

      +
      + + character(len=:), + public, + allocatable + ::cxx_flags +

      C++ compiler flags

      +
      + + type(file_scope_flag), + public, + allocatable + ::file_scope_flags(:) +

      File scope flags

      +
      + + character(len=:), + public, + allocatable + ::flags +

      Fortran compiler flags

      +
      + + logical, + public + + ::is_built_in =.false. +

      Is this profile one of the built-in ones?

      +
      + + character(len=:), + public, + allocatable + ::link_time_flags +

      Link time compiler flags

      +
      + + integer, + public + + ::os_type =OS_ALL +

      Value repesenting OS

      +
      + + character(len=:), + public, + allocatable + ::profile_name +

      Name of the profile

      +
      + +
      +
      + + + +
      +

      Type-Bound Procedures

      +
      +
      +
      + +

      + generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_dump_to_toml(self, table, error) +

        + +

        Dump dependency to toml table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine dump_to_file(self, file, error, json) +

        + +

        Write serializable object to file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine dump_to_unit(self, unit, error, json) +

        + +

        Write serializable object to a formatted Fortran unit

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        Formatted unit

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format requested?

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + dump_to_toml => profile_dump + +

      +
      +
        +
      • +

        + public subroutine profile_dump(self, table, error) +

        + + +

        Dump to toml table

        Read more… + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(profile_config_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + info + +

      +
      +
      + +

      Print information on this instance

      +
      +
        +
      • +

        + public subroutine info(self, unit, verbosity) +

        + + +

        Write information on instance

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(profile_config_t), + intent(in) + + ::self +

        Instance of the profile configuration

        +
        + + integer, + intent(in) + + ::unit +

        Unit for IO

        +
        + + integer, + intent(in),optional + + ::verbosity +

        Verbosity of the printout

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + load => load_from_toml, load_from_file, load_from_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_load_from_toml(self, table, error) +

        + +

        Read dependency from toml table (no checks made at this stage)

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine load_from_file(self, file, error, json) +

        + +

        Read dependency tree from file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine load_from_unit(self, unit, error, json) +

        + +

        Read dependency tree from file +init JSON interpreter +Read object from TOML table

        +

        use default TOML parser

        +

        Read object from TOML table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + load_from_toml => profile_load + +

      +
      +
        +
      • +

        + public subroutine profile_load(self, table, error) +

        + + +

        Read from toml table (no checks made at this stage)

        Read more… + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(profile_config_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + operator(==) => serializable_is_same + +

      +
      +
        +
      • +

        + private function srcfile_is_same(this, that) +

        + +

        Check that two source files are equal +All checks passed!

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + serializable_is_same => profile_same + +

      +
      +
      + +

      Serialization interface

      +
      +
        +
      • +

        + public function profile_same(this, that) +

        + + +

        All checks passed!

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(profile_config_t), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public, non_overridable :: + test_serialization + +

      +
      +
      + +

      Test load/write roundtrip

      +
      +
        +
      • +

        + private subroutine test_serialization(self, message, error) +

        + +

        Test serialization of a serializable object +Dump to scratch file +Load from scratch file +Check same

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self + +
        + + character(len=*), + intent(in) + + ::message + +
        + + type(error_t), + intent(out), + allocatable + ::error + +
        + + +
      • +
      +
      + +
      +
      + +
      +

      Source Code

      +
          type, extends(serializable_t) :: profile_config_t
      +      !> Name of the profile
      +      character(len=:), allocatable :: profile_name
      +
      +      !> Name of the compiler
      +      character(len=:), allocatable :: compiler
      +
      +      !> Value repesenting OS
      +      integer :: os_type = OS_ALL
      +
      +      !> Fortran compiler flags
      +      character(len=:), allocatable :: flags
      +
      +      !> C compiler flags
      +      character(len=:), allocatable :: c_flags
      +
      +      !> C++ compiler flags
      +      character(len=:), allocatable :: cxx_flags
      +
      +      !> Link time compiler flags
      +      character(len=:), allocatable :: link_time_flags
      +
      +      !> File scope flags
      +      type(file_scope_flag), allocatable :: file_scope_flags(:)
      +
      +      !> Is this profile one of the built-in ones?
      +      logical :: is_built_in = .false.
      +
      +      contains
      +
      +        !> Print information on this instance
      +        procedure :: info
      +
      +        !> Serialization interface
      +        procedure :: serializable_is_same => profile_same
      +        procedure :: dump_to_toml => profile_dump
      +        procedure :: load_from_toml => profile_load
      +
      +    end type profile_config_t
      +
      + +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/type/serializable_t.html b/type/serializable_t.html new file mode 100644 index 0000000000..fa68e76ca9 --- /dev/null +++ b/type/serializable_t.html @@ -0,0 +1,1163 @@ + + + + + + + + + + + + + serializable_t – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      serializable_t + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public, abstract :: serializable_t

      +

      An abstract interface for any fpm class that should be fully serializable to/from TOML/JSON

      +
      + + + + +
      +

      Type-Bound Procedures

      +
      +
      +
      + +

      + generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_dump_to_toml(self, table, error) +

        + +

        Dump dependency to toml table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine dump_to_file(self, file, error, json) +

        + +

        Write serializable object to file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine dump_to_unit(self, unit, error, json) +

        + +

        Write serializable object to a formatted Fortran unit

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        Formatted unit

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format requested?

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure(to_toml), public, deferred :: + dump_to_toml + +

      +
      +
      + +

      Dump to TOML table, unit, file

      +
      +
        +
      • +

        + subroutine to_toml(self, table, error) +Prototype

        + +

        Write object to TOML datastructure

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + load => load_from_toml, load_from_file, load_from_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_load_from_toml(self, table, error) +

        + +

        Read dependency from toml table (no checks made at this stage)

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine load_from_file(self, file, error, json) +

        + +

        Read dependency tree from file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine load_from_unit(self, unit, error, json) +

        + +

        Read dependency tree from file +init JSON interpreter +Read object from TOML table

        +

        use default TOML parser

        +

        Read object from TOML table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure(from_toml), public, deferred :: + load_from_toml + +

      +
      +
      + +

      Load from TOML table, unit, file

      +
      +
        +
      • +

        + subroutine from_toml(self, table, error) +Prototype

        + +

        Read dependency tree from TOML data structure

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + operator(==) => serializable_is_same + +

      +
      +
        +
      • +

        + private function srcfile_is_same(this, that) +

        + +

        Check that two source files are equal +All checks passed!

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure(is_equal), public, deferred :: + serializable_is_same + +

      +
      +
      + +

      Serializable entities need a way to check that they’re equal

      +
      +
        +
      • +

        + function is_equal(this, that) +Prototype

        + +

        Compare two serializable objects

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public, non_overridable :: + test_serialization + +

      +
      +
      + +

      Test load/write roundtrip

      +
      +
        +
      • +

        + private subroutine test_serialization(self, message, error) +

        + +

        Test serialization of a serializable object +Dump to scratch file +Load from scratch file +Check same

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self + +
        + + character(len=*), + intent(in) + + ::message + +
        + + type(error_t), + intent(out), + allocatable + ::error + +
        + + +
      • +
      +
      + +
      +
      + +
      +

      Source Code

      +
          type, abstract, public :: serializable_t
      +
      +        contains
      +
      +        !> Dump to TOML table, unit, file
      +        procedure(to_toml), deferred :: dump_to_toml
      +        procedure, non_overridable, private :: dump_to_file
      +        procedure, non_overridable, private :: dump_to_unit
      +        generic :: dump => dump_to_toml, dump_to_file, dump_to_unit
      +
      +        !> Load from TOML table, unit, file
      +        procedure(from_toml), deferred :: load_from_toml
      +        procedure, non_overridable, private :: load_from_file
      +        procedure, non_overridable, private :: load_from_unit
      +        generic :: load => load_from_toml, load_from_file, load_from_unit
      +
      +        !> Serializable entities need a way to check that they're equal
      +        procedure(is_equal), deferred :: serializable_is_same
      +        generic :: operator(==) => serializable_is_same
      +
      +        !> Test load/write roundtrip
      +        procedure, non_overridable :: test_serialization
      +
      +    end type serializable_t
      +
      + +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/type/srcfile_t.html b/type/srcfile_t.html new file mode 100644 index 0000000000..fdf2ee4aff --- /dev/null +++ b/type/srcfile_t.html @@ -0,0 +1,1378 @@ + + + + + + + + + + + + + srcfile_t – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      srcfile_t + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public, extends(serializable_t) :: srcfile_t

      +

      Type for describing a source file

      +
      + +
      +

      Components

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      TypeVisibility AttributesNameInitial
      + + integer(kind=int64), + public + + ::digest +

      Current hash

      +
      + + character(len=:), + public, + allocatable + ::exe_name +

      Name of executable for FPM_UNIT_PROGRAM

      +
      + + character(len=:), + public, + allocatable + ::file_name +

      File path relative to cwd

      +
      + + type(string_t), + public, + allocatable + ::include_dependencies(:) +

      Files INCLUDEd by this source file

      +
      + + type(string_t), + public, + allocatable + ::link_libraries(:) +

      Native libraries to link against

      +
      + + type(string_t), + public, + allocatable + ::modules_provided(:) +

      Modules provided by this source file (lowerstring)

      +
      + + type(string_t), + public, + allocatable + ::modules_used(:) +

      Modules USEd by this source file (lowerstring)

      +
      + + type(string_t), + public, + allocatable + ::parent_modules(:) +

      Parent modules (submodules only)

      +
      + + integer, + public + + ::unit_scope =FPM_SCOPE_UNKNOWN +

      Target module-use scope

      +
      + + integer, + public + + ::unit_type =FPM_UNIT_UNKNOWN +

      Type of source unit

      +
      + +
      +
      + + + +
      +

      Type-Bound Procedures

      +
      +
      +
      + +

      + generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_dump_to_toml(self, table, error) +

        + +

        Dump dependency to toml table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine dump_to_file(self, file, error, json) +

        + +

        Write serializable object to file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine dump_to_unit(self, unit, error, json) +

        + +

        Write serializable object to a formatted Fortran unit

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        Formatted unit

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format requested?

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + dump_to_toml => srcfile_dump_to_toml + +

      +
      +
        +
      • +

        + private subroutine srcfile_dump_to_toml(self, table, error) +

        + +

        Dump dependency to toml table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + load => load_from_toml, load_from_file, load_from_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_load_from_toml(self, table, error) +

        + +

        Read dependency from toml table (no checks made at this stage)

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine load_from_file(self, file, error, json) +

        + +

        Read dependency tree from file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine load_from_unit(self, unit, error, json) +

        + +

        Read dependency tree from file +init JSON interpreter +Read object from TOML table

        +

        use default TOML parser

        +

        Read object from TOML table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + load_from_toml => srcfile_load_from_toml + +

      +
      +
        +
      • +

        + private subroutine srcfile_load_from_toml(self, table, error) +

        + +

        Read dependency from toml table (no checks made at this stage)

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + operator(==) => serializable_is_same + +

      +
      +
        +
      • +

        + private function srcfile_is_same(this, that) +

        + +

        Check that two source files are equal +All checks passed!

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + serializable_is_same => srcfile_is_same + +

      +
      +
      + +

      Serialization interface

      +
      +
        +
      • +

        + private function srcfile_is_same(this, that) +

        + +

        Check that two source files are equal +All checks passed!

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public, non_overridable :: + test_serialization + +

      +
      +
      + +

      Test load/write roundtrip

      +
      +
        +
      • +

        + private subroutine test_serialization(self, message, error) +

        + +

        Test serialization of a serializable object +Dump to scratch file +Load from scratch file +Check same

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self + +
        + + character(len=*), + intent(in) + + ::message + +
        + + type(error_t), + intent(out), + allocatable + ::error + +
        + + +
      • +
      +
      + +
      +
      + +
      +

      Source Code

      +
      type, extends(serializable_t) :: srcfile_t
      +    !> File path relative to cwd
      +    character(:), allocatable :: file_name
      +
      +    !> Name of executable for FPM_UNIT_PROGRAM
      +    character(:), allocatable :: exe_name
      +
      +    !> Target module-use scope
      +    integer :: unit_scope = FPM_SCOPE_UNKNOWN
      +
      +    !> Modules provided by this source file (lowerstring)
      +    type(string_t), allocatable :: modules_provided(:)
      +
      +    !> Type of source unit
      +    integer :: unit_type = FPM_UNIT_UNKNOWN
      +
      +    !> Parent modules (submodules only)
      +    type(string_t), allocatable :: parent_modules(:)
      +
      +    !>  Modules USEd by this source file (lowerstring)
      +    type(string_t), allocatable :: modules_used(:)
      +
      +    !> Files INCLUDEd by this source file
      +    type(string_t), allocatable :: include_dependencies(:)
      +
      +    !> Native libraries to link against
      +    type(string_t), allocatable :: link_libraries(:)
      +
      +    !> Current hash
      +    integer(int64) :: digest
      +
      +    contains
      +
      +        !> Serialization interface
      +        procedure :: serializable_is_same => srcfile_is_same
      +        procedure :: dump_to_toml   => srcfile_dump_to_toml
      +        procedure :: load_from_toml => srcfile_load_from_toml
      +
      +end type srcfile_t
      +
      + +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/type/string_t.html b/type/string_t.html new file mode 100644 index 0000000000..c557dc75ef --- /dev/null +++ b/type/string_t.html @@ -0,0 +1,305 @@ + + + + + + + + + + + + + string_t – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      string_t + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public :: string_t

      + +
      + +
      +

      Components

      + + + + + + + + + + + + + + + + + + + + + +
      TypeVisibility AttributesNameInitial
      + + character(len=:), + public, + allocatable + ::s + +
      + +
      +
      + +
      +

      Constructor

      +
      +
      + +

      public interface string_t +

      +
      +
        +
      • +

        + private function new_string_t(s) result(string) + +

        +

        Helper function to generate a new string_t instance + (Required due to the allocatable component)

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + character(len=*), + intent(in) + + ::s + +
        + +

        + Return Value + type(string_t) +

        + + +
      • +
      +
      + +
      +
      + + + + +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/type/test_config_t.html b/type/test_config_t.html new file mode 100644 index 0000000000..f4c5a7c86f --- /dev/null +++ b/type/test_config_t.html @@ -0,0 +1,1347 @@ + + + + + + + + + + + + + test_config_t – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      test_config_t + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public, extends(executable_config_t) :: test_config_t

      +

      Configuation meta data for an test

      +
      + +
      +

      Components

      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      TypeVisibility AttributesNameInitial
      + + type(dependency_config_t), + public, + allocatable + ::dependency(:) +

      Dependency meta data for this executable

      +
      + + type(string_t), + public, + allocatable + ::link(:) +

      Libraries to link against

      +
      + + character(len=:), + public, + allocatable + ::main +

      Name of the source file declaring the main program

      +
      + + character(len=:), + public, + allocatable + ::name +

      Name of the resulting executable

      +
      + + character(len=:), + public, + allocatable + ::source_dir +

      Source directory for collecting the executable

      +
      + +
      +
      + + + +
      +

      Type-Bound Procedures

      +
      +
      +
      + +

      + generic, public :: + dump => dump_to_toml, dump_to_file, dump_to_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_dump_to_toml(self, table, error) +

        + +

        Dump dependency to toml table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine dump_to_file(self, file, error, json) +

        + +

        Write serializable object to file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine dump_to_unit(self, unit, error, json) +

        + +

        Write serializable object to a formatted Fortran unit

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        Formatted unit

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format requested?

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + dump_to_toml + +

      +
      +
        +
      • +

        + private subroutine dump_to_toml(self, table, error) +

        + +

        Dump install config to toml table

        +

        Because dependencies are named, fallback if this has no name +So, serialization will work regardless of size(self%dep) == self%ndep

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(executable_config_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + info + +

      +
      +
      + +

      Print information on this instance

      +
      +
        +
      • +

        + private subroutine info(self, unit, verbosity) +

        + +

        Write information on instance

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(test_config_t), + intent(in) + + ::self +

        Instance of the test configuration

        +
        + + integer, + intent(in) + + ::unit +

        Unit for IO

        +
        + + integer, + intent(in),optional + + ::verbosity +

        Verbosity of the printout

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + load => load_from_toml, load_from_file, load_from_unit + +

      +
      +
        +
      • +

        + private subroutine srcfile_load_from_toml(self, table, error) +

        + +

        Read dependency from toml table (no checks made at this stage)

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      • +

        + private subroutine load_from_file(self, file, error, json) +

        + +

        Read dependency tree from file

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + character(len=*), + intent(in) + + ::file +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      • +

        + private subroutine load_from_unit(self, unit, error, json) +

        + +

        Read dependency tree from file +init JSON interpreter +Read object from TOML table

        +

        use default TOML parser

        +

        Read object from TOML table

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self +

        Instance of the dependency tree

        +
        + + integer, + intent(in) + + ::unit +

        File name

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + logical, + intent(in),optional + + ::json +

        Optional JSON format

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + load_from_toml + +

      +
      +
        +
      • +

        + private subroutine load_from_toml(self, table, error) +

        + +

        Read install config from toml table (no checks made at this stage)

        +

        Read all dependencies

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(executable_config_t), + intent(inout) + + ::self +

        Instance of the serializable object

        +
        + + type(toml_table), + intent(inout) + + ::table +

        Data structure

        +
        + + type(error_t), + intent(out), + allocatable + ::error +

        Error handling

        +
        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + operator(==) => serializable_is_same + +

      +
      +
        +
      • +

        + private function srcfile_is_same(this, that) +

        + +

        Check that two source files are equal +All checks passed!

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(srcfile_t), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + serializable_is_same => exe_is_same + +

      +
      +
      + +

      Serialization interface

      +
      +
        +
      • +

        + private function exe_is_same(this, that) +

        + +

        All checks passed!

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(executable_config_t), + intent(in) + + ::this + +
        + + class(serializable_t), + intent(in) + + ::that + +
        + +

        + Return Value + logical +

        + + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public, non_overridable :: + test_serialization + +

      +
      +
      + +

      Test load/write roundtrip

      +
      +
        +
      • +

        + private subroutine test_serialization(self, message, error) +

        + +

        Test serialization of a serializable object +Dump to scratch file +Load from scratch file +Check same

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(serializable_t), + intent(inout) + + ::self + +
        + + character(len=*), + intent(in) + + ::message + +
        + + type(error_t), + intent(out), + allocatable + ::error + +
        + + +
      • +
      +
      + +
      +
      + +
      +

      Source Code

      +
          type, extends(executable_config_t) :: test_config_t
      +
      +    contains
      +
      +        !> Print information on this instance
      +        procedure :: info
      +
      +    end type test_config_t
      +
      + +
      + +
      +
      + +
      +
      +
      +
      +
      +
      +

      + Fortran-lang/fpm + was developed by fortran-lang/fpm contributors
      © 2025 +

      +
      +
      +

      + Documentation generated by + FORD + on 2025-06-07 07:02 +0000

      +
      +
      +
      +
      +
      + + \ No newline at end of file diff --git a/type/version_t.html b/type/version_t.html new file mode 100644 index 0000000000..a29cb4a8b6 --- /dev/null +++ b/type/version_t.html @@ -0,0 +1,834 @@ + + + + + + + + + + + + + version_t – Fortran-lang/fpm + + + + + + + + + + + + + + + + + + + + + + + +
      + +
      + +
      +
      +

      version_t + Derived Type + +

      +
      +
      +
      + +
      +
      + +
      +
      +
      + + +
      + +
      + + +
      +

      + type, public :: version_t

      + +
      + + + + +
      +

      Type-Bound Procedures

      +
      +
      +
      + +

      + generic, public :: + operator(.match.) => match + +

      +
      +
      + +

      Compare a version against a version constraint (x.x.0 <= v < x.x.HUGE)

      +
      +
        +
      • +

        + private elemental function match(lhs, rhs) +

        + +

        Try to match first version against second version

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(version_t), + intent(in) + + ::lhs +

        First version number

        +
        + + class(version_t), + intent(in) + + ::rhs +

        Second version number

        +
        + +

        + Return Value + logical +

        +

        Version match following semantic versioning rules

        + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + operator(/=) => not_equals + +

      +
      +
        +
      • +

        + private elemental function not_equals(lhs, rhs) result(not_equal) +

        + +

        Check two versions for inequality

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(version_t), + intent(in) + + ::lhs +

        First version number

        +
        + + class(version_t), + intent(in) + + ::rhs +

        Second version number

        +
        + +

        + Return Value + logical +

        +

        Version mismatch

        + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + operator(<) => less + +

      +
      +
        +
      • +

        + private elemental function less(lhs, rhs) result(is_less) +

        + +

        Relative comparison of two versions

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(version_t), + intent(in) + + ::lhs +

        First version number

        +
        + + class(version_t), + intent(in) + + ::rhs +

        Second version number

        +
        + +

        + Return Value + logical +

        +

        First version is less

        + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + operator(<=) => less_equals + +

      +
      +
        +
      • +

        + private elemental function less_equals(lhs, rhs) result(is_less_equal) +

        + +

        Relative comparison of two versions

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(version_t), + intent(in) + + ::lhs +

        First version number

        +
        + + class(version_t), + intent(in) + + ::rhs +

        Second version number

        +
        + +

        + Return Value + logical +

        +

        First version is less or equal

        + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + operator(==) => equals + +

      +
      +
        +
      • +

        + private elemental function equals(lhs, rhs) result(is_equal) +

        + +

        Check to version numbers for equality

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(version_t), + intent(in) + + ::lhs +

        First version number

        +
        + + class(version_t), + intent(in) + + ::rhs +

        Second version number

        +
        + +

        + Return Value + logical +

        +

        Version match

        + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + operator(>) => greater + +

      +
      +
        +
      • +

        + private elemental function greater(lhs, rhs) result(is_greater) +

        + +

        Relative comparison of two versions

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(version_t), + intent(in) + + ::lhs +

        First version number

        +
        + + class(version_t), + intent(in) + + ::rhs +

        Second version number

        +
        + +

        + Return Value + logical +

        +

        First version is greater

        + +
      • +
      +
      + +
      +
      +
      +
      + +

      + generic, public :: + operator(>=) => greater_equals + +

      +
      +
        +
      • +

        + private elemental function greater_equals(lhs, rhs) result(is_greater_equal) +

        + +

        Relative comparison of two versions

        + +

        Arguments

        + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(version_t), + intent(in) + + ::lhs +

        First version number

        +
        + + class(version_t), + intent(in) + + ::rhs +

        Second version number

        +
        + +

        + Return Value + logical +

        +

        First version is greater or equal

        + +
      • +
      +
      + +
      +
      +
      +
      + +

      + procedure, public :: + s + +

      +
      +
      + +

      Create a printable string from a version data type

      +
      +
        +
      • +

        + private pure function s(self) result(string) +

        + + + +

        Arguments

        + + + + + + + + + + + + + + + + + + + +
        TypeIntentOptional AttributesName
        + + class(version_t), + intent(in) + + ::self +

        Version number

        +
        + +

        + Return Value + character(len=:), allocatable +

        +

        Character representation of the version

        + +
      • +
      +
      + +
      +
      + +
      +

      Source Code

      +
          type :: version_t
      +        private
      +
      +        !> Version numbers found
      +        integer, allocatable :: num(:)
      +
      +    contains
      +
      +        generic :: operator(==) => equals
      +        procedure, private :: equals
      +
      +        generic :: operator(/=) => not_equals
      +        procedure, private :: not_equals
      +
      +        generic :: operator(>) => greater
      +        procedure, private :: greater
      +
      +        generic :: operator(<) => less
      +        procedure, private :: less
      +
      +        generic :: operator(>=) => greater_equals
      +        procedure, private :: greater_equals
      +
      +        generic :: operator(<=) => less_equals
      +        procedure, private :: less_equals
      +
      +        !> Compare a version against a version constraint (x.x.0 <= v < x.x.HUGE)
      +        generic :: operator(.match.) => match
      +        procedure, private :: match
      +
      +        !> Create a printable string from a version data type
      +        procedure :: s
      +
      +    end type version_t
      +
      + +
      + +
      +
      + +
      +
      + + + \ No newline at end of file diff --git a/webfonts/fa-brands-400.ttf b/webfonts/fa-brands-400.ttf new file mode 100644 index 0000000000..0f82a83605 Binary files /dev/null and b/webfonts/fa-brands-400.ttf differ diff --git a/webfonts/fa-brands-400.woff2 b/webfonts/fa-brands-400.woff2 new file mode 100644 index 0000000000..3c5cf97ec3 Binary files /dev/null and b/webfonts/fa-brands-400.woff2 differ diff --git a/webfonts/fa-regular-400.ttf b/webfonts/fa-regular-400.ttf new file mode 100644 index 0000000000..9ee1919dc2 Binary files /dev/null and b/webfonts/fa-regular-400.ttf differ diff --git a/webfonts/fa-regular-400.woff2 b/webfonts/fa-regular-400.woff2 new file mode 100644 index 0000000000..57d9179654 Binary files /dev/null and b/webfonts/fa-regular-400.woff2 differ diff --git a/webfonts/fa-solid-900.ttf b/webfonts/fa-solid-900.ttf new file mode 100644 index 0000000000..1c10972ece Binary files /dev/null and b/webfonts/fa-solid-900.ttf differ diff --git a/webfonts/fa-solid-900.woff2 b/webfonts/fa-solid-900.woff2 new file mode 100644 index 0000000000..16721020f0 Binary files /dev/null and b/webfonts/fa-solid-900.woff2 differ diff --git a/webfonts/fa-v4compatibility.ttf b/webfonts/fa-v4compatibility.ttf new file mode 100644 index 0000000000..3bcb67ffcc Binary files /dev/null and b/webfonts/fa-v4compatibility.ttf differ diff --git a/webfonts/fa-v4compatibility.woff2 b/webfonts/fa-v4compatibility.woff2 new file mode 100644 index 0000000000..fbafb22222 Binary files /dev/null and b/webfonts/fa-v4compatibility.woff2 differ