Difference between revisions of "FPMake"

From Free Pascal wiki
m (Changing Working Directory)
m (Fixed syntax highlighting; deleted category included in page template)
 
(47 intermediate revisions by 13 users not shown)
Line 1: Line 1:
== Introduction ==
+
{{fpmake}}
This page summarizes all available knowledge on FPMake. FPMake is a pascal based build system developed for and distributed with FPC. It is possible to use FPMake with non FPC development related projects as a replacement for Make or other build systems (like cons, scons, etc).
 
  
See also [[fppkg]].
+
'''FPMake''' is a build-system for Pascal code specifically. It can be compared with other build systems like Make, cons, scons, etc.  
  
== Basics ==
+
With FPMake the code is split up into packages. A FPMake-package can contain units, binaries, examples and documentation. Each package can depend on other packages, in which case a package can use the units of it's dependences. FPMake uses two different locations to search for packages, a system-wide (global) and a local location. By default the global location points to the location of the fpc-installation, while the local location is user-specific.
  
The upcoming 2.2 will contain the basics for a package system.
+
Some parts of fpc itself are compiled using FPMake. (The packages fastcgi and fcl-web in fpc 2.6 and all packages, utilities and the ide in fpc 2.7 and up)
Look at all directories in the fpc source dirs. You'll find there
 
a fpmake.pp or fpmake.inc.
 
  
The idea is that you do a  
+
The packages-manager [[fppkg]] can be used to manage the FPMake packages and to install them from a remote repository.
  
  fppkg <packagename>
 
  
this will look in a database for the package, extract it,
+
__TOC__
and the compile fpmake.pp and run it. The fpmake contains
 
all configuration to make and zip the package.
 
  
You could download a package manually, compile fpmake.pp and
+
== How does it work ==
run
+
FPMake works with Pascal-applications called fpmake, of which each can compile and install one or more FPMake-packages. All settings, location of the sources and instructions are defined inside the source of this fpmake-executable. This source-file is normally saved with the name fpmake.pp. The fpmake.pp is compiled into the fpmake-executable, and this executable can build and install the final packages.
  ./fpmake build
 
or
 
  ./fpmake install
 
which would install the file.
 
  
The fpmake.pp file is very simple, just look at the examples,
+
== Building FPMake packages ==
they are scattered all over the place.
+
The easiest is to use [[fppkg]] to build a FPMake package. But it can also be done manually. Locate the sources of the package you want to install and the fpmake.pp file. Now compile the fpmake.pp file:
  
The idea is that the release after 2.2 will use this system.
+
fpc fpmake.pp
  
== Commandline arguments ==
+
Typical output looks like:
  C:\FPC\packages\fpmkunit>fpmake --help
 
  
  Usage: C:\FPC\packages\fpmkunit\fpmake.exe command [options]
+
Free Pascal Compiler version 2.7.1 [2014/11/26] for i386
  Where command is one of the following:
+
Copyright (c) 1993-2014 by Florian Klaempfl and others
  compile      Compile all units in the package(s).
+
Target OS: Darwin for i386
  build        Build all units in the package(s).
+
Compiling fpmake.pp
  install      Install all units in the package(s).
+
Assembling (pipe) fpmake.s
  clean        Clean (remove) all units in the package(s).
+
Linking fpmake
  archive      Create archive (zip) with all units in the package(s).
+
203 lines compiled, 3.6 sec
  manifest    Create a manifest suitable for import in repository.
 
  Where options is one or more of the following:
 
  -h --help            This message.
 
  -l --list-commands    list commands instead of actually executing them.
 
  -n --nodefaults      Do not use defaults when compiling.
 
  -v --verbose          Be verbose when working.
 
  -C --CPU=Value            Compile for indicated CPU.
 
  -O --OS=Value            Compile for indicated OS
 
  -t --target=Value        Compile for indicated target
 
  -P --prefix=Value        Use indicated prefix directory for all commands.
 
  -B --baseinstalldir=Value Use indicated directory as base install dir.
 
  -r --compiler=Value      Use indicated binary as compiler
 
  -f --config=Value        Use indicated config file when compiling.
 
  
== Simple example fpmake.pp ==
+
Now run the new fpmake(.exe)-executable to build the package(s). This example only contains one package.
  
<pascal>
+
On unices or alike:
 +
./fpmake build --globalunitdir=/usr/local/lib/fpc/2.7.1
 +
 
 +
On Windows or alike:
 +
fpmake.exe build --globalunitdir=c:\pp
 +
 
 +
Typical output looks like:
 +
Start compiling package fcl-base for target i386-darwin.
 +
      Compiling src/ascii85.pp
 +
      Compiling src/avl_tree.pp
 +
      Compiling src/base64.pp
 +
      Compiling src/fpmimetypes.pp
 +
[100%] Compiled package fcl-base
 +
 
 +
The --globalunitdir parameter gives the location of the already installed global packages. This way FPMake can find the packages that this package depends on. When there is a second location where packages are installed, in addition the --localunitdir parameter can be used.
 +
 
 +
If you want to know which path you have to use for the --global(local)unitdir parameter, it's the directory which contains a directory called 'fpmkinst'.
 +
 
 +
To remove all files generated during the build and to be able to do a 'clean' build, perform a clean.
 +
 +
On unices or alike:
 +
./fpmake clean
 +
 
 +
On Windows or alike:
 +
fpmake.exe clean
 +
 
 +
Use the -h parameter to get an overview of all other available commands and options.
 +
 
 +
== Installing FPMake packages ==
 +
Just like building packages, using [[fppkg]] to install FPMake packages is the easiest. But it canbe done manually. First compile the package and then call the fpmake executable to install the package.
 +
 
 +
On unices or alike:
 +
./fpmake install --globalunitdir=/usr/local/lib/fpc/2.7.1 --prefix=/usr/local --baseinstalldir=/usr/local/lib/fpc/2.7.1
 +
 
 +
On Windows or alike:
 +
fpmake.exe install --globalunitdir=c:\pp --prefix=c:\pp --baseinstalldir=c:\pp
 +
 
 +
Typical output looks like:
 +
Installing package fcl-base
 +
Installation package fcl-base for target i386-darwin succeeded
 +
 
 +
The globalunitdir contains the location where to look for packages that the FPMake package can depend on, just like when building the package. The baseinstalldir is the location where the package should be installed to. In general this is the same path as is used for the global- or local-unitdir. Some packages also installs files outside of the baseinstalldir. like configuration files. These packages most often also need a prefix, so providing one is advisable.
 +
 
 +
== How to create FPMake-packages ==
 +
 
 +
=== Simple example fpmake.pp ===
 +
<syntaxhighlight lang=pascal>
 
   program fpmake;
 
   program fpmake;
  
Line 62: Line 84:
  
 
   Var
 
   Var
     T : TTarget;
+
    P: TPackage;
 +
     T: TTarget;
  
 
   begin
 
   begin
 
     With Installer do
 
     With Installer do
 
     begin
 
     begin
       StartPackage('MyNiceProgram'); // Actually optional.
+
       P := AddPackage('my-nice-program');
       Targets.DefaultOS:=[win32,openbsd,netbsd,freebsd,darwin,linux];
+
       P.OSes := [win32,openbsd,netbsd,freebsd,darwin,linux];
       T:=Targets.AddUnit('myunit');
+
       T := P.Targets.AddUnit('myunit');
       T.ResourceStrings:=True;  
+
       T.ResourceStrings := True;
       T:=Targets.AddUnit('myprogram');
+
       T := P.Targets.AddUnit('myprogram');
 
       T.Dependencies.Add('myunit');
 
       T.Dependencies.Add('myunit');
      EndPackage; // Actually optional.
 
 
       Run;
 
       Run;
 
     end;
 
     end;
 
   end.
 
   end.
</pascal>
+
</syntaxhighlight>
  
Compile with
+
=== More complex example fpmake.pp ===
 +
<syntaxhighlight lang=pascal>
 +
  program fpmake;
  
   fpc fpmake.pp
+
   uses fpmkunit;
  
or
+
   type TWidgetSet = (wsGDI, wsX, wsCarbon);
   fppkg build
 
  
which will build (if needed) fpmake and run fpmake in the
+
   var WidgetSet : TWidgetSet;
current directory.
+
      P : TPackage;
 
 
== More complex example fpmake.pp ==
 
 
 
<pascal>
 
   program fpmake;
 
 
 
  Type
 
    TWidgetSet = (wsGDI,wsX,wCarbon);
 
 
 
  Var
 
    WidgetSet : TWidgetSet;
 
  
 
   procedure DetermineWidgetSet;
 
   procedure DetermineWidgetSet;
Line 104: Line 116:
 
     I : Integer;
 
     I : Integer;
 
   begin
 
   begin
     Case Installer.OS of
+
     if Defaults.OS in AllWindowsOSes then
       Windows : WidgetSet:=wsGDI;
+
       WidgetSet := wsGDI else
      Linux : Widgetset:=wsX;
+
    if Defaults.OS = MacOS then
       MacOS : WidgetSet:=wsCarbon
+
       WidgetSet := wsCarbon else
     end;
+
     if Defaults.OS in AllUnixOSes then
 +
      Widgetset := wsX;
 +
 
 
     // Check paramstr() to see if the widgetset was overriden on the commandline;
 
     // Check paramstr() to see if the widgetset was overriden on the commandline;
     For I:=1 to ParamCount do
+
     For I := 1 to ParamCount do
       If ParamStr(i)='--widgetset=X' then
+
       If ParamStr(i) = '--widgetset=X' then
         WidgetSet:=wsX;
+
         WidgetSet := wsX;
   end;  
+
   end;
 
+
 
 
   begin
 
   begin
 
     DetermineWidgetSet;
 
     DetermineWidgetSet;
 
     With Installer do
 
     With Installer do
 
     begin
 
     begin
       ...  
+
       // ...
 
       Case WidgetSet of
 
       Case WidgetSet of
         wsGDI : T.UnitPath.Add('corelib/gdi');
+
         wsGDI : P.UnitPath.Add('corelib/gdi');
         wsX  : T.UnitPath.Add('corelib/x11');
+
         wsX  : P.UnitPath.Add('corelib/x11');
 
         // etc.
 
         // etc.
 
       end;
 
       end;
       ...
+
       //  ...
 
       Run;
 
       Run;
 
     end;
 
     end;
 
   end.
 
   end.
</pascal>
+
</syntaxhighlight>
  
== Changing Working Directory ==
+
=== Changing Working Directory ===
 
If working with units in a subfolder relative to ./fpmake, then "Directory" can be changed.
 
If working with units in a subfolder relative to ./fpmake, then "Directory" can be changed.
<pascal>
+
<syntaxhighlight lang=pascal>
 
     With Installer do
 
     With Installer do
 
     begin
 
     begin
Line 141: Line 155:
 
       ...
 
       ...
 
     end;
 
     end;
</pascal>
+
</syntaxhighlight>
  
== Adding directories ==
+
=== Adding directories ===
  
 
You can add directories with the unit path:
 
You can add directories with the unit path:
  
<pascal>
+
<syntaxhighlight lang=pascal>
   Case OS of
+
   Case Defaults.OS of
     Windows : begin
+
     Win32, Win64:  
                T.UnitPath.Add('corelib/gdi');
+
      begin
                T.Dependencies.Add('gfx_gdi');
+
        T.UnitPath.Add('corelib/gdi');
              end;
+
        T.Dependencies.Add('gfx_gdi');
     Linux   : begin
+
      end;
                T.UnitPath.Add('corelib/x11');
+
     Linux:  
                T.Dependencies.Add('gfx_x11');
+
      begin
              end;
+
        T.UnitPath.Add('corelib/x11');
    // etc.
+
        T.Dependencies.Add('gfx_x11');
 +
      end;
 
   end;
 
   end;
</pascal>
+
</syntaxhighlight>
  
== Appending Compiler Options ==
+
Often, it's more comfortable to use set constants like AllWindowsOSes, AllUnixOSes instead of specific OS names.
  
There is the ability append more custom compiler options (i.e. compiler command line parameters) by using TTarget.Options, TPackage.Options, or Defaults.Options.
+
=== Appending Compiler Options ===
  
<pascal>
+
Additional custom compiler options (i.e. compiler command line parameters) can be appended by using TTarget.Options, TPackage.Options, or Defaults.Options.
 +
 
 +
<syntaxhighlight lang=pascal>
 
   var T : TTarget;
 
   var T : TTarget;
 
   ...
 
   ...
   T.Options:= '-dSOMEDEFINE';
+
   T.Options.Append('-dSOMEDEFINE');
   T.Options:= T.Options + ' -xyzAnythingYouNeed';
+
   T.Options.Append('-xyzAnythingYouNeed');
</pascal>
+
</syntaxhighlight>
  
 
Or
 
Or
<pascal>
+
<syntaxhighlight lang=pascal>
 
   var P : TPackage;
 
   var P : TPackage;
 
   ...
 
   ...
   P.Options:='-dSOMEDEFINE';
+
   P.Options.Append('-dSOMEDEFINE');
</pascal>
+
</syntaxhighlight>
  
 
Or
 
Or
<pascal>
+
<syntaxhighlight lang=pascal>
   Defaults.Options:='-dSOMEDEFINE';
+
   Defaults.Options.Append('-dSOMEDEFINE');
</pascal>
+
</syntaxhighlight>
 
 
== Commands ==
 
 
 
The fpmake executable takes several commands that determine the behavior.
 
 
 
=== Compile ===
 
The most basic usage of fpmake is:
 
 
 
  ./fpmake
 
or
 
  ./fpmake compile
 
 
 
This will compile your project when required.
 
 
 
=== Build ===
 
 
 
To force a build of your project regardless whether it is nescesary or not a build command should be issued.
 
 
 
  ./fpmake build
 
 
 
When executing a build or compile command the units are placed in the directory:
 
 
 
  ./units/CPU-OS
 
 
 
The executable of library is placed under:
 
 
 
  ./bin/CPU-OS
 
 
 
If either of these directories does not exist, they are created.
 
 
 
The CPU and OS can be changed by using the following options:
 
 
 
  ./fpmake --CPU=PPC --OS=Darwin
 
 
 
where the CPU switch takes one from:
 
* Arm
 
* I386
 
* PPC
 
* SPARC
 
* X86_64
 
* M68K
 
* PPC64
 
 
 
and OS takes one from:
 
* Amiga
 
* Atari
 
* Darwin
 
* FreeBSD
 
* Go32v2
 
* Linux
 
* MacOS
 
* MorphOS
 
* NetBSD
 
* Netware
 
* NetwLibc
 
* OpenBSD
 
* OS2
 
* PalmOS
 
* Solaris
 
* Win32
 
* Win64
 
* WinCE
 
* Emx
 
 
 
=== Clean ===
 
  ./fpmake clean
 
 
 
Will clean units (i.e. ones that have been added with AddUnit).
 
 
 
=== Install ===
 
 
 
  ./fpmake install
 
 
 
Will install the project to the default location given in fpmake.pp. You can alter the install location with the following command:
 
 
 
  fpmake --baseinstalldir='c:\program files\my package';
 
  
There are two installer classes implemented:
+
'''Note''': Before FPC 2.4.0, Options property was a simple string, and it seems it supported passing only one parameter to the compiler. Since FPC 2.4.0 (more precisely, since svn revision 13223) Options is a TStrings instance, so it's much more flexible. This also means that you should use $ifdefs if you want to use Options and want your fpmake.pp be compatible with both FPC < 2.4.0 and >= 2.4.0.
  
 +
== Common error messages ==
 +
A few common error messages are explained here
  
 +
=== Unknown target for unit "[unitname]" in dependencies for [targetname] in package [packagename] ===
 +
This indicates a problem in the fpmake.pp file. There is a dependency on a unit, added using Target.Dependencies.AddUnit('unitname'). But there is no corresponding target added to the package with the same unitname.
  
'''TBasicInstaller'''
+
In other words: for every dependency on a unit, there must be a corresponding target within the same package. When there is a dependency on a unit in another package, add a dependency on that package. A dependency on a single file within a different package will not work.
  
Does not set the base output directory, this needs to be set in either the code:
+
Also note that the unit name has to be without the extension of the corresponding file. (Target.Dependencies.AddUnit('unitnams.pas') will not work, while Targets.Addunit requires the extension to be present)
  
<pascal>
+
=== Could not find unit directory for dependency package "rtl" ===
  with Installer(TBasicInstaller) do
+
In general the fpmake system scans the places typically used for fpc installations. In the case that fpmake doesn't find the FPC directory, you'll get the above mentioned error. In such case, set the FPCDIR environment variable to the base dir of the FPC installation, e.g.:
  begin
 
    BaseInstallDir := 'c:\fpmake_test\';
 
    {$i fpmake.inc}
 
    Run;
 
  end;
 
</pascal>
 
  
Or with the commandline option -B or --baseinstalldir. Either way the use of TBasicInstaller needs to be initiated with the Installer(TBasicInstaller) function.
+
  export FPCDIR=~/src/lib/fpc/2.6.4
 
 
 
 
'''TFPCInstaller'''
 
 
 
Sets the output directory in code. This is done in several consecutive steps.
 
 
 
#Value of FPCDIR environment variable
 
#Hardcoded value
 
 
 
Just like TBasicInstaller its possible to use commandline options to control the  base install directory.
 
 
 
=== Archive ===
 
 
 
  ./fpmake archive
 
 
 
will create a zip.
 
 
 
To filename of the archive by default is:
 
 
 
  packagename-version.zip
 
  
 
or
 
or
  
   packagename.zip
+
   set FPCDIR=C:\lazarus\fpc\2.6.4\
 
 
when no version is defined.
 
 
 
It's possible to modify the archive filename by setting the FileName property:
 
 
 
<pascal>
 
  with Installer do
 
  begin
 
    ...;
 
    FileName := 'myfile.zip';
 
    ...;
 
  end;
 
</pascal>
 
 
 
=== Manifest ===
 
 
 
To create a manifest file suitable for import in a repository like FPC will use in the near future issue the manifest command.
 
 
 
An example manifest file is shown below.
 
 
 
<xml>
 
  <?xml version="1.0" ?>
 
  <packages>
 
    <package name="my-package">
 
      <version release="0" major="7" minor="6" suffix="alpha" />
 
      <filename>my-package-0.7.6-alpha.zip</filename>
 
      <author>my name</author>
 
      <license>GPL</license>
 
      <externalurl>www.freepascal.org</externalurl>
 
      <email>myname@freepascal.org</email>
 
      <description>this is the package description</description>
 
    </package>
 
  </packages>
 
</xml>
 
 
 
This manifest file was created using the following code:
 
 
 
<pascal>
 
  with Installer do
 
  begin
 
    StartPackage('my-package');
 
 
 
    Author := 'my name';
 
    License := 'GPL';
 
    ExternalURL := 'www.freepascal.org';
 
    Email := 'myname@freepascal.org';
 
    Description := 'this is the package description';
 
    Version := '0.7.6-alpha';
 
   
 
    ...;
 
    EndPackage;
 
  end;
 
</pascal>
 
 
 
=== List sources===
 
 
 
  ./fpmake listsources
 
 
 
Will create an xml file called sources.xml which lists all sources in the package. Each item has a type node that reveals the function of the file.
 
 
 
<xml>
 
  <source type="document">readme.txt</source>
 
 
 
  <source type="source">project.pas</source>
 
 
 
  <source type="example">example.pas</source>
 
 
 
  <source type="test">test_unit.pas</source>
 
</xml>
 
 
 
The sources.xml file can be read by fppkg which uses it to create a package by itself.
 
 
 
=== Innosetup ===
 
 
 
The plan is to also add
 
 
 
  ./fpmake innosetup
 
  
Which will generate a file that can be included in an inno setup file.
+
This can also be useful if you have to disambiguate over multiple FPC installations.

Latest revision as of 05:32, 16 February 2020

English (en) русский (ru)

FPMake is a build-system for Pascal code specifically. It can be compared with other build systems like Make, cons, scons, etc.

With FPMake the code is split up into packages. A FPMake-package can contain units, binaries, examples and documentation. Each package can depend on other packages, in which case a package can use the units of it's dependences. FPMake uses two different locations to search for packages, a system-wide (global) and a local location. By default the global location points to the location of the fpc-installation, while the local location is user-specific.

Some parts of fpc itself are compiled using FPMake. (The packages fastcgi and fcl-web in fpc 2.6 and all packages, utilities and the ide in fpc 2.7 and up)

The packages-manager fppkg can be used to manage the FPMake packages and to install them from a remote repository.


How does it work

FPMake works with Pascal-applications called fpmake, of which each can compile and install one or more FPMake-packages. All settings, location of the sources and instructions are defined inside the source of this fpmake-executable. This source-file is normally saved with the name fpmake.pp. The fpmake.pp is compiled into the fpmake-executable, and this executable can build and install the final packages.

Building FPMake packages

The easiest is to use fppkg to build a FPMake package. But it can also be done manually. Locate the sources of the package you want to install and the fpmake.pp file. Now compile the fpmake.pp file:

fpc fpmake.pp

Typical output looks like:

Free Pascal Compiler version 2.7.1 [2014/11/26] for i386
Copyright (c) 1993-2014 by Florian Klaempfl and others
Target OS: Darwin for i386
Compiling fpmake.pp
Assembling (pipe) fpmake.s
Linking fpmake
203 lines compiled, 3.6 sec

Now run the new fpmake(.exe)-executable to build the package(s). This example only contains one package.

On unices or alike:

./fpmake build --globalunitdir=/usr/local/lib/fpc/2.7.1

On Windows or alike:

fpmake.exe build --globalunitdir=c:\pp

Typical output looks like:

Start compiling package fcl-base for target i386-darwin.
      Compiling src/ascii85.pp
      Compiling src/avl_tree.pp
      Compiling src/base64.pp
      Compiling src/fpmimetypes.pp
[100%] Compiled package fcl-base

The --globalunitdir parameter gives the location of the already installed global packages. This way FPMake can find the packages that this package depends on. When there is a second location where packages are installed, in addition the --localunitdir parameter can be used.

If you want to know which path you have to use for the --global(local)unitdir parameter, it's the directory which contains a directory called 'fpmkinst'.

To remove all files generated during the build and to be able to do a 'clean' build, perform a clean.

On unices or alike:

./fpmake clean

On Windows or alike:

fpmake.exe clean

Use the -h parameter to get an overview of all other available commands and options.

Installing FPMake packages

Just like building packages, using fppkg to install FPMake packages is the easiest. But it canbe done manually. First compile the package and then call the fpmake executable to install the package.

On unices or alike:

./fpmake install --globalunitdir=/usr/local/lib/fpc/2.7.1 --prefix=/usr/local --baseinstalldir=/usr/local/lib/fpc/2.7.1

On Windows or alike:

fpmake.exe install --globalunitdir=c:\pp --prefix=c:\pp --baseinstalldir=c:\pp

Typical output looks like:

Installing package fcl-base
Installation package fcl-base for target i386-darwin succeeded

The globalunitdir contains the location where to look for packages that the FPMake package can depend on, just like when building the package. The baseinstalldir is the location where the package should be installed to. In general this is the same path as is used for the global- or local-unitdir. Some packages also installs files outside of the baseinstalldir. like configuration files. These packages most often also need a prefix, so providing one is advisable.

How to create FPMake-packages

Simple example fpmake.pp

  program fpmake;

  uses fpmkunit;

  Var
    P: TPackage;
    T: TTarget;

  begin
    With Installer do
    begin
      P := AddPackage('my-nice-program');
      P.OSes := [win32,openbsd,netbsd,freebsd,darwin,linux];
      T := P.Targets.AddUnit('myunit');
      T.ResourceStrings := True;
      T := P.Targets.AddUnit('myprogram');
      T.Dependencies.Add('myunit');
      Run;
    end;
  end.

More complex example fpmake.pp

  program fpmake;

  uses fpmkunit;

  type TWidgetSet = (wsGDI, wsX, wsCarbon);

  var WidgetSet : TWidgetSet;
      P : TPackage;

  procedure DetermineWidgetSet;
  Var
    I : Integer;
  begin
    if Defaults.OS in AllWindowsOSes then
      WidgetSet := wsGDI else
    if Defaults.OS = MacOS then
      WidgetSet := wsCarbon else
    if Defaults.OS in AllUnixOSes then
      Widgetset := wsX;

    // Check paramstr() to see if the widgetset was overriden on the commandline;
    For I := 1 to ParamCount do
      If ParamStr(i) = '--widgetset=X' then
        WidgetSet := wsX;
  end;

  begin
    DetermineWidgetSet;
    With Installer do
    begin
      // ...
      Case WidgetSet of
        wsGDI : P.UnitPath.Add('corelib/gdi');
        wsX   : P.UnitPath.Add('corelib/x11');
        // etc.
      end;
      //  ...
      Run;
    end;
  end.

Changing Working Directory

If working with units in a subfolder relative to ./fpmake, then "Directory" can be changed.

    With Installer do
    begin
      ...
      Directory:='some/subdir';
      T:= Targets.AddUnit('unitinfolder');
      ...
    end;

Adding directories

You can add directories with the unit path:

  Case Defaults.OS of
    Win32, Win64: 
      begin
        T.UnitPath.Add('corelib/gdi');
        T.Dependencies.Add('gfx_gdi');
      end;
    Linux: 
      begin
        T.UnitPath.Add('corelib/x11');
        T.Dependencies.Add('gfx_x11');
      end;
  end;

Often, it's more comfortable to use set constants like AllWindowsOSes, AllUnixOSes instead of specific OS names.

Appending Compiler Options

Additional custom compiler options (i.e. compiler command line parameters) can be appended by using TTarget.Options, TPackage.Options, or Defaults.Options.

  var T : TTarget;
  ...
  T.Options.Append('-dSOMEDEFINE');
  T.Options.Append('-xyzAnythingYouNeed');

Or

  var P : TPackage;
  ...
  P.Options.Append('-dSOMEDEFINE');

Or

  Defaults.Options.Append('-dSOMEDEFINE');

Note: Before FPC 2.4.0, Options property was a simple string, and it seems it supported passing only one parameter to the compiler. Since FPC 2.4.0 (more precisely, since svn revision 13223) Options is a TStrings instance, so it's much more flexible. This also means that you should use $ifdefs if you want to use Options and want your fpmake.pp be compatible with both FPC < 2.4.0 and >= 2.4.0.

Common error messages

A few common error messages are explained here

Unknown target for unit "[unitname]" in dependencies for [targetname] in package [packagename]

This indicates a problem in the fpmake.pp file. There is a dependency on a unit, added using Target.Dependencies.AddUnit('unitname'). But there is no corresponding target added to the package with the same unitname.

In other words: for every dependency on a unit, there must be a corresponding target within the same package. When there is a dependency on a unit in another package, add a dependency on that package. A dependency on a single file within a different package will not work.

Also note that the unit name has to be without the extension of the corresponding file. (Target.Dependencies.AddUnit('unitnams.pas') will not work, while Targets.Addunit requires the extension to be present)

Could not find unit directory for dependency package "rtl"

In general the fpmake system scans the places typically used for fpc installations. In the case that fpmake doesn't find the FPC directory, you'll get the above mentioned error. In such case, set the FPCDIR environment variable to the base dir of the FPC installation, e.g.:

 export FPCDIR=~/src/lib/fpc/2.6.4

or

 set FPCDIR=C:\lazarus\fpc\2.6.4\

This can also be useful if you have to disambiguate over multiple FPC installations.