Difference between revisions of "FPMake"
m (Text replace - "<xml>" to "<syntaxhighlight lang="xml">") |
m (Text replace - "</xml>" to "</syntaxhighlight>") |
||
Line 367: | Line 367: | ||
</package> | </package> | ||
</packages> | </packages> | ||
− | </ | + | </syntaxhighlight> |
This manifest file was created using the following code: | This manifest file was created using the following code: | ||
Line 403: | Line 403: | ||
<source type="example">example.pas</source> | <source type="example">example.pas</source> | ||
<source type="test">test_unit.pas</source> | <source type="test">test_unit.pas</source> | ||
− | </ | + | </syntaxhighlight> |
The sources.xml file can be read by fppkg which uses it to create a package by itself. | The sources.xml file can be read by fppkg which uses it to create a package by itself. |
Revision as of 12:12, 24 March 2012
Introduction
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 standardizes the building by defining some limits. For example:
- The unit output directory can not be changed. It is always units/CPU-OS (e.g. units/i386-win32). You can only change the install directory.
Configuration
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 an error like:
Could not find unit directory for dependency package "rtl"
In such case, set the FPCDIR environment variable to the base dir of the FPC installation, e.g.:
export FPCDIR=~/src/lib/fpc/2.3.1
or
set FPCDIR=C:\lazarus\fpc\2.4.3\
This can also be useful if you have to disambiguate over multiple FPC installations.
Basics
The upcoming 2.2 will contain the basics for a package system. Look at any directory in the fpc source dirs. You'll find a file fpmake.pp or fpmake.inc there.
The idea is that you do a
fppkg <packagename>
This will look in a database for the package, extract it, and then compile fpmake.pp and run it. The fpmake contains all configurations to make and zip the package.
You could download a package manually, compile fpmake.pp and run
./fpmake build
or
./fpmake install
which would install the file.
The fpmake.pp file is very simple. Just look at the examples, they are scattered all over the place.
The idea is that the release after 2.2 will use this system.
Commandline arguments
./fpmake --help
Usage: fpmake command [options] Where command is one of the following: compile Compile all units in the package(s). build Build all units in the package(s). install Install all units in the package(s). clean Clean (remove) all units in the package(s). archive Create archive (zip) with all units in the package(s). 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 --nofpccfg Compiler will not use fpc.cfg -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. -UL --localunitdir=Value Use indicated directory as local (user) unit dir. -UG --globalunitdir=Value Use indicated directory as global unit dir. -r --compiler=Value Use indicated binary as compiler -f --config=Value Use indicated config file when compiling.
Simple example fpmake.pp
<pascal>
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.
</pascal>
Compile with
fpc fpmake.pp
or
fppkg build
which will build (if needed) fpmake and run fpmake in the current directory.
More complex example fpmake.pp
<pascal>
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.
</pascal>
Changing Working Directory
If working with units in a subfolder relative to ./fpmake, then "Directory" can be changed. <pascal>
With Installer do begin ... Directory:='some/subdir'; T:= Targets.AddUnit('unitinfolder'); ... end;
</pascal>
Adding directories
You can add directories with the unit path:
<pascal>
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;
</pascal>
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.
<pascal>
var T : TTarget; ... T.Options.Append('-dSOMEDEFINE'); T.Options.Append('-xyzAnythingYouNeed');
</pascal>
Or <pascal>
var P : TPackage; ... P.Options.Append('-dSOMEDEFINE');
</pascal>
Or <pascal>
Defaults.Options.Append('-dSOMEDEFINE');
</pascal>
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.
Commands
The fpmake executable takes several commands that determine its 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 a library is placed in the directory:
./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:
TBasicInstaller
Does not set the base output directory, this needs to be set in either the code:
<pascal>
with Installer(TBasicInstaller) do begin Defaults.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.
TFPCInstaller
Sets the output directory in code. This is done in several consecutive steps.
- Value of FPCDIR environment variable
- Hardcoded value
Just like TBasicInstaller it is possible to use commandline options to control the base install directory.
Archive
./fpmake archive
will create a zip.
The default filename of the archive is:
packagename-version.zip
or
packagename.zip
when no version is defined.
It is 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 into a repository FPC will use the manifest command.
An example manifest file is shown below.
<?xml version="1.0"?>
<packages>
<package name="my-package">
<version major="0" minor="7" micro="6" build="1"/>
<filename>my-package-0.7.6-1.zip</filename>
<author>my name</author>
<license>GPL</license>
<homepageurl>http://www.freepascal.org/</homepageurl>
<email>myname@freepascal.org</email>
<description>this is the package description</description>
<dependencies>
<dependency>
<package packagename="rtl"/>
</dependency>
</dependencies>
</package>
</packages>
This manifest file was created using the following code:
<pascal>
with Installer do begin P := AddPackage('my-package');
P.Author := 'my name'; P.License := 'GPL'; {$ifdef VER2_2_2} P.ExternalURL {$else} P.HomepageURL {$endif} := 'http://www.freepascal.org/'; P.Email := 'myname@freepascal.org'; P.Description := 'this is the package description'; P.Version := '0.7.6-1';
// ...;
Run; end;
</pascal>
List sources
Note: this seems not available in FPC 2.2.2 and 2.2.4rc1. Please remove this section (if this was old abandoned idea) or update to say "planned" if it's a future plan.
./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.
<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>
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.
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 an problem in the fpmake.pp file. There is a dependency on an 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 an 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 unitname 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)