Difference between revisions of "Macros and Conditionals"

From Free Pascal wiki
Jump to navigationJump to search
Line 111: Line 111:
  
 
A variable is '''false''' if it has the number 0 or the string '0'. Otherwise it is '''true'''.
 
A variable is '''false''' if it has the number 0 or the string '0'. Otherwise it is '''true'''.
 +
 +
You can change the type of a variable with:
 +
 +
<Delphi>
 +
a:='1'; // string
 +
a:=integer(a); // convert to a number using StrToInt()
 +
a:=int64(a); // convert to a number using StrToInt64()
 +
a:=string(a); // convert to a string
 +
</Delphi>
  
 
===Constants===
 
===Constants===

Revision as of 17:17, 30 September 2010

Overview

Macros 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. 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, ...).

Conditionals allow 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.

You can set the build macros and conditionals for a package via package editor / Compiler Options / Build Macros.

You can set the build macros and conditionals for a project via Project / Project Options / Compiler Options / Build Macros.

Build macros and conditionals exist since Lazarus 0.9.29.

Build Macros

A build macro has a name and a set of possible values.

Macro names

The name must be a valid pascal identifier and is case insensitive. For package macros it is recommended to prefix the macro name with the package name plus the underscore. For example a package named Pkg1 can have a macro named Pkg1_Macro1. When the package is renamed the IDE will automatically rename the macros too. It is allowed to define macros without the prefix, but keep in mind that this can lead easily to conflicts and misunderstandings. For example if you name a macro 'debug', 'release' or 'verbose' chances are high that some project defines a macro with the same name.

Possible macro values

You can and should define the set of possible values. These values are a clue for the users of your package. The user is free to set any other value, even empty or undefined. The list of values is shown in the comboxbox on the Build Modes page of the project's compiler options.

Scope

When the project defines the value of a macro via the build modes page, this value is visible to the project and all packages. The value is used when parsing conditionals and conditionals can not override them.

A macro value defined by the project's conditionals is only visible to the project's search paths and file names.

A macro value defined by the package's conditionals is only visible to the package's search paths and file names. Conditionals can set the build macro of the package and can alter the usage options of the package. See the examples below.

Conditionals

The conditionals use a simple scripting language. Here are some short examples:

Adding a compiler flag for target Linux

<Delphi> if TargetOS = 'linux' then

 CustomOptions := '-dUseCThreads';

</Delphi>

Note:

  • TargetOS is a predefined macro by the IDE.
  • CustomOptions is a result variable used by the IDE.
  • 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.
  • The IDE adds the first space automatically when adding the custom options.

Adding some linker options for target Mac OS X

The compiler uses for Mac OS X the value 'darwin' for TargetOS.

<Delphi> if TargetOS = 'darwin' then begin

 LinkerOptions += ' -k-framework -kCocoa';
 if TargetCPU = 'i386' then 
   LinkerOptions += ' -k-framework -kOpenGL';

end; </Delphi>

Notes:

  • TargetOS and TargetCPU are predefined macros by the IDE.
  • The += operator appends a string or adds a number.
  • When adding several options you have to add a space between options.
  • The IDE adds the first space automatically when adding the linker options.
  • You can nest begin..end just like Pascal.
  • If both conditions hold LinkerOptions will contain the value ' -k-framework -kCocoa -k-framework -kOpenGL'.

Changing compiler options with conditionals

Here is a complete list of the macros understood by the IDE:

  • 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.
  • IncPath: appended to Include Files (-Fi)
  • LibraryPath: appended to Libraries (-Fl)
  • SrcPath: appended to Other sources (not used by compiler, only IDE)
  • DebugPath: appended to Debugger path addition (not used by compiler, not by the codetools, only used by debugger)
  • LinkerOptions: appended to the linker options (-k). Path delimiters are not changed. Relative paths are not extended. Macros are replaced.
  • CustomOptions: appended to the compiler parameters. Path delimiters are not changed. Relative paths are not extended. Macros are replaced.
  • OutputDir: if set it will replace the current output directory. Path delimiters are changed. Relative path is extended. Macros are replaced.

For packages there are further variables:


Conditionals syntax

Supported syntax constructs

  • If expression then statement;
  • If expression then statement else statement;
  • begin statement; ... statement; end;
  • Variable:=expression;
  • Variable+=expression;
  • Comments //, { }, (* *)

Variables

Variables can be defined or undefined:

<Delphi> if defined(Name) then ... if undefined(Name) then ... undefine(Name); </Delphi>

If a Variable is defined it has one of these three types:

  • none
  • string
  • number (int64)

A variable is false if it has the number 0 or the string '0'. Otherwise it is true.

You can change the type of a variable with:

<Delphi> a:='1'; // string a:=integer(a); // convert to a number using StrToInt() a:=int64(a); // convert to a number using StrToInt64() a:=string(a); // convert to a string </Delphi>

Constants

<Delphi> a:=1234; // decimal a:=$A1B; // hexadecimal a:=&127; // octal a:=%101; // binary a:='10'; // string a:=#123; // character </Delphi>

Operators

  • +: Two numbers are added, otherwise they are treated as strings and concatenated.
  • <, >, <=, >=, =, <>: Two numbers are compared mathematically, otherwise they are treated as strings and compared lexicographically (case sensitive).
  • not: unary boolean operator
  • and, or, xor: boolean operators
  • (,): group operations
  • :=: assignment: not allowed in expressions.
  • +=: add and assign: not allowed in expressions.

Precedence levels:

  • 1 Not and unary minus
  • 1 And
  • 2 Or
  • 2 XOr
  • 2 +
  • 4 =
  • 4 <>
  • 4 <
  • 4 <=
  • 4 >
  • 4 >=