aboutsummaryrefslogtreecommitdiff
path: root/docs/markdown/Compiler-properties.md
blob: 9d533cdccff155c15d08ac9f18f3587c54b965de (plain)
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
# Compiler properties

Not all compilers and platforms are alike. Therefore Meson provides the tools to detect properties of the system during configure time. To get most of this information, you first need to extract the *compiler object* from the main *meson* variable.

```meson
compiler = meson.get_compiler('c')
```

Here we extract the C compiler. We could also have given the argument `cpp` to get the C++ compiler, `objc` to get the objective C compiler and so on. The call is valid for all languages specified in the *project* declaration. Trying to obtain some other compiler will lead to an unrecoverable error.

## System information

This is a bit complex and more throughly explained on the page on [cross compilation](Cross compilation). But if you just want to know the operating system your code will run on, issue this command:

```meson
host_machine.system()
```

Compiler id
==

The compiler object has a method called `get_id`, which returns a lower case string describing the "family" of the compiler. It has one of the following values.

| Value     | Compiler family                |
| -----     | ----------------               |
| gcc       | The GNU Compiler Collection    |
| clang     | The Clang compiler             |
| msvc      | Microsoft Visual Studio        |
| intel     | Intel compiler                 |
| pathscale | The Pathscale Fortran compiler |
| pgi       | The Portland Fortran compiler  |
| sun       | Sun Fortran compiler           |
| g95       | The G95 Fortran compiler       |
| open64    | The Open64 Fortran Compiler    |
| nagfor    | The NAG Fortran compiler       |

Does code compile?
==

Sometimes the only way to test the system is to try to compile some sample code and see if it works. This is a two-phase operation. First we define some code using the multiline string operator:

```meson
code = '''#include<stdio.h>
void func() { printf("Compile me.\n"); }
'''
```

Then we can run the test.

```meson
result = compiler.compiles(code, name : 'basic check')
```

The variable *result* will now contain either `true` or `false` depending on whether the compilation succeeded or not. The keyword argument `name` is optional. If it is specified, Meson will write the result of the check to its log.

Does code compile and link?
==

Sometimes it is necessary to check whether a certain code fragment not only
compiles, but also links successfully, e.g. to check if a symbol is actually
present in a library. This can be done using the '''.links()''' method on a
compiler object like this:

```meson
code = '''#include<stdio.h>
void func() { printf("Compile me.\n"); }
'''
```

Then we can run the test.

```meson
result = compiler.links(code, args : '-lfoo', name : 'link check')
```

The variable *result* will now contain either `true` or `false`
depending on whether the compilation and linking succeeded or not. The keyword
argument `name` is optional. If it is specified, Meson will write the
result of the check to its log.


Compile and run test application
==

Here is how you would compile and run a small test application.

```meson
code = '''#include<stdio.h>
int main(int argc, char **argv) {
  printf("%s\n", "stdout");
  fprintf(stderr, "%s\n", "stderr");
  return 0;
}
'''
result = compiler.run(code, name : 'basic check')
```

The `result` variable encapsulates the state of the test, which can be extracted with the following methods. The `name` keyword argument works the same as with `compiles`.

Method | Return value
-------|----------------
compiled | `True` if compilation succeeded. If `false` then all other methods return undefined values.
returncode | The return code of the application as an integer
stdout | Program's standard out as text.
stderr | Program's standard error as text.

Here is an example usage:

```meson
if result.stdout().strip() == 'some_value'
  # do something
endif
```


Does a header exist?
==

Header files provided by different platforms vary quite a lot. Meson has functionality to detect whether a given header file is available on the system. The test is done by trying to compile a simple test program that includes the specified header. The following snippet describes how this feature can be used.

```meson
if compiler.has_header('sys/fstat.h')
  # header exists, do something
endif
```

Expression size
==

Often you need to determine the size of a particular element (such as `int`, `wchar_t` or `char*`). Using the `compiler` variable mentioned above, the check can be done like this.

```meson
wcharsize = compiler.sizeof('wchar_t', prefix : '#include<wchar.h>')
```

This will put the size of `wchar_t` as reported by sizeof into variable `wcharsize`. The keyword argument `prefix` is optional. If specified its contents is put at the top of the source file. This argument is typically used for setting `#include` directives in configuration files.

In older versions (<= 0.30) meson would error out if the size could not be determined. Since version 0.31 it returns -1 if the size could not be determined.

Does a function exist?
==

Just having a header does say anything about its contents. Sometimes you need to explicitly check if some function exists. This is how we would check whether the function `somefunc` exists in header `someheader.h`

```meson
if compiler.has_function('somefunc', prefix : '#include<someheader.h>')
  # function exists, do whatever is required.
endif
```

Does a structure contain a member?
==

Some platforms have different standard structures. Here's how one would check if a struct called `mystruct` from header `myheader.h</hh> contains a member called `some_member`.

```meson
if compiler.has_member('struct mystruct', 'some_member', prefix : '#include<myheader.h>')
  # member exists, do whatever is required
endif
```

Type alignment
==

Most platforms can't access some data types at any address. For example it is common that a `char` can be at any address but a 32 bit integer only at locations which are divisible by four. Determining the alignment of data types is simple.

```meson
int_alignment = compiler.alignment('int') # Will most likely contain the value 4.
```

## Has argument

This method tests if the compiler supports a given command line argument. This is implemented by compiling a small file with the given argument.

```meson
has_special_flags = compiler.has_argument('-Wspecialthing')
```

*Note*: some compilers silently swallow command line arguments they do not understand. Thus this test can not be made 100% reliable.