HOWTO: Creating Metaports

A while ago I read article about creating metaports to avoid installing every dam port, that you need with portmaster

So I wanted to share mine [just finished], let it be example for many other metaports, that you create

Now I can simply # portmaster x11/ks86 :D

/usr/ports/x11/ks86/Makefile
Code:
# New ports collection makefile for: FreeBSD
# Date created:		2009.12.07.
# Whom:			Aldis Berjoza <killasmurf86@gmail.com>
# $FreeBSD:$
#

PORTNAME=	killasmurf86-desktop
PORTVERSION=	1.2
CATEGORIES=	x11
MASTER_SITES=
DISTFILES=

MAINTAINER=	killasmurf86@gmail.com
COMMENT=	The meta-port for killasmurf86\'s desktop

NO_BUILD=	YES
NO_WRKSUBDIR=   YES
USE_CDRTOOLS=	YES

# devel {{{1
RUN_DEPENDS+=	vim:${PORTSDIR}/editors/vim
RUN_DEPENDS+=	cscope:${PORTSDIR}/devel/cscope
RUN_DEPENDS+=	exctags:${PORTSDIR}/devel/ctags
RUN_DEPENDS+=	cscout:${PORTSDIR}/devel/cscout
RUN_DEPENDS+=	ht:${PORTSDIR}/editors/hte
RUN_DEPENDS+=	git:${PORTSDIR}/devel/git
RUN_DEPENDS+=	ccache:${PORTSDIR}/devel/ccache
RUN_DEPENDS+=	cgdb:${PORTSDIR}/devel/cgdb
#RUN_DEPENDS+=	svn:${PORTSDIR}/devel/subversion
# 1}}}

# minimal desktop {{{1
RUN_DEPENDS+=	${LOCALBASE}/libdata/xorg:${PORTSDIR}/x11/xorg
RUN_DEPENDS+=	fvwm2:${PORTSDIR}/x11-wm/fvwm2-devel
RUN_DEPENDS+=	xdm:${PORTSDIR}/x11/xdm
RUN_DEPENDS+=	urxvt:${PORTSDIR}/x11/rxvt-unicode
RUN_DEPENDS+=	convert:${PORTSDIR}/graphics/ImageMagick
RUN_DEPENDS+=	hsetroot:${PORTSDIR}/graphics/hsetroot
RUN_DEPENDS+=	mksh:${PORTSDIR}/shells/mksh
RUN_DEPENDS+=	tmux:${PORTSDIR}/sysutils/tmux
RUN_DEPENDS+=	numlockx:${PORTSDIR}/x11/numlockx
RUN_DEPENDS+=	xlock:${PORTSDIR}/x11/xlockmore
RUN_DEPENDS+=	xclip:${PORTSDIR}/x11/xclip
RUN_DEPENDS+=	gtk-theme-switch2:${PORTSDIR}/x11/gtk-theme-switch2
RUN_DEPENDS+=	conky:${PORTSDIR}/sysutils/conky
RUN_DEPENDS+=	xdg-mime:${PORTSDIR}/devel/xdg-utils
# 1}}}

# fonts {{{1
RUN_DEPENDS+=	${LOCALBASE}/lib/X11/fonts/local/unifont.ttf:${PORTSDIR}/x11-fonts/gnu-unifont-ttf
RUN_DEPENDS+=	${LOCALBASE}/lib/X11/fonts/webfonts:${PORTSDIR}/x11-fonts/webfonts
RUN_DEPENDS+=	${LOCALBASE}/lib/X11/fonts/junicode:${PORTSDIR}/x11-fonts/junicode
RUN_DEPENDS+=	${LOCALBASE}/lib/X11/fonts/terminus-font:${PORTSDIR}/x11-fonts/terminus-font
# 1}}}

# internet {{{1
RUN_DEPENDS+=	axel:${PORTSDIR}/ftp/axel
RUN_DEPENDS+=	irssi:${PORTSDIR}/irc/irssi
#RUN_DEPENDS+=	firefox3:${PORTSDIR}/www/firefox35
#RUN_DEPENDS+=	${LOCALBASE}/lib/browser_plugins/dummyflash/dummyflash.so:${PORTSDIR}/www/dummyflash
#RUN_DEPENDS+=	gnash:${PORTSDIR}/graphics/gnash
RUN_DEPENDS+=	opera:${PORTSDIR}/www/opera
#RUN_DEPENDS+=	psi:${PORTSDIR}/net-im/psi
RUN_DEPENDS+=	pidgin:${PORTSDIR}/net-im/pidgin
#RUN_DEPENDS+=	cclive:${PORTSDIR}/multimedia/cclive
RUN_DEPENDS+=	elinks:${PORTSDIR}/www/elinks
# 1}}}

# security {{{1
RUN_DEPENDS+=	gpg2:${PORTSDIR}/security/gnupg
RUN_DEPENDS+=	sudo:${PORTSDIR}/security/sudo
RUN_DEPENDS+=	keepassx:${PORTSDIR}/security/keepassx
RUN_DEPENDS+=	pinentry:${PORTSDIR}/security/pinentry
#RUN_DEPENDS+=	gpa:${PORTSDIR}/security/gpa
RUN_DEPENDS+=	nmap:${PORTSDIR}/security/nmap
# 1}}}

# sys various {{{1
#RUN_DEPENDS+=	mkisofs:${PORTSDIR}/sysutils/cdrtools # using USE_CDRTOOLS=yes instead
RUN_DEPENDS+=	gtk-send-pr:${PORTSDIR}/sysutils/gtk-send-pr
RUN_DEPENDS+=	growisofs:${PORTSDIR}/sysutils/dvd+rw-tools
#RUN_DEPENDS+=	sysinfo:${PORTSDIR}/sysutils/sysinfo
# 1}}}

# players {{{1
RUN_DEPENDS+=	mplayer:${PORTSDIR}/multimedia/mplayer
#RUN_DEPENDS+=	playd:${PORTSDIR}/multimedia/playd
#RUN_DEPENDS+=	playd2:${PORTSDIR}/multimedia/playd2
## I need this for my local playd2
#RUN_DEPENDS+=	${LOCALBASE}/lib/perl5/site_perl/5.8.9/File/Type.pm:${PORTSDIR}/devel/p5-File-Type
# 1}}}

# graphics editors {{{1
RUN_DEPENDS+=	gimp:${PORTSDIR}/graphics/gimp
RUN_DEPENDS+=	${LOCALBASE}share/gimp/brushes/50x50cone.gbr:${PORTSDIR}/graphics/gimp-data-extras
RUN_DEPENDS+=	${LOCALBASE}/share/gimp/patterns/worn_metal_chex.pat:${PORTSDIR}/graphics/gimp-data-extras
RUN_DEPENDS+=	${LOCALBASE}/share/gimp/scripts/egger-copyright.scm:${PORTSDIR}/graphics/gimpfx-foundry
RUN_DEPENDS+=	inkscape:${PORTSDIR}/graphics/inkscape
RUN_DEPENDS+=	pdftk:${PORTSDIR}/print/pdftk
# 1}}}

# viewers {{{1
RUN_DEPENDS+=	xpdf:${PORTSDIR}/graphics/xpdf
RUN_DEPENDS+=	djview4:${PORTSDIR}/graphics/djview4
RUN_DEPENDS+=	epdfview:${PORTSDIR}/graphics/epdfview
RUN_DEPENDS+=	gpicview:${PORTSDIR}/graphics/gpicview
# 1}}}

# mail {{{1
RUN_DEPENDS+=	postfix:${PORTSDIR}/mail/postfix
RUN_DEPENDS+=	mutt:${PORTSDIR}/mail/mutt-devel
# 1}}}

# stuff related to ports/packages {{{1
RUN_DEPENDS+=	portmaster:${PORTSDIR}/ports-mgmt/portmaster
RUN_DEPENDS+=	pkg_cutleaves:${PORTSDIR}/ports-mgmt/pkg_cutleaves
RUN_DEPENDS+=	portaudit:${PORTSDIR}/ports-mgmt/portaudit
RUN_DEPENDS+=	psearch:${PORTSDIR}/ports-mgmt/psearch
RUN_DEPENDS+=	bpkg:${PORTSDIR}/ports-mgmt/bpkg
RUN_DEPENDS+=	portlint:${PORTSDIR}/ports-mgmt/portlint
# 1}}}

# Peripheria (Printer/Scanner ...) {{{1
LIB_DEPENDS+=	gutenprint.2:${PORTSDIR}/print/gutenprint
RUN_DEPENDS+=	${LOCALBASE}/etc/rc.d/cupsd:${PORTSDIR}/print/cups
RUN_DEPENDS+=	${LOCALBASE}/libexec/cups/backend/cups-pdf:${PORTSDIR}/print/cups-pdf
RUN_DEPENDS+=	xsane:${PORTSDIR}/graphics/xsane
# 1}}}

# ARV programming {{{1
RUN_DEPENDS+=	avrdude:${PORTSDIR}/devel/avrdude
RUN_DEPENDS+=	avra:${PORTSDIR}/devel/avra
# 1}}}

# for OpenOffice.org you need these {{{1
RUN_DEPENDS+=	ldapadd:${PORTSDIR}/net/openldap24-client
RUN_DEPENDS+=	javavm:${PORTSDIR}/java/javavmwrapper
LIB_DEPENDS+=	Xm.3:${PORTSDIR}/x11-toolkits/open-motif
RUN_DEPENDS+=	${LOCALBASE}/libexec/gnome-vfs-daemon:${PORTSDIR}/devel/gnome-vfs
LIB_DEPENDS+=	cups.2:${PORTSDIR}/print/cups-base
## need JDK to compile. you can pkg_add openjdk6
#RUN_DEPENDS+=	${LOCALBASE}/openjdk7:${PORTSDIR}/java/openjdk7
#RUN_DEPENDS+=	${LOCALBASE}/openjdk6:${PORTSDIR}/java/openjdk6
# 1}}}

# Database {{{1
#RUN_DEPENDS+=	pgadmin3:${PORTSDIR}/databases/pgadmin3
#RUN_DEPENDS+=	sqliteman:${PORTSDIR}/databases/sqliteman
# 1}}}

# Emulators {{{1
RUN_DEPENDS+=	VirtualBox:${PORTSDIR}/emulators/virtualbox-ose
#RUN_DEPENDS+=	qemu:${PORTSDIR}/emulators/qemu
# 1}}}

# Math {{{1
RUN_DEPENDS+=	mathomatic:${PORTSDIR}/math/mathomatic
#RUN_DEPENDS+=	scilab:${PORTSDIR}/math/scilab
# 1}}}

# MISC {{{1
RUN_DEPENDS+=	gcolor2:${PORTSDIR}/graphics/gcolor2
RUN_DEPENDS+=	when:${PORTSDIR}/deskutils/when
RUN_DEPENDS+=	easytag:${PORTSDIR}/audio/easytag
RUN_DEPENDS+=	klavaro:${PORTSDIR}/games/klavaro
RUN_DEPENDS+=	tightvnc:${PORTSDIR}/net/tightvnc
RUN_DEPENDS+=	filezilla:${PORTSDIR}/ftp/filezilla
#RUN_DEPENDS+=	freemind:${PORTSDIR}/deskutils/freemind
RUN_DEPENDS+=	unrar:${PORTSDIR}/archivers/unrar
RUN_DEPENDS+=	zip:${PORTSDIR}/archivers/zip
# 1}}}

do-install:
	${DO_NADA}

.include <bsd.port.mk>


/usr/ports/x11/ks86/pkg_descr - not really needed... but I wanted ports-mgmt/portlint to stop complaining about it
Code:
This port is create to let me easelly instal my custom dekstop
enviroment....

Feel free to use, modify, do what ever you want to do
After install you should remove this metaport [pkg delete -f]
Code:
# pkg_delete -f killasmurf86-desktop-1.0
pkg_delete: the package info for package 'killasmurf86-desktop-0.9' is corrupt (but I'll delete it anyway)
pkg_delete: couldn't completely deinstall package 'killasmurf86-desktop-0.9',
only the log entry in /var/db/pkg/killasmurf86-desktop-0.9 was removed
Ignore errors :D


I find you that it's best if you specify app name thatget's installed.
Code:
RUN_DEPENDS+=	[red]ccache[/red]:${PORTSDIR}/devel/ccache

If something breaks in middle of install, next time you run this metaport it won't try to install ccache again.... but sometimes it's not possible..... for example for fonts.....
In this case you can specify full path to some other file or directory
for example
Code:
RUN_DEPENDS+= ${LOCALBASE}/libdata/xorg/drivers:${PORTSDIR}/x11-drivers/xorg-drivers
That line was from xorg Makefile

[red]UPDATE[/red]
I've updated my metaport to fix issues mentioned above. Now I can use my metaport whenever I want... even if all/some ports are installed

[red]UPDATE[/red]
Here's link to my current desktop metaports
http://hg.bsdroot.lv/aldis/ks86-desktop/
http://hg.bsdroot.lv/aldis/ks86-laptop/
http://hg.bsdroot.lv/aldis/ks86-desktop-core/
 
KDE4:
Code:
RUN_DEPENDS+=	KDE4:${PORTSDIR}/x11/kde4

Code:
RUN_DEPENDS+=	GNOME2:${PORTSDIR}/x11/gnome2

I wrote KDE4 and GNOME2 in capital to make sure thy will be rebuild each time you install your metaport... because if for example KDE4 fails to build at some point... we won't know what did it finish and what not.... let KDE4 metaport take care of that

Same for gnome.


I haven't tested this, so it's up to you, but I think this is best solution for sub-metaports. We don't want to do more work than we should, don't we?
 
On other hand (even better solution)... you can create your metaport with all utilities/apps you use, that aren't installed with kde/gnome, and simply put another argument at portmasters command line...

This will simplify things, and avoid unnecessary bugs

Code:
# portmaster x11/kde4 x11/ks86

still easier than typing 100 ports ;)
 
Let's say that we have a system with many ports on it and we are happy with the set up.

Now we want to create a meta-port to remember this instance of the system (to find all ports having been added so we can put them into the RUN_DEPENDS+= list). Is there a good way to do this?

I am still new with freeBSD with all the commands it has.
 
I'd probably improvise on this one:
I'd use ports-mgmg/pkg_cutleaves to get names top level ports, you still need to filter them, because there are many build time dependencies, but that's much easier, than going though some 500-600 ports

after that I'd check the list, and see if there is something that I use, but isn't in list (perhaps it was dependency for other port), and then add them as well. Reason for doing this is pure simple:
port dependencies might change and next time you may not install all soft that you use, but even better reason to do this is that you can commend out some ports, and then you still get rest of ports, that otherwise could have been omitted (because no other port depends on it)

Well, this is pretty much how I did it
 
this would probably work

Code:
.if ! ${.CURDIR:M*/java/openjdk6} || ${.CURDIR:M*/java/openjdk7}
NO_BUILD=       YES
.endif
 
jgh said:
this would probably work

Code:
.if ! ${.CURDIR:M*/java/openjdk6} || ${.CURDIR:M*/java/openjdk7}
NO_BUILD=       YES
.endif

hmmm? who are you answering?
Am I blind or you posted in wrong thread?
 
There's this in your opening post:

Code:
## need JDK to compile. you can pkg_add openjdk6

See if that makes some sense?
 
killasmurf86 said:
After install you should remove this metaport [pkg delete -f]

according to this (/usr/ports/Mk/bsd.port.mk)

Code:
.if defined(NO_INSTALL) && !target(install)
install: build
 @${TOUCH} ${TOUCH_FLAGS} ${INSTALL_COOKIE}
.endif

you should be able to avoid the # pkg_delete -f step by replacing

Code:
do-install:
        ${DO_NADA}

with

Code:
NO_INSTALL=     yes

and converting all RUN_DEPENDS to BUILD_DEPENDS

beware: i've not tested this ;)
 
DutchDaemon said:
There's this in your opening post:

Code:
## need JDK to compile. you can pkg_add openjdk6

See if that makes some sense?

It does make sense, however I was noting that if you are in any other directory than openjdk6 or openjdk7 to set NO_BUILD=YES, otherwise it would BUILD it.

Isn't that what it would do?
 
I was just adding that because killasmurf86 had absolutely no idea what you were talking about when you showed up in this thread. Next time quote or point to what you're commenting on ;)
 
FWIW, here's a script I put together to autogenerate a Makefile for a metaport like the one described here.

It was inspired by another thread, in which someone asked how to get a list of all the ports he had chosen to install. Well, you know how it goes. One thing led to another...

Save this as gen_metaport and run it as follows:

$ gen_metaport 2> metaport.handedits > Makefile

Unfortunately, as mentioned above, not every port installs an executable with the same name as the port. So the metaport Makefile needs to be hand-edited to tweak the test on the BUILD_DEPENDS line for the ports that don't have a corresponding executable. The script prints these to stderr as category/portname, and the above command redirects stderr to a file named metaport.handedits.

Code:
#!/bin/sh

echo "# New ports collection makefile for: FreeBSD"
echo "# Date created:           2011.01.13"
echo "# Whom:                   Charlie Kester <corky1951@comcast.net>"
echo "# $FreeBSD:$"
echo "#"
echo ""
echo "PORTNAME= ckester-desktop"
echo "PORTVERSION=      1.0"
echo "CATEGORIES=       x11"
echo "MASTER_SITES="
echo "DISTFILES="
echo ""
echo "MAINTAINER=       corky1951@comcast.net"
echo "COMMENT=  The meta-port for ckester\'s desktop"
echo ""
echo "NO_BUILD= YES"
echo "NO_INSTALL=       YES"
echo "NO_WRKSUBDIR=   YES"
echo "USE_CDRTOOLS=     YES"

portmaster --list-origins | sort | \
        while read p; do
                which `echo $p | awk 'FS="/" {print $2}'`  > /dev/null 2>&1 || echo $p >&2
                echo $p | awk 'FS="/" {print "BUILD_DEPENDS+= "$2":${PORTSDIR}/"$1"/"$2}'
        done

echo ""
echo ".include <bsd.port.mk>"  

# vim:set ft=sh

I think I've correctly implemented the advice avilla gave above. But other than generating the Makefile and handedit list, I haven't tested this yet. I still need to do my own hand-edits!

Further improvements are certainly possible. I'll welcome any comments.

NOTE: If you don't have and don't want portmaster installed, you can use pkg_cutleaves instead. Replace "portmaster --list-origins" in the script with the following:

Code:
pkg_cutleaves -l | while read p; do pkg_info -q -o $p; done

Is this the best way to re-install all of your ports? Certainly not! You can avoid a lot of effort by using the method described at the end of the manpage for portmaster() instead of the one described here.

But if like me, you're always looking for ways to idle away a dull afternoon...
 
Have you ever had an itch that you just can't stop scratching? ;)

It occurs to me that you can probably leverage the pkg-plist files to avoid the need to hand-edit many of the lines. Just pick any of the unconditionally-installed files.

Still leaves a need to hand-edit entries for ports with auto-generated plists or plist entries in their Makefiles, but it does narrow down the hand edits quite a lot.

Watch out for PLIST_SUB %%variables%% that get past the check because they're not at the beginning of a pkg-plist line. But otherwise, this seems to yield useful results:

Code:
#!/usr/local/bin/mksh
# this script should also work with bash, ksh93
# or any other shell that understands the ${s:n:m} syntax for extracting substrings
#
echo "# New ports collection makefile for: FreeBSD"
echo "# Date created:           2011.01.13"
echo "# Whom:                   Charlie Kester <corky1951@comcast.net>"
echo "# \$FreeBSD:\$"
echo "#"
echo ""
echo "PORTNAME= ckester-desktop"
echo "PORTVERSION=      1.0"
echo "CATEGORIES=       x11"
echo "MASTER_SITES="
echo "DISTFILES="
echo ""
echo "MAINTAINER=       corky1951@comcast.net"
echo "COMMENT=  The meta-port for ckester\'s desktop"
echo ""
echo "NO_BUILD= YES"
echo "NO_INSTALL=       YES"
echo "NO_WRKSUBDIR=   YES"
echo "USE_CDRTOOLS=     YES"
echo ""

PORTSDIR=/usr/ports
portmaster --list-origins | sort | \
        while read p; do
                f=`echo $p | awk 'FS="/" {print $2}'`
                if which $f  > /dev/null 2>&1; then
                        echo $p | awk 'FS="/" {print "BUILD_DEPENDS+= "$2":${PORTSDIR}/"$1"/"$2}'
                elif [ -r ${PORTSDIR}/$p/pkg-plist ]; then
                        found=""
                        while read f; do
                                # ignore conditional or commented lines
                                x=${f:0:1}
                                if [ $x != "%" ] && [ $x != "@" ]; then
                                        # if we found an executable, all we need is its name, otherwise add LOCALBASE prefix
                                        [ ${f:0:3} = "bin" ] && f=${f:#bin/} || f=\${LOCALBASE}/$f
                                        echo "BUILD_DEPENDS+= $f:\${PORTSDIR}/$p"
                                        found="yes"
                                        break;
                                fi
                        done < ${PORTSDIR}/$p/pkg-plist
                        [ found ] || echo $p >&2
                else
                        echo $p >&2
                fi

        done

echo ""
echo ".include <bsd.port.mk>"  

# vim:set ft=sh

Further tweaks might include:
- Special handling for libraries. Is there a way to script the addition of version numbers?
- Automate the grouping of ports as in killasmurf's original metaport. perhaps doing a lookup in some files listing the ports in each group? If those files use the category/portname format, they could be used to drive the script's main loop instead of the portmaster command. Hmm...scratch, scratch, scratch. ;)
 
Back
Top