Hi all,
This mail should start the discussion how to implement the package system for lazarus. Everyone is invited to join the discussion and comment it.
What is a package:
- Delphi: a package is a specially compiled library used by applications, the IDE or both. Delphi packages require compiler magic, which fpc is not capable of at the moment and of course this magic is not OS independent.
- 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. In contrary to Delphi, packages are not limited to libraries and they can be OS independent.
A package contains:
- name (valid pascal identifier)
- title, author, description
- version: major + minor + release + build
- filenames plus file type (unit, text)
- icon file
- information how to compile/update the package:
- compiler options to compile the package
- codetools defines
- package dependencies (= required packages)
- information how to be used in projects, other packages, IDE:
- compiler options (e.g. path additions and linker options)
- flag 'auto update'. Automatically compile package, when one of its required packages have changed.
- this information is stored in an xml file and will have the ending .lpk for Lazarus PacKage.
Example:
To compile a lcl package there will be compiler options to add the lcl paths and to put the .ppu/.ppw files into the output directory. Delphi defines one output directory for all packages. Let's call the macro $(PkgDir). I think, we should also support subdirectories. For instance, Tony can specify for his package the output directory $(PkgDir)/tony. The IDE will auto create this directory before package compilation. The package directory can be set in the environment options.
Notes:
- package dependencies:
When a project/package is to be compiled, the IDE should automatically check if a required package has changed and should auto compile till it gets a consistent state. For example: Project A depends on package B, B depends on C, C was recompiled and A should be compiled. Then the IDE should ask the user if package B should be recompiled (unless the auto update flag for package B is set). To accelerate this step the IDE will save information, when each package was compiled.
=============================================
Here are some ideas about the registration:
For Delphi compatibility we should support the 'register' procedure. That means the user adds a 'procedure register;' into the interface section of a unit, which register components, component editors, property editors, ... . Delphi packages automatically call these procedures via compiler magic. fpc can't do this magic for us, so we do lazarus magic:
When a package is compiled, the IDE automaticaly creates/updates the package unit. This package unit looks somewhat like this:
--------------------------------
{ automatically created by lazarus - do not edit } unit LPK_packagename;
{$mode objfpc}{$H+}
interface
uses
// all units in the package
ComponentUnit1, ComponentUnit2, Unit3, Unit4,
// the lazarus package registration unit
LazPkgReg;
implementation
procedure Register;
begin
// all units with 'register'
ComponentUnit1.Register;
ComponentUnit2.Register;
end;
initialization
LazPkgSystem.RegisterPackage('packagename',@Register);
end.
--------------------------------This package unit is only useful for the IDE and is not needed by applications unless they need the package registration.
I suggest to create a <lazarusdir>/package sub directory and put all units of the package system and also the LazPkgReg unit there.
=============================================
Installing a package:
Because fpc does not fully support libs, we can't add/remove components at runtime. We have
to restart the IDE. Gladly lazarus starts a lot quicker than Delphi. The installation itself is done internally by adding the package unit to a uses section. The IDE will have dialogs and will handle most of this automatically just like Delphi.
For example:
To install a package the following five steps are needed: Open a package file, compile it, install it, compile IDE and restart. Normally a user will simply open the package file and click 'install'. The IDE will automatically compile the package, then ask the user if the IDE should be recompiled. After that the IDE gives a note, that the user can now restart the IDE.
=============================================
Projects will get 'package dependencies'. This is simply a list of package names plus minimum versions.
=============================================
Missing points:
- design time / run time packages. Do we need this distinction?
- component icons: The current solution is to add a lazarus resource with the classname.
Sufficient? Or is the risk of redefinition too big?
- Naming. For example: Maybe 'package dependencies' is not as readable as 'package requirements' or 'required packages'.
- IDE front end
- other things ...
I hope I did not forget too much,
Mattias
