Wiki copymirror

This is a mirror of the wiki at pascal.chat. Editing, history and sign-in are there.

Lazarus Packages

Deutsch · English · Español · Français · Português · Slovenčina · Русский · 日本語

Overview of the Lazarus Package System

For other meanings of Package in the combined FPC/Lazarus projects see Packages(disambiguation).

What is a Lazarus package?

A Lazarus package is a collection of units and components, containing information how they can be compiled and how they can be used by projects or other packages or the IDE. The IDE automatically compiles packages if some of its files are modified. In contrast to Delphi, packages are not limited to libraries and they can be OS independent. (Library Packages are specially compiled libraries used by applications, the IDE or both. Delphi/Library packages require in-compiler support, which FPC is not capable of at the moment and of course this magic is OS dependent.)

Currently the Free Pascal compiler only supports static packages, not dynamic packages. Therefore you must compile and restart the IDE, each time a package is installed or uninstalled.

A lazarus package is identified/distinguished by the name and its version.

Packages are ideal for sharing code between projects.

Here is a typical directory layout of a Lazarus package:

pascal
/home/user/pascal/pkg1/  - an arbitrary directory, often it is named similar to the package name
  pkg1.lpk               - the package file
  pkg1.pas               - this unit is automatically created by the IDE and is only needed for compiling
  apackageunit.pas       - your shared unit, choose a unique name that do not clash with other sources/packages
  aform.pas              - your shared form
  aform.lfm              - the form file of your shared form
  lib/i386-linux/        - the output directory of the package. The directory and its content is automatically created.
    pkg1.compiled        - the state file containing the parameters how the package was compiled the last time.
    pkg1.ppu
    pkg1.o
    apackageunit.ppu
    apackageunit.o
    aform.ppu
    aform.o
    aform.lfm

Coming from Delphi

If you are familiar with Delphi packages then read the following paragraph, because there are some important differences between a Delphi and a Lazarus package.

FAQ

Q: Do I need to install a package?
A: You only need to install a package, if it contains designtime items, like components for the IDE component palette. If you don't use those items, you don't need to install the package. If you only want to use a package in your project, don't install it. Use the project inspector and add a requirement.

Q: I installed a package, but the IDE does not find the units
A: Installing a package means that the package is integrated into the IDE, not in your project. These are separate things. To use a package in your project, use Project -> Project Inspector -> Add -> New Requirement. And uninstall the package, if it does not contain any IDE goodies.

Quick Start

To see the packagesystem in action and to get used to it, do the following:

Creating a new package

Congratulations: You have just created your first package!

Adding a new component

Congratulations: You have just installed your first package with your first package component.

Add a component icon

Component icons can use Lazarus resources or FPC resources.

Using Lazarus resources

Also page exists here: How to add icons my package components.

The idea is to create a png, convert that into a lrs include file using the lazres tool and include that. Since 0.9.29 there is a button on the new component page to do that automatically.

Here are the details:

To create the lrs file run (where TMyComponent is the class name of your component and yourunit is the unit name):

text
~/lazarus/tools/lazres yourunit.lrs TMyComponent.png

Hint: You can add more than one image to the lrs file by appending the image filename at the end. For example

text
~/lazarus/tools/lazres yourunit.lrs TMyComponent.png TMyOtherCom.png ...

Following is a sample of the resulting yourunit.lrs file.

pascal
LazarusResources.Add('TMyComponent','PNG',[
  #137'PNG'#13#10#26#10#0#0#0#13'IHDR'#0#0#0#24#0#0#0#24#8#2#0#0#0'o'#21#170#175
  +#0#0#0#4'gAMA'#0#0#177#143#11#252'a'#5#0#0#0'|IDAT8O'#237#212#209#10#192' '#8
  +#5'P'#247#231#251's'#215#138#133#164#166'\'#220#195'`'#209'c'#157'L'#173#131
  +#153#169'd4'#168'dP'#137'r_'#235'5'#136'@Zmk'#16'd9'#144#176#232#164'1'#247
  +'I'#8#160'IL'#206'C'#179#144#12#199#140'.'#134#244#141'~'#168#247#209'S~;'#29
  +'V+'#196#201'^'#10#15#150'?'#255#18#227#206'NZ>42'#181#159#226#144#15'@'#201
  +#148#168'e'#224'7f<@4'#130'u_YD'#23#213#131#134'Q]'#158#188#135#0#0#0#0'IEND'
  +#174'B`'#130
]);
pascal
unit YourUnit;
...
uses 
  ..., LResources;
...
implementation
...
initialization
  {$I yourunit.lrs}
end.

Note: You can include more than one lrs file, but each only once.

Using FPC resources

Create a 24x24 16 color bitmap for each component. This format won't support PNG files. Then create an rc file as follows:

text
TMYCOMPONENT1NAME  BITMAP  "pathtobitmap1//bitmap1.bmp"
TMYCOMPONENT2NAME  BITMAP  "pathtobitmap2//bitmap2.bmp"
....
TMYCOMPONENTnNAME  BITMAP  "pathtobitmapn//bitmapn.bmp"

Note that double slashes (Linux) and double backslashes (Windows) are used in the bitmap path. It is advisable for the file's name to be the same as the package name with an extension of rc, ie MyPackageName.rc

Let windres (Binutils) create the actual resource:

text
pathToWindres/windres -J rc -O res "MyPackageName.rc" "MyPackageName.dcr"

Alternatively, you can use the lazres tool to create a .res file:

text
pathToLazarus/tools/lazres MyPackageName.res bitmap.bmp bitmap_150.bmp bitmap_200.bmp

Add to the registration unit of the package {$R *.dcr} or {$R *.res} right after the implementation keyword, and compile/install the package.

Creating a package for your common units

Let's say you have some units, that you want to use in your projects. Put the units in a separate directory, for instance C:\MySharedUnits.

Adding the LCL as dependency

If your package contains forms or any other GUI LCL unit, then it requires the LCL package.

You can see the what the LCL does, by clicking in the package editor of your package Compiler Options / Inherited.

If you only use non-GUI LCL components such as fileutil, you can add a dependency to LCLBase

Use your package in your project

You need to add a dependency from the project to your new package. There are several ways to do this:

The IDE menu items for packages

Removing Packages

If something goes wrong with a package (for instance a package directory is deleted without first uninstalling it), Lazarus may not allow you to uninstall packages. To fix the problem, at the IDE menu click Tools > Build Lazarus. Lazarus will rebuild all packages and restart. You should now be able to uninstall problematic packages.

The theory

Each Lazarus package has a .lpk file. A package is identified by its name and its version. The name must correspond to the lpk filename. For example:

Name: Package1, Version: 1.0, Filename: /home/.../package1.lpk.

For example:

pascal
{ This file was automatically created by Lazarus. Do not edit!
   This source is only used to compile and install
   the package GTKOpenGL 1.0.
}
unit GTKOpenGL;

interface

uses GTKGLArea, GTKGLArea_Int, NVGL, NVGLX, LazarusPackageIntf;

implementation

procedure Register;
begin
  RegisterUnit('GTKGLArea', @GTKGLArea.Register);
end;

initialization
  RegisterPackage('GTKOpenGL', @Register);
end.

For example: gtkopengl.compiled:

xml
<?xml version="1.0"?>
<CONFIG>
  <Compiler Value="/usr/bin/ppc386" Date="781388725"/>
  <Params Value=" -Rintel -S2cgi -CD -Ch8000000 -OG1p1
    -Tlinux -gl -vewnhi -l -Fu../../../lcl/units
    -Fu../../../lcl/units/gtk -Fu../../../packager/units
    -Fu. -FElib/ gtkopengl.pas"/>
</CONFIG>

Package states

A package can have none, one or several of the following states:

Hints and Tips

Please add any hints, tips or gotchas here.

Adding existing components to a Package

If you want to add a file that contains a component to an existing package, you can do the following:

That's it. The component should now show on the component palette.

Create a package with a unit that has the same name as the package

Normally the IDE auto creates the registration code into a unit with the same name as the package. If you want to name your package the same as an existing unit, for example because the package has only one unit, then you need at least Lazarus 0.9.29 and use this:

File Type

Select a file in the package editor, right click for the popup menu. File Type:

The Register procedure

To show a component on the component palette, it must be registered in Lazarus. This is done in the 'Register' procedure. This is a procedure that must appear in the interface section of the unit it is in, and must issue one or more RegisterComponent calls, as well as install property and component editors for the components.

One or more Register procedures can be present in a package: in the package editor, you must indicate the units that have a 'register' procedure, so Lazarus knows which procedures it must call when the package is installed.

There are 2 ways to mark a unit as having a register procedure:

Do not forget to recompile and install the package after changing the properties.

Search paths

All search paths are stored relative to the directory of the .lpk file. If you use an absolute path you have either not understood packages or you don't care.

Each package has two types of search paths:

Since 0.9.29 you can specify compiler options depending on the target platform.

Your package provides a library, how to extend the linker search path in all your projects

A package can define search paths that are added to packages and projects using it. See Options / Package Options / Usage.

Design Time vs Run Time package

There are four different types of packages.

  1. A design and runtime package can be installed in the IDE and can be used normally by projects. This is the default.
  2. A design time package can be installed in the IDE and provides IDE extensions like new components, new file or project types, new menu items, new component or property editors, etc. Projects can use design time packages (i.e. they are listed in the project inspector requirements), but by default a design time package is not compiled into the project. That means project units cannot use units of the design time package. When a project uses such a package the IDE warns before opening a form of the project, so the user can install it first. To test a design time package outside the IDE you may want to use it in a test project. For this case you can change this in Project Options / Miscellaneous / Use design time packages.
  3. A run time package can be used by projects. A user cannot install such a package directly (it is not listed). It cannot register things in the IDE. It can be used by design time packages, so it can be installed indirectly.
  4. A run time only package can only be used by projects. It cannot be installed in the IDE, not even indirectly. For example if the package is incompatible with the core IDE packages like the LCL. Since 0.9.31.

Typical scenario for a run time and design time package

You have a component library called Awesome and you want to write some IDE editors for some special properties. For example a property editor for the property Datafile which shows a TOpenDialog to let the user select a file. You can put the components into one run time package named AwesomeLaz.lpk' and create another directory design for the design time package AwesomeIDELaz.lpk. Move all units containing the IDE editors and registering stuff into the design directory. Add a dependency in AwesomeIDELaz to AwesomeLaz. Make sure they do not share units or search paths. For an example see components/turbopower_ipro/: The run time package is turbopoweripro.lpk and the design time package is design/turbopoweriprodsgn.lpk.

For Delphians: I can not install a run time package, why not?

Installing a package means compiling the whole code into the IDE. A run time package does not contain code for the IDE or maybe even bites it. In order to use a package in your project, simply open the package, right click on the package editor for the popup menu and click Add to project. Alternatively you can use View / Project Inspector. The project inspector shows what packages are used by your project, you can add dependencies or delete them.

Examples

Example for extending the Usage / Units path.

The tiOPF framework has the following directory layout, due to the fact that it compiles for FPC, Delphi 5-7, D2005 and D2006:

pascal
Source                <= full path \Programming\3rdParty\tiOPF\Source
  \Compilers
     \Delphi7          <= Delphi 7 package files live here
     \D2005
     \FPC              <= the tiOPF.lpk lived here
  \Core                <= core unit files
  \Options             <= optional unit file for extra features
  \GUI

Using this example, the following paths are included in the "Options - Usage - Units" editbox:

text
"$(PkgOutDir);..\..\Core;..\..\Options;..\..\GUI"

This search path will be added to whatever project uses this package. The default is $(PkgOutDir), which would add only the ppu files to the project. Adding more search paths has the effect that the .pas source files are found by the compiler a second time - once when compiling the package and once when compiling your project. Since package and project use different settings the compiler might create a second version of the ppu, which is put into your project's output directory. Then you have two ppu for one unit and then you can get strange errors. To avoid the duplication disable the compilation of the package, by setting it to compile only manually.

Platform specific units

There are various ways to deal with separating platform-specific code:

One unit per platform, several units with same name

For example the unit myconnect.pas has two versions, one for Windows and one for Unix/Linux/macOS/BSD. The idea is to put the units into different sub directories and use macros in search paths.

One unit for only one platform / conditional unit

For example: the unit mywin.pas should only be used under Windows, i.e. it should only be used and compiled if the flag Windows is defined.

The idea is to use the unit indirectly using IFDEFs. The following example shows how the unit mywin.pas is only used and compiled when the flag Windows is defined.

pascal
uses
  Classes
  {$IFDEF Windows}
  ,mywin
  {$ENDIF}
  ;

Note: mypkgcompile will be compiled under all platforms. mywin will only be compiled under Windows. You don't need to use the unit mypkgcompile in your project.

Different versions of a package

If you work with different versions of a package, you can open at any time the other package file. The old package will be closed and the new one will be opened. Registered items will be transferred to the new package. For example the component palette still shows the components of the old package, with which the IDE was built. But right clicking on a component will show a menu item to open the recently used package.

You can specify the minimum, maximum version required. When the project is opened and there are multiple .lpk files the IDE will automatically open the one with the right version.

If you work with different projects that require different versions of a package (for example with different branches of the same package), you can define the preferred one in the dependencies. In the project inspector right click on the dependency and click on Set file name as preferred for this dependency. When the project is opened, the preferred package will be opened. If there is already a package with the same name it will be replaced. This feature exists since 0.9.29.

Project Inspector

Example library with multiple lpk

A library has two lpk files, main.lpk and sub.lpk. main depends on sub. The library has two version 1.0 and 2.0.

pascal
trunk/
  main.lpk  version 2.0, requires sub
  sub.lpk   version 2.0
fixes/
  main.lpk  version 1.0, requires sub
  sub.lpk   version 1.0

When you open main.lpk 1.0 for the first time, the IDE searches the package sub in its database and then it searches sub.lpk in the current folder. It finds sub.lpk 1.0 and loads it.

When you then open main.lpk 2.0, the IDE knows already a sub.lpk, the version 1.0 and loads it. It does not load the sub.lpk 2.0.

There are two solutions:

Using minimum, maximum version

You can set for each dependency the minimum and maximum version. When you set the minimum and maximum version of the dependency the following will happen: The main 1.0 and sub 1.0 is open. You open main 2.0 which requires sub >=2.0 and <=2.0. The IDE unloads main 1.0, loads main 2.0. The sub 1.0 does not fit, so the IDE searches for sub 2.0. Again it first searches in its database and then in the current folder. It finds sub.lpk and loads sub 2.0.

Using preferred file name

If the two lpk files are always distributed together you can use instead of minimum and maximum versions the preferred option. Open from trunk the main.lpk and sub.lpk to make sure that the right versions are loaded. Then right click on the dependency from main to sub and choose preferred file name. The file name will appear to the right of the dependency. Repeat this step with the lpk files from version 2.0. The IDE will now always open the right sub.lpk.

Build modes

You can add build modes to your package. See here for the various ways to achieve this:

Build modes for packages

Compiling a package via make

The IDE can create a simple Makefile for a package via Package editor / More ... / Create Makefile. The IDE creates the file Makefile.fpc and calls fpcmake, which creates the Makefile. Since 0.9.29 the IDE also creates the file Makefile.compiled. If you are using a version control system like svn or git, add all three files to the repository:

text
Makefile
Makefile.fpc
Makefile.compiled

You can now run make (e.g. open a console, cd to the package directory with the Makefile) to compile the package. This will compile the package and after successful compilation copy the Makefile.compiled to the unit output directory.

Notes:

Creating a closed sourced package

Goal: you want to publish a package, but you want to keep the source closed.

At the moment many IDE functions require the source; the IDE warns if the source of a unit is missing. Therefore you must publish the interface parts of the units, and the files the compiler creates (ppu and o files).

Steps:

There is a command line utility sourcecloser which alters the lpk and removes implementation sections. You can find it under lazarus/components/codetools/examples/sourcecloser.lpi.

See also:

Parallel Compilation

The IDE and lazbuild compile packages in parallel (since 1.3). Each package is still compiled with one call of fpc (single threaded).

You can set the maximum number of parallel processes in Tools / Options / Messages Window. By default it tries to guess the amount of cpu cores with the function GetSystemThreadCount in unit UTF8Process.

See also


From the Free Pascal wiki, page "Lazarus Packages", as it stood on 2023-12-13 after a change by Coz, 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.

Revision 3, last changed by WikiArchive .