Packaging System and dividing FPC - Lazarus into packages

From Lazarus wiki
Jump to navigationJump to search

Introduction

FPC is quite a large body of source, and the organisation of the source is a constant problem, with immense effects on release engineering, deployment and packaging. On this page I try to describe some of the problems involved with how FPC is packaged. This is not a constant situation, it evolves as new packages, dependancies and insights are acquired.

Order of building

Besides merely splitting up the source into packages, there is also a dependancy and order-of-building problem. Currently, the order of compilation is splitted up in certain generations:

  • RTL
  • packages/base ( a collection of packages)
  • FCL (contains general DB, that uses headers in packages/base)
  • packages/extra ( a collection of packages)

Packages are now only allowed to use packages in generations before them. The split level packages hierarchy is unnecessary complicated, but is the easiest with FPCMAKE. A future build tool should address this.

Requirements

  • the order of building should be fairly predictable and static to not hinder development too much, and the same on all OSes.
  • Dependancies on external libraries shouldn't be introduced to soon in the dependancy hierarchy. (see also separate paragraph)
  • In the future, some packages (like Indy) might be externally maintained. These must be clearly marked as such, so that only emergency fixes and FPC specific release engineering is done on these packages. The rest should go to the package owners
  • It should be possible to map FPC package structure on lazarus packages and Delphi style dynamically loadable packages.

tips

  • avoid package/unit/class names that are too general like "Image", "xml" or "sockets", to avoid annoying name clashes with Delphi and other 3rd party pkgs, unless the package is really as compat as possible substitute for the Delphi package. Prefix "fp" if necessary.

External Library Dependancies

One should be careful where packages are put that have external libraries as dependancies, this because other packages that don't require the dependancy on the lib itself, acquire it because they use some parts of a package that requires it.

Examples:

  • if one makes the RTL depend on some graphical library which is used for Unit Graph, all programs with that RTL might inherit that dependancy
  • Another example (and true painpoint): the general db support in the FCL which depends on the client libraries of all supported databases.

This gets even more important if we start bundling packages into dynamic libs. If we would stuff all units in one big lib (which is easiest from a deployment and maintenance view), this big shared lib would have three dozen library dependancies, from Oracle to little things as X widget sets.

breaking the dependancy cycle

If you have a package that _must_ be relatively early in the hierachy, but there is a dependancy on a library that is only sideways relevant, then you have a problem. Their are several general solutions:

- If OOP, try to use plugin classes that can be specialized later. - If procedural Use the "driver" model. Try to build a record of procedurevariables that encapsulates the functionality, and can be registered later. Examples : threading (cthreads), memory drivers (cmem), widestrings (cwstring) - Go for a fully dynamical approach with a library plugin architecture. ([b]SF[/b] needs advanced dynamic linking support)

Documentation of the new package system

 20:13 < Synopsis> oliebol: there is no docs about fppkg
 20:13 < Synopsis> oliebol: the docs are the source :)
 20:14 < Synopsis> see compiler/utils/fppkg.pp and rtl/common/fpmkunit.pp