Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 4 Oct 2005 13:58:14 +0200
From:      Csaba Henk <csaba-ml@creo.hu>
To:        Eric Schuele <e.schuele@computer.org>, freebsd-questions@freebsd.org
Subject:   Re: Determining what a port will install... (more than pretty-print-*) [Soln]
Message-ID:  <20051004115814.GA99762@beastie.creo.hu>
In-Reply-To: <43416280.80403@computer.org>
References:  <43416280.80403@computer.org>

next in thread | previous in thread | raw e-mail | index | archive | help
On Mon, Oct 03, 2005 at 11:55:28AM -0500, Eric Schuele wrote:
> Hello,
> 
> Some time back I posted a question regarding how to determine what
> ports/packages would need to be installed on my machine when I install a 
> new (new to the local machine) port.
> 
> For example, if I do not presently have openoffice installed... what
> will get installed when I 'make install clean' it?  Note that I want the
> differences between what is needed to build/run the port and what is
> already present on the machine.
> 
> At the time no one responded with a clear way to do this... so I finally
> had a few minutes to write a script to do it for me.  I thought someone
> else might find it useful... So I'm posting it here for comments and
> thoughts (be gentle, I'm new to awk).

Here is an improved/spoiled (decide by yourself) version. I aimed to
sport a more orthogonal design and avoid some gotchas I run into (see
comments in awk code).

--------------------------------
#! /bin/sh

# Script to determine the differences between what is necessary for
# a port, and what is already present on the local machine.

awkprgt='{
        count = 0
        pkgs = ""
        for(i=5; i<=NF-2; i++) {
          pkg = $i

          # the "if" is here to hack it around when you get:
          # This port requires package(s) "" to build.
          if (pkg != "\"\"") {
            if (index(pkg, "\"") == 1)
              {pkg = substr(pkg, 2, length(pkg)-1)}
            if (index(pkg, "\"") > 1)
              {pkg = substr(pkg, 1, length(pkg)-1)}
  
            if ( system("pkg_info -e " pkg) == 1) {
              pkgs = pkgs " " pkg
              count++
            }
          }
        }

        if ( count ) {
          print "You need the following (%s) perequisites:"
          print pkgs
        }
        else {
          print "All (%s) prerequisites are present."
        }

      }
      END {
        # triggered, eg., by audio/artswrapper (on my box, at least)
        if( ! FNR) {
          print "Bogus (empty) %s dependency information"
        }
      }
'

awkit() {
        # Resolve "%s"-s via sed is a blunt hack
        # but good enough here and thus we don't have
        # to care about the number of occurrences
        awk "`echo "$awkprgt" | sed s/%s/$1/g`"
}


make pretty-print-build-depends-list | awkit build

make pretty-print-run-depends-list | awkit run
--------------------------------

Alas... while I was making these changes, I succeeded to recall why I
abandoned my earlier attempt to put together a script which fulfils this
(highly desired) functionality.

Because all such scripts are fundamentally broken.

When make decides which ports to pull in, it doesn't only use the flat
data of build and run dependencies, but uses its full Turing complete
computing power. Eg., what happens when a port needs a postscript
interpreter? Should it use the AFPL or the GNU edition as a dependency?
Of course, doing a favor toward one of them (and taking away user's
choice) is unacceptable. So what happens is that make directly checks
whether the gs executable is present.

See, for example, print/gv. Your script's output will include
ghostscript-gnu-7.07_13 both as a build and a run dependency.
Yet when I type make, my ghostscript-gnu-7.07_12 installation will
be happily utilized as the following output snippet shows:

=> Checksum OK for gv-3.6.1.tar.gz.
===>  Patching for gv-3.6.1
===>  Applying FreeBSD patches for gv-3.6.1
===>   gv-3.6.1 depends on executable: gmake - found
===>   gv-3.6.1 depends on executable: gs - found
===>   gv-3.6.1 depends on shared library: Xaw3d - found
===>   gv-3.6.1 depends on shared library: X11.6 - found
===>  Configuring for gv-3.6.1

The approach taken by FreeBSD's ports is to have more flexibility but
less predictability, and now we have to live with it. Maybe the Gentoo
guys are the ones who succeeded to find the proper balance between these
two quantities -- they made up a mini-markup-language for denoting
dependencies, which is clever enough to cover all cases but it's still
just an easy to parse flat data.

One solution for FreeBSD could be digging deep into the make backend of
the ports framework and insert the necessary hooks everywhere to produce
a reliable dry-run.

Or severely refactor the whole ports framework and switch to Gentoo style
dependency handling. This won't happen any soon IMHO as ports API
changes should be pushed through all ports...

(OFF: to have a bit of bitter laugh, I think Gentoo's portage suffers
from a fundamental design flaw: they can't tune installation prefixes
(which would be necessary to make it an acceptable cross platform 3rd
party package manager, akin to pkgsrc, but it would have other uses, too).
This is again such a thing which can be changed only by rewriting all of
their e-builds.)

Regards,
Csaba



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20051004115814.GA99762>