Skip to content

Commit ff66e8e

Browse files
authored
Merge pull request #99 from arjenmarkus/building_programs_revised
Update of the minibook on building programs:
2 parents 88fc72a + e06ec5f commit ff66e8e

9 files changed

+853
-1
lines changed

_data/learning.yml

+12-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,18 @@ books:
2828
- link: /learn/quickstart/organising_code
2929
- link: /learn/quickstart/derived_types
3030

31-
31+
- title: Building programs
32+
description: How to use the compiler to build an executable program
33+
category: Getting started
34+
link: /learn/building_programs
35+
pages:
36+
- link: /learn/building_programs/compiling_source
37+
- link: /learn/building_programs/linking_pieces
38+
- link: /learn/building_programs/runtime_libraries
39+
- link: /learn/building_programs/include_files
40+
- link: /learn/building_programs/managing_libraries
41+
- link: /learn/building_programs/build_tools
42+
- link: /learn/building_programs/distributing
3243

3344
# Web links listed at the bottom of the 'Learn' landing page
3445
#
+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
---
2+
layout: book
3+
title: Build tools
4+
permalink: /learn/building_programs/build_tools
5+
---
6+
7+
If this seems complicated, well, you are right and we are only
8+
scratching the surface here. The complications arise because of
9+
differences between platforms, differences between compilers/linkers and
10+
because of differences in the way programs are set up. Fortunately,
11+
there are many tools to help configure and maintain the build steps.
12+
We will not try and catalogue them, but give instead a very limited
13+
list of tools that you typically encounter:
14+
15+
* The `make` utility is a classical tool that uses instructions about
16+
how the various components of a program depend on each other to
17+
efficiently compile and link the program (or programs). It takes a
18+
so-called `Makefile` that contains the dependencies.
19+
20+
Simply put:
21+
22+
If a program file is older than any of the libraries and object files
23+
it depends on, the make utility knows it has to rebuild it and goes on
24+
to look at the libraries and object files - are any out of date?
25+
26+
If an object file is older than the corresponding source file, the
27+
make utility knows it has to compile the source file.
28+
29+
* Integrated development tools take care of many of the above details. A
30+
popular cross-platform tool is Microsoft's [Visual Studio Code](https://code.visualstudio.com/), but others exist,
31+
such as [Atom](https://atom.io/), [Eclipse Photran](https://www.eclipse.org/photran/), and [Code::Blocks](http://www.codeblocks.org/). They offer a graphical
32+
user-interface, but are often very specific for the compiler and
33+
platform.
34+
35+
* Maintenance tools like autotools and CMake can generate Makefiles or
36+
Visual Studio project files via a high-level description. They abstract
37+
away from the compiler and platform specifics.
38+
39+
Here is a very simple example of a `Makefile` as used by the `make` utility,
40+
just to give you an impression:
41+
42+
# Collect the macros at the beginning - easier to customise
43+
FC = gfortran
44+
LD = gfortran
45+
FCOPTS = -c
46+
LDOPTS = "-o "
47+
48+
EXE = .exe
49+
OBJ = .o
50+
51+
all: tabulate$(EXE)
52+
53+
tabulate$(EXE) : tabulate$(OBJ) function$(OBJ)
54+
{tab}$(LD) $(LDOPTS)tabulate$(EXE) tabulate.f90 function$(OBJ)
55+
56+
tabulate$(OBJ) : tabulate.f90 function.mod
57+
{tab}$(FC) $(FCOPTS) tabulate.f90
58+
59+
function$(OBJ) : function.f90
60+
{tab}$(FC) $(FCOPTS) function.f90
61+
62+
(A peculiarity of `make` is that in the input file, tab characters are used
63+
in several places - here indicated as "{tab}" - as significant whitespace.)
64+
65+
When stored in a file "Makefile" and "{tab}" replaced by a tab character,
66+
you can run it like:
67+
68+
```shell
69+
$ make
70+
```
71+
72+
(the name `Makefile` is the default, otherwise use the option `-f` to specify
73+
a different file name). Now only change the file "tabulate.f90" and run it
74+
again. You will see that only that file gets compiled again and then the
75+
program is built. The file "function.f90" was not changed, so the object
76+
file and the module intermediate file would remain unchanged, so there
77+
is no need to recompile it.
+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
---
2+
layout: book
3+
title: Compiling the source code
4+
permalink: /learn/building_programs/compiling_source
5+
---
6+
7+
The first step in the build process is to compile the source code. The
8+
output from this step is generally known as the object code - a set of
9+
instructions for the computer generated from the human-readable source
10+
code. Different compilers will produce different object codes from the
11+
same source code and the naming conventions are different.
12+
13+
The consequences:
14+
15+
* If you use a particular compiler for one source file, you need to use
16+
the same compiler (or a compatible one) for all other pieces. After
17+
all, a program may be built from many different source files and the
18+
compiled pieces have to cooperate.
19+
* Each source file will be compiled and the result is stored in a file
20+
with an extension like ".o" or ".obj". It is these object files that are
21+
the input for the next step: the link process.
22+
23+
Compilers are complex pieces of software: they have to understand the
24+
language in much more detail and depth than the average programmer. They
25+
also need to understand the inner working of the computer. And then,
26+
over the years they have been extended with numerous options to
27+
customise the compilation process and the final program that will be
28+
built.
29+
30+
But the basics are simple enough. Take the gfortran compiler, part of
31+
the GNU compiler collection. To compile a simple program as the one
32+
above, that consists of one source file, you run the following command,
33+
assuming the source code is stored in the file "hello.f90":
34+
35+
```shell
36+
$ gfortran -c hello.f90
37+
```
38+
39+
This results in a file "hello.o" (as the gfortran compiler uses ".o" as
40+
the extension for the object files).
41+
42+
The option "-c" means: only compile the source files. If you were to
43+
leave it out, then the default action of the compiler is to compile the
44+
source file and start the linker to build the actual executable program.
45+
The command:
46+
47+
```shell
48+
$ gfortran hello.f90
49+
```
50+
51+
results in an executable file, "a.out" on Linux or "a.exe" on
52+
Windows.
53+
54+
Some remarks:
55+
56+
* The compiler may complain about the contents of the source file, if it
57+
finds something wrong with it - a typo for instance or an unknown
58+
keyword. In that case the compilation process is broken off and you will
59+
not get an object file or an executable program. For instance, if
60+
the word "program" was inadvertently typed as "prgoram":
61+
62+
```shell
63+
$ gfortran hello3.f90
64+
hello.f90:1:0:
65+
66+
1 | prgoram hello
67+
|
68+
Error: Unclassifiable statement at (1)
69+
hello3.f90:3:17:
70+
71+
3 | end program hello
72+
| 1
73+
Error: Syntax error in END PROGRAM statement at (1)
74+
f951: Error: Unexpected end of file in 'hello.f90'
75+
```
76+
77+
Using this compilation report you can correct the source code and try
78+
again.
79+
80+
* The step without "-c" can only succeed if the source file contains a
81+
main program - characterised by the `program` statement in Fortran.
82+
Otherwise the link step will complain about a missing "symbol", something
83+
along these lines:
84+
85+
```shell
86+
$ gfortran hello2.f90
87+
/usr/lib/../lib64/crt1.o: In function `_start':
88+
(.text+0x20): undefined reference to `main'
89+
collect2: error: ld returned 1 exit status
90+
```
91+
92+
The file "hello2.f90" is almost the same as the file "hello.f90", except
93+
that the keyword `program` has been replaced by the keyword `subroutine`.
94+
95+
The above examples of output from the compiler will differ per compiler
96+
and platform on which it runs. These examples come from the gfortran
97+
compiler running in a Cygwin environment on Windows.
98+
99+
Compilers also differ in the options they support, but in general:
100+
101+
* Options for optimising the code - resulting in faster programs or
102+
smaller memory footprints;
103+
* Options for checking the source code - checks that a variable is not
104+
used before it has been given a value, for instance or checks if some
105+
extension to the language is used;
106+
* Options for the location of include or module files, see below;
107+
* Options for debugging.
108+
+135
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
---
2+
layout: book
3+
title: Distributing your programs
4+
permalink: /learn/building_programs/distributing
5+
---
6+
7+
When you distribute your programs, there are a number of options you can
8+
choose from:
9+
10+
1. Distribute the entire source code
11+
2. Distribute a pre-built executable program
12+
3. Distribute static or dynamic libraries that people can use
13+
14+
__Option 1: Distribute the entire source code__
15+
16+
By far the simplest - for you as a programmer - is this one: you leave it
17+
up to the user to build it on their own machine. Unfortunately, that
18+
means you will have to have a user-friendly build system in place and
19+
the user will have to have access to suitable compilers. For build systems:
20+
see the previous section.
21+
22+
__Option 2: Distribute a pre-built executable program__
23+
24+
A pre-built program that does not need to be customised, other than via its
25+
input, will still need to come with the various run-time libraries and will
26+
be specific to the operating system/environment it was built for.
27+
28+
The set of run-time libraries differs per operating system and compiler version.
29+
For a freely available compiler like gfortran, the easiest thing is to ask the
30+
user to install that compiler on their system. In the case of Windows: the Cygwin
31+
environment may be called for.
32+
33+
Alternatively, you can supply copies of the run-time libraries together with your
34+
program. Put them in the directory where they can be found at run-time.
35+
36+
Note: On Windows, the Intel Fortran comes with a set of _redistributable_ libraries.
37+
These will need to be made available.
38+
39+
In general: use a tool like "ldd" or "dependency walker" to find out what
40+
libraries are required and consult the documentation of the compiler.
41+
42+
If your program does allow customisation, consider using dynamic libraries for this.
43+
More is said about this below.
44+
45+
__Option 3: Distribute static or dynamic libraries that people can use__
46+
47+
This option is a combination of the first two options. It does put some burden on
48+
the user, as they must create a main program that calls your routines in the
49+
proper way, but they do not need to know much about the build system you used.
50+
You will have to deal with the run-time libraries, though.
51+
52+
If you choose this option, besides the compiled libraries, you will also need to
53+
supply the module intermediate files. These files are compiler-specific, but so are
54+
the static libraries you build.
55+
56+
## Distributing the tabulation program
57+
As shown above, the tabulation program can be built with the user-defined function
58+
in a dynamic library. This enables you to:
59+
60+
* Ship the executable (with the appropriate run-time libraries)
61+
* Provide a skeleton version of the module, something like:
62+
63+
```fortran
64+
module user_functions
65+
implicit none
66+
contains
67+
68+
real function f( x )
69+
!DEC$ ATTRIBUTES DLLEXPORT :: f
70+
real, intent(in) :: x
71+
72+
... TO BE FILLED IN ...
73+
74+
end function f
75+
end module user_functions
76+
```
77+
78+
* Provide a basic build script with a command like:
79+
80+
```shell
81+
gfortran -o function.dll function.f90 -shared
82+
```
83+
84+
or:
85+
86+
```shell
87+
ifort -exe:function.dll function.f90 -dll
88+
```
89+
90+
As said, you cannot control that the user has done the right thing - any
91+
DLL "function.dll" with a function `f` would be accepted, but not necessarily
92+
lead to a successful run.
93+
94+
An alternative set-up would be to change the main program into a subroutine
95+
and have the function as an argument:
96+
97+
```fortran
98+
module tabulation
99+
implicit none
100+
contains
101+
102+
subroutine tabulate( f )
103+
interface
104+
real function f( x )
105+
real, intent(in) :: x
106+
end function f
107+
end interface
108+
109+
... actual implementation
110+
111+
end subroutine tabulate
112+
113+
end module tabulation
114+
```
115+
116+
Then provide a skeleton main program:
117+
118+
```fortran
119+
program tabulate_f
120+
use tabulation
121+
122+
call tabulate( func1 )
123+
contains
124+
real function func1( x )
125+
real, intent(in) :: x
126+
127+
... TO BE FILLED IN ...
128+
129+
end function func1
130+
end program tabulate_f
131+
```
132+
133+
The advantage is that the compiler can check the interface of the
134+
function that is passed and that the user has more freedom in the use of the
135+
functionality provided by your library.

0 commit comments

Comments
 (0)