diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index dad610b..4c4b63b 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -7,9 +7,17 @@ jobs: strategy: fail-fast: false matrix: + build: [fpm, meson] os: [ubuntu-latest, macos-latest, windows-latest] gcc: [10] # Version of GFortran we want to use. - + defaults: + run: + shell: ${{ contains(matrix.os, 'windows') && 'powershell' || 'bash -l {0}' }} + env: + FC: gfortran + CC: gcc + FPM_FC: gfortran + FPM_CC: gcc steps: - name: Checkout code uses: actions/checkout@v2 @@ -21,6 +29,7 @@ jobs: run: | brew install gcc@${{ matrix.gcc }} ln -s /usr/local/bin/gfortran-${{ matrix.gcc }} /usr/local/bin/gfortran + ln -s /usr/local/bin/gcc-${{ matrix.gcc }} /usr/local/bin/gcc - name: Install GFortran (Linux) if: ${{ contains(matrix.os, 'ubuntu') }} @@ -36,35 +45,50 @@ jobs: Invoke-WebRequest -Uri ${{ env.DOWNLOAD }} -OutFile mingw-w64.zip Expand-Archive mingw-w64.zip echo "$pwd\mingw-w64\mingw64\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + shell: pwsh env: DOWNLOAD: "https://github.com/brechtsanders/winlibs_mingw/releases/download/10.3.0-12.0.0-9.0.0-r2/winlibs-x86_64-posix-seh-gcc-10.3.0-mingw-w64-9.0.0-r2.zip" - - name: Setup Fortran Package Manager - uses: fortran-lang/setup-fpm@v3 + - name: Install dependencies + uses: mamba-org/provision-with-micromamba@main with: - fpm-version: 'v0.3.0' + environment-file: config/ci/${{ matrix.build }}-env.yaml - - name: Compile + - name: Compile (fpm) + if: ${{ matrix.build == 'fpm' }} run: fpm build --profile release - - name: Run test + - name: Run test (fpm) + if: ${{ matrix.build == 'fpm' }} run: fpm test - - name: Run examples + - name: Run examples (fpm) + if: ${{ matrix.build == 'fpm' }} run: fpm run --example --all - Docs: - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest] - gcc_v: [9] # Version of GFortran we want to use. - python-version: [3.7] - env: - FC: gfortran-${{ matrix.gcc_v }} - GCC_V: ${{ matrix.gcc_v }} + - name: Setup build (meson) + if: ${{ matrix.build == 'meson' }} + run: >- + meson setup _build + --prefix=${{ contains(matrix.os, 'windows') && '$pwd\_dist' || '$PWD/_dist' }} + + - name: Compile project (meson) + if: ${{ matrix.build == 'meson' }} + run: meson compile -C _build + - name: Run testsuite (meson) + if: ${{ matrix.build == 'meson' }} + run: meson test -C _build --no-rebuild --print-errorlogs + + - name: Install project (meson) + if: ${{ matrix.build == 'meson' }} + run: meson install -C _build --no-rebuild + + Docs: + runs-on: ubuntu-latest + defaults: + run: + shell: bash -l {0} steps: - id: deploy-on-push run: @@ -77,30 +101,10 @@ jobs: with: submodules: recursive - - name: Set up Python 3.x - uses: actions/setup-python@v1 # Use pip to install latest CMake, & FORD/Jin2For, etc. + - name: Install dependencies + uses: mamba-org/provision-with-micromamba@main with: - python-version: ${{ matrix.python-version }} - - - name: Setup Graphviz - uses: ts-graphviz/setup-graphviz@v1 - - - name: Install Python dependencies - if: ${{ contains( matrix.os, 'ubuntu') }} - run: | - python -m pip install --upgrade pip - pip install numpy matplotlib ford - if [ -f requirements.txt ]; then pip install -r requirements.txt; fi - - - name: Install GFortran Linux - if: ${{ contains( matrix.os, 'ubuntu') }} - run: | - sudo add-apt-repository ppa:ubuntu-toolchain-r/test - sudo apt-get update - sudo apt-get install -y gcc-${GCC_V} gfortran-${GCC_V} - 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} + environment-file: config/ci/docs-env.yaml - name: Build documentation run: ford ./minpack.md diff --git a/config/ci/docs-env.yaml b/config/ci/docs-env.yaml new file mode 100644 index 0000000..2bd7c5d --- /dev/null +++ b/config/ci/docs-env.yaml @@ -0,0 +1,10 @@ +name: docs +channels: + - conda-forge +dependencies: + - python + - numpy + - matplotlib-base + - ford + - graphviz + - gfortran diff --git a/config/ci/fpm-env.yaml b/config/ci/fpm-env.yaml new file mode 100644 index 0000000..44a2dab --- /dev/null +++ b/config/ci/fpm-env.yaml @@ -0,0 +1,5 @@ +name: devel +channels: + - conda-forge +dependencies: + - fpm diff --git a/config/ci/meson-env.yaml b/config/ci/meson-env.yaml new file mode 100644 index 0000000..dbcf7fb --- /dev/null +++ b/config/ci/meson-env.yaml @@ -0,0 +1,6 @@ +name: devel +channels: + - conda-forge +dependencies: + - meson + - ninja diff --git a/config/install-mod.py b/config/install-mod.py new file mode 100644 index 0000000..f638c48 --- /dev/null +++ b/config/install-mod.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python + +from os import environ, listdir, makedirs +from os.path import join, isdir, exists +from sys import argv +from shutil import copy + +build_dir = environ["MESON_BUILD_ROOT"] +if "MESON_INSTALL_DESTDIR_PREFIX" in environ: + install_dir = environ["MESON_INSTALL_DESTDIR_PREFIX"] +else: + install_dir = environ["MESON_INSTALL_PREFIX"] + +include_dir = argv[1] if len(argv) > 1 else "include" +module_dir = join(install_dir, include_dir) + +modules = [] +for d in listdir(build_dir): + bd = join(build_dir, d) + if isdir(bd): + for f in listdir(bd): + if f.endswith(".mod"): + modules.append(join(bd, f)) + +if not exists(module_dir): + makedirs(module_dir) + +for mod in modules: + print("Installing", mod, "to", module_dir) + copy(mod, module_dir) diff --git a/examples/meson.build b/examples/meson.build new file mode 100644 index 0000000..a2ef8ca --- /dev/null +++ b/examples/meson.build @@ -0,0 +1,19 @@ +tests = [ + 'hybrd', + 'hybrd1', + 'lmder1', + 'lmdif1', + 'primes', +] + +foreach t : tests + test( + t, + executable( + 'example-@0@'.format(t), + sources: files('example_@0@.f90'.format(t.underscorify())), + dependencies: minpack_dep, + ), + suite: 'example', + ) +endforeach diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..52a600d --- /dev/null +++ b/meson.build @@ -0,0 +1,61 @@ +project( + 'minpack', + 'fortran', + version: '2.0.0', + meson_version: '>=0.55', + default_options: [ + 'default_library=both', + 'buildtype=debugoptimized', + ], +) + +minpack_lib = library( + meson.project_name(), + sources: files( + 'src/minpack.f90', + 'src/minpack_capi.f90', + ), + install: true, +) + +minpack_inc = minpack_lib.private_dir_include() +minpack_dep = declare_dependency( + link_with: minpack_lib, + include_directories: [minpack_inc, include_directories('include')], +) + +minpack_lic = files( + 'LICENSE.txt', +) + +minpack_header = files( + 'include/minpack.h', +) + +install_data( + minpack_lic, + install_dir: get_option('datadir')/'licenses'/meson.project_name() +) + +install_headers( + minpack_header, +) + +module_id = meson.project_name() +meson.add_install_script( + find_program(files('config'/'install-mod.py')), + get_option('includedir') / module_id, +) + +pkg = import('pkgconfig') +pkg.generate( + minpack_lib, + description: 'Solver for nonlinear equations and least squares problems', + subdirs: ['', module_id], +) + +# add examples +subdir('examples') + +# add the testsuite +subdir('test') diff --git a/test/meson.build b/test/meson.build new file mode 100644 index 0000000..6279d4b --- /dev/null +++ b/test/meson.build @@ -0,0 +1,32 @@ +tests = [ + 'chkder', + 'hybrd', + 'hybrj', + 'lmder', + 'lmdif', + 'lmstr', +] + +foreach t : tests + test( + t, + executable( + 'test-@0@'.format(t), + sources: files('test_@0@.f90'.format(t.underscorify())), + dependencies: minpack_dep, + ), + suite: 'unit', + ) +endforeach + +if add_languages('c', required: false, native: false) + test( + 'c-api', + executable( + 'c-tester', + sources: files('api/tester.c'), + dependencies: minpack_dep, + ), + suite: 'api', + ) +endif