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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
|
# Preparing your package for FPM
This document describes how you need to organize your application or library
for it to successfully build with the Fortran Package Manager (FPM).
* [What kind of package can FPM build?](#what-kind-of-package-can-fpm-build)
* [Example package layouts](#example-package-layouts)
- [Single program](#single-program)
- [Single-module library](#single-module-library)
- [Multi-module library](#multi-module-library)
- [Application and library](#application-and-library)
- [Multi-level library](#multi-level-library)
- [Be more explicit](#be-more-explicit)
- [Add some tests](#add-some-tests)
## What kind of package can FPM build?
You can use FPM to build:
* Applications (program only)
* Libraries (modules only)
* Combination of the two (programs and modules combined)
Let's look at some examples of different kinds of package layouts that you can
use with FPM.
## Example package layouts
This section describes some example package layouts that you can build with FPM.
You can use them to model the layout of your own package.
### Single program
Let's start with the simplest package imaginable--a single program without
dependencies or modules.
Here's what the layout of the top-level directory looks like:
```
.
├── app
│ └── main.f90
└── fpm.toml
```
We have one source file (`main.f90`) in one directory (`app`).
Its contents are:
```fortran
program hello
print *, 'Hello, World!'
end program hello
```
This program prints the usual greeting to the standard output, and nothing more.
There's another important file in the top-level directory, `fpm.toml`.
This is FPM's configuration file specific to your package.
It includes all the data that FPM needs to build your app.
In our simple case, it looks like this:
```toml
name = "hello"
version = "0.1.0"
license = "MIT"
author = "Jane Programmer"
maintainer = "jane@example.com"
copyright = "2020 Jane Programmer"
```
The preamble includes some metadata, such as `license`, `author`, and similar,
that you may have seen in other package manager configuration files.
The one option that matters here right now is:
```toml
name = "hello"
```
This line specifies the name of your package, which determines the name of
the executable file of your program.
In this example, our program executable, once built, will be called `hello`.
Let's now build this program using FPM:
```
$ fpm build
# gfortran (for build/debug/app/main.o)
# gfortran (for build/debug/app/hello)
```
On the first line, we ran `fpm build` to compile and link the application.
The latter two lines are emitted by FPM, and indicate which command was
executed at each build step (`gfortran`), and which files have been output
by it: object file `main.o`, and executable `hello`.
We can now run the app with `fpm run`:
```
$ fpm run
Hello, World!
```
If your application needs to use a module internally, but you don't intend
to build it as a library to be used in other projects, you can include the
module in your program source file as well.
For example:
```fortran
$ cat app/main.f90
module math_constants
real, parameter :: pi = 4 * atan(1.)
end module math_constants
program hello
use math_constants, only: pi
print *, 'Hello, World!'
print *, 'pi = ', pi
end program hello
```
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 the `fpm build` step,
and go straight to `fpm run`.
Although we have named our program `hello`, which is the same name as the
package name in `fpm.toml`, you can name it anything you want as long as it's
permitted by the language.
In this last example, our source file defined a `math_constants` module
inside the same source file as the main program.
Let's see how we can define an FPM package that makes this module available
as a library.
### Single-module library
The package layout for this example looks like this:
```
.
├── fpm.toml
└── src
└── math_constants.f90
```
In this example we'll build a simple math constants library that exports
the number pi as a parameter:
```fortran
$ cat src/math_constants.f90
module math_constants
real, parameter :: pi = 4 * atan(1.)
end module math_constants
```
and our `fpm.toml` is the same as before.
Now use `fpm build` to build the package:
```
$ fpm build
# gfortran (for build/debug/library/math_constants.o build/debug/library/math_constants.mod)
# ar (for build/debug/library/math_constants.a)
ar: creating build/debug/library/math_constants.a
```
Based on the output of `fpm build`, FPM first ran `gfortran` to emit the
binary object (`math_constants.o`) and module (`math_constants.mod`) files.
Then it ran `ar` to create a static library archive `math_constants.a`.
`build/debug/library` is thus both your include and library path, should you
want to compile and link an exteranl program with this library.
For modules in the top-level (`src`) directory, FPM requires that:
* The module has the same name as the source file.
* There is only one module per file.
These two requirements simplify the build process for FPM.
As Fortran compilers emit module files (`.mod`) with the same name as the
module itself (but not the source file, `.f90`), naming the module the same as
the source file allows FPM to:
* Uniquely and exactly map a source file (`.f90`) to its object (`.o`) and
module (`.mod`) files.
* Avoid conflicts with modules of the same name that could appear in dependency
packages (more on this in a bit).
Since this is a library without executable programs, `fpm run` here does
nothing.
In this example, our library is made of only one module.
However, most real-world libraries are likely to use multiple modules.
Let's see how you can package your multi-module library.
### Multi-module library
In this example, we'll use another module to define a 64-bit real kind
parameter and make it available in `math_constants` to define `pi` with
higher precision.
To make this exercise worthwhile, we'll define another math constant,
Euler's number.
Our package layout looks like this:
```
.
├── fpm.toml
└── src
├── math_constants.f90
└── type_kinds.f90
```
and our source file contents are:
```fortran
$ cat src/math_constants.f90
module math_constants
use type_kinds, only: rk
real(rk), parameter :: pi = 4 * atan(1._rk)
real(rk), parameter :: e = exp(1._rk)
end module math_constants
$ cat src/type_kinds.f90
module type_kinds
use iso_fortran_env, only: real64
integer, parameter :: rk = real64
end module type_kinds
```
and there are no changes to our `fpm.toml` relative to previous examples.
Like before, notice that the module `type_kinds` is name exactly as the
source file that contains it.
This is important.
By now you know how to build the package:
```
$ fpm build
# gfortran (for build/debug/library/type_kinds.o build/debug/library/type_kinds.mod)
# gfortran (for build/debug/library/math_constants.o build/debug/library/math_constants.mod)
# ar (for build/debug/library/math_constants.a)
ar: creating build/debug/library/math_constants.a
```
Our build path now contains:
```
$ ls build/debug/library/
math_constants.a math_constants.mod math_constants.o type_kinds.mod type_kinds.o
```
and the static library includes all the object files:
```
$ nm build/debug/library/math_constants.a
math_constants.o:
type_kinds.o:
```
The takeaways from this example are that:
* FPM automatically scanned the `src` directory for any source files.
* It also resolved the dependency order between different modules.
### Application and library
Let's now combine the two previous examples into one:
We'll build the math constants library _and_ an executable program that uses
it.
We'll use this program as a demo, and to verify that defining higher-precision
constants from the previous example actually worked.
Here's the package layout for your application + library package:
```
.
├── app
│ └── main.f90
├── fpm.toml
└── src
├── math_constants.f90
└── type_kinds.f90
```
Our `fpm.toml` remains unchanged and our executable program source file is:
```fortran
$ cat app/main.f90
program demo
use math_constants, only: e, pi
print *, 'math_constants library demo'
print *, 'pi = ', pi
print *, 'e = ', e
end program demo
```
Let's go straight to running the demo program:
```
$ fpm run
# gfortran (for build/debug/library/type_kinds.o build/debug/library/type_kinds.mod)
# gfortran (for build/debug/library/math_constants.o build/debug/library/math_constants.mod)
# ar (for build/debug/library/math_constants.a)
ar: creating build/debug/library/math_constants.a
# gfortran (for build/debug/app/main.o)
# gfortran (for build/debug/app/math_constants)
math_constants library demo
pi = 3.1415926535897931
e = 2.7182818284590451
```
The FPM build + run process works as expected, and our program correctly outputs
higher-precision constants.
So far we covered how FPM builds:
* A single program
* A single-module library
* A multi-module library
* A program and a library
However, all our modules so far have been organized in the top level source
directory.
More complex libraries may organize their modules in subdirectories.
Let's see how we can build this with FPM.
### Multi-level library
In this example, we'll define our library as a collection of modules,
two of which are defined in a subdirectory:
```
.
├── app
│ └── main.f90
├── fpm.toml
└── src
├── math_constants
│ ├── derived.f90
│ └── fundamental.f90
├── math_constants.f90
└── type_kinds.f90
```
First, `fpm.toml` and `src/type_kinds.f90` remain unchanged relative to the
previous example.
The rest of the source files are:
```fortran
$ cat src/math_constants.f90
module math_constants
use math_constants_fundamental, only: e, pi
use math_constants_derived, only: half_pi, two_pi
end module math_constants
$ cat src/math_constants/fundamental.f90
module math_constants_fundamental
use type_kinds, only: rk
real(rk), parameter :: pi = 4 * atan(1._rk)
real(rk), parameter :: e = exp(1._rk)
end module math_constants_fundamental
$ cat src/math_constants/derived.f90
module math_constants_derived
use math_constants_fundamental, only: pi
use type_kinds, only: rk
real(rk), parameter :: two_pi = 2 * pi
real(rk), parameter :: half_pi = pi / 2
end module math_constants_derived
$ cat app/main.f90
program demo
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 demo
```
Our top-level `math_constants` module now doesn't define the constants,
but imports them from the two modules in the subdirectory.
Constants `e` and `pi` we define in the `math_constants_fundamental` module,
and `two_pi` and `half_pi` in the `math_constants_derived` module.
From the main program, we access all the constants from the top-level
module `math_constants`.
Let's build and run this package:
```
$ fpm run
# gfortran (for build/debug/library/type_kinds.o build/debug/library/type_kinds.mod)
# gfortran (for build/debug/library/math_constants_fundamental.o build/debug/library/math_constants_fundamental.mod)
# gfortran (for build/debug/library/math_constants_derived.o build/debug/library/math_constants_derived.mod)
# gfortran (for build/debug/library/math_constants.o build/debug/library/math_constants.mod)
# ar (for build/debug/library/math_constants.a)
ar: creating build/debug/library/math_constants.a
# gfortran (for build/debug/app/main.o)
# gfortran (for build/debug/app/math_constants)
math_constants library demo
pi = 3.1415926535897931
2*pi = 6.2831853071795862
pi/2 = 1.5707963267948966
e = 2.7182818284590451
```
Again, FPM built and run the package as expected.
Recall from an earlier example that FPM required the modules in the top-level
`src` directory to be named the same as their source file.
This is why `src/math_constants.f90` defines `module math_constants`.
For modules defined in subdirectories, there's an additional requirement:
module name must contain the path components of the directory that its
source file is in.
In our case, `src/math_constants/fundamental.f90` defines
the `math_constants_fundamental` module.
Likewise, `src/math_constants/derived.f90` defines
the `math_constants_derived` module.
This rule applies generally to any number of nested directories and modules.
For example, `src/a/b/c/d.f90` must define a module called `a_b_c_d`.
Takeaways from this example are that:
* You can place your module source files in any levels of subdirectories inside `src`.
* The module name must include the path components and the source file name--for example,
`src/a/b/c/d.f90` must define a module called `a_b_c_d`.
### Be more explicit
So far we've let FPM use its defaults to determine the layout of our package.
It determined where our library sources would live, what the name of the
executable will be, and some other things. But we can be more explicit about it,
and make some changes to those things.
Let's look at what the `fpm.toml` file from our last example would look like if
we specified everything.
```toml
name = "math_constants"
version = "0.1.0"
license = "MIT"
author = "Jane Programmer"
maintainer = "jane@example.com"
copyright = "2020 Jane Programmer"
[library]
source-dir="src"
[[executable]]
name="math_constants"
source-dir="app"
main="main.f90"
```
You can see that by making these explicit in the `fpm.toml` we are able to
change many of the settings that FPM used by default. We can change the folders
where our sources are stored, we can change the name of our executable, and we
can change the name of the file our program is defined in.
### Add some tests
FPM also provides support for unit testing. By default, FPM looks for a program
in `test/main.f90` which it will compile and execute with the command `fpm test`.
The tests are treated pretty much exactly like the executables. Let's define
one explicitly in our `fpm.toml` file. We'll make sure that our definition of
`pi` satisfies the property `sin(pi) == 0.0`. Here's the `fpm.toml` file,
```toml
name = "math_constants"
version = "0.1.0"
license = "MIT"
author = "Jane Programmer"
maintainer = "jane@example.com"
copyright = "2020 Jane Programmer"
[library]
source-dir="src"
[[executable]]
name="math_constants"
source-dir="app"
main="main.f90"
[[test]]
name="runTests"
source-dir="test"
main="main.f90"
```
where the contents of the `main.f90` file are
```fortran
program tests
use math_constants, only: pi
print *, "sin(pi) = ", sin(pi)
end program tests
```
With this setup, we can run our tests.
```
$ fpm test
# gfortran (for build/debug/library/type_kinds.o build/debug/library/type_kinds.mod)
# gfortran (for build/debug/library/math_constants_fundamental.o build/debug/library/math_constants_fundamental.mod)
# gfortran (for build/debug/library/math_constants_derived.o build/debug/library/math_constants_derived.mod)
# gfortran (for build/debug/library/math_constants.o build/debug/library/math_constants.mod)
# ar (for build/debug/library/math_constants.a)
ar: creating build/debug/library/math_constants.a
# gfortran (for build/debug/app/main.o)
# gfortran (for build/debug/app/math_constants)
# gfortran (for build/debug/test/main.o)
# gfortran (for build/debug/test/runTests)
sin(pi) = 1.2246467991473532E-016
```
### Adding Dependencies
Inevitably you'll want to be able to include other libraries in your project.
fpm makes this incredibly simple, by taking care of fetching and compiling your
dependencies for you. You just tell it what your dependencies are, and where to
find them. Let's add a dependency to our library. Now our `fpm.toml` file looks
like this:
```toml
name = "math_constants"
version = "0.1.0"
license = "MIT"
author = "Jane Programmer"
maintainer = "jane@example.com"
copyright = "2020 Jane Programmer"
[library]
source-dir="src"
[dependencies]
helloff = { git = "https://gitlab.com/everythingfunctional/helloff.git" }
[[executable]]
name="math_constants"
source-dir="app"
main="main.f90"
[[test]]
name="runTests"
source-dir="test"
main="main.f90"
```
Now you can use any modules from this library anywhere in your code. Just like
this:
```fortran
program demo
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 demo
```
And now `fpm run` will output the following:
```
math_constants library demo
pi = 3.1415926535897931
2*pi = 6.2831853071795862
pi/2 = 1.5707963267948966
e = 2.7182818284590451
Hello, fpm!
```
Additionally, any users of your library will now automatically depend on your
dependencies too. So if you don't need that depedency for the library, like in
the above example, then you can specify it for the specific executable like
below. Then fpm will still fetch and compile it when building your executable,
but users of your library won't have to.
```toml
name = "math_constants"
version = "0.1.0"
license = "MIT"
author = "Jane Programmer"
maintainer = "jane@example.com"
copyright = "2020 Jane Programmer"
[library]
source-dir="src"
[[executable]]
name="math_constants"
source-dir="app"
main="main.f90"
[executable.dependencies]
helloff = { git = "https://gitlab.com/everythingfunctional/helloff.git" }
[[test]]
name="runTests"
source-dir="test"
main="main.f90"
```
You can also specify dependencies for your tests in a similar way, with
`[test.dependencies]` instead of `[executable.dependencies]`. There's also
another option for test dependencies. The below example makes the dependencies
available for all the tests, but again your users won't depend on these.
```toml
name = "math_constants"
version = "0.1.0"
license = "MIT"
author = "Jane Programmer"
maintainer = "jane@example.com"
copyright = "2020 Jane Programmer"
[library]
source-dir="src"
[dev-dependencies]
helloff = { git = "https://gitlab.com/everythingfunctional/helloff.git" }
[[executable]]
name="math_constants"
source-dir="app"
main="main.f90"
[[test]]
name="runTests"
source-dir="test"
main="main.f90"
```
You can also be specific about which version of a dependency you'd like. You can
specify a branch to use like `helloff = { git = "https://gitlab.com/everythingfunctional/helloff.git", branch = "master" }`,
or a tag like `helloff = { git = "https://gitlab.com/everythingfunctional/helloff.git", tag = "v1.2.3" }`,
or even a specific commit like `helloff = { git = "https://gitlab.com/everythingfunctional/helloff.git", rev = "a1b2c3" }`.
You can even specify the path to another folder, if for example you've got another
fpm package in the same repository. Like this: `helloff = { path = "helloff" }`.
Note that you should *not* specify paths outside of your repository, or things
won't work for your users.
|