diff options
author | Sebastian Ehlert <28669218+awvwgk@users.noreply.github.com> | 2021-03-31 16:13:58 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-03-31 16:13:58 +0200 |
commit | d9dc9f2ae5f196c15a7d35cddabc805c40ff86ce (patch) | |
tree | 6f61952c630b023edec391daae2747063703d489 | |
parent | 5422ec57f4081bf2225f5dde5cc07999bf8010f9 (diff) | |
download | fpm-d9dc9f2ae5f196c15a7d35cddabc805c40ff86ce.tar.gz fpm-d9dc9f2ae5f196c15a7d35cddabc805c40ff86ce.zip |
Phase out Haskell fpm (#420)
- remove bootstrap directory from repository
- remove stack-build from CI workflow
- move Fortran fpm to project root
- adjust install script and bootstrap instructions
-rw-r--r-- | .github/workflows/CI.yml | 143 | ||||
-rw-r--r-- | .gitignore | 4 | ||||
-rw-r--r-- | README.md | 48 | ||||
-rw-r--r-- | app/main.f90 (renamed from fpm/app/main.f90) | 0 | ||||
-rw-r--r-- | bootstrap/Setup.hs | 2 | ||||
-rw-r--r-- | bootstrap/app/Main.hs | 8 | ||||
-rw-r--r-- | bootstrap/package.yaml | 72 | ||||
-rw-r--r-- | bootstrap/src/Build.hs | 239 | ||||
-rw-r--r-- | bootstrap/src/BuildModel.hs | 411 | ||||
-rw-r--r-- | bootstrap/src/Fpm.hs | 1227 | ||||
-rw-r--r-- | bootstrap/stack.yaml | 74 | ||||
-rw-r--r-- | bootstrap/stack.yaml.lock | 43 | ||||
-rw-r--r-- | bootstrap/test/Spec.hs | 103 | ||||
l--------- | bootstrap/test/example_packages | 1 | ||||
-rw-r--r-- | bootstrap/unit_test/ModuleSourceConstructionTest.hs | 83 | ||||
-rw-r--r-- | bootstrap/unit_test/ModuleToCompileInfoTest.hs | 73 | ||||
-rw-r--r-- | bootstrap/unit_test/ProgramSourceConstructionTest.hs | 69 | ||||
-rw-r--r-- | bootstrap/unit_test/ProgramToCompileInfoTest.hs | 71 | ||||
-rw-r--r-- | bootstrap/unit_test/SubmoduleSourceConstructionTest.hs | 79 | ||||
-rw-r--r-- | bootstrap/unit_test/SubmoduleToCompileInfoTest.hs | 78 | ||||
-rw-r--r-- | bootstrap/unit_test/Trimmer.hs | 1 | ||||
-rw-r--r-- | docs.md | 6 | ||||
-rw-r--r-- | fpm.toml (renamed from fpm/fpm.toml) | 0 | ||||
-rw-r--r-- | fpm/.gitignore | 1 | ||||
-rw-r--r-- | fpm/README.md | 4 | ||||
-rwxr-xr-x | install.sh | 100 | ||||
-rw-r--r-- | manifest-reference.md | 21 | ||||
-rw-r--r-- | src/fpm.f90 (renamed from fpm/src/fpm.f90) | 0 | ||||
-rw-r--r-- | src/fpm/cmd/install.f90 (renamed from fpm/src/fpm/cmd/install.f90) | 0 | ||||
-rw-r--r-- | src/fpm/cmd/new.f90 (renamed from fpm/src/fpm/cmd/new.f90) | 0 | ||||
-rw-r--r-- | src/fpm/cmd/update.f90 (renamed from fpm/src/fpm/cmd/update.f90) | 0 | ||||
-rw-r--r-- | src/fpm/dependency.f90 (renamed from fpm/src/fpm/dependency.f90) | 0 | ||||
-rw-r--r-- | src/fpm/error.f90 (renamed from fpm/src/fpm/error.f90) | 0 | ||||
-rw-r--r-- | src/fpm/git.f90 (renamed from fpm/src/fpm/git.f90) | 0 | ||||
-rw-r--r-- | src/fpm/installer.f90 (renamed from fpm/src/fpm/installer.f90) | 0 | ||||
-rw-r--r-- | src/fpm/manifest.f90 (renamed from fpm/src/fpm/manifest.f90) | 0 | ||||
-rw-r--r-- | src/fpm/manifest/build.f90 (renamed from fpm/src/fpm/manifest/build.f90) | 0 | ||||
-rw-r--r-- | src/fpm/manifest/dependency.f90 (renamed from fpm/src/fpm/manifest/dependency.f90) | 0 | ||||
-rw-r--r-- | src/fpm/manifest/example.f90 (renamed from fpm/src/fpm/manifest/example.f90) | 0 | ||||
-rw-r--r-- | src/fpm/manifest/executable.f90 (renamed from fpm/src/fpm/manifest/executable.f90) | 0 | ||||
-rw-r--r-- | src/fpm/manifest/install.f90 (renamed from fpm/src/fpm/manifest/install.f90) | 0 | ||||
-rw-r--r-- | src/fpm/manifest/library.f90 (renamed from fpm/src/fpm/manifest/library.f90) | 0 | ||||
-rw-r--r-- | src/fpm/manifest/package.f90 (renamed from fpm/src/fpm/manifest/package.f90) | 0 | ||||
-rw-r--r-- | src/fpm/manifest/test.f90 (renamed from fpm/src/fpm/manifest/test.f90) | 0 | ||||
-rw-r--r-- | src/fpm/toml.f90 (renamed from fpm/src/fpm/toml.f90) | 0 | ||||
-rw-r--r-- | src/fpm/versioning.f90 (renamed from fpm/src/fpm/versioning.f90) | 0 | ||||
-rw-r--r-- | src/fpm_backend.f90 (renamed from fpm/src/fpm_backend.f90) | 0 | ||||
-rw-r--r-- | src/fpm_command_line.f90 (renamed from fpm/src/fpm_command_line.f90) | 0 | ||||
-rw-r--r-- | src/fpm_compiler.f90 (renamed from fpm/src/fpm_compiler.f90) | 0 | ||||
-rw-r--r-- | src/fpm_environment.f90 (renamed from fpm/src/fpm_environment.f90) | 0 | ||||
-rw-r--r-- | src/fpm_filesystem.f90 (renamed from fpm/src/fpm_filesystem.f90) | 0 | ||||
-rw-r--r-- | src/fpm_model.f90 (renamed from fpm/src/fpm_model.f90) | 0 | ||||
-rw-r--r-- | src/fpm_source_parsing.f90 (renamed from fpm/src/fpm_source_parsing.f90) | 0 | ||||
-rw-r--r-- | src/fpm_sources.f90 (renamed from fpm/src/fpm_sources.f90) | 0 | ||||
-rw-r--r-- | src/fpm_strings.f90 (renamed from fpm/src/fpm_strings.f90) | 0 | ||||
-rw-r--r-- | src/fpm_targets.f90 (renamed from fpm/src/fpm_targets.f90) | 0 | ||||
-rw-r--r-- | test/cli_test/cli_test.f90 (renamed from fpm/test/cli_test/cli_test.f90) | 0 | ||||
-rw-r--r-- | test/fpm_test/main.f90 (renamed from fpm/test/fpm_test/main.f90) | 0 | ||||
-rw-r--r-- | test/fpm_test/test_backend.f90 (renamed from fpm/test/fpm_test/test_backend.f90) | 0 | ||||
-rw-r--r-- | test/fpm_test/test_filesystem.f90 (renamed from fpm/test/fpm_test/test_filesystem.f90) | 0 | ||||
-rw-r--r-- | test/fpm_test/test_installer.f90 (renamed from fpm/test/fpm_test/test_installer.f90) | 0 | ||||
-rw-r--r-- | test/fpm_test/test_manifest.f90 (renamed from fpm/test/fpm_test/test_manifest.f90) | 0 | ||||
-rw-r--r-- | test/fpm_test/test_module_dependencies.f90 (renamed from fpm/test/fpm_test/test_module_dependencies.f90) | 0 | ||||
-rw-r--r-- | test/fpm_test/test_package_dependencies.f90 (renamed from fpm/test/fpm_test/test_package_dependencies.f90) | 0 | ||||
-rw-r--r-- | test/fpm_test/test_source_parsing.f90 (renamed from fpm/test/fpm_test/test_source_parsing.f90) | 0 | ||||
-rw-r--r-- | test/fpm_test/test_toml.f90 (renamed from fpm/test/fpm_test/test_toml.f90) | 0 | ||||
-rw-r--r-- | test/fpm_test/test_versioning.f90 (renamed from fpm/test/fpm_test/test_versioning.f90) | 0 | ||||
-rw-r--r-- | test/fpm_test/testsuite.f90 (renamed from fpm/test/fpm_test/testsuite.f90) | 0 | ||||
-rw-r--r-- | test/help_test/help_test.f90 (renamed from fpm/test/help_test/help_test.f90) | 0 | ||||
-rw-r--r-- | test/new_test/new_test.f90 (renamed from fpm/test/new_test/new_test.f90) | 0 |
70 files changed, 39 insertions, 2922 deletions
diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index 9fc7918..8aabcf5 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -13,138 +13,8 @@ env: HOMEBREW_NO_BOTTLE_SOURCE_FALLBACK: "ON" HOMEBREW_NO_GITHUB_API: "ON" HOMEBREW_NO_INSTALL_CLEANUP: "ON" - RUST_BACKTRACE: "full" # Make Rust print full backtrace on error jobs: - stack-build: - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest, macos-latest, windows-latest] - gcc_v: [9] # Version of GFortran we want to use. - include: - - os: ubuntu-latest - STACK_CACHE: "/home/runner/.stack/" - STACK_CACHE_VERSION: "" - TEST_SCRIPT: ci/run_tests.sh - GET_VERSION_CMD: echo ${{ github.ref }} | cut -dv -f2 - CHECK_VERSION_CMD: grep $(cat fpm_version) - RELEASE_CMD: "cp -- fpm-$(cat fpm_version)-linux-x86_64" - BOOTSTRAP_RELEASE_CMD: cp /home/runner/.local/bin/fpm fpm-haskell-$(cat fpm_version)-linux-x86_64 - HASH_CMD: ls fpm-*|xargs -i{} sh -c 'sha256sum $1 > $1.sha256' -- {} - RELEASE_FLAGS: --flag --static --flag -g --flag -fbacktrace --flag -O3 - - - os: macos-latest - STACK_CACHE: | - /Users/runner/.stack/snapshots - /Users/runner/.stack/setup-exe-src - STACK_CACHE_VERSION: "v2" - TEST_SCRIPT: ci/run_tests.sh - GET_VERSION_CMD: echo ${{ github.ref }} | cut -dv -f2 - CHECK_VERSION_CMD: grep $(cat fpm_version) - RELEASE_CMD: "cp -- fpm-$(cat fpm_version)-macos-x86_64" - BOOTSTRAP_RELEASE_CMD: cp /Users/runner/.local/bin/fpm fpm-haskell-$(cat fpm_version)-macos-x86_64 - HASH_CMD: ls fpm-*|xargs -I{} sh -c 'shasum -a 256 $1 > $1.sha256' -- {} - RELEASE_FLAGS: --flag -g --flag -fbacktrace --flag -O3 - - - os: windows-latest - STACK_CACHE: | - C:\Users\runneradmin\AppData\Roaming\stack - C:\Users\runneradmin\AppData\Local\Programs\stack - STACK_CACHE_VERSION: "v2" - TEST_SCRIPT: ci\run_tests.bat - GET_VERSION_CMD: ("${{ github.ref }}" -Split "v")[1] - CHECK_VERSION_CMD: Select-String -Pattern Version | Where-Object { if ($_ -like -join("*",(Get-Content fpm_version),"*")) {echo $_} else {Throw} } - RELEASE_CMD: copy -- (-join("fpm-",(Get-Content fpm_version),"-windows-x86_64.exe")) - BOOTSTRAP_RELEASE_CMD: copy C:\Users\runneradmin\AppData\Roaming\local\bin\fpm.exe (-join("fpm-haskell-",(Get-Content fpm_version),"-windows-x86_64.exe")) - HASH_CMD: Get-ChildItem -File -Filter "fpm-*" | Foreach-Object {echo (Get-FileHash -Algorithm SHA256 $PSItem | Select-Object hash | Format-Table -HideTableHeaders | Out-String) > (-join($PSItem,".sha256"))} - RELEASE_FLAGS: --flag --static --flag -g --flag -fbacktrace --flag -O3 - - env: - FC: gfortran - GCC_V: ${{ matrix.gcc_v }} - - steps: - - name: Checkout code - uses: actions/checkout@v1 - - - name: Install GFortran macOS - if: contains(matrix.os, 'macos') - run: | - ln -s /usr/local/bin/gfortran-${GCC_V} /usr/local/bin/gfortran - which gfortran-${GCC_V} - which gfortran - - - name: Install GFortran Linux - 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/bingcov gcov /usr/bin/gcov-${GCC_V} - - - name: Get Time - id: time - uses: nanzm/get-time-action@v1.0 - with: - format: 'YYYY-MM' - - - name: Setup github actions cache - id: cache - uses: actions/cache@v2 - with: - path: ${{matrix.STACK_CACHE}} - key: ${{ runner.os }}-${{ steps.time.outputs.time }}${{matrix.STACK_CACHE_VERSION}} - - - name: Build Haskell fpm - run: | - stack build - stack install - working-directory: bootstrap - - - name: put fpm to PATH (macOS) - if: contains(matrix.os, 'macos') - run: | - cp /Users/runner/.local/bin/fpm /usr/local/bin - - - name: put fpm to PATH (Windows) - if: contains(matrix.os, 'windows') - run: | - copy "C:\Users\runneradmin\AppData\Roaming\local\bin\fpm.exe" "C:\Program Files\Git\usr\bin" - - - name: put fpm to PATH (Linux) - if: contains(matrix.os, 'ubuntu') - run: | - sudo cp /home/runner/.local/bin/fpm /usr/local/bin - - - name: Run tests on Haskell fpm - run: | - stack test - working-directory: bootstrap - - # ----- Upload binaries if creating a release ----- - - name: Check that fpm --version matches release tag - if: github.event_name == 'release' - run: | - ${{ matrix.GET_VERSION_CMD }} > fpm_version - working-directory: fpm - - - name: Stage release files for upload - if: github.event_name == 'release' - run: | - ${{ matrix.BOOTSTRAP_RELEASE_CMD }} - ${{ matrix.HASH_CMD }} - working-directory: fpm - - - name: Upload assets - if: github.event_name == 'release' - uses: svenstaro/upload-release-action@v2 - with: - repo_token: ${{ secrets.GITHUB_TOKEN }} - file: fpm/fpm-* - file_glob: true - tag: ${{ github.ref }} - overwrite: true build: runs-on: ${{ matrix.os }} @@ -208,7 +78,6 @@ jobs: shell: bash run: | ${{ env.BOOTSTRAP }} build - working-directory: fpm - name: Run Fortran fpm (bootstrap) shell: bash @@ -216,19 +85,16 @@ jobs: ${{ env.BOOTSTRAP }} run ${{ env.BOOTSTRAP }} run -- --version ${{ env.BOOTSTRAP }} run -- --help - working-directory: fpm - name: Test Fortran fpm (bootstrap) shell: bash run: | ${{ env.BOOTSTRAP }} test - working-directory: fpm - name: Install Fortran fpm (bootstrap) shell: bash run: | ${{ env.BOOTSTRAP }} install - working-directory: fpm # Phase 2: Bootstrap fpm with itself - name: Replace bootstrapping version @@ -237,7 +103,6 @@ jobs: ${{ env.BOOTSTRAP }} run --runner cp -- fpm-debug${{ matrix.exe }} rm -v ${{ env.BOOTSTRAP }} echo "FPM=$PWD/fpm-debug" | cat >> $GITHUB_ENV - working-directory: fpm - name: Get version (normal) if: github.event_name != 'release' @@ -266,7 +131,6 @@ jobs: shell: bash run: | ${{ env.FPM }} build ${{ matrix.release-flags }} - working-directory: fpm - name: Run Fortran fpm shell: bash @@ -274,19 +138,16 @@ jobs: ${{ env.FPM }} run ${{ matrix.release-flags }} ${{ env.FPM }} run ${{ matrix.release-flags }} -- --version ${{ env.FPM }} run ${{ matrix.release-flags }} -- --help - working-directory: fpm - name: Test Fortran fpm shell: bash run: | ${{ env.FPM }} test ${{ matrix.release-flags }} - working-directory: fpm - name: Install Fortran fpm shell: bash run: | ${{ env.FPM }} install ${{ matrix.release-flags }} - working-directory: fpm - name: Package release version shell: bash @@ -294,7 +155,6 @@ jobs: ${{ env.FPM }} run ${{ matrix.release-flags }} --runner cp -- ${{ env.EXE }} rm -v ${{ env.FPM }} echo "FPM_RELEASE=$PWD/${{ env.EXE }}" | cat >> $GITHUB_ENV - working-directory: fpm env: EXE: fpm-${{ env.VERSION }}-${{ matrix.os-arch }}${{ matrix.exe }} @@ -308,14 +168,13 @@ jobs: shell: bash run: | ${{ matrix.sha256sum }} ${{ env.FPM_RELEASE }} > ${{ env.FPM_RELEASE }}.sha256 - working-directory: fpm - name: Upload assets if: github.event_name == 'release' uses: svenstaro/upload-release-action@v2 with: repo_token: ${{ secrets.GITHUB_TOKEN }} - file: fpm/fpm-* + file: fpm-* file_glob: true tag: ${{ github.ref }} overwrite: true @@ -1,3 +1 @@ -.stack-work/ -fpm.cabal -*~ +build/* @@ -18,7 +18,10 @@ 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/) +[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, @@ -71,8 +74,8 @@ with the following contents and initialized as a git repository. * `README.md` – with your project’s name * `.gitignore` * `src/project_name.f90` – with a simple hello world subroutine -* `app/main.f90` (if `--with-executable` flag used) – a program that calls the subroutine -* `test/main.f90` (if `--with-test` flag used) – an empty test program +* `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 @@ -81,6 +84,7 @@ with the following contents and initialized as a git repository. * `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 @@ -94,36 +98,24 @@ the [manifest reference](manifest-reference.md). ### Bootstrapping instructions This guide explains the process of building *fpm* on a platform for the first time. -If your platform and architecture are already supported, download the binary from the [release page](https://github.com/fortran-lang/fpm/releases) instead. +To build *fpm* without a prior *fpm* version a single source file version is available +at each release. -#### Download this repository +To build manually using the single source distribution use -```bash -$ git clone https://github.com/fortran-lang/fpm -$ cd fpm/ ``` - -#### Build a bootstrap version of fpm - -You can use the install script to bootstrap and install *fpm*: - -```bash -$ ./install.sh +mkdir _tmp +curl -LJ https://github.com/fortran-lang/fpm/releases/download/v0.2.0/fpm-0.2.0.f90 > _tmp/fpm.f90 +gfortran -J _tmp _tmp/fpm.f90 -o _tmp/fpm +_tmp/fpm install --flag "-g -fbacktrace -O3" +rm -r _tmp ``` -By default, the above command installs `fpm` to `${HOME}/.local/bin/`. -To specify an alternative destination use the `--prefix=` flag, for example: +To automatically bootstrap using this appoach run the install script -```bash -$ ./install.sh --prefix=/usr/local ``` - -which will install *fpm* to `/usr/local/bin`. - -To test that everything is working as expected you can now build *fpm* -with itself and run the tests with: - -```bash -$ cd fpm -$ fpm test +./install.sh ``` + +You can set your Fortran compiler and the compiler flags with the ``FC`` and ``FFLAGS`` +environment variables. diff --git a/fpm/app/main.f90 b/app/main.f90 index 7476df6..7476df6 100644 --- a/fpm/app/main.f90 +++ b/app/main.f90 diff --git a/bootstrap/Setup.hs b/bootstrap/Setup.hs deleted file mode 100644 index 9a994af..0000000 --- a/bootstrap/Setup.hs +++ /dev/null @@ -1,2 +0,0 @@ -import Distribution.Simple -main = defaultMain diff --git a/bootstrap/app/Main.hs b/bootstrap/app/Main.hs deleted file mode 100644 index 4897901..0000000 --- a/bootstrap/app/Main.hs +++ /dev/null @@ -1,8 +0,0 @@ -module Main where - -import Fpm ( getArguments - , start - ) - -main :: IO () -main = getArguments >>= start diff --git a/bootstrap/package.yaml b/bootstrap/package.yaml deleted file mode 100644 index 1f5d0fd..0000000 --- a/bootstrap/package.yaml +++ /dev/null @@ -1,72 +0,0 @@ -name: fpm -version: 0.1.0.0 -github: "githubuser/fpm" -license: BSD3 -author: "Author name here" -maintainer: "example@example.com" -copyright: "2020 Author name here" - -extra-source-files: -- ../README.md -- ../ChangeLog.md - -# Metadata used when publishing your package -# synopsis: Short description of your package -# category: Web - -# To avoid duplicated efforts in documentation and dealing with the -# complications of embedding Haddock markup inside cabal files, it is -# common to point users to the README.md file. -description: Please see the README on GitHub at <https://github.com/githubuser/fpm#readme> - -dependencies: -- base >= 4.7 && < 5 -- containers -- directory -- extra -- filepath -- hashable -- MissingH -- optparse-applicative -- process -- shake -- split -- text -- tomland >= 1.0 - - -library: - source-dirs: src - -executables: - fpm: - main: Main.hs - source-dirs: app - ghc-options: - - -threaded - - -rtsopts - - -with-rtsopts=-N - dependencies: - - fpm - -tests: - fpm-test: - main: Spec.hs - source-dirs: test - ghc-options: - - -threaded - - -rtsopts - - -with-rtsopts=-N - dependencies: - - fpm - fpm-unittest: - main: Trimmer.hs - source-dirs: unit_test - ghc-options: - - -threaded - - -rtsopts - - -with-rtsopts=-N - dependencies: - - fpm - - hedge - - hedge-trimmer diff --git a/bootstrap/src/Build.hs b/bootstrap/src/Build.hs deleted file mode 100644 index 724a1c6..0000000 --- a/bootstrap/src/Build.hs +++ /dev/null @@ -1,239 +0,0 @@ -{-# LANGUAGE MultiWayIf #-} -module Build - ( CompilerSettings(..) - , buildLibrary - , buildProgram - , buildWithScript - ) -where - -import BuildModel ( AvailableModule(..) - , CompileTimeInfo(..) - , RawSource(..) - , Source(..) - , constructCompileTimeInfo - , getAllObjectFiles - , getAvailableModules - , getSourceFileName - , processRawSource - ) -import Data.List ( intercalate - , isSuffixOf - ) -import Data.List.Utils ( replace ) -import Development.Shake ( FilePattern - , Change(ChangeModtimeAndDigest) - , cmd - , getDirectoryFilesIO - , liftIO - , need - , progressSimple - , shake - , shakeChange - , shakeColor - , shakeFiles - , shakeOptions - , shakeProgress - , shakeThreads - , want - , (<//>) - , (%>) - , (&?>) - ) -import Development.Shake.FilePath ( exe - , splitDirectories - , (</>) - , (<.>) - ) -import System.Environment ( setEnv ) -import System.FilePath ( takeBaseName ) -import System.Process ( system ) -import System.Directory ( createDirectoryIfMissing - , makeAbsolute - , withCurrentDirectory - ) - -data CompilerSettings = CompilerSettings { - compilerSettingsCompiler :: FilePath - , compilerSettingsFlags :: [String] - , compilerSettingsModuleFlag :: String - , compilerSettingsIncludeFlag :: String -} - -buildProgram - :: FilePath - -> [FilePath] - -> [FilePattern] - -> FilePath - -> CompilerSettings - -> String - -> FilePath - -> [FilePath] - -> IO () -buildProgram programDirectory' libraryDirectories sourceExtensions buildDirectory' (CompilerSettings { compilerSettingsCompiler = compiler, compilerSettingsFlags = flags, compilerSettingsModuleFlag = moduleFlag, compilerSettingsIncludeFlag = includeFlag }) programName programSource archives - = do - libraryModules <- findAvailableModules libraryDirectories - let programDirectory = foldl1 (</>) (splitDirectories programDirectory') - let buildDirectory = foldl1 (</>) (splitDirectories buildDirectory') - let includeFlags = (includeFlag ++ buildDirectory) : map (includeFlag ++) libraryDirectories - sourceFiles <- getDirectoriesFiles [programDirectory] sourceExtensions - rawSources <- mapM sourceFileToRawSource sourceFiles - let sources' = map processRawSource rawSources - let isThisProgramOrNotProgram p@(Program{}) = - programSourceFileName p == programDirectory </> programSource - isThisProgramOrNotProgram _ = True - let sources = filter isThisProgramOrNotProgram sources' - let availableModules = (getAvailableModules sources buildDirectory) ++ libraryModules - let compileTimeInfo = map - (\s -> constructCompileTimeInfo s availableModules buildDirectory) - sources - let objectFiles = getAllObjectFiles buildDirectory sources - shake shakeOptions { shakeFiles = buildDirectory - , shakeChange = ChangeModtimeAndDigest - , shakeColor = True - , shakeThreads = 0 - , shakeProgress = progressSimple - } - $ do - let infoToRule cti = - let obj = compileTimeInfoObjectFileProduced cti - other = compileTimeInfoOtherFilesProduced cti - directDependencies = compileTimeInfoDirectDependencies cti - sourceFile = compileTimeInfoSourceFileName cti - fileMatcher f = - let realf = foldl1 (</>) (splitDirectories f) - in if realf == obj || realf `elem` other - then Just (obj : other) - else Nothing - in fileMatcher &?> \(objectFile : _) -> do - need (sourceFile : directDependencies) - cmd compiler - ["-c", moduleFlag, buildDirectory] - includeFlags - flags - ["-o", objectFile, sourceFile] - want [buildDirectory </> programName <.> exe] - buildDirectory </> programName <.> exe %> \executable -> do - need objectFiles - need archives - cmd compiler objectFiles archives ["-o", executable] flags - mapM_ infoToRule compileTimeInfo - -buildLibrary - :: FilePath - -> [FilePattern] - -> FilePath - -> CompilerSettings - -> String - -> [FilePath] - -> IO (FilePath) -buildLibrary libraryDirectory sourceExtensions buildDirectory (CompilerSettings { compilerSettingsCompiler = compiler, compilerSettingsFlags = flags, compilerSettingsModuleFlag = moduleFlag, compilerSettingsIncludeFlag = includeFlag }) libraryName otherLibraryDirectories - = do - otherModules <- findAvailableModules otherLibraryDirectories - let includeFlags = (includeFlag ++ buildDirectory) : map (includeFlag ++) otherLibraryDirectories - sourceFiles <- getDirectoriesFiles [libraryDirectory] sourceExtensions - rawSources <- mapM sourceFileToRawSource sourceFiles - let sources = map processRawSource rawSources - let availableModules = (getAvailableModules sources buildDirectory) ++ otherModules - let compileTimeInfo = map - (\s -> constructCompileTimeInfo s availableModules buildDirectory) - sources - let objectFiles = getAllObjectFiles buildDirectory sources - let archiveFile = buildDirectory </> "lib" ++ libraryName <.> "a" - shake shakeOptions { shakeFiles = buildDirectory - , shakeChange = ChangeModtimeAndDigest - , shakeColor = True - , shakeThreads = 0 - , shakeProgress = progressSimple - } - $ do - let infoToRule cti = - let obj = compileTimeInfoObjectFileProduced cti - other = compileTimeInfoOtherFilesProduced cti - directDependencies = compileTimeInfoDirectDependencies cti - sourceFile = compileTimeInfoSourceFileName cti - fileMatcher f = - let realf = foldl1 (</>) (splitDirectories f) - in if realf == obj || realf `elem` other - then Just (obj : other) - else Nothing - in fileMatcher &?> \(objectFile : _) -> do - need (sourceFile : directDependencies) - cmd compiler - ["-c", moduleFlag, buildDirectory] - includeFlags - flags - ["-o", objectFile, sourceFile] - want [archiveFile] - archiveFile %> \a -> do - need objectFiles - cmd "ar" ["rs"] a objectFiles - mapM_ infoToRule compileTimeInfo - return archiveFile - -buildWithScript - :: String - -> FilePath - -> FilePath - -> CompilerSettings - -> String - -> [FilePath] - -> IO (FilePath) -buildWithScript script projectDirectory buildDirectory (CompilerSettings { compilerSettingsCompiler = compiler, compilerSettingsFlags = flags, compilerSettingsModuleFlag = moduleFlag, compilerSettingsIncludeFlag = includeFlag }) libraryName otherLibraryDirectories - = do - absoluteBuildDirectory <- makeAbsolute buildDirectory - createDirectoryIfMissing True absoluteBuildDirectory - absoluteLibraryDirectories <- mapM makeAbsolute otherLibraryDirectories - setEnv "FC" compiler - setEnv "FFLAGS" (intercalate " " flags) - setEnv "FINCLUDEFLAG" includeFlag - setEnv "FMODUELFLAG" moduleFlag - setEnv "BUILD_DIR" $ unWindowsPath absoluteBuildDirectory - setEnv "INCLUDE_DIRS" - (intercalate " " (map unWindowsPath absoluteLibraryDirectories)) - let archiveFile = - (unWindowsPath absoluteBuildDirectory) - ++ "/lib" - ++ libraryName - <.> "a" - withCurrentDirectory - projectDirectory - if - | isMakefile script -> system - ("make -f " ++ script ++ " " ++ archiveFile) - | otherwise -> system (script ++ " " ++ archiveFile) - return archiveFile - --- A little wrapper around getDirectoryFiles so we can get files from multiple directories -getDirectoriesFiles :: [FilePath] -> [FilePattern] -> IO [FilePath] -getDirectoriesFiles dirs exts = getDirectoryFilesIO "" newPatterns - where - newPatterns = concatMap appendExts dirs - appendExts dir = map ((dir <//> "*") ++) exts - -sourceFileToRawSource :: FilePath -> IO RawSource -sourceFileToRawSource sourceFile = do - contents <- readFile sourceFile - return $ RawSource sourceFile contents - -isMakefile :: String -> Bool -isMakefile script | script == "Makefile" = True - | script == "makefile" = True - | ".mk" `isSuffixOf` script = True - | otherwise = False - -unWindowsPath :: String -> String -unWindowsPath = changeSeparators . removeDriveLetter - -removeDriveLetter :: String -> String -removeDriveLetter path | ':' `elem` path = (tail . dropWhile (/= ':')) path - | otherwise = path - -changeSeparators :: String -> String -changeSeparators = replace "\\" "/" - -findAvailableModules :: [FilePath] -> IO [AvailableModule] -findAvailableModules directories = do - moduleFiles <- getDirectoriesFiles directories ["*.mod"] - let availableModules = map (\mf -> AvailableModule { availableModuleName = takeBaseName mf, availableModuleFile = mf }) moduleFiles - return availableModules diff --git a/bootstrap/src/BuildModel.hs b/bootstrap/src/BuildModel.hs deleted file mode 100644 index 4ca5959..0000000 --- a/bootstrap/src/BuildModel.hs +++ /dev/null @@ -1,411 +0,0 @@ -module BuildModel where - -import Control.Applicative ( (<|>) ) -import Control.Monad ( when ) -import Data.Char ( isAsciiLower - , isDigit - , toLower - ) -import Data.Maybe ( fromMaybe - , mapMaybe - ) -import Data.List ( intercalate ) -import System.FilePath ( (</>) - , (<.>) - , splitDirectories - ) -import Text.ParserCombinators.ReadP ( ReadP - , char - , eof - , many - , many1 - , option - , readP_to_S - , satisfy - , skipSpaces - , string - ) - -data LineContents = - ProgramDeclaration - | ModuleDeclaration String - | ModuleUsed String - | ModuleSubprogramDeclaration - | SubmoduleDeclaration String String String - | Other - -data RawSource = RawSource { - rawSourceFilename :: FilePath - , rawSourceContents :: String -} - -data Source = - Program - { programSourceFileName :: FilePath - , programObjectFileName :: FilePath -> FilePath - , programModulesUsed :: [String] - } - | Module - { moduleSourceFileName :: FilePath - , moduleObjectFileName :: FilePath -> FilePath - , moduleModulesUsed :: [String] - , moduleName :: String - , moduleProducesSmod :: Bool - } - | Submodule - { submoduleSourceFileName :: FilePath - , submoduleObjectFileName :: FilePath -> FilePath - , submoduleModulesUsed :: [String] - , submoduleBaseModuleName :: String - , submoduleParentName :: String - , submoduleName :: String - } - -data CompileTimeInfo = CompileTimeInfo { - compileTimeInfoSourceFileName :: FilePath - , compileTimeInfoObjectFileProduced :: FilePath - , compileTimeInfoOtherFilesProduced :: [FilePath] - , compileTimeInfoDirectDependencies :: [FilePath] -} - -data AvailableModule = AvailableModule { - availableModuleName :: String - , availableModuleFile :: FilePath -} - -processRawSource :: RawSource -> Source -processRawSource rawSource = - let - sourceFileName = rawSourceFilename rawSource - parsedContents = parseContents rawSource - objectFileName = - \bd -> bd </> (pathSeparatorsToUnderscores sourceFileName) <.> "o" - modulesUsed = getModulesUsed parsedContents - in - if hasProgramDeclaration parsedContents - then Program { programSourceFileName = sourceFileName - , programObjectFileName = objectFileName - , programModulesUsed = modulesUsed - } - else if hasModuleDeclaration parsedContents - then Module - { moduleSourceFileName = sourceFileName - , moduleObjectFileName = objectFileName - , moduleModulesUsed = modulesUsed - , moduleName = getModuleName parsedContents - , moduleProducesSmod = hasModuleSubprogramDeclaration parsedContents - } - else if hasSubmoduleDeclaration parsedContents - then Submodule - { submoduleSourceFileName = sourceFileName - , submoduleObjectFileName = objectFileName - , submoduleModulesUsed = modulesUsed - , submoduleBaseModuleName = getSubmoduleBaseModuleName - parsedContents - , submoduleParentName = getSubmoduleParentName parsedContents - , submoduleName = getSubmoduleName parsedContents - } - else undefined - -getAvailableModules :: [Source] -> FilePath -> [AvailableModule] -getAvailableModules sources buildDirectory = mapMaybe maybeModule sources - where - maybeModule m@(Module{}) = - let mName = moduleName m - modFile = buildDirectory </> mName <.> "mod" - in Just $ AvailableModule { availableModuleName = mName, availableModuleFile = modFile } - maybeModule _ = Nothing - -getAllObjectFiles :: FilePath -> [Source] -> [FilePath] -getAllObjectFiles buildDirectory sources = map getObjectFile sources - where - getObjectFile p@(Program{} ) = (programObjectFileName p) buildDirectory - getObjectFile m@(Module{} ) = (moduleObjectFileName m) buildDirectory - getObjectFile s@(Submodule{}) = (submoduleObjectFileName s) buildDirectory - -getSourceFileName :: Source -> FilePath -getSourceFileName p@(Program{} ) = programSourceFileName p -getSourceFileName m@(Module{} ) = moduleSourceFileName m -getSourceFileName s@(Submodule{}) = submoduleSourceFileName s - -constructCompileTimeInfo :: Source -> [AvailableModule] -> FilePath -> CompileTimeInfo -constructCompileTimeInfo p@(Program{}) availableModules buildDirectory = - CompileTimeInfo - { compileTimeInfoSourceFileName = programSourceFileName p - , compileTimeInfoObjectFileProduced = (programObjectFileName p) - buildDirectory - , compileTimeInfoOtherFilesProduced = [] - , compileTimeInfoDirectDependencies = map - (\am -> availableModuleFile am) - (filter (\am -> (availableModuleName am) `elem` (programModulesUsed p)) availableModules) - } -constructCompileTimeInfo m@(Module{}) availableModules buildDirectory = - CompileTimeInfo - { compileTimeInfoSourceFileName = moduleSourceFileName m - , compileTimeInfoObjectFileProduced = (moduleObjectFileName m) - buildDirectory - , compileTimeInfoOtherFilesProduced = - (buildDirectory </> moduleName m <.> "mod") : if moduleProducesSmod m - then [buildDirectory </> moduleName m <.> "smod"] - else [] - , compileTimeInfoDirectDependencies = map - (\am -> availableModuleFile am) - (filter (\am -> (availableModuleName am) `elem` (moduleModulesUsed m)) availableModules) - } -constructCompileTimeInfo s@(Submodule{}) availableModules buildDirectory = - CompileTimeInfo - { compileTimeInfoSourceFileName = submoduleSourceFileName s - , compileTimeInfoObjectFileProduced = (submoduleObjectFileName s) - buildDirectory - , compileTimeInfoOtherFilesProduced = [ buildDirectory - </> submoduleBaseModuleName s - ++ "@" - ++ submoduleName s - <.> "smod" - ] - , compileTimeInfoDirectDependencies = - (buildDirectory </> submoduleParentName s <.> "smod") - : (map (\am -> availableModuleFile am) - (filter (\am -> (availableModuleName am) `elem` (submoduleModulesUsed s)) availableModules) - ) - } - -pathSeparatorsToUnderscores :: FilePath -> FilePath -pathSeparatorsToUnderscores fileName = - intercalate "_" (splitDirectories fileName) - -parseContents :: RawSource -> [LineContents] -parseContents rawSource = - let fileLines = lines $ rawSourceContents rawSource - in map parseFortranLine fileLines - -hasProgramDeclaration :: [LineContents] -> Bool -hasProgramDeclaration parsedContents = case filter f parsedContents of - x : _ -> True - _ -> False - where - f lc = case lc of - ProgramDeclaration -> True - _ -> False - -hasModuleDeclaration :: [LineContents] -> Bool -hasModuleDeclaration parsedContents = case filter f parsedContents of - x : _ -> True - _ -> False - where - f lc = case lc of - ModuleDeclaration{} -> True - _ -> False - -hasSubmoduleDeclaration :: [LineContents] -> Bool -hasSubmoduleDeclaration parsedContents = case filter f parsedContents of - x : _ -> True - _ -> False - where - f lc = case lc of - SubmoduleDeclaration{} -> True - _ -> False - -hasModuleSubprogramDeclaration :: [LineContents] -> Bool -hasModuleSubprogramDeclaration parsedContents = case filter f parsedContents of - x : _ -> True - _ -> False - where - f lc = case lc of - ModuleSubprogramDeclaration -> True - _ -> False - -getModulesUsed :: [LineContents] -> [String] -getModulesUsed = mapMaybe contentToMaybeModuleName - where - contentToMaybeModuleName content = case content of - ModuleUsed moduleName -> Just moduleName - _ -> Nothing - -getModuleName :: [LineContents] -> String -getModuleName pc = head $ mapMaybe contentToMaybeModuleName pc - where - contentToMaybeModuleName content = case content of - ModuleDeclaration moduleName -> Just moduleName - _ -> Nothing - -getSubmoduleBaseModuleName :: [LineContents] -> String -getSubmoduleBaseModuleName pc = head $ mapMaybe contentToMaybeModuleName pc - where - contentToMaybeModuleName content = case content of - SubmoduleDeclaration baseModuleName submoduleParentName submoduleName -> - Just baseModuleName - _ -> Nothing - -getSubmoduleParentName :: [LineContents] -> String -getSubmoduleParentName pc = head $ mapMaybe contentToMaybeModuleName pc - where - contentToMaybeModuleName content = case content of - SubmoduleDeclaration baseModuleName submoduleParentName submoduleName -> - Just submoduleParentName - _ -> Nothing - -getSubmoduleName :: [LineContents] -> String -getSubmoduleName pc = head $ mapMaybe contentToMaybeModuleName pc - where - contentToMaybeModuleName content = case content of - SubmoduleDeclaration baseModuleName submoduleParentName submoduleName -> - Just submoduleName - _ -> Nothing - -readFileLinesIO :: FilePath -> IO [String] -readFileLinesIO file = do - contents <- readFile file - return $ lines contents - -parseFortranLine :: String -> LineContents -parseFortranLine line = - let line' = map toLower line - result = readP_to_S doFortranLineParse line' - in getResult result - where - getResult (_ : (contents, _) : _) = contents - getResult [(contents, _) ] = contents - getResult [] = Other - -doFortranLineParse :: ReadP LineContents -doFortranLineParse = option Other fortranUsefulContents - -fortranUsefulContents :: ReadP LineContents -fortranUsefulContents = - programDeclaration - <|> moduleSubprogramDeclaration - <|> moduleDeclaration - <|> submoduleDeclaration - <|> useStatement - -programDeclaration :: ReadP LineContents -programDeclaration = do - skipSpaces - _ <- string "program" - skipAtLeastOneWhiteSpace - _ <- validIdentifier - return ProgramDeclaration - -moduleDeclaration :: ReadP LineContents -moduleDeclaration = do - skipSpaces - _ <- string "module" - skipAtLeastOneWhiteSpace - moduleName <- validIdentifier - when (moduleName == "procedure") (fail "") - skipSpaceCommentOrEnd - return $ ModuleDeclaration moduleName - -submoduleDeclaration :: ReadP LineContents -submoduleDeclaration = do - skipSpaces - _ <- string "submodule" - parents <- submoduleParents - let parentName = case parents of - (baseModule : []) -> baseModule - (multiple ) -> (head multiple) ++ "@" ++ (last multiple) - skipSpaces - name <- validIdentifier - skipSpaceCommentOrEnd - return $ SubmoduleDeclaration (head parents) parentName name - -submoduleParents :: ReadP [String] -submoduleParents = do - skipSpaces - _ <- char '(' - skipSpaces - firstParent <- validIdentifier - remainingParents <- many - (do - skipSpaces - _ <- char ':' - skipSpaces - name <- validIdentifier - return name - ) - skipSpaces - _ <- char ')' - return $ firstParent : remainingParents - -useStatement :: ReadP LineContents -useStatement = do - skipSpaces - _ <- string "use" - skipAtLeastOneWhiteSpace - modName <- validIdentifier - skipSpaceCommaOrEnd - return $ ModuleUsed modName - -moduleSubprogramDeclaration :: ReadP LineContents -moduleSubprogramDeclaration = do - skipSpaces - skipProcedureQualifiers - _ <- string "module" - skipAtLeastOneWhiteSpace - _ <- string "function" <|> string "subroutine" - skipAtLeastOneWhiteSpace - return $ ModuleSubprogramDeclaration - -skipProcedureQualifiers :: ReadP () -skipProcedureQualifiers = do - many skipPossibleQualifier - return () - -skipPossibleQualifier :: ReadP () -skipPossibleQualifier = do - _ <- string "pure" <|> string "elemental" <|> string "impure" - skipAtLeastOneWhiteSpace - -skipAtLeastOneWhiteSpace :: ReadP () -skipAtLeastOneWhiteSpace = do - _ <- many1 whiteSpace - return () - -skipSpaceOrEnd :: ReadP () -skipSpaceOrEnd = eof <|> skipAtLeastOneWhiteSpace - -skipSpaceCommaOrEnd :: ReadP () -skipSpaceCommaOrEnd = eof <|> skipComma <|> skipAtLeastOneWhiteSpace - -skipSpaceCommentOrEnd :: ReadP () -skipSpaceCommentOrEnd = eof <|> skipComment <|> skipAtLeastOneWhiteSpace - -skipComma :: ReadP () -skipComma = do - _ <- char ',' - return () - -skipComment :: ReadP () -skipComment = do - _ <- char '!' - return () - -skipAnything :: ReadP () -skipAnything = do - _ <- many (satisfy (const True)) - return () - -whiteSpace :: ReadP Char -whiteSpace = satisfy (`elem` " \t") - -validIdentifier :: ReadP String -validIdentifier = do - first <- validFirstCharacter - rest <- many validIdentifierCharacter - return $ first : rest - -validFirstCharacter :: ReadP Char -validFirstCharacter = alphabet - -validIdentifierCharacter :: ReadP Char -validIdentifierCharacter = alphabet <|> digit <|> underscore - -alphabet :: ReadP Char -alphabet = satisfy isAsciiLower - -digit :: ReadP Char -digit = satisfy isDigit - -underscore :: ReadP Char -underscore = char '_' diff --git a/bootstrap/src/Fpm.hs b/bootstrap/src/Fpm.hs deleted file mode 100644 index 56e2d90..0000000 --- a/bootstrap/src/Fpm.hs +++ /dev/null @@ -1,1227 +0,0 @@ -{-# LANGUAGE LambdaCase #-} -{-# LANGUAGE OverloadedStrings #-} - -module Fpm - ( Arguments(..) - , getArguments - , start - ) -where - -import Build ( CompilerSettings(..) - , buildLibrary - , buildProgram - , buildWithScript - ) -import Control.Monad.Extra ( concatMapM - , forM_ - , when - ) -import Data.Hashable ( hash ) -import Data.List ( intercalate - , isInfixOf - , isSuffixOf - , find - , nub - ) -import qualified Data.Map as Map -import qualified Data.Text.IO as TIO -import Development.Shake ( FilePattern - , (<//>) - , getDirectoryFilesIO - ) -import Development.Shake.FilePath ( (</>) - , (<.>) - , exe - , splitDirectories - ) -import Numeric ( showHex ) -import Options.Applicative ( Parser - , (<**>) - , (<|>) - , auto - , command - , execParser - , fullDesc - , header - , help - , helper - , info - , long - , many - , metavar - , option - , optional - , progDesc - , short - , showDefault - , strArgument - , strOption - , subparser - , switch - , value - ) -import System.Directory ( createDirectory - , doesDirectoryExist - , doesFileExist - , makeAbsolute - , withCurrentDirectory - ) -import System.Exit ( ExitCode(..) - , exitWith - ) -import System.Process ( readProcess - , readProcessWithExitCode - , system - ) -import Toml ( TomlCodec - , (.=) - ) -import qualified Toml - -data Arguments = - New - { newName :: String - , newWithExecutable :: Bool - , newWithTest :: Bool - , newWithLib :: Bool - } - | Build - { buildRelease :: Bool - , buildCompiler :: FilePath - , buildFlags :: [String] - } - | Run - { runRelease :: Bool - , runExample :: Bool - , runCompiler :: FilePath - , runFlags :: [String] - , runRunner :: Maybe String - , runTarget :: Maybe String - , runArgs :: Maybe [String] - } - | Test - { testRelease :: Bool - , testCompiler :: FilePath - , testFlags :: [String] - , testRunner :: Maybe String - , testTarget :: Maybe String - , testArgs :: Maybe [String] - } - -data TomlSettings = TomlSettings { - tomlSettingsProjectName :: String - , tomlSettingsLibrary :: (Maybe Library) - , tomlSettingsExecutables :: [Executable] - , tomlSettingsExamples :: [Executable] - , tomlSettingsTests :: [Executable] - , tomlSettingsDependencies :: (Map.Map String Version) - , tomlSettingsDevDependencies :: (Map.Map String Version) -} - -data AppSettings = AppSettings { - appSettingsCompiler :: CompilerSettings - , appSettingsProjectName :: String - , appSettingsBuildPrefix :: String - , appSettingsLibrary :: (Maybe Library) - , appSettingsExecutables :: [Executable] - , appSettingsExamples :: [Executable] - , appSettingsTests :: [Executable] - , appSettingsDependencies :: (Map.Map String Version) - , appSettingsDevDependencies :: (Map.Map String Version) -} - -data Library = Library { librarySourceDir :: String, libraryBuildScript :: Maybe String } - -data Executable = Executable { - executableSourceDir :: String - , executableMainFile :: String - , executableName :: String - , executableDependencies :: (Map.Map String Version) -} deriving Show - -data Version = SimpleVersion String | GitVersion GitVersionSpec | PathVersion PathVersionSpec deriving Show - -data GitVersionSpec = GitVersionSpec { gitVersionSpecUrl :: String, gitVersionSpecRef :: Maybe GitRef } deriving Show - -data GitRef = Tag String | Branch String | Commit String deriving Show - -data PathVersionSpec = PathVersionSpec { pathVersionSpecPath :: String } deriving Show - -data DependencyTree = Dependency { - dependencyName :: String - , dependencyPath :: FilePath - , dependencySourcePath :: FilePath - , dependencyBuildScript :: Maybe String - , dependencyDependencies :: [DependencyTree] -} - -start :: Arguments -> IO () -start args = case args of - New { newName = name, newWithExecutable = withExecutable, newWithTest = withTest, newWithLib = withLib } - -> createNewProject name withExecutable withTest withLib - _ -> do - fpmContents <- TIO.readFile "fpm.toml" - let tomlSettings = Toml.decode settingsCodec fpmContents - case tomlSettings of - Left err -> print err - Right tomlSettings' -> do - appSettings <- toml2AppSettings tomlSettings' args - app args appSettings - -app :: Arguments -> AppSettings -> IO () -app args settings = case args of - Build{} -> build settings - Run { runTarget = whichOne, runArgs = runArgs, runRunner = runner, runExample = runExample } -> do - build settings - let buildPrefix = appSettingsBuildPrefix settings - let - executableNames = if runExample - then - map - (\Executable { executableSourceDir = sourceDir, executableMainFile = mainFile, executableName = name } -> - sourceDir </> name - ) - (appSettingsExamples settings) - else - map - (\Executable { executableSourceDir = sourceDir, executableMainFile = mainFile, executableName = name } -> - sourceDir </> name - ) - (appSettingsExecutables settings) - let executables = - map (buildPrefix </>) $ map (flip (<.>) exe) executableNames - canonicalExecutables <- mapM makeAbsolute executables - case canonicalExecutables of - [] -> putStrLn "No Executables Found" - _ -> - let commandPrefix = case runner of - Nothing -> "" - Just r -> r ++ " " - commandSufix = case runArgs of - Nothing -> "" - Just a -> " " ++ (intercalate " " a) - in case whichOne of - Nothing -> do - exitCodes <- mapM - system - (map (\exe -> commandPrefix ++ exe ++ commandSufix) - canonicalExecutables - ) - forM_ - exitCodes - (\exitCode -> when - (case exitCode of - ExitSuccess -> False - _ -> True - ) - (exitWith exitCode) - ) - Just name -> do - case find (name `isSuffixOf`) canonicalExecutables of - Nothing -> putStrLn "Executable Not Found" - Just specified -> do - exitCode <- system - (commandPrefix ++ specified ++ commandSufix) - exitWith exitCode - Test { testTarget = whichOne, testArgs = testArgs, testRunner = runner } -> - do - build settings - let buildPrefix = appSettingsBuildPrefix settings - let - executableNames = map - (\Executable { executableSourceDir = sourceDir, executableMainFile = mainFile, executableName = name } -> - sourceDir </> name - ) - (appSettingsTests settings) - let executables = - map (buildPrefix </>) $ map (flip (<.>) exe) executableNames - canonicalExecutables <- mapM makeAbsolute executables - case canonicalExecutables of - [] -> putStrLn "No Tests Found" - _ -> - let commandPrefix = case runner of - Nothing -> "" - Just r -> r ++ " " - commandSufix = case testArgs of - Nothing -> "" - Just a -> " " ++ (intercalate " " a) - in case whichOne of - Nothing -> do - exitCodes <- mapM - system - (map (\exe -> commandPrefix ++ exe ++ commandSufix) - canonicalExecutables - ) - forM_ - exitCodes - (\exitCode -> when - (case exitCode of - ExitSuccess -> False - _ -> True - ) - (exitWith exitCode) - ) - Just name -> do - case find (name `isSuffixOf`) canonicalExecutables of - Nothing -> putStrLn "Test Not Found" - Just specified -> do - exitCode <- system - (commandPrefix ++ specified ++ commandSufix) - exitWith exitCode - _ -> putStrLn "Shouldn't be able to get here" - -build :: AppSettings -> IO () -build settings = do - let compilerSettings = appSettingsCompiler settings - let projectName = appSettingsProjectName settings - let buildPrefix = appSettingsBuildPrefix settings - let executables = appSettingsExecutables settings - let examples = appSettingsExamples settings - let tests = appSettingsTests settings - mainDependencyTrees <- fetchDependencies (appSettingsDependencies settings) - builtDependencies <- buildDependencies buildPrefix - compilerSettings - mainDependencyTrees - (executableDepends, maybeTree) <- case appSettingsLibrary settings of - Just librarySettings -> do - let librarySourceDir' = librarySourceDir librarySettings - let thisDependencyTree = Dependency - { dependencyName = projectName - , dependencyPath = "." - , dependencySourcePath = librarySourceDir' - , dependencyBuildScript = libraryBuildScript librarySettings - , dependencyDependencies = mainDependencyTrees - } - thisArchive <- case libraryBuildScript librarySettings of - Just script -> buildWithScript script - "." - (buildPrefix </> projectName) - compilerSettings - projectName - (map fst builtDependencies) - Nothing -> buildLibrary librarySourceDir' - [".f90", ".f", ".F", ".F90", ".f95", ".f03"] - (buildPrefix </> projectName) - compilerSettings - projectName - (map fst builtDependencies) - return - $ ( (buildPrefix </> projectName, thisArchive) : builtDependencies - , Just thisDependencyTree - ) - Nothing -> do - return (builtDependencies, Nothing) - mapM_ - (\Executable { executableSourceDir = sourceDir, executableMainFile = mainFile, executableName = name, executableDependencies = dependencies } -> - do - localDependencies <- - fetchExecutableDependencies maybeTree dependencies - >>= buildDependencies buildPrefix compilerSettings - buildProgram - sourceDir - ((map fst executableDepends) ++ (map fst localDependencies)) - [".f90", ".f", ".F", ".F90", ".f95", ".f03"] - (buildPrefix </> sourceDir) - compilerSettings - name - mainFile - ((map snd executableDepends) ++ (map snd localDependencies)) - ) - executables - devDependencies <- - fetchExecutableDependencies maybeTree (appSettingsDevDependencies settings) - >>= buildDependencies buildPrefix compilerSettings - mapM_ - (\Executable { executableSourceDir = sourceDir, executableMainFile = mainFile, executableName = name, executableDependencies = dependencies } -> - do - localDependencies <- - fetchExecutableDependencies maybeTree dependencies - >>= buildDependencies buildPrefix compilerSettings - buildProgram - sourceDir - ( (map fst executableDepends) - ++ (map fst devDependencies) - ++ (map fst localDependencies) - ) - [".f90", ".f", ".F", ".F90", ".f95", ".f03"] - (buildPrefix </> sourceDir) - compilerSettings - name - mainFile - ( (map snd executableDepends) - ++ (map snd devDependencies) - ++ (map snd localDependencies) - ) - ) - examples - mapM_ - (\Executable { executableSourceDir = sourceDir, executableMainFile = mainFile, executableName = name, executableDependencies = dependencies } -> - do - localDependencies <- - fetchExecutableDependencies maybeTree dependencies - >>= buildDependencies buildPrefix compilerSettings - buildProgram - sourceDir - ( (map fst executableDepends) - ++ (map fst devDependencies) - ++ (map fst localDependencies) - ) - [".f90", ".f", ".F", ".F90", ".f95", ".f03"] - (buildPrefix </> sourceDir) - compilerSettings - name - mainFile - ( (map snd executableDepends) - ++ (map snd devDependencies) - ++ (map snd localDependencies) - ) - ) - tests - -getArguments :: IO Arguments -getArguments = execParser - (info - (arguments <**> helper) - (fullDesc <> progDesc "Work with Fortran projects" <> header - "fpm - A Fortran package manager and build system" - ) - ) - -arguments :: Parser Arguments -arguments = subparser - ( command - "new" - (info (newArguments <**> helper) - (progDesc "Create a new project in a new directory") - ) - <> command - "build" - (info (buildArguments <**> helper) (progDesc "Build the project")) - <> command - "run" - (info (runArguments <**> helper) (progDesc "Run the executable(s)")) - <> command "test" - (info (testArguments <**> helper) (progDesc "Run the test(s)")) - ) - -newArguments :: Parser Arguments -newArguments = - New - <$> strArgument - ( metavar "NAME" - <> help "Name of new project (must be a valid Fortran identifier)" - ) - <*> switch (long "app" <> help "Include an executable") - <*> switch (long "test" <> help "Include a test") - <*> switch (long "lib" <> help "Include a library") - -buildArguments :: Parser Arguments -buildArguments = - Build - <$> switch - ( long "release" - <> help "Build with optimizations instead of debugging" - ) - <*> strOption - ( long "compiler" - <> metavar "COMPILER" - <> value "gfortran" - <> help "specify the compiler to use" - <> showDefault - ) - <*> many - (strOption - ( long "flag" - <> metavar "FLAG" - <> help - "specify an addional argument to pass to the compiler (can appear multiple times)" - ) - ) - -runArguments :: Parser Arguments -runArguments = - Run - <$> switch - ( long "release" - <> help "Build with optimizations instead of debugging" - ) - <*> switch - ( long "example" - <> help "Run example programs instead of applications" - ) - <*> strOption - ( long "compiler" - <> metavar "COMPILER" - <> value "gfortran" - <> help "specify the compiler to use" - <> showDefault - ) - <*> many - (strOption - ( long "flag" - <> metavar "FLAG" - <> help - "specify an addional argument to pass to the compiler (can appear multiple times)" - ) - ) - <*> optional - (strOption - (long "runner" <> metavar "RUNNER" <> help - "specify a command to be used to run the executable(s)" - ) - ) - <*> optional - (strOption - (long "target" <> metavar "TARGET" <> help - "Name of the executable to run" - ) - ) - <*> optional - (many - (strArgument - ( metavar "ARGS" - <> help "Arguments to the executable(s) (should follow '--')" - ) - ) - ) - -testArguments :: Parser Arguments -testArguments = - Test - <$> switch - ( long "release" - <> help "Build with optimizations instead of debugging" - ) - <*> strOption - ( long "compiler" - <> metavar "COMPILER" - <> value "gfortran" - <> help "specify the compiler to use" - <> showDefault - ) - <*> many - (strOption - ( long "flag" - <> metavar "FLAG" - <> help - "specify an addional argument to pass to the compiler (can appear multiple times)" - ) - ) - <*> optional - (strOption - (long "runner" <> metavar "RUNNER" <> help - "specify a command to be used to run the test(s)" - ) - ) - <*> optional - (strOption - (long "target" <> metavar "TARGET" <> help "Name of the test to run" - ) - ) - <*> optional - (many - (strArgument - ( metavar "ARGS" - <> help "Arguments to the test(s) (should follow '--')" - ) - ) - ) - -getDirectoriesFiles :: [FilePath] -> [FilePattern] -> IO [FilePath] -getDirectoriesFiles dirs exts = getDirectoryFilesIO "" newPatterns - where - newPatterns = concatMap appendExts dirs - appendExts dir = map ((dir <//> "*") ++) exts - -settingsCodec :: TomlCodec TomlSettings -settingsCodec = - TomlSettings - <$> Toml.string "name" - .= tomlSettingsProjectName - <*> Toml.dioptional (Toml.table libraryCodec "library") - .= tomlSettingsLibrary - <*> Toml.list executableCodec "executable" - .= tomlSettingsExecutables - <*> Toml.list executableCodec "example" - .= tomlSettingsExamples - <*> Toml.list executableCodec "test" - .= tomlSettingsTests - <*> Toml.tableMap Toml._KeyString versionCodec "dependencies" - .= tomlSettingsDependencies - <*> Toml.tableMap Toml._KeyString versionCodec "dev-dependencies" - .= tomlSettingsDevDependencies - -libraryCodec :: TomlCodec Library -libraryCodec = - Library - <$> Toml.string "source-dir" - .= librarySourceDir - <*> Toml.dioptional (Toml.string "build-script") - .= libraryBuildScript - -executableCodec :: TomlCodec Executable -executableCodec = - Executable - <$> Toml.string "source-dir" - .= executableSourceDir - <*> Toml.string "main" - .= executableMainFile - <*> Toml.string "name" - .= executableName - <*> Toml.tableMap Toml._KeyString versionCodec "dependencies" - .= executableDependencies - -matchSimpleVersion :: Version -> Maybe String -matchSimpleVersion = \case - SimpleVersion v -> Just v - _ -> Nothing - -matchGitVersion :: Version -> Maybe GitVersionSpec -matchGitVersion = \case - GitVersion v -> Just v - _ -> Nothing - -matchPathVersion :: Version -> Maybe PathVersionSpec -matchPathVersion = \case - PathVersion v -> Just v - _ -> Nothing - -matchTag :: GitRef -> Maybe String -matchTag = \case - Tag v -> Just v - _ -> Nothing - -matchBranch :: GitRef -> Maybe String -matchBranch = \case - Branch v -> Just v - _ -> Nothing - -matchCommit :: GitRef -> Maybe String -matchCommit = \case - Commit v -> Just v - _ -> Nothing - -versionCodec :: Toml.Key -> Toml.TomlCodec Version -versionCodec key = - Toml.dimatch matchSimpleVersion SimpleVersion (Toml.string key) - <|> Toml.dimatch matchGitVersion GitVersion (Toml.table gitVersionCodec key) - <|> Toml.dimatch matchPathVersion - PathVersion - (Toml.table pathVersionCodec key) - -gitVersionCodec :: Toml.TomlCodec GitVersionSpec -gitVersionCodec = - GitVersionSpec - <$> Toml.string "git" - .= gitVersionSpecUrl - <*> Toml.dioptional gitRefCodec - .= gitVersionSpecRef - -gitRefCodec :: Toml.TomlCodec GitRef -gitRefCodec = - Toml.dimatch matchTag Tag (Toml.string "tag") - <|> Toml.dimatch matchBranch Branch (Toml.string "branch") - <|> Toml.dimatch matchCommit Commit (Toml.string "rev") - -pathVersionCodec :: Toml.TomlCodec PathVersionSpec -pathVersionCodec = - PathVersionSpec <$> Toml.string "path" .= pathVersionSpecPath - -toml2AppSettings :: TomlSettings -> Arguments -> IO AppSettings -toml2AppSettings tomlSettings args = do - let release = case args of - Build { buildRelease = r } -> r - Run { runRelease = r } -> r - Test { testRelease = r } -> r - let projectName = tomlSettingsProjectName tomlSettings - let compiler = case args of - Build { buildCompiler = c } -> c - Run { runCompiler = c } -> c - Test { testCompiler = c } -> c - let specifiedFlags = case args of - Build { buildFlags = f } -> f - Run { runFlags = f } -> f - Test { testFlags = f } -> f - when (release && (length specifiedFlags > 0)) $ do - putStrLn "--release and --flag are mutually exclusive" - exitWith (ExitFailure 1) - librarySettings <- getLibrarySettings $ tomlSettingsLibrary tomlSettings - executableSettings <- getExecutableSettings - (tomlSettingsExecutables tomlSettings) - projectName - exampleSettings <- getExampleSettings $ tomlSettingsExamples tomlSettings - testSettings <- getTestSettings $ tomlSettingsTests tomlSettings - compilerSettings <- defineCompilerSettings specifiedFlags compiler release - buildPrefix <- makeBuildPrefix (compilerSettingsCompiler compilerSettings) - (compilerSettingsFlags compilerSettings) - let dependencies = tomlSettingsDependencies tomlSettings - let devDependencies = tomlSettingsDevDependencies tomlSettings - return AppSettings { appSettingsCompiler = compilerSettings - , appSettingsProjectName = projectName - , appSettingsBuildPrefix = buildPrefix - , appSettingsLibrary = librarySettings - , appSettingsExecutables = executableSettings - , appSettingsExamples = exampleSettings - , appSettingsTests = testSettings - , appSettingsDependencies = dependencies - , appSettingsDevDependencies = devDependencies - } - -defineCompilerSettings :: [String] -> FilePath -> Bool -> IO CompilerSettings -defineCompilerSettings specifiedFlags compiler release - | "gfortran" `isInfixOf` compiler - = let flags = case specifiedFlags of - [] -> if release - then - [ "-Wall" - , "-Wextra" - , "-Wimplicit-interface" - , "-fPIC" - , "-fmax-errors=1" - , "-O3" - , "-march=native" - , "-funroll-loops" - , "-fcoarray=single" - ] - else - [ "-Wall" - , "-Wextra" - , "-Wimplicit-interface" - , "-fPIC" - , "-fmax-errors=1" - , "-g" - , "-fbounds-check" - , "-fcheck-array-temporaries" - , "-fbacktrace" - , "-fcoarray=single" - ] - fs -> fs - in return $ CompilerSettings { compilerSettingsCompiler = compiler - , compilerSettingsFlags = flags - , compilerSettingsModuleFlag = "-J" - , compilerSettingsIncludeFlag = "-I" - } - | "caf" `isInfixOf` compiler - = let flags = case specifiedFlags of - [] -> if release - then - [ "-Wall" - , "-Wextra" - , "-Wimplicit-interface" - , "-fPIC" - , "-fmax-errors=1" - , "-O3" - , "-march=native" - , "-funroll-loops" - ] - else - [ "-Wall" - , "-Wextra" - , "-Wimplicit-interface" - , "-fPIC" - , "-fmax-errors=1" - , "-g" - , "-fbounds-check" - , "-fcheck-array-temporaries" - , "-fbacktrace" - ] - fs -> fs - in return $ CompilerSettings { compilerSettingsCompiler = compiler - , compilerSettingsFlags = flags - , compilerSettingsModuleFlag = "-J" - , compilerSettingsIncludeFlag = "-I" - } - | "f95" `isInfixOf` compiler - = let flags = case specifiedFlags of - [] -> if release - then - [ "-O3" - , "-Wimplicit-interface" - , "-fPIC" - , "-fmax-errors=1" - , "-funroll-loops" - ] - else - [ "-Wall" - , "-Wextra" - , "-Wimplicit-interface" - , "-fPIC" - , "-fmax-errors=1" - , "-g" - , "-fbounds-check" - , "-fcheck-array-temporaries" - , "-Wno-maybe-uninitialized" - , "-Wno-uninitialized" - , "-fbacktrace" - ] - fs -> fs - in return $ CompilerSettings { compilerSettingsCompiler = compiler - , compilerSettingsFlags = flags - , compilerSettingsModuleFlag = "-J" - , compilerSettingsIncludeFlag = "-I" - } - | "nvfortran" `isInfixOf` compiler - = let flags = case specifiedFlags of - [] -> if release - then - [ "-Mbackslash" - ] - else - [ "-Minform=inform" - , "-Mbackslash" - , "-g" - , "-Mbounds" - , "-Mchkptr" - , "-Mchkstk" - , "-traceback" - ] - fs -> fs - in return $ CompilerSettings { compilerSettingsCompiler = compiler - , compilerSettingsFlags = flags - , compilerSettingsModuleFlag = "-module" - , compilerSettingsIncludeFlag = "-I" - } - | "ifort" `isInfixOf` compiler - = let flags = case specifiedFlags of - [] -> if release - then - [ "-fp-model", "precise" - , "-pc", "64" - , "-align", "all" - , "-error-limit", "1" - , "-reentrancy", "threaded" - , "-nogen-interfaces" - , "-assume", "byterecl" - , "-assume", "nounderscore" - ] - else - [ "-warn", "all" - , "-check:all:noarg_temp_created" - , "-error-limit", "1" - , "-O0" - , "-g" - , "-assume", "byterecl" - , "-traceback" - ] - fs -> fs - in return $ CompilerSettings { compilerSettingsCompiler = compiler - , compilerSettingsFlags = flags - , compilerSettingsModuleFlag = "-module" - , compilerSettingsIncludeFlag = "-I" - } - | "ifx" `isInfixOf` compiler - = let flags = case specifiedFlags of - [] -> if release - then - [] - else - [] - fs -> fs - in return $ CompilerSettings { compilerSettingsCompiler = compiler - , compilerSettingsFlags = flags - , compilerSettingsModuleFlag = "-module" - , compilerSettingsIncludeFlag = "-I" - } - | "pgfortran" `isInfixOf` compiler || "pgf90" `isInfixOf` compiler || "pgf95" `isInfixOf` compiler - = let flags = case specifiedFlags of - [] -> if release - then - [] - else - [] - fs -> fs - in return $ CompilerSettings { compilerSettingsCompiler = compiler - , compilerSettingsFlags = flags - , compilerSettingsModuleFlag = "-module" - , compilerSettingsIncludeFlag = "-I" - } - | "flang" `isInfixOf` compiler - = let flags = case specifiedFlags of - [] -> if release - then - [] - else - [] - fs -> fs - in return $ CompilerSettings { compilerSettingsCompiler = compiler - , compilerSettingsFlags = flags - , compilerSettingsModuleFlag = "-module" - , compilerSettingsIncludeFlag = "-I" - } - | "lfc" `isInfixOf` compiler - = let flags = case specifiedFlags of - [] -> if release - then - [] - else - [] - fs -> fs - in return $ CompilerSettings { compilerSettingsCompiler = compiler - , compilerSettingsFlags = flags - , compilerSettingsModuleFlag = "-M" - , compilerSettingsIncludeFlag = "-I" - } - | "nagfor" `isInfixOf` compiler - = let flags = case specifiedFlags of - [] -> if release - then - [ "-O4" - , "-coarray=single" - , "-PIC" - ] - else - [ "-g" - , "-C=all" - , "-O0" - , "-gline" - , "-coarray=single" - , "-PIC" - ] - fs -> fs - in return $ CompilerSettings { compilerSettingsCompiler = compiler - , compilerSettingsFlags = flags - , compilerSettingsModuleFlag = "-mdir" - , compilerSettingsIncludeFlag = "-I" - } - | "crayftn" `isInfixOf` compiler - = let flags = case specifiedFlags of - [] -> if release - then - [] - else - [] - fs -> fs - in return $ CompilerSettings { compilerSettingsCompiler = compiler - , compilerSettingsFlags = flags - , compilerSettingsModuleFlag = "-J" - , compilerSettingsIncludeFlag = "-I" - } - | "xlf90" `isInfixOf` compiler - = let flags = case specifiedFlags of - [] -> if release - then - [] - else - [] - fs -> fs - in return $ CompilerSettings { compilerSettingsCompiler = compiler - , compilerSettingsFlags = flags - , compilerSettingsModuleFlag = "-qmoddir" - , compilerSettingsIncludeFlag = "-I" - } - | otherwise - = do - putStrLn $ "Sorry, compiler is currently unsupported: " ++ compiler - exitWith (ExitFailure 1) - -getLibrarySettings :: Maybe Library -> IO (Maybe Library) -getLibrarySettings maybeSettings = case maybeSettings of - Just settings -> return maybeSettings - Nothing -> do - defaultExists <- doesDirectoryExist "src" - if defaultExists - then return - (Just - (Library { librarySourceDir = "src", libraryBuildScript = Nothing }) - ) - else return Nothing - -getExecutableSettings :: [Executable] -> String -> IO [Executable] -getExecutableSettings [] projectName = do - defaultDirectoryExists <- doesDirectoryExist "app" - if defaultDirectoryExists - then do - defaultMainExists <- doesFileExist ("app" </> "main.f90") - if defaultMainExists - then return - [ Executable { executableSourceDir = "app" - , executableMainFile = "main.f90" - , executableName = projectName - , executableDependencies = Map.empty - } - ] - else return [] - else return [] -getExecutableSettings executables _ = return executables - -getExampleSettings :: [Executable] -> IO [Executable] -getExampleSettings [] = do - defaultDirectoryExists <- doesDirectoryExist "example" - if defaultDirectoryExists - then do - defaultMainExists <- doesFileExist ("example" </> "main.f90") - if defaultMainExists - then return - [ Executable { executableSourceDir = "example" - , executableMainFile = "main.f90" - , executableName = "demo" - , executableDependencies = Map.empty - } - ] - else return [] - else return [] -getExampleSettings examples = return examples - -getTestSettings :: [Executable] -> IO [Executable] -getTestSettings [] = do - defaultDirectoryExists <- doesDirectoryExist "test" - if defaultDirectoryExists - then do - defaultMainExists <- doesFileExist ("test" </> "main.f90") - if defaultMainExists - then return - [ Executable { executableSourceDir = "test" - , executableMainFile = "main.f90" - , executableName = "runTests" - , executableDependencies = Map.empty - } - ] - else return [] - else return [] -getTestSettings tests = return tests - -makeBuildPrefix :: FilePath -> [String] -> IO FilePath -makeBuildPrefix compiler flags = do - -- TODO Figure out what other info should be part of this - -- Probably version, and make sure to not include path to the compiler - versionInfo <- do - (exitCode, stdout, stderr) <- readProcessWithExitCode compiler - ["--version"] - [] - case exitCode of - ExitSuccess -> case stdout of - "" -> return stderr -- Guess this compiler outputs version info to stderr instead? - _ -> return stdout - _ -> do -- guess this compiler doesn't support the --version option. let's try -version - (exitCode, stdout, stderr) <- readProcessWithExitCode compiler - ["-version"] - [] - case exitCode of - ExitSuccess -> case stdout of - "" -> return stderr -- Guess this compiler outputs version info to stderr instead? - _ -> return stdout - _ -> return "" -- Don't know how to get version info, we'll let defineCompilerSettings report it as unsupported - let compilerName = last (splitDirectories compiler) - let versionHash = abs (hash versionInfo) - let flagsHash = abs (hash flags) - return - $ "build" - </> compilerName - ++ "_" - ++ showHex versionHash "" - ++ "_" - ++ showHex flagsHash "" - -{- - Fetching the dependencies is done on a sort of breadth first approach. All - of the dependencies are fetched before doing the transitive dependencies. - This means that the top level dependencies dictate which version is fetched. - The fetchDependency function is idempotent, so we don't have to worry about - dealing with half fetched, or adding dependencies. - TODO check for version compatibility issues --} -fetchDependencies :: Map.Map String Version -> IO [DependencyTree] -fetchDependencies dependencies = do - theseDependencies <- mapM (uncurry fetchDependency) (Map.toList dependencies) - mapM fetchTransitiveDependencies theseDependencies - where - fetchTransitiveDependencies :: (String, FilePath) -> IO DependencyTree - fetchTransitiveDependencies (name, path) = do - tomlSettings <- Toml.decodeFile settingsCodec (path </> "fpm.toml") - librarySettingsM <- withCurrentDirectory path - $ getLibrarySettings (tomlSettingsLibrary tomlSettings) - case librarySettingsM of - Just librarySettings -> do - newDependencies <- fetchDependencies - (tomlSettingsDependencies tomlSettings) - return $ Dependency - { dependencyName = name - , dependencyPath = path - , dependencySourcePath = path </> (librarySourceDir librarySettings) - , dependencyBuildScript = libraryBuildScript librarySettings - , dependencyDependencies = newDependencies - } - Nothing -> do - putStrLn $ "No library found in " ++ name - undefined - -fetchExecutableDependencies - :: (Maybe DependencyTree) -> Map.Map String Version -> IO [DependencyTree] -fetchExecutableDependencies maybeProjectTree dependencies = - case maybeProjectTree of - Just projectTree@(Dependency name _ _ _ _) -> - if name `Map.member` dependencies {- map contains this project-} - then fmap (projectTree :) - (fetchDependencies (Map.delete name dependencies)) {- fetch the other dependencies and include the project tree in the result -} - else do {- fetch all the dependencies, passing the project tree on down -} - theseDependencies <- mapM (uncurry fetchDependency) - (Map.toList dependencies) - mapM fetchTransitiveDependencies theseDependencies - Nothing -> fetchDependencies dependencies - where - fetchTransitiveDependencies :: (String, FilePath) -> IO DependencyTree - fetchTransitiveDependencies (name, path) = do - tomlSettings <- Toml.decodeFile settingsCodec (path </> "fpm.toml") - librarySettingsM <- withCurrentDirectory path - $ getLibrarySettings (tomlSettingsLibrary tomlSettings) - case librarySettingsM of - Just librarySettings -> do - newDependencies <- fetchExecutableDependencies - maybeProjectTree - (tomlSettingsDependencies tomlSettings) - return $ Dependency - { dependencyName = name - , dependencyPath = path - , dependencySourcePath = path </> (librarySourceDir librarySettings) - , dependencyBuildScript = libraryBuildScript librarySettings - , dependencyDependencies = newDependencies - } - Nothing -> do - putStrLn $ "No library found in " ++ name - undefined - -fetchDependency :: String -> Version -> IO (String, FilePath) -fetchDependency name version = do - let clonePath = "build" </> "dependencies" </> name - alreadyFetched <- doesDirectoryExist clonePath - if alreadyFetched - then return (name, clonePath) - else case version of - SimpleVersion _ -> do - putStrLn "Simple dependencies are not yet supported :(" - undefined - GitVersion versionSpec -> do - system ("git init " ++ clonePath) - case gitVersionSpecRef versionSpec of - Just ref -> do - system - ( "git -C " - ++ clonePath - ++ " fetch " - ++ gitVersionSpecUrl versionSpec - ++ " " - ++ (case ref of - Tag tag -> tag - Branch branch -> branch - Commit commit -> commit - ) - ) - Nothing -> do - system - ( "git -C " - ++ clonePath - ++ " fetch " - ++ gitVersionSpecUrl versionSpec - ) - system ("git -C " ++ clonePath ++ " checkout -qf FETCH_HEAD") - return (name, clonePath) - PathVersion versionSpec -> return (name, pathVersionSpecPath versionSpec) - -{- - Bulding the dependencies is done on a depth first basis to ensure all of - the transitive dependencies have been built before trying to build this one --} -buildDependencies - :: String -> CompilerSettings -> [DependencyTree] -> IO [(FilePath, FilePath)] -buildDependencies buildPrefix compilerSettings dependencies = do - built <- concatMapM (buildDependency buildPrefix compilerSettings) - dependencies - return $ reverse (nub (reverse built)) - -buildDependency - :: String -> CompilerSettings -> DependencyTree -> IO [(FilePath, FilePath)] -buildDependency buildPrefix compilerSettings (Dependency name path sourcePath mBuildScript dependencies) - = do - transitiveDependencies <- buildDependencies buildPrefix - compilerSettings - dependencies - let buildPath = buildPrefix </> name - thisArchive <- case mBuildScript of - Just script -> buildWithScript script - path - buildPath - compilerSettings - name - (map fst transitiveDependencies) - Nothing -> buildLibrary sourcePath - [".f90", ".f", ".F", ".F90", ".f95", ".f03"] - buildPath - compilerSettings - name - (map fst transitiveDependencies) - return $ (buildPath, thisArchive) : transitiveDependencies - -createNewProject :: String -> Bool -> Bool -> Bool -> IO () -createNewProject projectName withExecutable withTest withLib = do - createDirectory projectName - writeFile (projectName </> "fpm.toml") (templateFpmToml projectName) - writeFile (projectName </> "README.md") (templateReadme projectName) - writeFile (projectName </> ".gitignore") "build/*\n" - when withLib $ do - createDirectory (projectName </> "src") - writeFile (projectName </> "src" </> projectName <.> "f90") - (templateModule projectName) - when withExecutable $ do - createDirectory (projectName </> "app") - writeFile (projectName </> "app" </> "main.f90") - (templateProgram projectName withLib) - when withTest $ do - createDirectory (projectName </> "test") - writeFile (projectName </> "test" </> "main.f90") templateTest - withCurrentDirectory projectName $ do - system "git init" - return () - -templateFpmToml :: String -> String -templateFpmToml projectName = - "name = \"" - ++ projectName - ++ "\"\n" - ++ "version = \"0.1.0\"\n" - ++ "license = \"license\"\n" - ++ "author = \"Jane Doe\"\n" - ++ "maintainer = \"jane.doe@example.com\"\n" - ++ "copyright = \"2020 Jane Doe\"\n" - -templateModule :: String -> String -templateModule projectName = - "module " - ++ projectName - ++ "\n" - ++ " implicit none\n" - ++ " private\n" - ++ "\n" - ++ " public :: say_hello\n" - ++ "contains\n" - ++ " subroutine say_hello\n" - ++ " print *, \"Hello, " - ++ projectName - ++ "!\"\n" - ++ " end subroutine say_hello\n" - ++ "end module " - ++ projectName - ++ "\n" - -templateReadme :: String -> String -templateReadme projectName = - "# " ++ projectName ++ "\n" ++ "\n" ++ "My cool new project!\n" - -templateProgram :: String -> Bool -> String -templateProgram projectName withLib = - "program main\n" - ++ (if withLib then " use " ++ projectName ++ ", only: say_hello\n" else "" - ) - ++ "\n" - ++ " implicit none\n" - ++ "\n" - ++ " call say_hello\n" - ++ "end program main\n" - -templateTest :: String -templateTest = - "program main\n" - ++ " implicit none\n" - ++ "\n" - ++ " print *, \"Put some tests in here!\"\n" - ++ "end program main\n" diff --git a/bootstrap/stack.yaml b/bootstrap/stack.yaml deleted file mode 100644 index 7147c40..0000000 --- a/bootstrap/stack.yaml +++ /dev/null @@ -1,74 +0,0 @@ -# This file was automatically generated by 'stack init' -# -# Some commonly used options have been documented as comments in this file. -# For advanced use and comprehensive documentation of the format, please see: -# https://docs.haskellstack.org/en/stable/yaml_configuration/ - -# Resolver to choose a 'specific' stackage snapshot or a compiler version. -# A snapshot resolver dictates the compiler version and the set of packages -# to be used for project dependencies. For example: -# -# resolver: lts-3.5 -# resolver: nightly-2015-09-21 -# resolver: ghc-7.10.2 -# -# The location of a snapshot can be provided as a file or url. Stack assumes -# a snapshot provided as a file might change, whereas a url resource does not. -# -# resolver: ./custom-snapshot.yaml -# resolver: https://example.com/snapshots/2018-01-01.yaml -resolver: lts-14.27 - -# User packages to be built. -# Various formats can be used as shown in the example below. -# -# packages: -# - some-directory -# - https://example.com/foo/bar/baz-0.0.2.tar.gz -# subdirs: -# - auto-update -# - wai -packages: -- . -# Dependency packages to be pulled from upstream that are not in the resolver. -# These entries can reference officially published versions as well as -# forks / in-progress versions pinned to a git hash. For example: -# -# extra-deps: -# - acme-missiles-0.3 -# - git: https://github.com/commercialhaskell/stack.git -# commit: e7b331f14bcffb8367cd58fbfc8b40ec7642100a -# -extra-deps: -- git: https://github.com/kowainik/tomland.git - commit: 536a5e6ffb148d0dd4e4c4b120913a6744097676 -- git: https://gitlab.com/everythingfunctional/hedge.git - commit: 1c6cba3b5f8e52cf317f2421aaca13a0ddab4e92 - subdirs: - - . - - hedge-trimmer -- quickcheck-with-counterexamples-1.2 - -# Override default flag values for local packages and extra-deps -# flags: {} - -# Extra package databases containing global packages -# extra-package-dbs: [] - -# Control whether we use the GHC we find on the path -# system-ghc: true -# -# Require a specific version of stack, using version ranges -# require-stack-version: -any # Default -# require-stack-version: ">=2.1" -# -# Override the architecture used by stack, especially useful on Windows -# arch: i386 -# arch: x86_64 -# -# Extra directories used by stack for building -# extra-include-dirs: [/path/to/dir] -# extra-lib-dirs: [/path/to/dir] -# -# Allow a newer minor version of GHC than the snapshot specifies -# compiler-check: newer-minor diff --git a/bootstrap/stack.yaml.lock b/bootstrap/stack.yaml.lock deleted file mode 100644 index 0ca18ae..0000000 --- a/bootstrap/stack.yaml.lock +++ /dev/null @@ -1,43 +0,0 @@ -# This file was autogenerated by Stack. -# You should not edit this file by hand. -# For more information, please see the documentation at: -# https://docs.haskellstack.org/en/stable/lock_files - -packages: -- completed: - name: tomland - version: 1.3.0.0 - git: https://github.com/kowainik/tomland.git - pantry-tree: - size: 5000 - sha256: 68d6f9a3e4c20cc4645374b30000017a75c4ab1c131590538edad2ea0e4a53bd - commit: 536a5e6ffb148d0dd4e4c4b120913a6744097676 - original: - git: https://github.com/kowainik/tomland.git - commit: 536a5e6ffb148d0dd4e4c4b120913a6744097676 -- completed: - subdir: hedge-trimmer - name: hedge-trimmer - version: 1.0.0.0 - git: https://gitlab.com/everythingfunctional/hedge.git - pantry-tree: - size: 226 - sha256: 19972f5b81c7627d6b66c852dfb7e0e67b3931ed4f418663c152717ce4ea267e - commit: 1c6cba3b5f8e52cf317f2421aaca13a0ddab4e92 - original: - subdir: hedge-trimmer - git: https://gitlab.com/everythingfunctional/hedge.git - commit: 1c6cba3b5f8e52cf317f2421aaca13a0ddab4e92 -- completed: - hackage: quickcheck-with-counterexamples-1.2@sha256:d322d79008602df26f5eb4e1379e5b58bf1a92604df8601e71e200cfc3e847a3,1688 - pantry-tree: - size: 724 - sha256: 0046517e3cc2adebfce19d4aad05a06dcf55ec9e572fa1c661ba9abe81386484 - original: - hackage: quickcheck-with-counterexamples-1.2 -snapshots: -- completed: - size: 524996 - url: https://raw.githubusercontent.com/commercialhaskell/stackage-snapshots/master/lts/14/27.yaml - sha256: 7ea31a280c56bf36ff591a7397cc384d0dff622e7f9e4225b47d8980f019a0f0 - original: lts-14.27 diff --git a/bootstrap/test/Spec.hs b/bootstrap/test/Spec.hs deleted file mode 100644 index 6e9daa2..0000000 --- a/bootstrap/test/Spec.hs +++ /dev/null @@ -1,103 +0,0 @@ -import Development.Shake.FilePath ( (</>) ) -import Fpm ( Arguments(..) - , start - ) -import System.Directory ( withCurrentDirectory ) - -example_path = "test" </> "example_packages" - -main :: IO () -main = do - testHelloWorld - testHelloComplex - testHelloFpm - testCircular - testWithMakefile - testMakefileComplex - testSubmodule - -testHelloWorld :: IO () -testHelloWorld = - withCurrentDirectory (example_path </> "hello_world") $ start $ Run - { runRelease = False - , runExample = False - , runCompiler = "gfortran" - , runFlags = [] - , runRunner = Nothing - , runTarget = Nothing - , runArgs = Nothing - } - -testHelloComplex :: IO () -testHelloComplex = - withCurrentDirectory (example_path </> "hello_complex") $ start $ Test - { testRelease = False - , testCompiler = "gfortran" - , testFlags = [] - , testRunner = Nothing - , testTarget = Nothing - , testArgs = Nothing - } - -testHelloFpm :: IO () -testHelloFpm = - withCurrentDirectory (example_path </> "hello_fpm") $ start $ Run - { runRelease = False - , runExample = False - , runCompiler = "gfortran" - , runFlags = [] - , runRunner = Nothing - , runTarget = Nothing - , runArgs = Nothing - } - -testWithExamples :: IO () -testWithExamples = - withCurrentDirectory (example_path </> "with_examples") $ start $ Run - { runRelease = False - , runExample = True - , runCompiler = "gfortran" - , runFlags = [] - , runRunner = Nothing - , runTarget = Nothing - , runArgs = Nothing - } - -testCircular :: IO () -testCircular = - withCurrentDirectory (example_path </> "circular_example") $ start $ Test - { testRelease = False - , testCompiler = "gfortran" - , testFlags = [] - , testRunner = Nothing - , testTarget = Nothing - , testArgs = Nothing - } - -testWithMakefile :: IO () -testWithMakefile = - withCurrentDirectory (example_path </> "with_makefile") $ start $ Build - { buildRelease = False - , buildCompiler = "gfortran" - , buildFlags = [] - } - -testMakefileComplex :: IO () -testMakefileComplex = - withCurrentDirectory (example_path </> "makefile_complex") $ start $ Run - { runRelease = False - , runExample = False - , runCompiler = "gfortran" - , runFlags = [] - , runRunner = Nothing - , runTarget = Nothing - , runArgs = Nothing - } - -testSubmodule :: IO () -testSubmodule = - withCurrentDirectory (example_path </> "submodules") $ start $ Build - { buildRelease = False - , buildCompiler = "gfortran" - , buildFlags = [] - } diff --git a/bootstrap/test/example_packages b/bootstrap/test/example_packages deleted file mode 120000 index b7c12dc..0000000 --- a/bootstrap/test/example_packages +++ /dev/null @@ -1 +0,0 @@ -../../example_packages
\ No newline at end of file diff --git a/bootstrap/unit_test/ModuleSourceConstructionTest.hs b/bootstrap/unit_test/ModuleSourceConstructionTest.hs deleted file mode 100644 index b98e9d3..0000000 --- a/bootstrap/unit_test/ModuleSourceConstructionTest.hs +++ /dev/null @@ -1,83 +0,0 @@ -module ModuleSourceConstructionTest - ( test - ) -where - -import BuildModel ( RawSource(..) - , Source(..) - , processRawSource - ) -import Hedge ( Result - , Test - , assertEquals - , assertThat - , fail' - , givenInput - , then' - , whenTransformed - ) -import System.FilePath ( (</>) ) - -test :: IO (Test ()) -test = return $ givenInput - "a module" - exampleModule - [ whenTransformed - "processed to a source" - processRawSource - [ then' "it is a Module" checkIsModule - , then' "its source file name is the same as the original" - checkModuleSourceFileName - , then' - "its object file name is the 'flattened' path of the source file with '.o' appeneded" - checkModuleObjectFileName - , then' "it knows what modules it uses directly" checkModuleModulesUsed - , then' "it knows its name" checkModuleName - , then' "it can tell that it will produce a '.smod' file" checkSmod - ] - ] - -exampleModule :: RawSource -exampleModule = RawSource moduleSourceFileName' $ unlines - [ "module some_module" - , " use module1" - , " USE MODULE2" - , " implicit none" - , " interface" - , " pure module function some_func()" - , " integer :: some_func" - , " end function" - , " end interface" - , "end module" - ] - -moduleSourceFileName' :: String -moduleSourceFileName' = "some" </> "file" </> "somewhere.f90" - -checkIsModule :: Source -> Result -checkIsModule Module{} = assertThat True -checkIsModule _ = assertThat False - -checkModuleSourceFileName :: Source -> Result -checkModuleSourceFileName m@(Module{}) = - assertEquals moduleSourceFileName' $ moduleSourceFileName m -checkModuleSourceFileName _ = fail' "wasn't a Module" - -checkModuleObjectFileName :: Source -> Result -checkModuleObjectFileName m@(Module{}) = - assertEquals ("." </> "some_file_somewhere.f90.o") - $ (moduleObjectFileName m) "." -checkModuleObjectFileName _ = fail' "wasn't a Module" - -checkModuleModulesUsed :: Source -> Result -checkModuleModulesUsed m@(Module{}) = - assertEquals ["module1", "module2"] $ moduleModulesUsed m -checkModuleModulesUsed _ = fail' "wasn't a Module" - -checkModuleName :: Source -> Result -checkModuleName m@(Module{}) = assertEquals "some_module" $ moduleName m -checkModuleName _ = fail' "wasn't a Module" - -checkSmod :: Source -> Result -checkSmod m@(Module{}) = assertThat $ moduleProducesSmod m -checkSmod _ = fail' "wasn't a Module" diff --git a/bootstrap/unit_test/ModuleToCompileInfoTest.hs b/bootstrap/unit_test/ModuleToCompileInfoTest.hs deleted file mode 100644 index 08cd67c..0000000 --- a/bootstrap/unit_test/ModuleToCompileInfoTest.hs +++ /dev/null @@ -1,73 +0,0 @@ -module ModuleToCompileInfoTest - ( test - ) -where - -import BuildModel ( AvailableModule(..) - , CompileTimeInfo(..) - , Source(..) - , constructCompileTimeInfo - ) -import Hedge ( Result - , Test - , assertEquals - , givenInput - , then' - , whenTransformed - ) -import System.FilePath ( (</>) ) - -test :: IO (Test ()) -test = return $ givenInput - "a module and available modules" - (exampleModule, availableModules) - [ whenTransformed - "its compileTimeInfo is determined" - doCompileTimeTransformation - [ then' "it stil knows the original source file" checkSourceFileName - , then' "it knows what object file will be produced" checkObjectFileName - , then' "the mod and smod files are also produced" checkOtherFilesProduced - , then' "the direct dependencies are only the available modules used" - checkDirectDependencies - ] - ] - -exampleModule :: Source -exampleModule = Module - { moduleSourceFileName = moduleSourceFileName' - , moduleObjectFileName = \bd -> bd </> "some_file_somewhere.f90.o" - , moduleModulesUsed = ["module1", "module2", "module3"] - , moduleName = "some_module" - , moduleProducesSmod = True - } - -moduleSourceFileName' :: FilePath -moduleSourceFileName' = "some" </> "file" </> "somewhere.f90" - -availableModules :: [AvailableModule] -availableModules = [ AvailableModule {availableModuleName = "module1", availableModuleFile = "build_dir" </> "module1.mod"} - , AvailableModule {availableModuleName = "module3", availableModuleFile = "build_dir" </> "module3.mod"} - ] - -doCompileTimeTransformation :: (Source, [AvailableModule]) -> CompileTimeInfo -doCompileTimeTransformation (programSource, otherSources) = - constructCompileTimeInfo programSource otherSources "build_dir" - -checkSourceFileName :: CompileTimeInfo -> Result -checkSourceFileName cti = - assertEquals moduleSourceFileName' (compileTimeInfoSourceFileName cti) - -checkObjectFileName :: CompileTimeInfo -> Result -checkObjectFileName cti = assertEquals - ("build_dir" </> "some_file_somewhere.f90.o") - (compileTimeInfoObjectFileProduced cti) - -checkOtherFilesProduced :: CompileTimeInfo -> Result -checkOtherFilesProduced cti = assertEquals - ["build_dir" </> "some_module.mod", "build_dir" </> "some_module.smod"] - (compileTimeInfoOtherFilesProduced cti) - -checkDirectDependencies :: CompileTimeInfo -> Result -checkDirectDependencies cti = assertEquals - ["build_dir" </> "module1.mod", "build_dir" </> "module3.mod"] - (compileTimeInfoDirectDependencies cti) diff --git a/bootstrap/unit_test/ProgramSourceConstructionTest.hs b/bootstrap/unit_test/ProgramSourceConstructionTest.hs deleted file mode 100644 index 6369965..0000000 --- a/bootstrap/unit_test/ProgramSourceConstructionTest.hs +++ /dev/null @@ -1,69 +0,0 @@ -module ProgramSourceConstructionTest - ( test - ) -where - -import BuildModel ( RawSource(..) - , Source(..) - , processRawSource - ) -import Hedge ( Result - , Test - , assertEquals - , assertThat - , fail' - , givenInput - , then' - , whenTransformed - ) -import System.FilePath ( (</>) ) - -test :: IO (Test ()) -test = return $ givenInput - "a program" - exampleProgram - [ whenTransformed - "processed to a source" - processRawSource - [ then' "it is a Program" checkIsProgram - , then' "its source file name is the same as the original" - checkProgramSourceFileName - , then' - "its object file name is the 'flattened' path of the source file with '.o' appended" - checkProgramObjectFileName - , then' "it knows what modules it uses directly" checkProgramModulesUsed - ] - ] - -exampleProgram :: RawSource -exampleProgram = RawSource programSourceFileName' $ unlines - [ "program some_program" - , " use module1" - , " USE MODULE2" - , " implicit none" - , " print *, \"Hello, World!\"" - , "end program" - ] - -programSourceFileName' :: String -programSourceFileName' = "some" </> "file" </> "somewhere.f90" - -checkIsProgram :: Source -> Result -checkIsProgram Program{} = assertThat True -checkIsProgram _ = assertThat False - -checkProgramSourceFileName :: Source -> Result -checkProgramSourceFileName p@(Program{}) = - assertEquals programSourceFileName' $ programSourceFileName p -checkProgramSourceFileName _ = fail' "wasn't a Program" - -checkProgramObjectFileName :: Source -> Result -checkProgramObjectFileName p@(Program{}) = - assertEquals ("." </> "some_file_somewhere.f90.o") - $ (programObjectFileName p) "." -checkProgramObjectFileName _ = fail' "wasn't a Program" - -checkProgramModulesUsed :: Source -> Result -checkProgramModulesUsed p@(Program{}) = - assertEquals ["module1", "module2"] $ programModulesUsed p -checkProgramModulesUsed _ = fail' "wasn't a Program" diff --git a/bootstrap/unit_test/ProgramToCompileInfoTest.hs b/bootstrap/unit_test/ProgramToCompileInfoTest.hs deleted file mode 100644 index a9ad39b..0000000 --- a/bootstrap/unit_test/ProgramToCompileInfoTest.hs +++ /dev/null @@ -1,71 +0,0 @@ -module ProgramToCompileInfoTest - ( test - ) -where - -import BuildModel ( AvailableModule(..) - , CompileTimeInfo(..) - , Source(..) - , constructCompileTimeInfo - ) -import Hedge ( Result - , Test - , assertEmpty - , assertEquals - , givenInput - , then' - , whenTransformed - ) -import System.FilePath ( (</>) ) - -test :: IO (Test ()) -test = return $ givenInput - "a program and available modules" - (exampleProgram, availableModules) - [ whenTransformed - "its compileTimeInfo is determined" - doCompileTimeTransformation - [ then' "it still knows the original source file" checkSourceFileName - , then' "it knows what object file will be produced" checkObjectFileName - , then' "there are no other files produced" checkOtherFilesProduced - , then' "the direct dependencies are only the available modules used" - checkDirectDependencies - ] - ] - -exampleProgram :: Source -exampleProgram = Program - { programSourceFileName = programSourceFileName' - , programObjectFileName = \bd -> bd </> "some_file_somewhere.f90.o" - , programModulesUsed = ["module1", "module2", "module3"] - } - -programSourceFileName' :: FilePath -programSourceFileName' = "some" </> "file" </> "somewhere.f90" - -availableModules :: [AvailableModule] -availableModules = [ AvailableModule {availableModuleName = "module1", availableModuleFile = "build_dir" </> "module1.mod"} - , AvailableModule {availableModuleName = "module3", availableModuleFile = "build_dir" </> "module3.mod"} - ] - -doCompileTimeTransformation :: (Source, [AvailableModule]) -> CompileTimeInfo -doCompileTimeTransformation (programSource, otherSources) = - constructCompileTimeInfo programSource otherSources "build_dir" - -checkSourceFileName :: CompileTimeInfo -> Result -checkSourceFileName cti = - assertEquals programSourceFileName' (compileTimeInfoSourceFileName cti) - -checkObjectFileName :: CompileTimeInfo -> Result -checkObjectFileName cti = assertEquals - ("build_dir" </> "some_file_somewhere.f90.o") - (compileTimeInfoObjectFileProduced cti) - -checkOtherFilesProduced :: CompileTimeInfo -> Result -checkOtherFilesProduced cti = - assertEmpty (compileTimeInfoOtherFilesProduced cti) - -checkDirectDependencies :: CompileTimeInfo -> Result -checkDirectDependencies cti = assertEquals - ["build_dir" </> "module1.mod", "build_dir" </> "module3.mod"] - (compileTimeInfoDirectDependencies cti) diff --git a/bootstrap/unit_test/SubmoduleSourceConstructionTest.hs b/bootstrap/unit_test/SubmoduleSourceConstructionTest.hs deleted file mode 100644 index d07a6ed..0000000 --- a/bootstrap/unit_test/SubmoduleSourceConstructionTest.hs +++ /dev/null @@ -1,79 +0,0 @@ -module SubmoduleSourceConstructionTest - ( test - ) -where - -import BuildModel ( RawSource(..) - , Source(..) - , processRawSource - ) -import Hedge ( Result - , Test - , assertEquals - , assertThat - , fail' - , givenInput - , then' - , whenTransformed - ) -import System.FilePath ( (</>) ) - -test :: IO (Test ()) -test = return $ givenInput - "a submodule" - exampleSubmodule - [ whenTransformed - "processed to a source" - processRawSource - [ then' "it is a Submodule" checkIsSubmodule - , then' "its source file name is the same as the original" - checkSubmoduleSourceFileName - , then' - "its object file name is the 'flattened' path of the source file with '.o' appeneded" - checkSubmoduleObjectFileName - , then' "it knows what modules it uses directly" checkSubmoduleModulesUsed - , then' "it knows its parent's name" checkSubmoduleParentName - , then' "it knows its name" checkSubmoduleName - ] - ] - -exampleSubmodule :: RawSource -exampleSubmodule = RawSource submoduleSourceFileName' $ unlines - [ "submodule (some_module:parent) child" - , " use module1" - , " USE MODULE2" - , " implicit none" - , "end submodule" - ] - -submoduleSourceFileName' :: String -submoduleSourceFileName' = "some" </> "file" </> "somewhere.f90" - -checkIsSubmodule :: Source -> Result -checkIsSubmodule Submodule{} = assertThat True -checkIsSubmodule _ = assertThat False - -checkSubmoduleSourceFileName :: Source -> Result -checkSubmoduleSourceFileName s@(Submodule{}) = - assertEquals submoduleSourceFileName' $ submoduleSourceFileName s -checkSubmoduleSourceFileName _ = fail' "wasn't a Submodule" - -checkSubmoduleObjectFileName :: Source -> Result -checkSubmoduleObjectFileName s@(Submodule{}) = - assertEquals ("." </> "some_file_somewhere.f90.o") - $ (submoduleObjectFileName s) "." -checkSubmoduleObjectFileName _ = fail' "wasn't a Submodule" - -checkSubmoduleModulesUsed :: Source -> Result -checkSubmoduleModulesUsed s@(Submodule{}) = - assertEquals ["module1", "module2"] $ submoduleModulesUsed s -checkSubmoduleModulesUsed _ = fail' "wasn't a Submodule" - -checkSubmoduleParentName :: Source -> Result -checkSubmoduleParentName s@(Submodule{}) = - assertEquals "some_module@parent" (submoduleParentName s) -checkSubmoduleParentName _ = fail' "wasn't a Submodule" - -checkSubmoduleName :: Source -> Result -checkSubmoduleName s@(Submodule{}) = assertEquals "child" $ submoduleName s -checkSubmoduleName _ = fail' "wasn't a Submodule" diff --git a/bootstrap/unit_test/SubmoduleToCompileInfoTest.hs b/bootstrap/unit_test/SubmoduleToCompileInfoTest.hs deleted file mode 100644 index 621b0d5..0000000 --- a/bootstrap/unit_test/SubmoduleToCompileInfoTest.hs +++ /dev/null @@ -1,78 +0,0 @@ -module SubmoduleToCompileInfoTest - ( test - ) -where - -import BuildModel ( AvailableModule(..) - , CompileTimeInfo(..) - , Source(..) - , constructCompileTimeInfo - ) -import Hedge ( Result - , Test - , assertEquals - , givenInput - , then' - , whenTransformed - ) -import System.FilePath ( (</>) ) - -test :: IO (Test ()) -test = return $ givenInput - "a submodule and available modules" - (exampleSubmodule, availableModules) - [ whenTransformed - "its compileTimeInfo is determined" - doCompileTimeTransformation - [ then' "it still knows the original source file" checkSourceFileName - , then' "it knows what object file will be produced" checkObjectFileName - , then' "the smod file is also produced" checkOtherFilesProduced - , then' - "the direct dependencies are the parent smod and the available modules used" - checkDirectDependencies - ] - ] - -exampleSubmodule :: Source -exampleSubmodule = Submodule - { submoduleSourceFileName = submoduleSourceFileName' - , submoduleObjectFileName = \bd -> bd </> "some_file_somewhere.f90.o" - , submoduleModulesUsed = ["module1", "module2", "module3"] - , submoduleBaseModuleName = "base_module" - , submoduleParentName = "base_module@parent" - , submoduleName = "some_submodule" - } - -submoduleSourceFileName' :: FilePath -submoduleSourceFileName' = "some" </> "file" </> "somewhere.f90" - -availableModules :: [AvailableModule] -availableModules = [ AvailableModule {availableModuleName = "module1", availableModuleFile = "build_dir" </> "module1.mod"} - , AvailableModule {availableModuleName = "module3", availableModuleFile = "build_dir" </> "module3.mod"} - ] - -doCompileTimeTransformation :: (Source, [AvailableModule]) -> CompileTimeInfo -doCompileTimeTransformation (programSource, otherSources) = - constructCompileTimeInfo programSource otherSources "build_dir" - -checkSourceFileName :: CompileTimeInfo -> Result -checkSourceFileName cti = - assertEquals submoduleSourceFileName' (compileTimeInfoSourceFileName cti) - -checkObjectFileName :: CompileTimeInfo -> Result -checkObjectFileName cti = assertEquals - ("build_dir" </> "some_file_somewhere.f90.o") - (compileTimeInfoObjectFileProduced cti) - -checkOtherFilesProduced :: CompileTimeInfo -> Result -checkOtherFilesProduced cti = assertEquals - ["build_dir" </> "base_module@some_submodule.smod"] - (compileTimeInfoOtherFilesProduced cti) - -checkDirectDependencies :: CompileTimeInfo -> Result -checkDirectDependencies cti = assertEquals - [ "build_dir" </> "base_module@parent.smod" - , "build_dir" </> "module1.mod" - , "build_dir" </> "module3.mod" - ] - (compileTimeInfoDirectDependencies cti) diff --git a/bootstrap/unit_test/Trimmer.hs b/bootstrap/unit_test/Trimmer.hs deleted file mode 100644 index 4e0f91d..0000000 --- a/bootstrap/unit_test/Trimmer.hs +++ /dev/null @@ -1 +0,0 @@ -{-# OPTIONS_GHC -F -pgmF hedge-trimmer #-} @@ -9,12 +9,12 @@ author_email: fortran-lang@groups.io github: https://github.com/fortran-lang twitter: https://twitter.com/fortranlang website: https://fortran-lang.org -src_dir: ./fpm/src +src_dir: ./src + ./app output_dir: ./fpm-doc page_dir: ./doc media_dir: ./doc/media -exclude_dir: ./bootstrap - ./archive +exclude_dir: ./example_packages ./test display: public protected diff --git a/fpm/.gitignore b/fpm/.gitignore deleted file mode 100644 index a007fea..0000000 --- a/fpm/.gitignore +++ /dev/null @@ -1 +0,0 @@ -build/* diff --git a/fpm/README.md b/fpm/README.md deleted file mode 100644 index d993787..0000000 --- a/fpm/README.md +++ /dev/null @@ -1,4 +0,0 @@ -# Fortran Package Manager - -This is the Fortran Package Manager, implemented in Fortran as an fpm package. -Use fpm to build it. @@ -7,33 +7,18 @@ usage() echo "Fortran Package Manager Bootstrap Script" echo "" echo "USAGE:" - echo "./install.sh [--help | [--prefix=PREFIX] [--update[=REF]]" - echo " [--no-openmp] [--static] [--haskell] ]" + 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 " --update[=REF] Update repository from latest release tag" - echo " or from git reference REF if specified" - echo " --no-openmp Don't build fpm with openmp support" - echo " --static Statically link fpm executable" - echo " (implies --no-openmp)" - echo " --haskell Only install Haskell fpm" echo "" - echo " '--no-openmp' and '--static' do not affect the Haskell fpm" - echo " build." + echo "FC and FFLAGS environment variables can be used to select the" + echo "Fortran compiler and the build flags." echo "" } PREFIX="$HOME/.local" -UPDATE=false -OMP=true -STATIC=false -HASKELL_ONLY=false - -STACK_BIN_PATH="$HOME/.local/bin" -REF=$(git describe --tag --abbrev=0) -RELEASE_FLAGS="--flag -g --flag -fbacktrace --flag -O3" while [ "$1" != "" ]; do PARAM=$(echo "$1" | awk -F= '{print $1}') @@ -46,22 +31,6 @@ while [ "$1" != "" ]; do --prefix) PREFIX=$VALUE ;; - --update) - UPDATE=true - if [ "$VALUE" != "" ]; then - REF=$VALUE - fi - ;; - --no-openmp) - OMP=false - ;; - --static) - STATIC=true - OMP=false - ;; - --haskell) - HASKELL_ONLY=true - ;; *) echo "ERROR: unknown parameter \"$PARAM\"" usage @@ -73,59 +42,18 @@ done set -u # error on use of undefined variable -INSTALL_PATH="$PREFIX/bin" - -if command -v stack 1> /dev/null 2>&1 ; then - echo "Found stack" -else - echo "Haskell stack not found." - echo "Installing Haskell stack" - curl -sSL https://get.haskellstack.org/ | sh - if command -v stack 1> /dev/null 2>&1 ; then - echo "Haskell stack installation successful." - else - echo "ERROR: Haskell stack installation unsuccessful." - exit 1 - fi +SOURCE_URL="https://github.com/fortran-lang/fpm/releases/download/v0.2.0/fpm-0.2.0.f90" +BOOTSTRAP_DIR="build/bootstrap" +if [ -z ${FC+x} ]; then + FC="gfortran" fi - -if [ -x "$INSTALL_PATH/fpm" ]; then - echo "Overwriting existing fpm installation in $INSTALL_PATH" +if [ -z ${FFLAGS+x} ]; then + FFLAGS="-g -fbacktrace -O3" fi -if [ "$UPDATE" = true ]; then - git checkout "$REF" - if [ $? != 0 ]; then - echo "ERROR: Unable to checkout $REF." - exit 1 - fi -fi +mkdir -p $BOOTSTRAP_DIR +curl -LJ $SOURCE_URL > $BOOTSTRAP_DIR/fpm.f90 +$FC $FFLAGS -J $BOOTSTRAP_DIR $BOOTSTRAP_DIR/fpm.f90 -o $BOOTSTRAP_DIR/fpm -cd bootstrap -stack install - -if [ "$STACK_BIN_PATH" != "$INSTALL_PATH" ]; then - mv "$STACK_BIN_PATH/fpm" "$INSTALL_PATH/" -fi - -if [ "$HASKELL_ONLY" = true ]; then - exit -fi - -if [ "$STATIC" = true ]; then - RELEASE_FLAGS="$RELEASE_FLAGS --flag -static" -fi - -if [ "$OMP" = true ]; then - RELEASE_FLAGS="$RELEASE_FLAGS --flag -fopenmp" -fi - -cd ../fpm -"$INSTALL_PATH/fpm" run $RELEASE_FLAGS --runner mv -- "$INSTALL_PATH/" - -if [ -x "$INSTALL_PATH/fpm" ]; then - echo "fpm installed successfully to $INSTALL_PATH" -else - echo "ERROR: fpm installation unsuccessful: fpm not found in $INSTALL_PATH" - exit 1 -fi +$BOOTSTRAP_DIR/fpm install --compiler "$FC" --flag "$FFLAGS" --prefix "$PREFIX" +rm -r $BOOTSTRAP_DIR diff --git a/manifest-reference.md b/manifest-reference.md index b40eef8..1a33dc1 100644 --- a/manifest-reference.md +++ b/manifest-reference.md @@ -217,27 +217,6 @@ include-dir = ["include", "third_party/include"] > *include-dir* does not currently allow using pre-built module `.mod` files -#### Custom build script - -> Supported in Bootstrap fpm only - -Projects with custom build scripts can specify those in the *build-script* entry. -The custom build script will be executed when the library build step is reached. - -*Example:* - -```toml -[library] -build-script = "build.sh" -``` - -Build scripts written in ``make`` are automatically detected and executed with ``make`` - -```toml -[library] -build-script = "Makefile" -``` - ### Executable targets diff --git a/fpm/src/fpm.f90 b/src/fpm.f90 index 31b68ff..31b68ff 100644 --- a/fpm/src/fpm.f90 +++ b/src/fpm.f90 diff --git a/fpm/src/fpm/cmd/install.f90 b/src/fpm/cmd/install.f90 index db7a9f8..db7a9f8 100644 --- a/fpm/src/fpm/cmd/install.f90 +++ b/src/fpm/cmd/install.f90 diff --git a/fpm/src/fpm/cmd/new.f90 b/src/fpm/cmd/new.f90 index 5149bea..5149bea 100644 --- a/fpm/src/fpm/cmd/new.f90 +++ b/src/fpm/cmd/new.f90 diff --git a/fpm/src/fpm/cmd/update.f90 b/src/fpm/cmd/update.f90 index d7cc549..d7cc549 100644 --- a/fpm/src/fpm/cmd/update.f90 +++ b/src/fpm/cmd/update.f90 diff --git a/fpm/src/fpm/dependency.f90 b/src/fpm/dependency.f90 index 144ffbe..144ffbe 100644 --- a/fpm/src/fpm/dependency.f90 +++ b/src/fpm/dependency.f90 diff --git a/fpm/src/fpm/error.f90 b/src/fpm/error.f90 index e69ff1e..e69ff1e 100644 --- a/fpm/src/fpm/error.f90 +++ b/src/fpm/error.f90 diff --git a/fpm/src/fpm/git.f90 b/src/fpm/git.f90 index 08e27b2..08e27b2 100644 --- a/fpm/src/fpm/git.f90 +++ b/src/fpm/git.f90 diff --git a/fpm/src/fpm/installer.f90 b/src/fpm/installer.f90 index d01bd27..d01bd27 100644 --- a/fpm/src/fpm/installer.f90 +++ b/src/fpm/installer.f90 diff --git a/fpm/src/fpm/manifest.f90 b/src/fpm/manifest.f90 index 4170b91..4170b91 100644 --- a/fpm/src/fpm/manifest.f90 +++ b/src/fpm/manifest.f90 diff --git a/fpm/src/fpm/manifest/build.f90 b/src/fpm/manifest/build.f90 index d96974f..d96974f 100644 --- a/fpm/src/fpm/manifest/build.f90 +++ b/src/fpm/manifest/build.f90 diff --git a/fpm/src/fpm/manifest/dependency.f90 b/src/fpm/manifest/dependency.f90 index 26b76ee..26b76ee 100644 --- a/fpm/src/fpm/manifest/dependency.f90 +++ b/src/fpm/manifest/dependency.f90 diff --git a/fpm/src/fpm/manifest/example.f90 b/src/fpm/manifest/example.f90 index fc2a0af..fc2a0af 100644 --- a/fpm/src/fpm/manifest/example.f90 +++ b/src/fpm/manifest/example.f90 diff --git a/fpm/src/fpm/manifest/executable.f90 b/src/fpm/manifest/executable.f90 index be02974..be02974 100644 --- a/fpm/src/fpm/manifest/executable.f90 +++ b/src/fpm/manifest/executable.f90 diff --git a/fpm/src/fpm/manifest/install.f90 b/src/fpm/manifest/install.f90 index 6175873..6175873 100644 --- a/fpm/src/fpm/manifest/install.f90 +++ b/src/fpm/manifest/install.f90 diff --git a/fpm/src/fpm/manifest/library.f90 b/src/fpm/manifest/library.f90 index c8ce049..c8ce049 100644 --- a/fpm/src/fpm/manifest/library.f90 +++ b/src/fpm/manifest/library.f90 diff --git a/fpm/src/fpm/manifest/package.f90 b/src/fpm/manifest/package.f90 index bbaa51d..bbaa51d 100644 --- a/fpm/src/fpm/manifest/package.f90 +++ b/src/fpm/manifest/package.f90 diff --git a/fpm/src/fpm/manifest/test.f90 b/src/fpm/manifest/test.f90 index bcacbd8..bcacbd8 100644 --- a/fpm/src/fpm/manifest/test.f90 +++ b/src/fpm/manifest/test.f90 diff --git a/fpm/src/fpm/toml.f90 b/src/fpm/toml.f90 index dbaafcb..dbaafcb 100644 --- a/fpm/src/fpm/toml.f90 +++ b/src/fpm/toml.f90 diff --git a/fpm/src/fpm/versioning.f90 b/src/fpm/versioning.f90 index b24fc3c..b24fc3c 100644 --- a/fpm/src/fpm/versioning.f90 +++ b/src/fpm/versioning.f90 diff --git a/fpm/src/fpm_backend.f90 b/src/fpm_backend.f90 index 74cef61..74cef61 100644 --- a/fpm/src/fpm_backend.f90 +++ b/src/fpm_backend.f90 diff --git a/fpm/src/fpm_command_line.f90 b/src/fpm_command_line.f90 index 9e9a572..9e9a572 100644 --- a/fpm/src/fpm_command_line.f90 +++ b/src/fpm_command_line.f90 diff --git a/fpm/src/fpm_compiler.f90 b/src/fpm_compiler.f90 index 51cda20..51cda20 100644 --- a/fpm/src/fpm_compiler.f90 +++ b/src/fpm_compiler.f90 diff --git a/fpm/src/fpm_environment.f90 b/src/fpm_environment.f90 index 0408ec4..0408ec4 100644 --- a/fpm/src/fpm_environment.f90 +++ b/src/fpm_environment.f90 diff --git a/fpm/src/fpm_filesystem.f90 b/src/fpm_filesystem.f90 index 6acd383..6acd383 100644 --- a/fpm/src/fpm_filesystem.f90 +++ b/src/fpm_filesystem.f90 diff --git a/fpm/src/fpm_model.f90 b/src/fpm_model.f90 index bfb0115..bfb0115 100644 --- a/fpm/src/fpm_model.f90 +++ b/src/fpm_model.f90 diff --git a/fpm/src/fpm_source_parsing.f90 b/src/fpm_source_parsing.f90 index dd9a4c5..dd9a4c5 100644 --- a/fpm/src/fpm_source_parsing.f90 +++ b/src/fpm_source_parsing.f90 diff --git a/fpm/src/fpm_sources.f90 b/src/fpm_sources.f90 index c781535..c781535 100644 --- a/fpm/src/fpm_sources.f90 +++ b/src/fpm_sources.f90 diff --git a/fpm/src/fpm_strings.f90 b/src/fpm_strings.f90 index 3d7d7b1..3d7d7b1 100644 --- a/fpm/src/fpm_strings.f90 +++ b/src/fpm_strings.f90 diff --git a/fpm/src/fpm_targets.f90 b/src/fpm_targets.f90 index 02bb600..02bb600 100644 --- a/fpm/src/fpm_targets.f90 +++ b/src/fpm_targets.f90 diff --git a/fpm/test/cli_test/cli_test.f90 b/test/cli_test/cli_test.f90 index d979f1a..d979f1a 100644 --- a/fpm/test/cli_test/cli_test.f90 +++ b/test/cli_test/cli_test.f90 diff --git a/fpm/test/fpm_test/main.f90 b/test/fpm_test/main.f90 index 0a65307..0a65307 100644 --- a/fpm/test/fpm_test/main.f90 +++ b/test/fpm_test/main.f90 diff --git a/fpm/test/fpm_test/test_backend.f90 b/test/fpm_test/test_backend.f90 index 662e470..662e470 100644 --- a/fpm/test/fpm_test/test_backend.f90 +++ b/test/fpm_test/test_backend.f90 diff --git a/fpm/test/fpm_test/test_filesystem.f90 b/test/fpm_test/test_filesystem.f90 index 5a7e18a..5a7e18a 100644 --- a/fpm/test/fpm_test/test_filesystem.f90 +++ b/test/fpm_test/test_filesystem.f90 diff --git a/fpm/test/fpm_test/test_installer.f90 b/test/fpm_test/test_installer.f90 index 1235ba5..1235ba5 100644 --- a/fpm/test/fpm_test/test_installer.f90 +++ b/test/fpm_test/test_installer.f90 diff --git a/fpm/test/fpm_test/test_manifest.f90 b/test/fpm_test/test_manifest.f90 index 94e5e07..94e5e07 100644 --- a/fpm/test/fpm_test/test_manifest.f90 +++ b/test/fpm_test/test_manifest.f90 diff --git a/fpm/test/fpm_test/test_module_dependencies.f90 b/test/fpm_test/test_module_dependencies.f90 index f193646..f193646 100644 --- a/fpm/test/fpm_test/test_module_dependencies.f90 +++ b/test/fpm_test/test_module_dependencies.f90 diff --git a/fpm/test/fpm_test/test_package_dependencies.f90 b/test/fpm_test/test_package_dependencies.f90 index b70ac13..b70ac13 100644 --- a/fpm/test/fpm_test/test_package_dependencies.f90 +++ b/test/fpm_test/test_package_dependencies.f90 diff --git a/fpm/test/fpm_test/test_source_parsing.f90 b/test/fpm_test/test_source_parsing.f90 index 79a4d7a..79a4d7a 100644 --- a/fpm/test/fpm_test/test_source_parsing.f90 +++ b/test/fpm_test/test_source_parsing.f90 diff --git a/fpm/test/fpm_test/test_toml.f90 b/test/fpm_test/test_toml.f90 index ba48307..ba48307 100644 --- a/fpm/test/fpm_test/test_toml.f90 +++ b/test/fpm_test/test_toml.f90 diff --git a/fpm/test/fpm_test/test_versioning.f90 b/test/fpm_test/test_versioning.f90 index f6dcb57..f6dcb57 100644 --- a/fpm/test/fpm_test/test_versioning.f90 +++ b/test/fpm_test/test_versioning.f90 diff --git a/fpm/test/fpm_test/testsuite.f90 b/test/fpm_test/testsuite.f90 index 124d19a..124d19a 100644 --- a/fpm/test/fpm_test/testsuite.f90 +++ b/test/fpm_test/testsuite.f90 diff --git a/fpm/test/help_test/help_test.f90 b/test/help_test/help_test.f90 index 8f0c455..8f0c455 100644 --- a/fpm/test/help_test/help_test.f90 +++ b/test/help_test/help_test.f90 diff --git a/fpm/test/new_test/new_test.f90 b/test/new_test/new_test.f90 index 3c8c453..3c8c453 100644 --- a/fpm/test/new_test/new_test.f90 +++ b/test/new_test/new_test.f90 |