Fortran 包管理器 fpm 介绍

基于 Fortran 包管理器 fpm 文档, 总结功能及基本用法 [目前尚有诸多不完善, 文档不全]

introduction

Fortran 包管理器 fpm (Fortran Package Manager) 主要目的是简化 Fortran 程序或库的构建与分发, 主要功能包括

  1. 项目创建:使用 fpm new 命令可以快速创建一个新的 Fortran 项目
  2. 依赖管理:fpm 支持本地和在线注册表, 可以轻松管理项目的依赖项
  3. 构建和测试:fpm 可以自动构建项目, 并运行可执行文件、测试和示例
  4. 发布和分发:通过 fpm publish 命令, 可以将项目发布到注册表中, 供其他 Fortran 项目使用
  5. 配置选项:支持启用和禁用语言特性, 如隐式类型和默认源码形式

Fortran 包管理器官方文档 (https://fpm.fortran-lang.org//index.html), 中文文档 (https://fpm.fortran-lang.cn/tutorial/hello-fpm.html)

install

安装可以直接下载发行包或使用 conda, 此处采用前者, 下载地址 (https://github.com/fortran-lang/fpm/releases)

1
2
wget https://github.com/fortran-lang/fpm/releases/download/v0.10.1/fpm-0.10.1-linux-x86_64 -P ~/Environment/Fortran/bin
wget https://github.com/fortran-lang/fpm/releases/download/v0.10.1/fpm-0.10.1-linux-x86_64.sha256 -P ~/Environment/Fortran/bin

以.sha256结尾的链接提供加密哈希, 可以使用这些哈希来验证二进制文件的下载是否成功

1
2
3
4
$ openssl sha256 -r fpm-0.10.1-linux-x86_64
2c0759e349fb8c91fc6d4cbc1c355f52cfd1dd15589273550327daf6e7f9932c *fpm-0.10.1-linux-x86_64
$ cat fpm-0.10.1-linux-x86_64.sha256
2c0759e349fb8c91fc6d4cbc1c355f52cfd1dd15589273550327daf6e7f9932c fpm-0.10.1-linux-x86_64

添加可执行权限和软链接

1
2
chmod +x fpm-0.10.1-linux-x86_64
ln -s ~/Environment/Fortran/bin/fpm-0.10.1-linux-x86_64 ~/Environment/Fortran/bin/fpm

通过 Environment Modules 工具管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#%Module
proc ModulesHelp {} {
puts stderr "Program: fpm $::version"
puts stderr "Description: A Fortran package manager and build system"
puts stderr "Home Page: https://github.com/fortran-lang/fpm"
puts stderr "License: MIT"
puts stderr "OS Type: Linux"
puts stderr {}
}
set version 0.10.1
set prefix /home/user/Environment/Fortran
module-whatis "Fortran package manager and build system"
setenv FPM_HOME $prefix
prepend-path PATH $prefix/bin

Command

fpm 包含以下指令

Command Function
fpm new project Compile the packages into the “build/” directory
fpm build create git repository in the fpm standard layout
fpm test run tests
fpm run --example Run the local package binaries.
fpm clean Delete directories in the “build/” directory
fpm update Update the project dependencies
fpm publish Publish package to the registry
fpm install installs the executables locally, NOT RECOMMEND

这里主要关心如何通过 fpm 构建程序并测试

layout

通过 fpm new test 创建新项目结构如下

1
2
3
4
5
6
7
8
9
test
├── app
│   └── main.f90
├── fpm.toml
├── README.md
├── src
│   └── test.f90
└── test
└── check.f90

执行 fpm build 创建 build 目录结构如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
build
├── cache.toml
├── dependencies
├── gfortran_50F62D7499E64B65
│   └── test
│   ├── libtest.a
│   └── libtest.a.log
├── gfortran_87E2AE0597D39913
│   ├── test
│   │   ├── app_main.f90.o
│   │   ├── app_main.f90.o.digest
│   │   ├── app_main.f90.o.log
│   │   ├── src_test.f90.o
│   │   ├── src_test.f90.o.digest
│   │   └── src_test.f90.o.log
│   └── test.mod
└── gfortran_E167FD2A985B468F
├── app
│   ├── test
│   └── test.log
└── test
├── check
└── check.log

不同路径及文件功能

File Description
app/main.f90 Fortran program
fpm.toml manifest
src/test.f90 Fortran subroutine
test/check.f90 test program
build compile path
build/cache.toml compile cache
build/dependencies dependencies library
gfortran_5** build static library
libtest.a static library
libtest.a.log log file of static library
gfortran_8** compile file
**.f90.o object file
**.f90.o.digest digest(hash) file used to skip compilation of unmodified sources
**.f90.o.log log file of object file
test.mod module file
gfortran_E** build executable
app executable folder
test binary executable
test.log log file of binary executable
check binary executable for test
check.log log file of test

manifest

每个项目的 fpm.toml 文件称为清单 (manifest), 使用TOML格式编写, 详细内容参考 (https://fpm.fortran-lang.org/zh_CN/spec/manifest.html)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# *********************************************** #
[library] #
source-dir = "src" # source file path
include-dir = ["include", "third_party/include"] # include path
# *********************************************** #
[build] #
auto-executables = true # automatic target
auto-tests = true #
auto-examples = true #
module-naming = false #
link = ["z", "blas", "lapack"] # link external library
external-modules = ["netcdf", "h5lt"] # use external modules
# *********************************************** #
[install] # install exe to local
library = false # install module files
# *********************************************** #
[fortran] # Fortran features
implicit-typing = false # default implicit typing
implicit-external = false # external interfaces type
source-form = "free" # source form "fixed/default"
# *********************************************** #
[dependencies] # project dependencies
stdlib = "*" # fortran std library
[dependencies.toml-f] #
git = "https://github.com/toml-f/toml-f" # git repository
branch = "main" # specific upstream branc
rev = "2f5eaba864ff630ba0c3791126a3f811b6e437f3" # specific revision specify
#
[dependencies] #
my-package.namespace = "my-namespace" # registry (remote/local)
example-package.v = "1.0.0" # version
#
[dependencies] #
my-utils = { path = "utils" } # local dependencies
# *********************************************** #
[preprocess] # preprocess
cpp.suffixes = ["F90", "f90"] #
cpp.directories = ["src/feature1", "src/models"] #
cpp.macros = ["FOO", "BAR"] #

[preprocess] #
[preprocess.cpp] # cpp
suffixes = ["F90", "f90"] #
directories = ["src/feature1", "src/models"] #
macros = ["FOO", "BAR"] #

[preprocess] #
[preprocess.fypp] # fypp
# *********************************************** #
[[executable]] # executable targets
name = "app-name" #
source-dir = "app" # exe source file path
main = "program.f90" # exe source file name
# multi-executables
executable = [
{ name = "a-prog" },
{ name = "app-tool", source-dir = "tool" },
]
[executable.dependencies] # dependencies
helloff = { git = "https://gitlab.com/fun/helloff.git" }
# *********************************************** #
[[test]] # test targets
name = "test-name" # test exe name
source-dir = "test" # test source file path
main = "check.F90" # test source file name
[test.dependencies] # dependencies
helloff = { git = "https://gitlab.com/fun/helloff.git" }
# *********************************************** #
0%