Portfile DevelopmentThis chapter covers a brief introduction to Portfiles, how to create a
local Portfile repository for development, and creating Portfiles.Portfile IntroductionA MacPorts Portfile is a TCL script that usually
contains only the simple keyword/value combinations and Tcl extensions as
described in the Portfile Reference
chapter, though it may also contain arbitrary TCL code. Every port has a
corresponding Portfile, but Portfiles do not completely define a port's
installation behavior since MacPorts base has default port installation
characteristics coded within it. Therefore Portfiles need only specify
required options, though some ports may require non-default
options.A common way for Portfiles to augment or override MacPorts base
default installation phase characteristics is by using
Portfile phase declaration(s). If you use Portfile
phase declaration(s), you should know how to identify the
global section of a Portfile. Any statements not contained
within a phase declaration, no matter where they are located in a Portfile,
are said to be in the global section of the Portfile; therefore the global
section need not be contiguous. Likewise, to remove statements from the
global section they must be placed within a phase declaration.The main phases you need to be aware of when making a Portfile are
these:FetchExtractPatchConfigureBuildDestrootThe default installation phase behavior performed by the MacPorts
base works fine for applications that use the standard
configure, make, and make
install steps, which conform to phases configure, build, and
destroot respectively. For applications that do not conform to this
standard behavior, any installation phase may be augmented using pre- and/or post- phases, or
even overridden or
eliminated. See
Example Portfiles
below.For a detailed description of all port phases, see the Portfile Reference chapter.Creating a PortfileHere we list the individual Portfile components for an application
that conforms to the standard configure,
make, and make install steps of most
open source application installs.ModelineThis should be the first line of a Portfile. It sets the correct
editing options for vim and emacs. See Port Style for more
information. Its use is optional and up to the port maintainer.# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4Subversion ID tag lineThis must be a Portfile's second line (or the first, if a
modeline is not used). When a port is committed to the repository, ID
tags are expanded to include the filename and the revision number,
date and time, and author of the last commit.# $Id$PortSystem lineThis statement is required for all ports.PortSystem 1.0Port namename rrdtoolPort versionversion 1.2.23Port categoriesA port may belong to more than one category, but the first
(primary) category should match the directory name in the ports tree
where the Portfile is to reside.categories netPlatform statementplatforms darwinPort maintainersA port's maintainers are the people who have agreed to take
responsibility for keeping the port up-to-date. The
maintainers keyword lists the maintainers' email
addresses, preferrably in the obfuscated form which hides them
from spambots. For more, see the full explanation of the maintainers keyword in
the Global Keywords section
of the Portfile Reference
chapter.maintainers jdoe \
example.org:julesvernePort descriptiondescription Round Robin DatabasePort long_descriptionlong_description RRDtool is a system to store and display time-series \
dataA port's application homepagehomepage http://people.ee.ethz.ch/~oetiker/webtools/rrdtool/A port's download URLsmaster_sites http://oss.oetiker.ch/rrdtool/pub/ \
ftp://ftp.pucpr.br/rrdtool/Port checksumsThe checksums specified in a Portfile are checked with the
fetched tarball for security. For the best security, use rmd160
and sha256 checksum types.checksums rmd160 7bbfce4fecc2a8e1ca081169e70c1a298ab1b75a \
sha256 2829fcb7393bac85925090b286b1f9c3cd3fbbf8e7f35796ef4131322509aa53To find the correct checksums for a port's distribution file,
follow this example:%%openssl rmd160 rrdtool-1.2.23.tar.gz%%openssl sha256 rrdtool-1.2.23.tar.gzRIPEMD160( ... rrdtool-1.2.23.tar.gz)= 7bbfce4fecc2a8e1ca081169e70c1a298ab1b75a
SHA256( ... rrdtool-1.2.23.tar.gz)= 2829fcb7393bac85925090b286b1f9c3cd3fbbf8e7f35796ef4131322509aa53Port dependenciesA port's dependencies are ports that must be installed before
another port is installed.depends_lib port:perl5.8 \
port:tcl \
port:zlibPort configure arguments (optional)configure.args --enable-perl-site-install \
--mandir=${prefix}/share/manExample PortfilesIn this section we begin by taking a look at a complete simple
Portfile; then we see how to augment default phases by
defining pre- and post- phases, how to override default phases,
and finally how to eliminate port
phases.A Basic Portfile# $Id$
PortSystem 1.0
name rrdtool
version 1.2.23
categories net
platforms darwin
license GPL
maintainers julesverne
description Round Robin Database
long_description RRDtool is a system to store and display time-series data
homepage http://people.ee.ethz.ch/~oetiker/webtools/rrdtool/
master_sites http://oss.oetiker.ch/rrdtool/pub/ \
ftp://ftp.pucpr.br/rrdtool/
checksums rmd160 7bbfce4fecc2a8e1ca081169e70c1a298ab1b75a \
sha256 2829fcb7393bac85925090b286b1f9c3cd3fbbf8e7f35796ef4131322509aa53
depends_lib path:bin/perl:perl5 \
port:tcl \
port:zlib
configure.args --enable-perl-site-install \
--mandir=${prefix}/share/manAugment Phases Using pre- / post-To augment a port's installation phase, and not override it, you
may use pre- and post- installation phases as shown in this
example.post-destroot {
# Install example files not installed by the Makefile
file mkdir ${destroot}${prefix}/share/doc/${name}/examples
file copy ${worksrcpath}/examples/ \
${destroot}${prefix}/share/doc/${name}/examples
}Overriding PhasesTo override the automatic MacPorts installation phase processing,
define your own installation phases as shown in this example.destroot {
xinstall -m 755 -d ${destroot}${prefix}/share/doc/${name}
xinstall -m 755 ${worksrcpath}/README ${destroot}${prefix}/share/doc/${name}
}Eliminating PhasesTo eliminate a default phase, simply define a phase with no
contents as shown.build {}Because many software packages do not use
, a keyword is provided to eliminate the
phase. Another exception is the
phase may not be eliminated. See the
chapter Portfile Reference for full
information.Creating a StartupItemStartupitems may be placed in the global section of a
Portfile.startupitem.create yes
startupitem.name nmicmpd
startupitem.executable "${prefix}/bin/nmicmpd"Port VariantsVariants are a way for port authors to provide options that may be
invoked at install time. They are declared in the global section of a
Portfile using the variant keyword, and should include carefully chosen variant
descriptions.Example VariantsThe most common actions for user-selected variants is to add or
remove dependencies, configure arguments, and build arguments according
to various options a port author wishes to provide. Here is an example
of several variants that modify depends_lib and configure arguments for
a port.variant fastcgi description {Add fastcgi binary} {
configure.args-append \
--enable-fastcgi \
--enable-force-cgi-redirect \
--enable-memory-limit
}
variant gmp description {Add GNU MP functions} {
depends_lib-append port:gmp
configure.args-append --with-gmp=${prefix}
}
variant sqlite description {Build sqlite support} {
depends_lib-append \
port:sqlite3
configure.args-delete \
--without-sqlite \
--without-pdo-sqlite
configure.args-append \
--with-sqlite \
--with-pdo-sqlite=${prefix} \
--enable-sqlite-utf8
}Variant names may contain only the characters A-Z, a-z, and the
underscore character _. Therefore, take care to never
use hyphens in variant names.In the example variant declaration below, the configure argument
--without-x is removed and a number of others are
appended.variant x11 description {Builds port as an X11 program with Lucid widgets} {
configure.args-delete --without-x
configure.args-append --with-x-toolkit=lucid \
--without-carbon \
--with-xpm \
--with-jpeg \
--with-tiff \
--with-gif \
--with-png
depends_lib-append lib:libX11:XFree86 \
lib:libXpm:XFree86 \
port:jpeg \
port:tiff \
port:libungif \
port:libpng
}Variant Actions in a PhaseIf a variant requires options in addition to those provided by
keywords using -append and/or -delete, in other words, any actions that
would normally take place within a port installation phase, do not try
to do this within the variant declaration. Rather, modify the behavior
of any affected phases when the variant is invoked using the
variant_isset keyword.post-destroot {
xinstall -m 755 -d ${destroot}${prefix}/etc/
xinstall ${worksrcpath}/examples/foo.conf \
${destroot}${prefix}/etc/
if {[variant_isset carbon]} {
delete ${destroot}${prefix}/bin/emacs
delete ${destroot}${prefix}/bin/emacs-${version}
}
}Default VariantsVariants are used to specify actions that lie outside the core
functions of an application or port, but there may be some cases where
you wish to specify these non-core functions by default. For this
purpose you may use the keyword default_variants.default_variants +foo +barThe default_variant keyword may only be used in the global
Portfile section.Patch FilesPatch files are files created with the Unix command
diff that are applied using the command
patch to modify text files to fix bugs or extend
functionality.Creating Portfile PatchesIf you wish to contribute modifications or fixes to a Portfile,
you should do so in the form of a patch. Follow the steps below to
create Portfile patch filesMake a copy of the Portfile you wish to modify; both files
must be in the same directory, though it may be any
directory.%%cp -p Portfile Portfile.origEdit the file to make it as you want it to be after it is
fetched.Now use the Unix command diff -u to create
a unified diff patch file. Put the name of the port in
the patchfile, for example, Portfile-rrdtool.diff.%%diff -u Portfile.orig Portfile > Portfile-rrdtool.diffA patch file that is a unified diff file is the
easiest to interpret by humans and this type should always be used
for ports. The Portfile patch below will change the version and
checksums when applied.--- Portfile.orig 2011-07-25 18:52:12.000000000 -0700
+++ Portfile 2011-07-25 18:53:35.000000000 -0700
@@ -2,7 +2,7 @@
PortSystem 1.0
name foo
-version 1.3.0
+version 1.4.0
categories net
maintainers nomaintainer
description A network monitoring daemon.
@@ -13,9 +13,9 @@
homepage http://rsug.itd.umich.edu/software/${name}
master_sites ${homepage}/files/
-checksums rmd160 f0953b21cdb5eb327e40d4b215110b71
+checksums rmd160 01532e67a596bfff6a54aa36face26ae
extract.suffix .tgz
platforms darwin
Now you may attach the patch file to a MacPorts Trac ticket for
the port author to evaluate.Creating Source Code PatchesNecessary or useful patches to application source code should
generally be sent to the application developer rather than the port
author so the modifications may be included in the next version of the
application.Generally speaking, you should create one patch file for each file
to be patched. Patchfile filenames should uniquely distinguish the file
and generally be of the form
patch-<directory>-<filename>.diff,
as shown in this example:
patch-src-Makefile.in.diff.You may use patch files that patch multiple files under these
conditions:You find existing patch files that do so.If fixing a particular problem or bug requires changes in
multiple files -in those cases the patch filename should reference
the problem or bug, for example:
patch-<destroot_variable_fix>.diffTo create a patch to modify a single file, follow the steps
below.Locate the file you wish to patch in its original location
within the unpacked source directory and make a duplicate of
it.%%cd ~/Downloads/foo-1.34/src%%cp -p Makefile.in Makefile.in.origEdit the file and modify the text to reflect your
corrections.Now cd to the top-level directory of the
unpacked source, and use the Unix command diff -u
to create a unified diff patch file.%%cd ~/Downloads/foo-1.34%%diff -u src/Makefile.in.orig src/Makefile.in > patch-src-Makefile.in.diffYou should execute the diff command from
the top-level directory of the unpacked source code, because during
the patch phase MacPorts by default uses the patch argument
, which does not strip prefixes with any leading
slashes from file names found in the patch file (as opposed to
that strips one, etc), and any path not
relative to the top-level directory of the unpacked source will fail
during the patch phase.If you find an existing source file patch you wish to use
that contains leading path information (diff was executed from a
directory higher than the top-level source directory), you will
need to use the patch phase
keyword patch.pre_args to specify a
value for how many prefixes with leading
slashes are to be stripped off.A patch file that is a unified diff file is the
easiest to interpret by humans and this type should always be used
for ports. See the example below where a patch adds
DESTDIR support to a
Makefile.in file.--- src/Makefile.in.orig 2007-06-01 16:30:47.000000000 -0700
+++ src/Makefile.in 2007-06-20 10:10:59.000000000 -0700
@@ -131,23 +131,23 @@
$(INSTALL_DATA)/gdata $(INSTALL_DATA)/perl
install-lib:
- -mkdir -p $(INSTALL_LIB)
+ -mkdir -p $(DESTDIR)$(INSTALL_LIB)
$(PERL) tools/install_lib -s src -l $(INSTALL_LIB) $(LIBS)
- cp $(TEXT) $(INSTALL_LIB)/
+ cp $(TEXT) $(DESTDIR)$(INSTALL_LIB)/Place the patch
patch-src-Makefile.in.diff in the directory
${portpath}/files and use it in a port using
the patchfiles keyword. ${portpath}
may be in a local Portfile repository during development, or
files/ may be in a port's
${portpath} in the global MacPorts
repository.patchfiles patch-src-Makefile.in.diffManually Applying PatchesMacPorts applies patch files automatically, but you may want to
know how to apply patch files manually if you want to test patch files
you have created or you wish to apply uncommitted Portfile
patches.Change to the directory containing the file to be patched. In
this example, we'll apply a Portfile patch to the postfix
port.%%cd $(port dir postfix)Now apply the patch from your Downloads folder, or wherever you
put it. The patchfile knows the name of the file to be patched.%%patch -p0 < ~/Downloads/Portfile-postfix.diffpatching file PortfileLocal Portfile RepositoriesTo create and test Portfiles that are not yet committed to
Subversion, you may create a local Portfile repository as shown. Replace
the hypothetical user julesverne with your username
in the example below.Open the sources.conf file in a text
editor. For example, to open it into TextEdit:%%open -e ${prefix}/etc/macports/sources.confInsert a URL pointing to your local repository location before
the rsync URL as shown.file:///Users/julesverne/ports
rsync://rsync.macports.org/release/ports [default]
The file URL should always appear before the rsync URL so that
local Portfiles can be tested that are duplicated in the MacPorts
tree, because the port command will always
operate on the first Portfile it encounters.Place the Portfiles you create inside a directory whose name
matches the port, which should in turn be placed inside a directory
that reflects the port's primary category (the first category entry in
the Portfile). For example, to create the directory for a hypothetical
port bestevergame and to begin editing its Portfile in
TextEdit, you can use these commands:%%mkdir -p ~/ports/games/bestevergame%%cd ~/ports/games/bestevergame%%touch Portfile%%open -e PortfileSee other sections in the Guide for help writing Portfiles. If
you've already written the Portfile elsewhere, you can instead copy
the Portfile into this directory.If your Portfile needs to apply any patches to the port's source
files, create a files directory and place the
patchfiles in it, and reference the patchfiles in your Portfile, as
explained in
Creating Source Code Patches.After you create or update your Portfile, use the MacPorts
portindex command in the local repository's
directory to create or update the index of the ports in your local
repository.%% cd ~/ports
%% portindexCreating software index in /Users/julesverne/ports
Adding port games/bestevergame
Total number of ports parsed: 1
Ports successfully parsed: 1
Ports failed: 0Once the local port is added to the PortIndex,
it becomes available for searching or installation as with any other
Portfile in the MacPorts tree:%%port search besteverbestevergame @1.1 (games)
The Best Ever GamePortfile Best PracticesThis section contains practical guidelines for creating Portfiles
that install smoothly and provide consistency between ports. The following
sections are on the TODO list.Port StylePortfiles may be thought of as a table of keys and values in two
columns separated by spaces (not tabs), so you should set your editor to
use soft tabs, which are tabs emulated by spaces. By default, the top
line of all Portfiles should use a modeline that defines soft tabs for
the vim and emacs editors as shown.# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:ft=tcl:et:sw=4:ts=4:sts=4The left column should consist of single words, and will be
separated from the more complex right side by spaces in multiples of
four. Variable assignments and variant declarations are exceptions, and
may be considered a single word on the left side, with a single space
between words.set libver "8.5"
variant mysql5 { ... }Frequently multiple items are necessary in the second column. For
example, to set multiple source download locations, multiple
master_sites must be defined. Unless the second column
items are few and short you should place each additional item on a new
line and separate lines with a backslash. Indent the lines after the
first line to make it clear the items are second column values and also
to emphasize the unity of the block.destroot.keepdirs ${destroot}${prefix}/var/run \
${destroot}${prefix}/var/log \
${destroot}${prefix}/var/cache/mrtgDon't Overwrite Config FilesTODO:Install Docs and ExamplesTODO:Provide User MessagesTODO:Use VariablesTODO: Set variables so changing paths may be done in one place;
use them anytime it makes updates simpler: distname
${name}-src-${version}Renaming or replacing a portIf there is the need to replace a port with another port or a
renaming is necessary for some reason, the port should be marked as
replaced_by.As an illustration of a typical workflow the port
skrooge-devel shall be taken. This port had been used for
testing new versions of skrooge, but it turned out to have become
unnecessary due to the fact that skrooge's developers currently prefer a
distribution via port skrooge instead. At the end of this section the use of the obsolete PortGroup is suggested
as an even shorter approach to the below described workflow.The long waySkrooge's original devel port file looked like this:# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; truncate-lines: t -*- vim:fenc=utf-8:et:sw=4:ts=4:sts=4
# $Id$
PortSystem 1.0
PortGroup kde4 1.1
fetch.type svn
svn.url svn://anonsvn.kde.org/home/kde/trunk/extragear/office/skrooge
svn.revision 1215845
name skrooge-devel
version 0.8.0-${svn.revision}
categories kde finance
maintainers mk pixilla openmaintainer
description Skrooge
long_description Personal finance management tool for KDE4, with the aim of being highly intuitive, while \
providing powerful functions such as reporting (including graphics), persistent \
Undo/Redo, encryption, and much more...
conflicts skrooge
platforms darwin
license GPL-3
homepage http://skrooge.org
master_sites http://skrooge.org/files/
livecheck.type none
distname skrooge
depends_lib-append port:kdelibs4 \
port:libofx \
port:qca-ossl \
port:kdebase4-runtime \
port:oxygen-iconsThe following steps have to be taken to ensure a smooth transition
for a MacPorts user updating his local installation using
sudo port upgrade: add the line replaced_by foo where foo is the
port this one is replaced by; when a user upgrades this port,
MacPorts will instead install the replacement portreplaced_by skrooge increase the version, revision, or epoch, so that users who
have this port installed will get notice in port
outdated that they should upgrade it and trigger the above
processrevision 1 clear distfiles (have a line reading only
distfiles) so that no distfile is downloaded for this
stub portdistfiles delete master_sites since there aren't any distfiles to
download disable livechecklivecheck.type none add a pre-configure block with a ui_error and
return -code error explaining to users who try to
install this port that the port has been replacedpre-configure {
ui_error "Please do not install this port since it has been replaced by 'skrooge'."
return -code error
}With above modifications the port file eventually looks like
this:# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; truncate-lines: t -*- vim:fenc=utf-8:et:sw=4:ts=4:sts=4
# $Id$
PortSystem 1.0
name skrooge-devel
svn.revision 1215845
version 0.8.0-${svn.revision}
revision 1
replaced_by skrooge
categories kde finance
maintainers mk pixilla openmaintainer
description Skrooge
long_description Personal finance management tool for KDE4, with the aim of being highly intuitive, while \
providing powerful functions such as reporting (including graphics), persistent \
Undo/Redo, encryption, and much more...
platforms darwin
license GPL-3
homepage http://skrooge.org
livecheck.type none
pre-configure {
ui_error "Please do not install this port since it has been replaced by 'skrooge'."
return -code error
}
distfilesA user upgrading ports will experience the following for port
skrooge-devel:%%sudo port upgrade skrooge-devel---> skrooge-devel is replaced by skrooge
---> Computing dependencies for skrooge
---> Fetching skrooge
---> Verifying checksum(s) for skrooge
---> Extracting skrooge
---> Configuring skrooge
---> Building skrooge
---> Staging skrooge into destroot
---> Deactivating skrooge-devel @0.8.0-1215845_0
---> Cleaning skrooge-devel
---> Computing dependencies for skrooge
---> Installing skrooge @0.8.0.6_0
---> Activating skrooge @0.8.0.6_0
##########################################################
# Don't forget that dbus needs to be started as the local
# user (not with sudo) before any KDE programs will launch
# To start it run the following command:
# launchctl load /Library/LaunchAgents/org.freedesktop.dbus-session.plist
##########################################################
######################################################
# Programs will not start until you run the command
# 'sudo chown -R $USER ~/Library/Preferences/KDE'
# replacing $USER with your username.
######################################################
---> Cleaning skroogeIn case a user actually tries to install the obsolete port
skrooge-devel it would be pointed out by an error message that
this is impossible now:%%sudo port install skrooge-devel---> Fetching skrooge-devel
---> Verifying checksum(s) for skrooge-devel
---> Extracting skrooge-devel
---> Configuring skrooge-devel
Error: Please do not install this port since it has been replaced by 'skrooge'.
Error: Target org.macports.configure returned:
Log for skrooge-devel is at: /opt/local/var/macports/logs/_opt_local_var_macports_sources_rsync.macports.org_release_ports_kde_skrooge-devel/main.log
Error: Status 1 encountered during processing.
To report a bug, see <http://guide.macports.org/#project.tickets>The shortcut: PortGroup obsoleteUsing the PortGroup obsolete makes the task described in the previous subsection
much easier:
# -*- coding: utf-8; mode: tcl; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; truncate-lines: t -*- vim:fenc=utf-8:et:sw=4:ts=4:sts=4
# $Id$
PortSystem 1.0
replaced_by skrooge
PortGroup obsolete 1.0
name skrooge-devel
svn.revision 1215845
version 0.8.0-${svn.revision}
revision 2The PortGroup defines a number of reasonable defaults for a port that is only
there to inform users that they should uninstall it and install something else
instead. You might want to override some of the defaults though. For details have
a look at the PortGroup's source code in
${prefix}/var/macports/sources/rsync.macports.org/release/ports/_resources/port1.0/group/obsolete-1.0.tcl.It is important to specify replaced_by BEFORE the
PortGroup line!Removing a portIf a port has to be removed from MacPorts one should consider
the hints concerning replacing it by some alternative port given
above.
If there is no replacement for it, insert a pre-configure
block as described there to alert the user about why the port is not
allowed for installation anymore.It is recommended to wait about a year before the port directory
is actually being removed from MacPorts' Subversion repository.MacPorts' buildbotThe buildbot is a port
build-service currently supporting building of all committed ports for Snow Leopard,
Lion, and Mountain Lion using the MacPorts AutoBuild
(MPAB)
scripts.Every time a maintainer commits changes to MacPorts' central SVN repository
the buildbot will check whether a rebuild of the corresponding port(s) would
be necessary. If the port(s) in question are distributable their binary
archives will be kept for subsequent distribution for the three most current
versions of the Mac OS X operating system.If a build error occurred for a port its maintainer will be informed via
an email so that problems which did not surface on the maintainer's machine will
not go unnoticed.
Port maintainers will find the
waterfall
and the
builders
views most useful since they give information about the build status and offer
the possibility to build ones port(s) on specific builders.Thus the buildbot helps to keep MacPorts consistent on various
OSX versions, i.e. a maintainer does not need access to these versions anymore in
order to assure that the port(s) maintained build without problems. Currently only
the default port variants will be build and kept.