Packages (Delphi)

From RAD Studio
Jump to: navigation, search

Go Up to Libraries and Packages Index

Packages are typically the preferred way to export items other than simple procedures and functions. Libraries should only be considered when interopability with other programming is a requirement.

The following topics describe packages and various issues involved in creating and compiling them.

  • Package declarations and source files
  • Naming packages
  • The requires clause
  • Avoiding circular package references
  • Duplicate package references
  • The contains clause
  • Avoiding redundant source code uses
  • Compiling packages
  • Generated files
  • Package-specific compiler directives
  • Package-specific command-line compiler switches

Understanding Packages

A package is a specially compiled library used by applications, the IDE, or both. Packages allow you to rearrange where code resides without affecting the source code. This is sometimes referred to as application partitioning.

Runtime packages provide functionality when a user runs an application. Design-time packages are used to install components in the IDE and to create special property editors for custom components. A single package can function at both design time and runtime, and design-time packages frequently work by referencing runtime packages in their requires clauses.

On Win32, package files end with the .bpl (Borland package library) extension.

Ordinarily, packages are loaded statically when an applications starts. But you can use the LoadPackage and UnloadPackage routines (in the SysUtils unit) to load packages dynamically.

Note: When an application utilizes packages, the name of each packaged unit still must appear in the uses clause of any source file that references it.

Package Declarations and Source Files

Each package is declared in a separate source file, which should be saved with the .dpk extension to avoid confusion with other files containing Delphi code. A package source file does not contain type, data, procedure, or function declarations. Instead, it contains:

  • a name for the package.
  • a list of other packages required by the new package. These are packages to which the new package is linked.
  • a list of unit files contained by, or bound into, the package when it is compiled. The package is essentially a wrapper for these source-code units, which provide the functionality of the compiled package.

A package declaration has the form:

package packageName;

  requiresClause;

  containsClause;

end.

where packageName is any valid identifier. The requiresClause and containsClause are both optional. For example, the following code declares the DATAX package:

 package DATAX;
   requires
   rtl,
   contains Db, DBLocal, DBXpress, ... ;
 end.

The requires clause lists other, external packages used by the package being declared. It consists of the directive requires, followed by a comma-delimited list of package names, followed by a semicolon. If a package does not reference other packages, it does not need a requires clause.

The contains clause identifies the unit files to be compiled and bound into the package. It consists of the directive contains, followed by a comma-delimited list of unit names, followed by a semicolon. Any unit name may be followed by the reserved word in and the name of a source file, with or without a directory path, in single quotation marks; directory paths can be absolute or relative. For example:

 contains MyUnit in 'C:\MyProject\MyUnit.pas';
Note: Thread-local variables (declared with threadvar) in a packaged unit cannot be accessed from clients that use the package.

Naming packages

A compiled package involves several generated files. For example, the source file for the package called DATAX is DATAX.DPK, from which the compiler generates an executable and a binary image called

DATAX.BPL and DATAX.DCP

DATAX is used to refer to the package in the requires clauses of other packages, or when using the package in an application. Package names must be unique within a project.

The requires clause

The requires clause lists other, external packages that are used by the current package. It functions like the uses clause in a unit file. An external package listed in the requires clause is automatically linked at compile time into any application that uses both the current package and one of the units contained in the external package.

If the unit files contained in a package make references to other packaged units, the other packages should be included in the first package's requires clause. If the other packages are omitted from the requires clause, the compiler loads the referenced units from their .dcu files.

Avoiding circular package references

Packages cannot contain circular references in their requires clauses. This means that

  • A package cannot reference itself in its own requires clause.
  • A chain of references must terminate without rereferencing any package in the chain. If package A requires package B, then package B cannot require package A; if package A requires package B and package B requires package C, then package C cannot require package A.

Duplicate package references

The compiler ignores duplicate references in a package's requires clause. For programming clarity and readability, however, duplicate references should be removed.

The contains clause

The contains clause identifies the unit files to be bound into the package. Do not include file-name extensions in the contains clause.

Avoiding redundant source code uses

A package cannot be listed in the contains clause of another package or the uses clause of a unit.

All units included directly in a package's contains clause, or indirectly in the uses clauses of those units, are bound into the package at compile time. The units contained (directly or indirectly) in a package cannot be contained in any other packages referenced in requires clause of that package.

A unit cannot be contained (directly or indirectly) in more than one package used by the same application.

Compiling Packages

Packages are ordinarily compiled from the IDE using .dpk files generated by the Project Manager. You can also compile .dpk files directly from the command line. When you build a project that contains a package, the package is implicitly recompiled, if necessary.

Generated Files

The following table lists the files produced by the successful compilation of a package.

Compiled package files

File extension Contents

DCP

A binary image containing a package header and the concatenation of all .dcu (Win32) files in the package. A single .dcp or .dcp file is created for each package. The base name for the file is the base name of the .dpk source file.

BPL

The runtime package. This file is a DLL on Win32 with special RAD Studio-specific features. The base name for the package is the base name of the dpk source file.

Package-Specific Compiler Directives

The following table lists package-specific compiler directives that can be inserted into source code.

Package-specific compiler directives

Directive Purpose

{$IMPLICITBUILD OFF}

Prevents a package from being implicitly recompiled later. Use in .dpk files when compiling packages that provide low-level functionality, that change infrequently between builds, or whose source code will not be distributed.

{$G-} or {$IMPORTEDDATA OFF}

Disables creation of imported data references. This directive increases memory-access efficiency, but prevents the unit where it occurs from referencing variables in other packages.

{$WEAKPACKAGEUNIT ON}

Packages unit weakly.

{$DENYPACKAGEUNIT ON}

Prevents unit from being placed in a package.

{$DESIGNONLY ON}

Compiles the package for installation in the IDE. (Put in .dpk file.)

{$RUNONLY ON}

Compiles the package as runtime only. (Put in .dpk file.)


Including {$DENYPACKAGEUNIT ON} in source code prevents the unit file from being packaged. Including {$G-} or {$IMPORTEDDATA OFF} may prevent a package from being used in the same application with other packages.

Other compiler directives may be included, if appropriate, in package source code.

Package-Specific Command-Line Compiler Switches

The following package-specific switches are available for the command-line compiler.

Package-specific command-line compiler switches

Switch Purpose

-$G-

Disables creation of imported data references. Using this switch increases memory-access efficiency, but prevents packages compiled with it from referencing variables in other packages.

-LEpath

Specifies the directory where the compiled package file .bpl will be placed.

-LNpath

Specifies the directory where the .dcp file will be placed.

-LUpackageName[;packageName2;...]

Specifies additional runtime packages to use in an application. Used when compiling a project.

-Z

Prevents a package from being implicitly recompiled later. Use when compiling packages that provide low-level functionality, that change infrequently between builds, or whose source code will not be distributed.


Using the -$G- switch may prevent a package from being used in the same application with other packages.

Other command-line options may be used, if appropriate, when compiling packages.

See Also