<center>
FAQ:寻找关于fortran的项目管理方法(FPM)</center>
SSSSSSSSSSSSSSSSSSS
umake/make,2020
The Ultimate Makefile to compile all your C, C++, Assembly and Fortran projects.
Tired of installing aditional tools to compile your projects? (Automake, CMake and Ant). Missing the old days, when all you needed to do was typing
make
? Here is the solution! A single generalized Makefile which aims to compile and mix almost everything related to C, C++, Assembly and Fortran projects - with support to many executables, static and shared libraries, lexer and parser generators, dependency management,file creation and much more! Everything just 4 letters away from you.
starting
Good tools are simple. That’s why make
is so successful. And that’s the goal of Ultimate Makefile.
In order to start, just download the Makefile:
curl -O https://raw.githubusercontent.com/umake/make/master/Makefile
To begin a new project, just type:
make init
A group of directories and a git repository are now ready for you!
运行fortran单个文件
umake例子:https://github.com/umake/make/blob/master/test/fortran/test_single-file.sh
运行时间及其缓慢,7000+行代码,可读性…;
This is a simple CMake tutorial project which contains some different scenarios.
hello-world
: Demo a simplest CMake project.hello-world-clear
: Separate the output files and src files.hello-world-lib
: Demo how to make a static/shared library.hello-world-shared
: Demo how to utilize external static/shared library.curl
: Demo how to use cmake with curl.hello-module
: Demo how to use cmake find module.config-file
: Demo how to work with config.h.hunter-simple
: Demo how to use hunter and gtest.boost
: Demo how to use boost library.
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
Akagi201/learning-cmake
SSSSSSSSSSSSSSSSSSSSSSSS FPM
【国外老哥对fpm介绍】
https://www.bilibili.com/video/BV145411w7Pr?p=26
00:35 Outline
00:53 what problems does a package manager solve?
01:57 How does fpm solve these problems?
01:57 managing dependecies
02:50 building
03:25 testing
04:11 new projects
04:58 finding libraries
05:32 demo
05:32 new projects
07:50 testing
08:10 managing dependencies
12:11 future development
13:25 fortran/fpm
14:08 question (听不懂…)
SSSSSSSSSSSSSSSSSSSSSSSSSSS
【fortran-lang/fpm】
https://github.com/fortran-lang/fpm
Setting up fpm
Fpm is available as MinGW package in the MSYS2 package manager. To install fpm with pacman use
pacman -S mingw-w64-x86_64-fpm
Afterwards fpm will be available for usage. Currently i686
, x86_64
and ucrt-x86_64
are supported MinGW architectures for fpm. For more details check the package information here.
Creating a new project
Creating a new fpm project is as simple as running the command fpm new project_name
. This will create a new folder in your current directory with the following contents and initialized as a git repository.
fpm.toml
– with your project’s name and some default standard meta-dataREADME.md
– with your project’s name.gitignore
src/project_name.f90
– with a simple hello world subroutineapp/main.f90
(if--app
flag used) – a program that calls the subroutinetest/main.f90
(if--test
flag used) – an empty test program
Building your Fortran project with fpm
Enter your Fortran project cd $project_name
.
fpm understands the basic commands:
fpm build
– build your library, executables and testsfpm run
– run executables进入到project,直接就
fpm run
,会出错:删掉
src
文件夹,fpm run
,还是会出错;fpm test
– run testsfpm install
- installs the executables locally
The command fpm run
can optionally accept the name of the specific executable to run, as can fpm test
; like fpm run specific_executable
. Command line arguments can also be passed to the executable(s) or test(s) with the option -- some arguments
.
See additional instructions in the Packaging guide or the manifest reference.
SSSSSSSSSSSSSSSSSSSSSSSSS
【fpm 手册doc(有中文cn)】
https://fpm.fortran-lang.org/en/
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
First steps with fpm
This tutorial covers the basic usage of the Fortran Package Manager (fpm) command line. It will cover the generation of a new project and the possibility to compile a project into an executable as well as the possibility to run the resulting program.
To start a new project with fpm use the fpm new command
❯ fpm new first_steps
By default fpm creates a git repository with a dummy project in the fpm standard layout
❯ cd first_steps
❯ tree .
.
├── README.md
├── app
│ └── main.f90
├── fpm.toml
├── src
│ └── first_steps.f90
└── test
└── check.f90
3 directories, 5 files
This is everything we need to start our new project. First, we inspect the package manifest, fpm.toml
, which is populated with stub entries for us:
fpm.toml
name = "first_steps"
version = "0.1.0"
license = "license"
author = "Jane Doe"
maintainer = "jane.doe@example.com"
copyright = "Copyright 2021, Jane Doe"
[build]
auto-executables = true
auto-tests = true
auto-examples = true
[install]
library = false
The package manifest contains all the required meta data for the new project. Next we checkout the main executable, app/main.f90
, fpm has generated for us:
app/main.f90
program main
use first_steps, only: say_hello
implicit none
call say_hello()
end program main
The program already uses a module from our library, which we can find in src/first_steps.f90
:
src/first_steps.f90
module first_steps
implicit none
private
public :: say_hello
contains
subroutine say_hello
print *, "Hello, first_steps!"
end subroutine say_hello
end module first_steps
We can run the executable directly with the command fpm run
:
❯ fpm run
...
Hello, first_steps!
Similarly, fpm has already created a stub for testing, which can be invoked with fpm test
:
❯ fpm test
...
Put some tests in here!
Fpm will automatically track changes in your project when running your project using the run and test commands.
Summary
In this tutorial you learned how to
- create a new project from the fpm command line
- build and run your project executables with fpm
- run tests with fpm
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
Adding dependency
This tutorial covers the usage of dependencies with fpm and how to reuse existing fpm projects.
In this tutorial you learned how to
- depend on another fpm project in the package manifest
- add development dependencies for testing
- use dependencies for executables
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
Using the standard library(失败->成功)
We start with a new project with fpm, we want to build a command line application to read a file, find a certain pattern and replace it. Since we do not want to write the replace function ourselves, we will use the Fortran standard library (stdlib) as dependency. In the package manifest we define stdlib in the dependencies table:
fpm.toml
name = "demo"
version = "0.1.0"
[dependencies]
stdlib.git = "https://github.com/fortran-lang/stdlib"
stdlib.branch = "stdlib-fpm"
Now we create a module with a procedure to perform the substitution. It requires three steps:
- reading a whole line from one unit
- replace the pattern in the string
- write the new string to an output
We will use the replace_all function from the stdlib_strings module for this purpose. The implementation is shown here
src/demo.f90
module demo
use stdlib_io, only : getline
use stdlib_strings, only : replace_all
implicit none
private
public :: substitute
contains
!> Read all lines from input, replace pattern and print it to output
subroutine substitute(input, output, pattern, replacement)
!> Formatted input unit
integer, intent(in) :: input
!> Formatted output unit
integer, intent(in) :: output
!> Pattern to replace in input
character(len=*), intent(in) :: pattern
!> Replacement for pattern in output
character(len=*), intent(in) :: replacement
character(len=:), allocatable :: line
integer :: stat
do
call getline(input, line, stat)
if (stat /= 0) exit
write(output, '(a)') replace_all(line, pattern, replacement)
end do
end subroutine substitute
end module demo
Finally, we need a command line driver to make use of our new function.
app/main.f90
program main
use, intrinsic :: iso_fortran_env, only : output_unit
use demo, only : substitute
implicit none
character(len=256) :: pattern, replacement, input_file
integer :: input
call get_command_argument(1, pattern)
call get_command_argument(2, replacement)
call get_command_argument(3, input_file)
open(newunit=input, file=input_file, status='old')
call substitute(input, output_unit, trim(pattern), trim(replacement))
close(input)
end program main
We can check our command line driver by running it with fpm:
❯ fpm run -- demo substitute fpm.toml
name = "substitute"
version = "0.1.0"
[dependencies]
stdlib.git = "https://github.com/fortran-lang/stdlib"
stdlib.branch = "stdlib-fpm"
运行失败:
刘锦灿@LAPTOP-085N0595 /d/zetero/VScode/Fortran/fpm/demo
$ gfortran -c build/dependencies/stdlib/src/stdlib_hash_64bit.f90 -g -I build/gfortran_2A42023B310FA28D -o build/gfortran_2A42023B310FA28D/demo/build_dependencies_stdlib_src_stdlib_io_npy.f90.o错误:f951.exe: Fatal Error: Reading module ‘build/gfortran_2A42023B310FA28D/stdlib_kinds.mod’ at line 18 column 1: Unexpected EOF compilation terminated.
使用 MSYS2-MinGW 64 解决
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
Adding a testing framework
Before we continue implementing new features, we want to add some tests to verify that our implementation keeps worked as we modify it. A minimalist testing framework is available with test-drive. Since the testing framework is only required when developing the package itself, but not for other packages which might in the future make use of our modules, we add a local dependency. The test-drive package is added in the dev-dependencies table as shown below
fpm.toml
name = "demo"
version = "0.1.0"
[dependencies]
stdlib.git = "https://github.com/fortran-lang/stdlib"
stdlib.branch = "stdlib-fpm"
[dev-dependencies]
test-drive.git = "https://github.com/fortran-lang/test-drive"
test-drive.tag = "v0.4.0"
Note
For a development dependency like a testing framework we choose a strict version pin by specifying the tag we want to use.
Now we can write a simple unit test, since our function works with units, we will create scratch units to create the input and capture the output. For now we will add a simple one line substitution as single test case
test/main.f90
module test_demo
use demo, only : substitute
use stdlib_io, only : getline
use testdrive, only : error_type, unittest_type, new_unittest, check
implicit none
private
public :: collect_demo
contains
!> Collect all exported unit tests
subroutine collect_demo(testsuite)
!> Collection of tests
type(unittest_type), allocatable, intent(out) :: testsuite(:)
testsuite = [new_unittest("substitute", test_substitute)]
end subroutine collect_demo
!> Check substitution of a single line
subroutine test_substitute(error)
!> Error handling
type(error_type), allocatable, intent(out) :: error
integer :: input, output, stat
character(len=:), allocatable :: line
open(newunit=input, status="scratch")
write(input, '(a)') "This is a valid test"
rewind(input)
open(newunit=output, status="scratch")
call substitute(input, output, "test", "example")
close(input)
rewind(output)
call getline(output, line, stat)
close(output)
call check(error, line, "This is a valid example")
end subroutine test_substitute
end module test_demo
program tester
use, intrinsic :: iso_fortran_env, only : error_unit
use testdrive, only : run_testsuite
use test_demo, only : collect_demo
implicit none
integer :: stat
stat = 0
call run_testsuite(collect_demo, error_unit, stat)
if (stat > 0) then
write(error_unit, '(i0, 1x, a)') stat, "test(s) failed!"
error stop
end if
end program tester
We run our new test using fpm
❯ fpm test
Starting substitute ... (1/1)
... substitute [PASSED]
Creating the scratch units for multiple unit tests will be repetitive, this kind of tasks can usually be done in a separate procedure and reused in several tests.
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
Target-specific dependencies
Dependencies can also be used for specific targets only. This can be used for adding a command line interface package, which is only used for the executable but not part of the library dependencies.
fpm.toml
name = "demo"
version = "0.1.0"
[dependencies]
stdlib.git = "https://github.com/fortran-lang/stdlib"
stdlib.branch = "stdlib-fpm"
[dev-dependencies]
test-drive.git = "https://github.com/fortran-lang/test-drive"
test-drive.tag = "v0.4.0"
[[executable]]
name = "demo"
[executable.dependencies]
M_CLI2.git = "https://github.com/urbanjost/M_CLI2"
We restructure our main program a bit for using M_CLI2 to handle the command line input. The unnamed array contains all positional command line arguments, we still use the first two as pattern and replacement, and use all remaining arguments as input. We also add an option to redirect the output. Our final main program looks like
app/main.f90
program main
use, intrinsic :: iso_fortran_env, only : output_unit
use demo, only : substitute
use m_cli2, only : set_args, unnamed, sget
implicit none
character(len=:), allocatable :: input_file, output_file, pattern, replacement
integer :: input, output, i
call set_args("--output:o ''")
output_file = trim(sget("output"))
if (len(output_file) > 0) then
open(file=output_file, newunit=output)
else
output = output_unit
end if
pattern = trim(unnamed(1))
replacement = trim(unnamed(2))
do i = 3, size(unnamed)
input_file = trim(unnamed(i))
open(file=input_file, newunit=input, status='old')
call substitute(input, output_unit, trim(pattern), trim(replacement))
close(input)
end do
if (output /= output_unit) close(output)
end program main
Again we run a quick check using fpm
❯ fpm run -- demo substitute fpm.toml
name = "substitute"
version = "0.1.0"
[dependencies]
stdlib.git = "https://github.com/fortran-lang/stdlib"
stdlib.branch = "stdlib-fpm"
[dev-dependencies]
test-drive.git = "https://github.com/fortran-lang/test-drive"
test-drive.tag = "v0.4.0"
[[executable]]
name = "substitute"
[executable.dependencies]
M_CLI2.git = "https://github.com/urbanjost/M_CLI2"
The output looks as expected with two substitutions.
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
Extending fpm with plugins
The Fortran package manager has a plugin system which allows to easily extend its functionality. This tutorial will show how to install a plugin with fpm and use it.
In this tutorial you learned how to
- installing an fpm plugin
- use the fpm-search plugin to query the registry
- generate a dependency entry from a query result
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
注册表搜索工具(失败)
The fpm-search project is a plugin to query the package registry. Since it is built with fpm we can easily install it on our system with
git clone https://github.com/urbanjost/fpm-search
cd fpm-search
fpm install --profile release
这会将二进制文件 fpm-search
安装到 ~/.local/bin
(或在Windows上的 %APPDATA%\local\bin
)。
…
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
Manifest reference
The fpm.toml
file for each project is called its manifest. It is written using the TOML format.
项目目标
每个fpm项目都可以定义函数库、可执行程序和测试目标。库目标被导出并可用于其他项目。
库配置
定义项目的导出库目标。如果在项目中找到源目录或包含目录,则会生成库。默认的源目录和包含目录是 src
和 include
;这些可以在库(library)部分中使用源目录(source-dir)和包含目录(include-dir)条目进行修改。源目录和包含目录的目录相对于项目根目录给出,并在所有平台上使用 /
用作目录分隔符。
例如:
[library]
source-dir = "lib"
include-dir = "inc"
包含目录
备注
仅在Fortran fpm中受支持。
使用Fortran语句或C预处理器语句的项目可以使用包含目录(include-dir)键为包含的文件指定搜索目录。包含目录(include-dir)可以包含一个或多个目录,其中使用字符串列表指定多个目录。所有项目依赖项中的包含目录都使用相应的编译器标志传递给编译器。
例如:
[library]
include-dir = ["include", "third_party/include"]
备注
包含目录(include-dir)当前不允许使用预构建的 .mod
模块文件。
可执行目标
可执行目标是定义为可执行部分的Fortran程序。如果未指定可执行文件(executable)部分,则会在 app
目录中搜索程序定义。对于显式指定的可执行文件,必须始终指定名称(name)条目。每个可执行文件的源目录都可以在源目录(source-dir)条目中进行调整。源目录的路径是相对于项目根目录给出的,并在所有平台上使用 /
用作路径分隔符。可以在主(main)条目中指定包含程序正文的源文件。
可执行文件可以有自己的依赖项。有关更多详细信息,请参阅指定依赖项。
可执行文件还可以指定自己的外部库依赖项。有关更多详细信息,请参阅外部库。
备注
仅在Fortran fpm中支持针对库的链接。
例如:
[[executable]]
name = "app-name"
source-dir = "prog"
main = "program.f90"
[[executable]]
name = "app-tool"
link = "z"
[executable.dependencies]
helloff = { git = "https://gitlab.com/everythingfunctional/helloff.git" }
指定许多单独的可执行文件可以通过使用内联表来完成,以便简洁。
executable = [
{ name = "a-prog" },
{ name = "app-tool", source-dir = "tool" },
]
示例目标
项目的示例应用程序被定义为示例部分。如果未指定示例(example)部分,则会在 example
目录中搜索程序定义。对于显式指定的示例,必须始终指定名称(name)条目。每个示例的源目录都可以在源目录(source-dir)条目中进行调整。源目录的路径是相对于项目根目录给出的,并在所有平台上使用 /
用作路径分隔符。可以在主(main)条目中指定包含程序正文的源文件。
可执行文件可以有自己的依赖项。有关更多详细信息,请参阅指定依赖项。
可执行文件还可以指定自己的外部库依赖项。有关更多详细信息,请参阅外部库。
备注
仅在Fortran fpm中支持针对库的链接。
例如:
[[example]]
name = "demo-app"
source-dir = "demo"
main = "program.f90"
[[example]]
name = "example-tool"
link = "z"
[example.dependencies]
helloff = { git = "https://gitlab.com/everythingfunctional/helloff.git" }
测试目标
测试目标是定义为测试部分的Fortran程序。它们遵循与可执行目标类似的规则。如果未指定测试(test)部分,则会在 test
目录中搜索程序定义。对于显式指定的测试,必须始终指定名称(name)条目。每个测试的源目录都可以在源目录(source-dir)条目中进行调整。源目录的路径是相对于项目根目录给出的,并在所有平台上使用 /
用作路径分隔符。可以在主(main)条目中指定包含程序正文的源文件。
可执行文件可以有自己的依赖项。有关更多详细信息,请参阅指定依赖项。
可执行文件还可以指定自己的外部库依赖项。有关更多详细信息,请参阅外部库。
备注
仅在Fortran fpm中支持针对库的链接。
例如:
[[test]]
name = "test-name"
source-dir = "testing"
main = "tester.F90"
[[test]]
name = "tester"
link = ["blas", "lapack"]
[test.dependencies]
helloff = { git = "https://gitlab.com/everythingfunctional/helloff.git" }
链接外部库
备注
仅在Fortran fpm中受支持。
要声明外部库的链接时间依赖关系,可以在链接(link)条目中指定本机库的列表。将一个库指定为字符串,或指定一个字符串列表,以防应链接多个库。如果可能,项目应仅链接一个本机库。库依赖项列表将导出到从属包。
例如:
使用zlib链接库:
[build]
link = "z"
要依赖LAPACK,BLAS也应该被链接起来。在这种情况下,库的顺序很重要:
[build]
link = ["blas", "lapack"]
使用系统安装的模块
若要使用未在fpm包或其依赖项中定义的模块,请使用生成(build)表中的外部模块(external-modules)键指定模块名称。
重要
fpm无法自动定位外部模块文件;用户有责任使用编译器标志指定必要的包含目录,以便编译器可以在编译期间找到外部模块文件。
例如:
[build]
external-modules = "netcdf"
可以将多个外部模块指定为一个列表。
例如:
[build]
external-modules = ["netcdf", "h5lt"]
目标自动发现
备注
仅在Fortran fpm中受支持。
可执行文件和测试可以在其默认目录中自动发现。自动发现以递归方式在 app
、example
和 test
目录中搜索定义,并分别将它们声明为可执行目标、示例目标和测试目标。默认情况下,自动发现处于启用状态。
要禁用目标的自动发现,请将自动可执行文件(auto-executables)、自动示例(auto-examples)和自动测试(auto-tests)条目设置为false。
[build]
auto-executables = false
auto-examples = false
auto-tests = false
指定依赖项
…
SSSSSSSSSSSSSSSSSSSSSSS
方流返,Fortran编程 – FPM包管理器介绍(建议感兴趣的跳着看);
00:01 bilibili直播配置
05:30 xmake官网
06:40 xmake演示,主要c,c++,
11:39 xmake作者,知乎,国人软件,支持很多语言,fortran,但可能没其他语言官方的包管理器好
16:03 xmake缺陷
- mod,贡献,
23:10 fpm文档,方流返在写,
- cargo,
- 环境路径,
32:42 fpm缺点,issue,
- …
35:45 fpm演示,运行c,交互c,
39:27 fpm演示,图形界面
- 编码问题
- flag的管理,
47:26 中文学习文档,https://fortran-fans.github.io/Fortran-in-Action/,
SSSSSSSSSSSSSSSS xmake?
xmake作者B站账号
https://space.bilibili.com/2058574066
SSSSSSSSSSSSSSSSSSSSSSS
【我创建的对应FPM的github项目(nice)】
https://github.com/Liu-Jincan/study-fpm
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
【Preparing your package for FPM,重点】
https://github.com/fortran-lang/fpm/blob/main/PACKAGING.md
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
What kind of package can fpm build?
You can use fpm to build:
- Applications (program only)
- Libraries (modules only)
- Combination of the two (programs and modules combined)
Let’s look at some examples of different kinds of package layouts that you can use with fpm.
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
Single program (失败,简单的例子,体现的也是前面的失败,WHY?已解决)
Let’s start with the simplest package imaginable—a single program without dependencies or modules. Here’s what the layout of the top-level directory looks like:
.
├── app
│ └── main.f90
└── fpm.toml
We have one source file (main.f90
) in one directory (app
). Its contents are:
program main
print *, 'Hello, World!'
end program main
This program prints the usual greeting to the standard output, and nothing more.
There’s another important file in the top-level directory, fpm.toml
. This is fpm’s configuration file specific to your package. It includes all the data that fpm needs to build your app. In our simple case, it looks like this:
name = "hello"
version = "0.1.0"
license = "MIT"
author = "Jane Programmer"
maintainer = "jane@example.com"
copyright = "2020 Jane Programmer"
The preamble includes some metadata, such as license
, author
, and similar, that you may have seen in other package manager configuration files. The one option that matters here right now is:
name = "hello"
This line specifies the name of your package, which determines the name of the executable file of your program. In this example, our program executable, once built, will be called hello
.
Let’s now build this program using fpm:
$ fpm build
# gfortran (for build/debug/app/main.o)
# gfortran (for build/debug/app/hello)
On the first line, we ran fpm build
to compile and link the application. The latter two lines are emitted by fpm, and indicate which command was executed at each build step (gfortran
), and which files have been output by it: object file main.o
, and executable hello
.
We can now run the app with fpm run
:
$ fpm run
Hello, World!
If your application needs to use a module internally, but you don’t intend to build it as a library to be used in other projects, you can include the module in your program source file as well. For example:
$ cat app/main.f90
module math_constants
real, parameter :: pi = 4 * atan(1.)
end module math_constants
program main
use math_constants, only: pi
print *, 'Hello, World!'
print *, 'pi = ', pi
end program main
Now, run this using fpm run
:
$ fpm run
# gfortran (for build/debug/app/main.o)
# gfortran (for build/debug/app/hello)
Hello, World!
pi = 3.14159274
- Notice that you can run
fpm run
, and if the package hasn’t been built yet,fpm build
will run automatically for you. This is true if the source files have been updated since the last build. Thus, if you want to run your application, you can skip thefpm build
step, and go straight tofpm run
. - Although we have named our program
hello
, which is the same name as the package name infpm.toml
, you can name it anything you want as long as it’s permitted by the language.
==》
FAQ已解决
==》
In this last example, our source file defined a math_constants
module inside the same source file as the main program. Let’s see how we can define an fpm package that makes this module available as a library.
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
Multi-module library
In this example, we’ll use another module to define a 64-bit real kind parameter and make it available in math_constants
to define pi
with higher precision. To make this exercise worthwhile, we’ll define another math constant, Euler’s number.
Our package layout looks like this:
.
├── fpm.toml
└── src
├── math_constants.f90
└── type_kinds.f90
And our source file contents are:
$ cat src/math_constants.f90
module math_constants
use type_kinds, only: rk
real(rk), parameter :: pi = 4 * atan(1._rk)
real(rk), parameter :: e = exp(1._rk)
end module math_constants
$ cat src/type_kinds.f90
module type_kinds
use iso_fortran_env, only: real64
integer, parameter :: rk = real64
end module type_kinds
and there are no changes to our fpm.toml
relative to previous examples.
Like before, notice that the module
type_kinds
is name exactly as the source file that contains it. This is important.模块名称和其文件名称一致;
By now you know how to build the package:
$ fpm build
# gfortran (for build/debug/library/type_kinds.o build/debug/library/type_kinds.mod)
# gfortran (for build/debug/library/math_constants.o build/debug/library/math_constants.mod)
# ar (for build/debug/library/math_constants.a)
ar: creating build/debug/library/math_constants.a
Our build path now contains:
$ ls build/debug/library/
math_constants.a math_constants.mod math_constants.o type_kinds.mod type_kinds.o
- 没看到
build/debug/library
,
And the static library includes all the object files:
$ nm build/debug/library/math_constants.a
math_constants.o:
type_kinds.o:
- 没看到
math_constants.a
,- nm命令是什么,
The takeaways from this example are that:
fpm automatically scanned the
src
directory for any source files.自动浏览资源文件,
It also resolved the dependency order between different modules.
解决了不同modules的依赖问题(👍),
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
Single program+Multi-module library
Let’s now combine the two previous examples into one: We’ll build the math constants library and an executable program that uses it. We’ll use this program as a demo, and to verify that defining higher-precision constants from the previous example actually worked.
Here’s the package layout for your application + library package:
.
├── app
│ └── main.f90
├── fpm.toml
└── src
├── math_constants.f90
└── type_kinds.f90
Our fpm.toml
remains unchanged and our executable program source file is:
$ cat app/main.f90
program main
use math_constants, only: e, pi
print *, 'math_constants library demo'
print *, 'pi = ', pi
print *, 'e = ', e
end program main
Let’s go straight to running the demo program:
$ fpm run
# gfortran (for build/debug/library/type_kinds.o build/debug/library/type_kinds.mod)
# gfortran (for build/debug/library/math_constants.o build/debug/library/math_constants.mod)
# ar (for build/debug/library/math_constants.a)
ar: creating build/debug/library/math_constants.a
# gfortran (for build/debug/app/main.o)
# gfortran (for build/debug/app/math_constants)
math_constants library demo
pi = 3.1415926535897931
e = 2.7182818284590451
直接运行
fpm run
会出错,刘锦灿@LAPTOP-085N0595 MINGW64 /d/zetero/VScode/Fortran/fpm/multi-module $ fpm run <INFO> No executables to run STOP 0 刘锦灿@LAPTOP-085N0595 MINGW64 /d/zetero/VScode/Fortran/fpm/multi-module $ fpm build 刘锦灿@LAPTOP-085N0595 MINGW64 /d/zetero/VScode/Fortran/fpm/multi-module $ fpm run <INFO> No executables to run STOP 0
解决方法:删除mod文件和
build
文件夹,再fpm run
,RM -f ./src/*.mod && RM -f -R build && RM -f ./app/*.mod && fpm run
The fpm build + run process works as expected, and our program correctly outputs higher-precision constants.
So far we covered how fpm builds:
- A single program
- A single-module library
- A multi-module library
- A program and a library
However, all our modules so far have been organized in the top level source directory. More complex libraries may organize their modules in subdirectories. Let’s see how we can build this with fpm.
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
Single program+Multi-level library
In this example, we’ll define our library as a collection of modules, two of which are defined in a subdirectory:
.
├── app
│ └── main.f90
├── fpm.toml
└── src
├── math_constants
│ ├── derived.f90
│ └── fundamental.f90
├── math_constants.f90
└── type_kinds.f90
First, fpm.toml
and src/type_kinds.f90
remain unchanged relative to the previous example.
The rest of the source files are:
$ cat src/math_constants.f90
module math_constants
use math_constants_fundamental, only: e, pi
use math_constants_derived, only: half_pi, two_pi
end module math_constants
$ cat src/math_constants/fundamental.f90
module math_constants_fundamental
use type_kinds, only: rk
real(rk), parameter :: pi = 4 * atan(1._rk)
real(rk), parameter :: e = exp(1._rk)
end module math_constants_fundamental
$ cat src/math_constants/derived.f90
module math_constants_derived
use math_constants_fundamental, only: pi
use type_kinds, only: rk
real(rk), parameter :: two_pi = 2 * pi
real(rk), parameter :: half_pi = pi / 2
end module math_constants_derived
$ cat app/main.f90
program main
use math_constants, only: e, pi, half_pi, two_pi
print *, 'math_constants library demo'
print *, 'pi = ', pi
print *, '2*pi = ', two_pi
print *, 'pi/2 = ', half_pi
print *, 'e = ', e
end program main
Our top-level math_constants
module now doesn’t define the constants, but imports them from the two modules in the subdirectory. Constants e
and pi
we define in the math_constants_fundamental
module, and two_pi
and half_pi
in the math_constants_derived
module. From the main program, we access all the constants from the top-level module math_constants
.
Let’s build and run this package:
$ fpm run
# gfortran (for build/debug/library/type_kinds.o build/debug/library/type_kinds.mod)
# gfortran (for build/debug/library/math_constants_fundamental.o build/debug/library/math_constants_fundamental.mod)
# gfortran (for build/debug/library/math_constants_derived.o build/debug/library/math_constants_derived.mod)
# gfortran (for build/debug/library/math_constants.o build/debug/library/math_constants.mod)
# ar (for build/debug/library/math_constants.a)
ar: creating build/debug/library/math_constants.a
# gfortran (for build/debug/app/main.o)
# gfortran (for build/debug/app/math_constants)
math_constants library demo
pi = 3.1415926535897931
2*pi = 6.2831853071795862
pi/2 = 1.5707963267948966
e = 2.7182818284590451
Again, fpm built and run the package as expected.
Recall from an earlier example that fpm required the modules in the top-level
src
directory to be named the same as their source file. This is whysrc/math_constants.f90
definesmodule math_constants
.For modules defined in subdirectories, there’s an additional requirement: module name must contain the path components of the directory that its source file is in. In our case,
src/math_constants/fundamental.f90
defines themath_constants_fundamental
module. Likewise,src/math_constants/derived.f90
defines themath_constants_derived
module.This rule applies generally to any number of nested directories and modules. For example,
src/a/b/c/d.f90
must define a module calleda_b_c_d
.很重要的一点;
Takeaways from this example are that:
- You can place your module source files in any levels of subdirectories inside
src
. - The module name must include the path components and the source file name–for example,
src/a/b/c/d.f90
must define a module calleda_b_c_d
.
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
fpm.toml: [library],[[executable]]
So far we’ve let fpm use its defaults to determine the layout of our package. It determined where our library sources would live, what the name of the executable will be, and some other things. But we can be more explicit about it, and make some changes to those things.
Let’s look at what the fpm.toml
file from our last example would look like if we specified everything.
name = "math_constants"
version = "0.1.0"
license = "MIT"
author = "Jane Programmer"
maintainer = "jane@example.com"
copyright = "2020 Jane Programmer"
[library]
source-dir="src"
[[ executable ]]
name="math_constants"
source-dir="app"
main="main.f90"
You can see that by making these explicit in the fpm.toml
we are able to change many of the settings that fpm used by default. We can change the folders where our sources are stored, we can change the name of our executable, and we can change the name of the file our program is defined in.
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
FAQ:如何实现每一个application文件与一个executable对应?
为了明确每一个
executable
与每一个application文件的对应关系,将auto-executables
设置为false,可以通过
fpm run --list
查询executable
的个数,fpm run --list
如果
auto-executables
不设置为false,其默认为true,那么按照上面的操作会出错,因为auto=executables
会对应一个application文件,加上executable
对应的三个application文件,而实际上只有三个application文件,肯定存在某一个application文件有重复的executable
文件,这在fpm
中是不允许的。想运行某一个文件可以,例如
fpn run "app1_exe2"
,像运行所有的target文件,即executable文件,可以
fpm run --all
,
example
和test
与executable
类似;
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
FAQ:每次 fpm run
都要删除 mod
和 build
文件夹?
不是的,
在每次 fpm run
前可以删除 mod
,(因为 mod
文件时自动生成的,fpm
实际运行是不需要 mod
)
但是对于 build
文件夹不应该删除,否则信息会丢失,
建议:find . -name *.mod | xargs rm -f && fpm run
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
fpm.toml: [test]
fpm also provides support for unit testing. By default, fpm looks for a program in test/main.f90
which it will compile and execute with the command fpm test
. The tests are treated pretty much exactly like the executables.
[test]和[executable]不是相似,现在看来,是基本一摸一样;
Let’s define one explicitly in our fpm.toml
file. We’ll make sure that our definition of pi
satisfies the property sin(pi) == 0.0
. Here’s the fpm.toml
file:
name = "math_constants"
version = "0.1.0"
license = "MIT"
author = "Jane Programmer"
maintainer = "jane@example.com"
copyright = "2020 Jane Programmer"
[library]
source-dir="src"
[[ executable ]]
name="math_constants"
source-dir="app"
main="main.f90"
[[ test ]]
name="runTests"
source-dir="test"
main="main.f90"
where the contents of the main.f90
file are
program main
use math_constants, only: pi
print *, "sin(pi) = ", sin(pi)
end program main
With this setup, we can run our tests.
$ fpm test
# gfortran (for build/debug/library/type_kinds.o build/debug/library/type_kinds.mod)
# gfortran (for build/debug/library/math_constants_fundamental.o build/debug/library/math_constants_fundamental.mod)
# gfortran (for build/debug/library/math_constants_derived.o build/debug/library/math_constants_derived.mod)
# gfortran (for build/debug/library/math_constants.o build/debug/library/math_constants.mod)
# ar (for build/debug/library/math_constants.a)
ar: creating build/debug/library/math_constants.a
# gfortran (for build/debug/app/main.o)
# gfortran (for build/debug/app/math_constants)
# gfortran (for build/debug/test/main.o)
# gfortran (for build/debug/test/runTests)
sin(pi) = 1.2246467991473532E-016
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
fpm.toml: [example]
Here’s the fpm.toml
file:
[build]
auto-examples=false
[[ example ]]
name="math_constants"
source-dir="app"
main="main.f90"
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
Adding dependencies
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
fpm.toml:[dependencies]
Inevitably, you’ll want to be able to include other libraries in your project. fpm makes this incredibly simple, by taking care of fetching and compiling your dependencies for you. You just tell it what your dependencies are, and where to find them. Let’s add a dependency to our library. Now our fpm.toml
file looks like this:
name = "math_constants"
version = "0.1.0"
license = "MIT"
author = "Jane Programmer"
maintainer = "jane@example.com"
copyright = "2020 Jane Programmer"
[library]
source-dir="src"
[dependencies]
helloff = { git = "https://gitlab.com/everythingfunctional/helloff.git" }
[[ executable ]]
name="math_constants"
source-dir="app"
main="main.f90"
[[ test ]]
name="runTests"
source-dir="test"
main="main.f90"
Now you can use any modules from this library anywhere in your code. Just like this:
program main
use helloff, only: create_greeting
use math_constants, only: e, pi, half_pi, two_pi
print *, 'math_constants library demo'
print *, 'pi = ', pi
print *, '2*pi = ', two_pi
print *, 'pi/2 = ', half_pi
print *, 'e = ', e
print *, create_greeting("fpm")
end program main
这里
use helloff
中,helloff
是一个module
And now, fpm run
will output the following:
math_constants library demo
pi = 3.1415926535897931
2*pi = 6.2831853071795862
pi/2 = 1.5707963267948966
e = 2.7182818284590451
Hello, fpm!
You can also be specific about which version of a dependency you’d like.
- You can specify a branch to use like
helloff = { git = "https://gitlab.com/everythingfunctional/helloff.git", branch = "master" }
, - or a tag like
helloff = { git = "https://gitlab.com/everythingfunctional/helloff.git", tag = "v1.2.3" }
, - or even a specific commit like
helloff = { git = "https://gitlab.com/everythingfunctional/helloff.git", rev = "a1b2c3" }
.
You can even specify the path to another folder, if for example you’ve got another fpm package in the same repository. Like this: helloff = { path = "helloff" }
. Note that you should not specify paths outside of your repository, or things won’t work for your users.
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
fpm.toml: [executable.dependencies]
Additionally, any users of your library will now automatically depend on your dependencies too. So if you don’t need that dependency for the library, like in the above example, then you can specify it for the specific executable like below. Then fpm will still fetch and compile it when building your executable, but users of your library won’t have to.
name = "math_constants"
version = "0.1.0"
license = "MIT"
author = "Jane Programmer"
maintainer = "jane@example.com"
copyright = "2020 Jane Programmer"
[library]
source-dir="src"
[[ executable ]]
name="math_constants"
source-dir="app"
main="main.f90"
[executable.dependencies]
helloff = { git = "https://gitlab.com/everythingfunctional/helloff.git" }
[[ test ]]
name="runTests"
source-dir="test"
main="main.f90"
You can also specify dependencies for your tests in a similar way, with [test.dependencies]
instead of [executable.dependencies]
. There’s also another option for test dependencies.
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
fpm.toml: [dev-dependencies]
The below example makes the dependencies available for all the tests, but again your users won’t depend on these.
name = "math_constants"
version = "0.1.0"
license = "MIT"
author = "Jane Programmer"
maintainer = "jane@example.com"
copyright = "2020 Jane Programmer"
[library]
source-dir="src"
[dev-dependencies]
helloff = { git = "https://gitlab.com/everythingfunctional/helloff.git" }
[[ executable ]]
name="math_constants"
source-dir="app"
main="main.f90"
[[ test ]]
name="runTests"
source-dir="test"
main="main.f90"
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
FAQ:这几类的dependencies有什么区别吗?
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
Custom build scripts (FAQ:不知道在干什么)
fpm.toml: build-script
If there is something special about your library that makes fpm unable to build it, you can provide your own build script. fpm will then simply call your build script to build the library.
To specify a build script to be used, put it in the library section of your fpm.toml
file, like:
[library]
source-dir="src"
build-script="my_build_script"
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
flag
fpm will set the following environment variables to specify some parameters to the build script:
FC
– The Fortran compiler to be used.FFLAGS
– The flags that should be passed to the Fortran compiler.BUILD_DIR
– Where the compiled files should be placed.INCLUDE_DIRS
– The folders where any dependencies can be found, space separated. It is then the responsibility of the build script to generate the appropriate include flags.
Additionally, script will be called with the name of the archive (*.a
file) that should be produced as the command line argument.
Note: If the name of the build script is
Makefile
or ends with.mk
, then the make program will be used to run it. Not the the archive file is explicitly specified as the target to be built
Note: All file and directory names are specified with their full canonical path.
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
FAQ:求助,ReadingModule问题(code:block大哥解决)
@LAPTOP-085N0595 /d/zetero/VScode/Fortran/fpm/demo
$ gfortran -c build/dependencies/stdlib/src/stdlib_hash_64bit.f90 -g -Ibuild/gfortran_2A42023B310FA28D -o build/gfortran_2A42023B310FA28D/demo/build_dependencies_stdlib_src_stdlib_io_npy.f90.o
错误:f951.exe: Fatal Error: Reading module ‘build/gfortran_2A42023B310FA28D/stdlib_kinds.mod’ at line 18 column 1: Unexpected EOF compilation terminated.
==》
【管理员】code::blocks(1943133009) 21:37:58
https://github.com/msys2/MINGW-packages/issues/6908
【新进】Win10+VScode+Gfortran(3079779149) 21:38:59
用的是msys2的bash
【新进】Win10+VScode+Gfortran(3079779149) 22:03:36
code::blocks https://github.com/msys2/MINGW-packages/issues/6908
@code::blocks 十分感谢,我遇到的情况和这个issue一样。在VScode中即使使用msys2的bash还是会发生这种问题,将module名称换成更短的情况可能编译成功,保险起见,还是建议在WSYS2 MinGW中使用gfortran。再次感谢~~
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
FAQ:fpm中git下载依赖问题
刘锦灿@LAPTOP-085N0595 /d/zetero/VScode/Fortran/fpm/fpm-search
$ fpm install --profile release
Initialized empty Git repository in D:/zetero/VScode/Fortran/fpm/fpm-search/build/dependencies/M_CLI2/.git/
fatal: unable to access 'https://github.com/urbanjost/M_CLI2/': OpenSSL SSL_read: Connection was aborted, errno 10053
<ERROR>Error while fetching git repository for remote dependency
STOP 1
设计到git安装依赖库的命令,总是会发病,需要多试几次,
对应不是dev依赖库的安装,记住安装失败后,去build指定位置删除对应文件夹,否则:
刘锦灿@LAPTOP-085N0595 /d/zetero/VScode/Fortran/fpm/fpm-search $ fpm install --profile release fatal: your current branch 'main' does not have any commits yet <ERROR>Error while retrieving commit information STOP 1
SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS
FAQ:NotGNU问题
刘锦灿@LAPTOP-085N0595 MINGW64 /d/zetero/VScode/Fortran/fpm/multi-module
$ fpm build
+ mkdir build\dependencies
+ mkdir build\gfortran_2A42023B310FA28D
+ mkdir build\gfortran_2A42023B310FA28D\hello\
+ gfortran -c .\.\src\type_kinds.f90 -Wall -Wextra -Wimplicit-interface -fPIC -fmax-errors=1 -g -fcheck=bounds -fcheck=array-temps -fbacktrace -fcoarray=single -J build\gfortran_2A42023B310FA28D -Ibuild\gfortran_2A42023B310FA28D -o build\gfortran_2A42023B310FA28D\hello\src_type_kinds.f90.o
+ gfortran -c .\.\src\math_constants.f90 -Wall -Wextra -Wimplicit-interface -fPIC -fmax-errors=1 -g -fcheck=bounds -fcheck=array-temps -fbacktrace -fcoarray=single -J build\gfortran_2A42023B310FA28D -Ibuild\gfortran_2A42023B310FA28D -o build\gfortran_2A42023B310FA28D\hello\src_math_constants.f90.o
.\.\src\math_constants.f90:2:9:
2 | use type_kinds, only: rk
| 1
Fatal Error: File '.\.\src/type_kinds.mod' opened at (1) is not a GNU Fortran module file
compilation terminated.
<ERROR> Compilation failed for object " src_math_constants.f90.o "
<ERROR>stopping due to failed compilation
STOP 1
解决方法:
RM -f ./src/*.mod && RM -f -R build && RM -f ./app/*.mod && fpm run
find --help
find ./app ./src ./lib -name *.mod | xargs rm -f && RM -f -R build && fpm run
find . -name *.mod | xargs rm -f && fpm run
FAQ:Fortran runtime error: File cannot be deleted
解决方法:多运行几次