Sign in Join
Wiki copytemporary

Macros and Conditionals: what changed

Revision 1 to 2. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
11# Overview
22
33Macros can be used in search paths and file names to let the IDE automatically adapt them to the target platform. **Build macros** are project/package specific macros. They are **not** passed to the compiler. A prominent example is the **LCLWidgetType**, which is defined by the package *LCL* and allows to choose the widget set (carbon, gtk, qt, win32, wince, ...).
44
55**Conditionals** are rules allowing to set macros depending on the target platform and/or other macros. For example you can use them to define special linker options when compiling for Mac OS X. They use a pascal like scripting language allowing to define even complex rules.
66
77You can set the build macros via [[IDE Window: Compiler Options|Project / Project Options / Compiler Options / Additions and Overrides]].
88
99You can set the conditionals via Project / Project Options / Compiler Options / Other / Conditionals.
1010
1111Build macros and conditionals exist since Lazarus 0.9.29.
1212
13-<figure>
14-<img src="CompilerAdditionsAndOverrides1.png" title="CompilerAdditionsAndOverrides1.png" />
15-<figcaption>CompilerAdditionsAndOverrides1.png</figcaption>
16-</figure>
13+![](/wiki-images/c/cd/CompilerAdditionsAndOverrides1.png)
1714
1815# Conditionals
1916
2017The conditionals use a simple scripting language.
2118
2219## Changing compiler options with conditionals
2320
2421The conditionals script can define some variables which values are used by the IDE for the compiler options:
2522
2623- **UnitPath**: appended to *Other Source Files (-Fu)*. The / and \\ characters are automatically converted to the current path delimiter. After adding the search path(s) with a semicolon macros are replaced and relative paths are extended by the package/project directory.
2724- **IncPath**: appended to *Include Files (-Fi)*.
2825- **LibraryPath**: appended to *Libraries (-Fl)*.
2926- **SrcPath**: appended to *Other sources (not used by compiler, only IDE)*.
3027- **DebugPath**: appended to *Debugger path addition (not used by compiler, not by the codetools, only used by debugger)*
3128- **LinkerOptions**: appended to the linker options (-k). Path delimiters are not changed. Relative paths are not extended. Macros are replaced.
3229- **CustomOptions**: appended to the compiler parameters. Path delimiters are not changed. Relative paths are not extended. Macros are replaced.
3330- **OutputDir**: if set it will replace the current output directory. Path delimiters are changed. Relative path is extended. Macros are replaced.
3431
3532For packages there are more variables for the usage options. These paths are inherited, that means appended to all packages/projects using this package, directly or indirectly:
3633
3734- **UsageUnitPath**: appended to *Unit (-Fu)* usage path. The / and \\ characters are automatically converted to the current path delimiter. After adding the search path(s) with a semicolon macros are replaced and relative paths are extended by the package/project directory.
3835- **UsageIncPath**: appended to *Include (-Fi)* usage path.
3936- **UsageLibraryPath**: appended to *Library (-Fl)* usage path.
4037- **UsageSrcPath**: appended to *Source (not used by compiler, only IDE)* usage path.
4138- **UsageDebugPath**: appended to *Debugger (not used by compiler, not by the codetools, only used by debugger)* usage path.
4239- **UsageLinkerOptions**: appended to the usage linker options (-k). Path delimiters are not changed. Relative paths are not extended. Macros are replaced.
4340- **UsageCustomOptions**: appended to the usage compiler parameters. Path delimiters are not changed. Relative paths are not extended.
4441
4542## Conditionals syntax
4643
4744### Supported syntax constructs
4845
4946- If expression then statement;
5047- If expression then statement else statement;
5148- begin statement; ... statement; end;
5249- Variable:=expression;
5350- Variable+=expression;
5451- Comments //, { }, (* *)
5552- Spaces, tabs and line breaks are the same. Like Pascal they are only needed to separate two identifiers/keywords.
5653
5754### Variables
5855
5956Variables are defined simply by assigning a value. There are some predefined variables. See further below for a list.
6057
6158Variables can be defined or undefined:
6259
6360``` pascal
6461if defined(Name) then ...
6562if undefined(Name) then ...
6663undefine(Name);
6764```
6865
6966If a Variable is defined it has one of these three types:
7067
7168- none
7269- string
7370- number (int64)
7471
7572A variable is **false** if it has the number 0 or the string '0'. Otherwise it is **true**. That means a variable without a value is true and an undefined variable is true.
7673
7774You can change the type of a variable with:
7875
7976``` pascal
8077a := '1'; // string
8178a := integer(a); // convert to a number using StrToInt(), on failure 'a' remains a string
8279a := int64(a); // convert to a number using StrToInt64(), on failure 'a' remains a string
8380a := string(a); // convert to a string
8481```
8582
8683### Constants
8784
8885``` pascal
8986a := 1234; // decimal
9087a := $A1B; // hexadecimal
9188a := &127; // octal
9289a := %101; // binary
9390a := '10'; // string
9491a := #123; // character
9592```
9693
9794### Operators
9895
9996- **+**: Two numbers are added, otherwise they are treated as strings and concatenated.
10097- **\<**, **\>**, **\<=**, **\>=**, **=**, **\<\>**: Two numbers are compared mathematically, otherwise they are treated as strings and compared lexicographically (case sensitive).
10198- **not**: Unary boolean operator
10299- **and**, **or**, **xor**: Boolean operators
103100- **(**,**)**: Group operations
104101- **:=**: Assignment. Not allowed in expressions.
105102- **+=**: Add and assign. Not allowed in expressions.
106103
107104Precedence levels:
108105
109106- 1 Not and unary minus
110107- 1 And
111108- 2 Or
112109- 2 XOr
113110- 2 +
114111- 4 =
115112- 4 \<\>
116113- 4 \<
117114- 4 \<=
118115- 4 \>
119116- 4 \>=
120117
121118## Predefined Variables
122119
123120Before the conditionals script is run the IDE initializes a few variables:
124121
125122- **TargetOS**: the project's target operating system as defined by fpc. e.g. 'linux', 'win32', 'darwin', 'freebsd', 'wince'.
126123- **TargetCPU**: the project's target processor as defined by fpc. e.g. 'i386', 'x86_64', 'arm'
127124- **SrcOS**: the value 'win' for all MS Windows platforms and 'unix' for all unix like platforms. The value depends on the TargetOS.
128125- **SrcOS2**: the value 'bsd' for all BSD like platforms. The value depends on the TargetOS.
129126- **Laz_FullVersion**: same number as *laz_fullversion* in *unit lazversion*.
130127- **True**: value 1
131128- **False**: value 0
132129- all build macros defined by the current project.
133130- all build macros defined by used packages. That means if the project has not defined a value for a package macro the value of the conditionals of the used package will be used.
134131
135132## Predefined Functions
136133
137134- **Defined(Variable)**: returns 1 (true) if the variable is defined otherwise 0 (false). Example if Defined(Macro1) then ;
138135- **Undefine(Variable)**: undefine the variable. Example: Undefine(A);
139136- **Int64(expression)**: Returns the int64 value of expression. Example: i:=int64('3');
140137- **Integer(expression)**: Returns the integer value of expression. Example: i:=integer('3');
141138- **String(expression)**: Returns the string value of expression. Example: s:=string(3);
142139- **GetIDEValue(string)**: See [[IDE Macros in paths and filenames|IDE macros]]
143140 - GetIDEValue('OS'): Returns the OS with which the IDE was compiled. since 1.0.
144141 - GetIDEValue('CPU'): Returns the CPU with which the IDE was compiled. since 1.0.
145142 - GetIDEValue('SrcOS'): SrcOS of IDE. since 1.0.
146143 - GetIDEValue('SrcOS2'): SrcOS2 of IDE. since 1.0.
147144 - GetIDEValue('LCLWidgeType'): LCL platform of the IDE, which might be different than project. lazbuild returns win32, carbon or gtk2 depending on its OS. since 1.0.
148145- **GetEnv(string)**: Returns the environment variable. For example GetEnv('HOME') returns under Linux the user's home directory. since 1.0.
149146- **GetProjValue(string)**: Returns a project value.
150147 - GetProjValue('FPC_FULLVERSION'): Returns the FPC_FULLVERSION fetched from the project compiler. The version is an integer e.g. 20701. since 1.3.
151148
152149# Order of macro computation
153150
1541511. the values of the current project are taken
1551522. if the project does not define values for TargetOS, TargetCPU the IDE sets defaults
1561533. SrcOS and SrcOS2 are computed from TargetOS
1571544. the conditionals of used packages are computed. If package A uses package B, then the conditionals of B are computed before the conditionals of A.
1581555. Every conditional script starts with the values of the project.
159156 - If the project does not define a value for a package macro, the result of the used package is used.
160157 - A script can alter any macro while it runs, but only the build macros and the built-in macros are used. For example you can set TargetOS to another value, but this has no effect on any other script, nor on any search path using \$(TargetOS), not even the search path of the package itself.
161158 - If two packages define the same build macro, then both can alter the value (unless the project sets a value). The exact effect depends on the dependency order.
1621596. the default IDE macros are used last.
163160
164161# Examples
165162
166163## Adding a compiler flag for target Linux
167164
168165``` pascal
169166if TargetOS = 'linux' then
170167 CustomOptions := '-dUseCThreads';
171168```
172169
173170Notes:
174171
175172- TargetOS is a predefined macro by the IDE.
176173- CustomOptions is a result variable used by the IDE.
177174- The identifiers are case insensitive, but **=** (equal) operator is not. The TargetOS macro uses the same case as the compiler does, which is currently all lowercase.
178175- The IDE adds the first space automatically when adding the custom options.
179176- When used in a package the above only will be applied to the options used for compiling the package, not to the project using the package.
180177
181178## Adding a define depending on Lazarus version
182179
183180``` pascal
184181if Laz_FullVersion >= 3990000 then
185182 CustomOptions := '-dHasFeature1';
186183```
187184
188185Notes:
189186
190187- Laz_FullVersion is a predefined macro by the IDE having the same value as in unit lazversion and exists since 3.99. On earlier versions it does not exist and so evaluates to 0.
191188- see notes in *Adding a compiler flag for target Linux*
192189
193190## Adding some linker options for target Mac OS X
194191
195192The compiler uses for *Mac OS X* the value 'darwin' for *TargetOS*.
196193
197194``` pascal
198195if TargetOS = 'darwin' then begin
199196 LinkerOptions += ' -framework Cocoa';
200197 if TargetCPU = 'i386' then
201198 LinkerOptions += ' -framework OpenGL';
202199end;
203200```
204201
205202Notes:
206203
207204- TargetOS and TargetCPU are predefined macros by the IDE.
208205- The **+=** operator appends a string or adds a number.
209206- When adding several options you have to add a space between options.
210207- The IDE adds the first space automatically when adding the linker options.
211208- You can nest **begin**..**end** just like Pascal.
212209- If both conditions hold **LinkerOptions** will contain the value ' -framework Cocoa -framework OpenGL'.
213210- The IDE automatically prepends the -k option when passing linker options to the compiler.
214211- The above only works for project's conditionals.
215212
216213## Adding some linker options for Mac OS X for all projects using a package
217214
218215Packages have two different sets of options. The set used for compiling the package itself and the options added to all projects/packages using the package. You have to change the **usage** options of the package:
219216
220217``` pascal
221218if TargetOS = 'darwin' then begin
222219 UsageLinkerOptions += ' -framework Cocoa';
223220 if TargetCPU = 'i386' then
224221 UsageLinkerOptions += ' -framework OpenGL';
225222end;
226223```
227224
228225## Adding an option to a package
229226
230227If your package provides some optional parts, for example the ability to use opengl you can define a build macro. The following explains how to set this up step by step:
231228
232229Let's say your package is called *Pkg1* and allows to switch on opengl support by compiling it with the flag **-dEnableOpenGL**. The package should provide a boolean option **Pkg1_UseOpenGL** with the values 'True' and 'False'.
233230
234231Open the package editor of your package 'pkg1', click on *compiler options*, select the page *IDE Macros*.
235232
236233Click on the left **+** button to add a new macro. It will be called 'Pkg1_Macro1'. Click on the tree node to rename it to 'Pkg1_UseOpenGL'.
237234
238235Click on the middle **+** button to add a new macro value. It will be called 'Value1'. Click on the tree node to rename it to 'True'. Repeat this for the value 'False'.
239236
240237Add the following code into the Conditionals (Compiler Options / Other / Conditionals) text box:
241238
242239``` pascal
243240if Pkg1_UseOpenGL = 'True' then
244241 CustomOptions := '-dEnableOpenGL';
245242```
246243
247-<figure>
248-<img src="Compileroptions_buildmacro_example1.png" title="Compileroptions_buildmacro_example1.png" />
249-<figcaption>Compileroptions_buildmacro_example1.png</figcaption>
250-</figure>
244+![](/wiki-images/c/c2/Compileroptions_buildmacro_example1.png)
251245
252246Notes:
253247
254248- The value 'True' is case sensitive. Because the value is usually selected from the combobox, there is no chance of typos.
255249- If the user has not set any value for the macro, the Variable 'Pkg1_UseOpenGL' is undefined and the expression results to false.
256250
257251## Add a release/debug mode
258252
259253### A release/debug mode for your project and all your packages
260254
261255Note: This requires Lazarus 0.9.31 or higher.
262256
263257In the project's compiler options (Project / Project Options / Compiler Options / Build modes) add a build mode *Release*. Adding this build mode will automatically activate it, so all changes to the compiler options are now only done in this build mode.
264258
265259In "Set Macro Values" click on the left column on the last row "(none)". Set it to "MyPackageOptions". Note: It is not listed in the combo box.
266260
267261Set its value to the options. For example "-O3".
268262
269-<figure>
270-<img src="Build_mode_release_macro1.png" title="Build_mode_release_macro1.png" />
271-<figcaption>Build_mode_release_macro1.png</figcaption>
272-</figure>
263+![](/wiki-images/1/1f/Build_mode_release_macro1.png)
273264
274265This macro is usable in the project compiler options and all packages.
275266
276267For each package do: Open the compiler options of the package, go to the page *Other*. Add to *Custom options* the text \$(MyPackageOptions).
277268
278269### A special release/debug mode for one package
279270
280271Let's say the normal mode is the debug mode and you want another mode for the release.
281272
282273Open the package editor of your package 'pkg1', click on *compiler options*, select the page *Build Macros*.
283274
284275Under *Build macros* click on the left **+** button to add a new macro. It will be called 'Pkg1_Macro1'. Click on the tree node to rename it to 'Pkg1_Release'.
285276
286277Click on the middle **+** button to add a new macro *value*. It will be called 'Value1'. Click on the tree node to rename it to 'True'. Repeat this for the value 'False'.
287278
288279Add the following code into the Conditionals text box:
289280
290281``` pascal
291282if Pkg1_Release = 'True' then
292283 // release mode
293284 CustomOptions := '-O3'
294285else
295286 // debug mode
296287 CustomOptions := '-Sa Ctroi';
297288```
298289
299290Notes:
300291
301292- The value 'True' is case sensitive. Because the value is usually selected from the combobox, there is no chance of typos.
302293- If the user has not set any value for the macro, the Variable 'Pkg1_Release' is undefined and the expression results to false.
303294
304295## Adding a macro for search paths to handle different platforms
305296
306297Let's say your package is called *Pkg1* and uses the windows GDI on MS Windows and X11 on Linux and BSD. The platform independent units are in the package main directory and you have created two sub directories 'gdi' and 'x11' containing the platform dependent units:
307298
308299 /path/of/your/package/pkg1/
309300 pkg1.lpk
310301 pkg1.pas
311302 generalunit.pas
312303 gdi/
313304 backend.pas
314305 x11/
315306 backend.pas
316307
317308The unit *backend* in *gdi* should be used on Win32, Win64 and WinCE, while under Linux and FreeBSD the *backend* unit in the *x11* should be used. This means the *Other unit files (-Fu)* search path must be adapted depending on the target OS. The following describes how to set this up step by step:
318309
319310Open the package editor of your package 'pkg1', click on compiler options, select the page *Build Macros*.
320311
321312Click on the left **+** button to add a new macro. It will be called 'Pkg1_Macro1'. Click on the tree node to rename it to 'Pkg1_Backend'.
322313
323314Click on the middle **+** button to add a new macro value. It will be called 'Value1'. Click on the tree node to rename it to 'gdi'. Repeat this for the value 'x11'.
324315
325316Add the following code into the Conditionals text box:
326317
327318``` pascal
328319// choose a value for Pkg1_Backend depending on the TargetOS
329320if undefined(Pkg1_Backend) then begin
330321 if SrcOS='win' then
331322 Pkg1_Backend:='gdi'
332323 else
333324 Pkg1_Backend:='x11';
334325end;
335326```
336327
337328The macro **\$(Pkg1_Backend)** will become usable once you click Ok. So, click 'Ok' to close the compiler options and open it again to use it in the search path *Other unit files (-Fu)*.
338329
339-<figure>
340-<img src="Compileroptions_buildmacro_example2.png" title="Compileroptions_buildmacro_example2.png" />
341-<figcaption>Compileroptions_buildmacro_example2.png</figcaption>
342-</figure>
330+![](/wiki-images/7/70/Compileroptions_buildmacro_example2.png)
343331
344332Notes:
345333
346334- The user can override the value of Pkg1_Backend. Therefore it is good practice to enclose the setting in *if undefined(Pkg1_Backend)*.
347335- Instead of the SrcOS macro you could use if (TargetOS='win32') or (TargetOS='win64') or (TargetOS='wince') then
348336
349337---
350338*From the Free Pascal wiki, page "Macros and Conditionals", as it stood on 2023-07-28 after a change by Mattias2, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history