Conditional Compiler Options

From Lazarus wiki
Jump to navigationJump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

This page collects ideas of how to implement conditional compiler options in lazarus.

First it should be collected the cases, where conditional compiler options are needed.

Case studies

Conditional Package Requirement: VirtualTreeView / multilog

Make it possible to define a package requirement as optional (Should be available both to package and program). Concrete situation: VirtualTreeView requires multilog package to help debug code. In a release it is not desired to have such dependency. Currently there are two possibilities:

  • in the release remove the dependency from the package, and then add again to reenable debugging.
  • enclose the units of the package with {$IFNDEF MYRELEASE} and add -dMYRELEASE to the project and all package compiler options (or fpc.cfg).

An idea is to have groups of conditional requirements. Each group would have a define value associated to be used at compile time (e.g: 'DEBUG_CODE') and child packages. Each group would have an enabled flag. If group is enabled, the child packages are added as requirements and the define value passed with -d to the compiler.

  • Disadvantage: Other packages will use the same Debug/Release differences. In big projects normally only a small part should be set verbose (into debugging mode).

Target specific units - Doable via FPC directives, no lazarus extras needed

Concrete situation: LCL extensions package has a unit (OleUtils) that implements TOLEStream. It only makes sense in Windows. Currently the unit is added in all widgetsets but all code is wrapped around a ifdef Windows define so is seen as a dummy unit in other widgetsets.

Notes:

  • All units should be added to the package, independent if they are used. If a unit should not always be compiled (not added to the uses section of the package), just unset the 'uses unit' checkbox and add for example {$IFDEF win32}uses oleutils{$ENDIF} to a package unit.
  • You can put units and include files specific to targets into sub directories as demonstrated in the Lazarus and FPC sources (units/$(TargetOS)).
  • Conclusion: There is no real need for conditional options for single units, as this is already possible via FPC directives. And FPC directives can be arbitrary complex.

Special build modes

Any application will desire different options for at least 2 possibilities:

  • Debug - which should be default
  • Release

So, any application should already come with those 2 options, and legacy applications could have them added automatically.

To have a trully flexible system any number of compilation modes should be supported (maybe >= 1 to have at least one). One idea to implement this system would be having any mode use all options set on the dialog, but also have a list of which options it will override to a custom value.

An extra idea is having the build options available on the Project -> Build menu

We could have: Project -> Build mode -> Debug; Release; Etc (submenu with all build modes), like Xcode has.

Arbitrary number of build modes - Virtual Magnifying Glass

One case where an arbitrary number of build modes would be excelent is the Virtual Magnifying Glass. Because Mac OS X requires special build options which can't be used on other operating systems, the magnifier could have the following options:

  • Debug
  • Release
  • Mac Qt4 Debug
  • Mac Qt4 Release
  • Mac Carbon Debug
  • Mac Carbon Release

The Mac Qt4 options need to add "-framework Qt4Intf -lobjc" to the extra linker options and active the extra linker options.

The Mac Carbon options need to add "-framework carbon" to the extra linker options and active the extra linker options.

Note:

  • There is redundancy in the build modes. If each package/project would have only one type of build mode, this would be pretty uncomfortable for packages like the LCL. Better split them up in: Debug / Release and Default/Mac Qt4/MacCarbon

Road map

At the moment the LCLWidgetSet options is hardwired. It would be great if this could be done by the conditionals, because

  • If the IDE can handle such a complex beast like the LCL as normal package it can handle almost anything
  • The conditionals will be well supported/tested, because they are used by everyone everyday.

Details

  • define a flag (LCLWidgetSet) with a list of values (carbon, gtk, gtk2, ...), a default value and names plus localization. This flag must be usable as IDE macro (not pascal source macro). The macro can be used in paths and descendant package paths.
  • Somehow a default must be defined depending on target platform.
  • conditional codetools defines. This could be achieved by a dialog or extra compiler options page like the codetools defines editor. This may be used for the FPC source packages too.
    • Advantage: Full control and very flexible
    • Disadvantage: Only very few packages need this flexibility. Most conditional packages only need two modes like release/debug. For these simple cases more intuitive frontends could be created. The problem is, that the simple frontends can not show the complex setups correctly.
  • paths (linker, custom options) must be conditional
  • All such flags of all packages used by the project should be collected and the user must be able to easily switch the flags.

Proposal for adding new IDE macros

  • Each project/package can define one or more IDE macros. For example the LCL will define LCLWidgetType.
  • An IDE macro needs a name (LCLWidgetType), a default value and a list of standard values (gtk, gtk2, win32, ...) plus descriptions (gtk, gtk 2 (beta), win32/win64, ...).
  • The IDE macro name should start with the package name, because IDE Macros must work globally.
  • The list of standard values is a list of strings.
  • Each standard value can optionally have a short description, a long description and i18n identifiers. The IDE can lookup the translations in the .po files of the project/package. For example the LCLWidgetType has as short descriptions gtk, gtk2 (beta), win32/win64, ..., a list of long descriptions (some flavor text for every widgetset) and two lists of i18n identifiers, one for the short descriptions and one for the long descriptions.
  • The default value can be a simple value (even empty) or a complex value. A complex value can be defined by a codetools defines template. The template can use global values, like TargetOS, TargetCPU and all macros from the required packages. Because this macro defines the compiler options, it can not use IDE, codetools or compiler macros.
  • The user can select the value of the IDE macro. Either from the list or set to default.

Proposal for conditional package requirements

  • Each package requirement/dependency can define a condition. This must be a codetools define expression, which can use global macros like TargetOS, TargetCPU and IDE macros from installed packages. It can not use IDE macros from dynamically loaded packages.

Proposal for conditional linker, custom, search path options

  • The IDE macros can be used normally in linker options, custom options and search paths.

Proposal for static compiler sets

Basically this proposal is just an improvement of the Save/Load compiler options.

  • Each package/project can have several static sets of compiler options stored in the .lpi/.lpk.
  • Each set has a name.
  • One set is the default.
  • The user can add, delete and switch the set in the compiler options.
  • The user can switch all available sets in a new dialog.
  • In the project's session info the active sets are stored.

What will not be implemented

  • A global Debug/Verbose buildmode. Almost no one wants to increase verbosity of all packages, nor debug all packages.
  • Conditional units. This is already flexible doable via FPC directives and IDE macros.

Example: Use a package only under windows

A package/project should use a package only under windows (not wince).

When the above is implemented, it will work like this:

  • Add the dependency/requirement to the project/package.
  • Right click on the requirement and select 'set condition'
  • A dialog will appear. Set the expression to
 $(TargetOS)='windows'

Example: Add framework linker option under Mac OS X

A package requires a special --framework option under Mac OS X. For example a package 'testpkg' should add the linker option --framework=opengl under OS X.

When the above is implemented, it will work like this:

  • open the compiler options dialog of the project or package
  • add a new IDE macro. For example 'TestPkgLinkerOption'.
  • Define the default value as 'complex' and define it as:
 if $(TargetOS)='darwin'
   Result:=--framework=opengl
  • Then you can use the new macro in the linker options:
 $(TestPkgLinkerOption)

Example: Compile the project in Release/Debug mode

A project should have two different sets of compiler options for debugging and release.

When the above is implemented, it will work like this:

  • Open the compiler options
  • add a new 'set' and name it 'release'. You can switch between the default set and the release set either in the compiler options or in a new dialog that contains the table of all IDE macros and all sets defined by all projects/packages.

Example: Compile the project and all packages in Release mode

When the above is implemented, it will work like this:

  • Open the dialog that contains the table of all IDE macros and all sets defined by all projects/packages.
  • Set all to release. There might be a button for this special case.

Pros

  • Conditional dependencies
  • Conditional linker options, custom options and search path options
  • easier handling of different sets of compiler options
  • No cross dependencies between options. For example the linker options can vary due to OS and CPU, but not due to the linker options of another package. This avoids circles and spaghetti options.

Cons

  • Packages can only reliably use macros for dependencies from installed packages. That means if you install a package its dependencies can not reliably use macros form other packages. So basically it means, dependencies should only use basic IDE macros. Note: Normally it will work, but many things can go wrong, so using complex relationships is asking for troubles.
  • No cross dependencies between options. For example the linker options can not vary due to the linker options of another package. Note: Unless the other package uses IDE macros, which it should.
  • No standard for Debug, Verbosity build modes. Note: If all packages use the names 'Debug' and/or 'Verbose' the same, then there is a standard. But I think this is unrealistic.
  • No simple way to change a flag in all options sets. For example if a package has three compiler sets Normal, Debug and Release you can not change a flag in all of them. You must change the flag three times. Note: This feature can be added later.
  • Codetools defines are to strict/ugly. It would be better to use pascal script. Note: we have no simple pascal script interpreter.