about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--GNUmakefile8
-rw-r--r--buildtools/debian/README122
-rwxr-xr-xbuildtools/debian/mkdeb541
-rwxr-xr-xbuildtools/debian/postinst5
-rwxr-xr-xbuildtools/debian/postrm5
5 files changed, 681 insertions, 0 deletions
diff --git a/GNUmakefile b/GNUmakefile
index c1c2d0a3..17199c77 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -8,6 +8,8 @@
 #   merge:        Build everything as merged executables, in the source dir
 #   package:      Make a package of Netpbm files ready to install
 #   
+#   deb:          Make a .deb file in the current dir.
+#
 #   The default target is either "merge" or "nonmerge", as determined by
 #   the DEFAULT_TARGET variable set by config.mk.
 
@@ -393,6 +395,12 @@ install.sharedlibstub:
 	$(MAKE) -C lib -f $(SRCDIR)/lib/Makefile \
 	    SRCDIR=$(SRCDIR) BUILDDIR=$(BUILDDIR) install.sharedlibstub 
 
+# Make the 'deb' target after making 'package'.  It generates a .deb
+# file in the current directory.
+.PHONY: deb
+deb:
+	buildtools/debian/mkdeb --buildtools=buildtools --pkgdir=$(PKGDIR)
+
 clean: localclean
 
 .PHONY: localclean
diff --git a/buildtools/debian/README b/buildtools/debian/README
new file mode 100644
index 00000000..02fae4b5
--- /dev/null
+++ b/buildtools/debian/README
@@ -0,0 +1,122 @@
+Files in this directory are for creating a Debian package (.deb file),
+which one can use to install Netpbm on a Debian system (or a system running
+a derivative of Debian, such as Ubuntu or Mint).
+
+You can of course install on one of these systems by running 'installnetpbm',
+or otherwise inserting all the files in the proper place in your system file
+tree, but having a Debian package allows you to manage those files using
+Debian's normal package management.  The package management system will know
+where the Netpbm files came from, and you can upgrade or remove Netpbm easily.
+The package management system will also be aware of prerequisites of Netpbm
+and ensure that you don't have Debian's own inferior version of Netpbm
+installed (which would cause conflicts).
+
+The package we create is named 'netpbm-sf' (where the "sf" is from
+"SourceForge"), to be distinct from the package named "netpbm" which is part
+of Debian.
+
+To install Netpbm as a Debian package:
+
+  1) Follow the regular instructions to build and package Netpbm
+     (configure, make, make package).
+
+  2) With the root of the built Netpbm build tree as your current
+     directory:
+
+     $ make deb
+
+     (This defaults to getting Netpbm from /tmp/netpbm, which is also where
+     'make package' defaults to putting it).
+
+  3) $ dpkg --install netpbm-sfXXXX.deb
+
+     (netpbm-sfXXXX.deb is the file created by 'make deb', in the current
+     directory).
+
+
+PREREQUSISITES
+--------------
+
+The following information was taken from the Wheezy version (Version 7) of
+Debian, in January 2014.
+
+You don't actually need the current version of any of these.  For example,
+while we list package libjpeg8-dev, the package libjpeg62-dev works fine.
+
+
+Building
+--------
+
+You need the following Debian packages to build all of Netpbm.
+
+You could omit some of these and, in the Netpbm build configuration dialog,
+indicate you don't have them, and the build will simply omit some parts.
+For example, if you don't install libx11-dev, the Netpbm build process
+will not build the 'pamx' program.
+
+  libjpeg8-dev
+  libpng12-0-dev
+  libsvga1-dev
+  libtiff5-dev
+  libx11-dev
+  libxml2a-dev
+  zlib1g-dev
+
+
+In addition, you need the following build tools:
+
+  make
+  gcc
+  flex
+  perl
+  pkg-config
+
+
+
+Running
+-------
+
+The following Debian packages are the known prerequisites for running Netpbm
+(and the package created by 'mkdeb' knows this).
+
+    libc6
+    libjpeg8
+    libpng12-0
+    libsvga1
+    libtiff5
+    libx11-6
+    zlib1g
+    ghostscript
+    perl
+    perl-base
+    bash
+
+Note that many of these are needed only for a few parts of Netpbm, and it will
+be pretty obvious what the problem is when you need the prerequisite package
+and don't have it, so if you don't want to install a prerequisite, it would
+probably be fine to force install Netpbm, ignoring the prerequisites.
+
+
+CONFLICTS WITH DEBIAN'S NETPBM
+------------------------------
+
+Debian has several packages of Netpbm, all based on a slightly modified
+Sourceforge Netpbm 9.25 from 2002 (don't be confused by Debian's numbering
+system, which makes it look like it is Netpbm 10).  If you want to install
+Sourceforge Netpbm on your system, you will want first to remove any of these
+you have installed:
+
+  netpbm
+  netpbm-dev
+  libnetpbm9
+  libnetpbm10
+
+Sourceforge Netpbm should be backward compatible with all of those.  Note that
+'mkdeb' makes only one package.  It contains the programs, the runtime
+libraries, and the development files.
+
+We have not yet worked out what has to be done about the fact that the Debian
+packaging system thinks the Debian Netpbm packages are prerequisites for
+things.  If you install Sourceforge Netpbm via the package created by mkdeb,
+you should tell the Netpbm maintainer whatever you learn about that.
+
diff --git a/buildtools/debian/mkdeb b/buildtools/debian/mkdeb
new file mode 100755
index 00000000..42a986eb
--- /dev/null
+++ b/buildtools/debian/mkdeb
@@ -0,0 +1,541 @@
+#!/usr/bin/perl
+###############################################################################
+#                                mkdeb
+###############################################################################
+#
+#  This generates a Debian packge file (.deb) to install Sourceforge
+#  Netpbm on a Debian system.
+#
+#  This is especially useful because Debian does not have a good Debian
+#  package (what Debian contains is derived from Sourceforge Netpbm ca.
+#  2002).
+#
+###############################################################################
+
+use strict;
+use warnings;
+use English;
+use Getopt::Long;
+
+my $TRUE=1; my $FALSE = 0;
+
+
+
+sub parseCommandLine(@) {
+
+    local @ARGV = @_;  # GetOptions takes input from @ARGV only
+
+    my %cmdline;
+
+    my $validOptions = GetOptions(\%cmdline,
+                                  "buildtools=s",
+                                  "arch=s",
+                                  "pkgdir=s",
+        );
+
+    if (!$validOptions) {
+        print(STDERR "Invalid option syntax.\n");
+        exit(1);
+    }
+    if (@ARGV > 0) {
+        print(STDERR "This program takes no non-option arguments.  " .
+              "You specified ",
+              scalar(@ARGV), "\n");
+        exit(1);
+    } 
+
+    return(\%cmdline);
+}
+
+
+
+sub writeFile($$$$) {
+    my ($fileLinesR, $fileName, $executable, $errorR) = @_;
+
+    my $success = open(FILE, ">$fileName");
+    if ($success) {
+        if ($executable eq 'EXECUTABLE') {
+            chmod(0755, $fileName);
+        } else {
+            chmod(0644, $fileName);
+        }
+        foreach (@{$fileLinesR}) { print FILE; }
+        close(FILE);
+    } else {
+        $$errorR = "Unable to open the file " .
+            "'$fileName' for writing.  Errno=$ERRNO\n";
+    }
+}
+
+
+
+sub netpbmVersion($) {
+    my ($pkgdir) = @_;
+
+    my $versionFileName = "$pkgdir/VERSION";
+
+    my $versionOpened = open(VERSION, "<$versionFileName");
+
+    my $retval;
+    my $error;
+
+    if (!$versionOpened) {
+        $error = "Unable to open '$versionFileName' for reading.  " .
+            "Errno=$ERRNO\n";
+    } else {
+        my $version = <VERSION>;
+        chomp($version);
+
+        if ($version =~ m{^Netpbm (\S*)}) {
+            my ($versionNumber) = ($1);
+            $retval = $versionNumber;
+        } else {
+            die("Can't understand format of '$versionFileName': '$version'");
+        }
+        close(VERSION);
+    }
+
+    if ($error) {
+        print("Failed to determine the version of Netpbm from the package, "
+              . "so that will not be correct in netpbm.config and netpbm.pc.  "
+              . $error . "\n");
+        $retval = "???";
+    }
+    return $retval;
+}
+
+
+
+sub control($$) {
+    my ($release, $architecture) = @_;
+
+# The Debian packaging system doesn't provide a way to express Netpbm's actual
+# prerequisites.  For example, Netpbm needs Version 6.2 or better of Libjpeg,
+# but there is no way to state that here.  Instead, we state Libjpeg 8.
+# This makes the Netpbm package less useful.
+
+    my %control;
+
+    my $debianNativeNetpbm = 
+        'netpbm, ' .
+        'libnetpbm10, ' .
+        'libnetpbm10-dev, ' .
+        'netpbm-dev, ' .
+        'netpbm-nonfree, ' .
+        'pbmwbmp, ' .
+        'pnmtopng, ' .
+        'ucbmpeg';
+
+    $control{'Package'} = 'netpbm-sf';
+    $control{'Version'} = $release;
+    $control{'Architecture'} = $architecture;
+    $control{'Maintainer'} = 'Bryan Henderson <bryanh@giraffe-data.com>';
+    $control{'Installed-Size'} = '6164';
+    $control{'Depends'} =
+        'libc6, ' .
+        'libjpeg62, ' .
+        'libpng12-0, ' .
+        'libsvga1, ' .
+        'libtiff4, ' .
+        'libx11-6, ' .
+        'libxml2, ' .
+        'zlib1g, ' .
+        'ghostscript, ' .
+        'perl, ' .
+        'perl-base, ' .
+        'bash'
+        ;
+    $control{'Recommends'} = '';
+    $control{'Recommends'} = '';
+    $control{'Conflicts'} = $debianNativeNetpbm;
+    $control{'Replaces'} = $debianNativeNetpbm;
+    $control{'Provides'} = 
+        'netpbm, ' .
+        'pbmwbmp, ' .
+        'pnmtopng, ' .
+        'netpbm-dev, ' .
+        'libnetpbm10'
+        ;
+    $control{'Section'} = 'graphics';
+    $control{'Priority'} = 'optional';
+    $control{'Section'} = 'graphics';
+    $control{'Description'} = 'Graphics conversion tools between image formats
+ Netpbm is a toolkit for manipulation of graphic images, including
+ conversion of images between a variety of different formats. There
+ are over 300 separate tools in the package including converters for
+ more than 80 graphics formats.  This is the Super Stable version from
+ the Sourceforge Netpbm project, unmodified.';
+
+    return \%control;
+}
+
+
+
+sub writeControlFile($$) {
+    my ($controlR, $fileName) = @_;
+
+    open(CTL, '>', $fileName)
+        or die "Can't open '$fileName': $ERRNO";
+
+    while (my ($key, $value) = each %{$controlR}) {
+        print CTL ("$key: $value\n");
+    }
+    
+    close(CTL);
+}
+
+
+
+sub createScripts($$) {
+    my ($dpkgDirName, $buildToolsDir) = @_;
+
+    my @scriptList = ('postinst', 'postrm');
+
+    my @scriptFileList = map("$buildToolsDir/debian/$_", @scriptList);
+
+    system('cp', @scriptFileList, "$dpkgDirName/DEBIAN/") &&
+        die("Failed to copy postinst, etc. to '$dpkgDirName/DEBIAN'.");
+
+    my @createdFileList = map("$dpkgDirName/DEBIAN/$_", @scriptList);
+
+    chmod(0755, @createdFileList);
+}
+
+
+
+sub createDirOrDie($) {
+    my ($newDirName) = @_;
+
+    mkdir($newDirName)
+        or die("Couldn't create directory '$newDirName'.  $ERRNO");
+
+    chmod(0755, $newDirName);
+}
+
+
+
+sub 
+processTemplate($$$) {
+    my ($templateR, $infoR, $outputR) = @_;
+
+    my @output;
+
+    foreach (@{$templateR}) {
+        if (m{^@}) {
+            # Comment -- ignore it.
+        } else {
+            if (defined($infoR->{VERSION})) {
+                s/\@VERSION\@/$infoR->{VERSION}/;
+            }
+            if (defined($infoR->{BINDIR})) {
+                s/\@BINDIR@/$infoR->{BINDIR}/;
+            }
+            if (defined($infoR->{LIBDIR})) {
+                s/\@LIBDIR@/$infoR-.{LIBDIR}/;
+            }
+            if (defined($infoR->{LINKDIR})) {
+                s/\@LINKDIR@/$infoR->{LINKDIR}/;
+            }
+            if (defined($infoR->{DATADIR})) {
+                s/\@DATADIR@/$infoR->{DATADIR}/;
+            }
+            if (defined($infoR->{INCLUDEDIR})) {
+                s/\@INCLUDEDIR@/$infoR->{INCLUDEDIR}/;
+            }
+            if (defined($infoR->{MANDIR})) {
+                s/\@MANDIR@/$infoR->{MANDIR}/;
+            }
+            push(@output, $_);
+        }
+    }
+    $$outputR = \@output;
+}
+
+
+
+
+
+sub makeConfig($$$) {
+    my ($fileName, $templateSubsR, $netpbmPkgDir) = @_;
+#-----------------------------------------------------------------------------
+# Install 'netpbm-config' -- a program you run to tell you things about
+# how Netpbm is installed.
+#-----------------------------------------------------------------------------
+    my $error;
+
+    my $configTemplateFilename = $netpbmPkgDir . "/config_template";
+
+    my $templateOpened = open(TEMPLATE, "<$configTemplateFilename");
+    if (!$templateOpened) {
+        $error = "Can't open template file '$configTemplateFilename'.\n";
+    } else {
+        my @template = <TEMPLATE>;
+
+        close(TEMPLATE);
+
+        processTemplate(\@template, $templateSubsR, \my $fileContentsR);
+
+        writeFile($fileContentsR, $fileName, 'EXECUTABLE', \$error);
+    }
+    if ($error) {
+        print(STDERR "Failed to create the Netpbm configuration program.  " .
+              "$error\n");
+    }
+}
+
+
+
+sub makePkgConfig($$$) {
+    my ($fileName, $templateSubsR, $netpbmPkgDir) = @_;
+#-----------------------------------------------------------------------------
+# Install a pkg-config file (netpbm.pc) - used by the 'pkg-config' program to
+# find out various things about how Netpbm is installed.
+#-----------------------------------------------------------------------------
+    my $error;
+
+    my $pcTemplateFilename = "$netpbmPkgDir/pkgconfig_template";
+
+    my $templateOpened = open(TEMPLATE, "<$pcTemplateFilename");
+    if (!$templateOpened) {
+        $error = "Can't open template file '$pcTemplateFilename'.\n";
+    } else {
+        my @template = <TEMPLATE>;
+
+        close(TEMPLATE);
+
+        processTemplate(\@template, $templateSubsR,
+                        \my $fileContentsR);
+
+        writeFile($fileContentsR, $fileName, 'NOTEXECUTABLE', \$error);
+    }
+    if ($error) {
+        print(STDERR "Failed to create the Netpbm Pkg-config file.  " .
+              "$error\n");
+    }
+}
+
+
+
+sub makeManweb($$) {
+    my ($dpkgDirName, $netpbmPkgDir) = @_;
+#-----------------------------------------------------------------------------
+#  Set up things so one can read the manual with e.g.
+#
+#    $ manweb pnmtojpeg
+#-----------------------------------------------------------------------------
+    my @manwebConfContents;
+
+    push(@manwebConfContents, "#Configuration file for Manweb\n");
+    push(@manwebConfContents, "webdir=/usr/man/web\n");
+
+    createDirOrDie("$dpkgDirName/etc");
+
+    my $manwebConfFileName = "$dpkgDirName/etc/manweb.conf";
+
+    writeFile(\@manwebConfContents, $manwebConfFileName,
+        'NOTEXECUTABLE', \my $error);
+
+    if ($error) {
+        die("Failed to create Manweb configuration file $manwebConfFileName");
+    }
+    createDirOrDie("$dpkgDirName/usr/man");
+
+    system('cp', '--archive',
+           "$netpbmPkgDir/man/web", "$dpkgDirName/usr/man/web") &&
+               die("Failed to copy executables from '$netpbmPkgDir/bin' " .
+                   "to '$dpkgDirName/usr/bin'");
+}
+
+
+
+sub buildDpkgBuildTree($$$$$) {
+    my ($dpkgDirName, $release, $netpbmPkgDir, $architecture,
+        $buildToolsDir) = @_;
+#-----------------------------------------------------------------------------
+#  Create the directory tree that is the input to Dpkg-deb --build.
+#  This tree contains all the files to be installed, _plus_ the control
+#  subdirectory named DEBIAN.
+#-----------------------------------------------------------------------------
+    print("Creating file tree for input to dpkg-deb --build as " .
+          "'$dpkgDirName'\n");
+
+    createDirOrDie($dpkgDirName);
+
+    createDirOrDie("$dpkgDirName/DEBIAN");
+
+    my $controlR = control($release, $architecture);
+
+    writeControlFile($controlR, "$dpkgDirName/DEBIAN/control");
+
+    createScripts($dpkgDirName, $buildToolsDir);
+
+    createDirOrDie("$dpkgDirName/usr");
+
+    system('cp', '--archive',
+           "$netpbmPkgDir/bin", "$dpkgDirName/usr/bin") &&
+               die("Failed to copy executables from '$netpbmPkgDir/bin' " .
+                   "to '$dpkgDirName/usr/bin'");
+
+    # doc.url is inappropriate with the program installed into the global
+    # /usr/bin .
+    unlink("$dpkgDirName/usr/bin/doc.url");
+
+    system("cp", "--archive", "$netpbmPkgDir/include",
+           "$dpkgDirName/usr/include") &&
+               die("Failed to copy header files from " .
+                   "'$netpbmPkgDir/include' " .
+                   "to '$dpkgDirName/usr/include'");
+
+    system("cp", "--archive",
+           "$netpbmPkgDir/lib", "$dpkgDirName/usr/lib") &&
+               die("Failed to copy libraries from '$netpbmPkgDir/lib' " .
+                   "to '$dpkgDirName/usr/lib'");
+
+    my @linkFileList = glob("$netpbmPkgDir/link/*");
+
+    if (@linkFileList > 0) {
+        system("cp", "--archive",
+               @linkFileList, "$dpkgDirName/usr/lib/") &&
+                   die("Failed to copy libraries from '$netpbmPkgDir/link' " .
+                       "to '$dpkgDirName/usr/lib'");
+    }
+    createDirOrDie("$dpkgDirName/usr/share");
+
+    system("cp", "--archive",
+           "$netpbmPkgDir/misc", "$dpkgDirName/usr/share/netpbm") &&
+               die("Failed to copy files from '$netpbmPkgDir/misc' " .
+                   "to '$dpkgDirName/usr/share/netpbm'");
+
+    # We install Netpbm in the default search path, so most of the values
+    # 'netpbm-config' returns are null strings.
+    my $templateSubsR =
+    {VERSION    => $release,
+     BINDIR     => '',
+     LIBDIR     => '',
+     LINKDIR    => '',
+     DATADIR    => '/usr/share/netpbm',
+     INCLUDEDIR => '',
+     MANDIR     => ''};
+
+    makeConfig("$dpkgDirName/usr/bin/netpbm-config", $templateSubsR,
+               $netpbmPkgDir);
+
+    createDirOrDie("$dpkgDirName/usr/lib/pkgconfig");
+
+    makePkgConfig("$dpkgDirName/usr/lib/pkgconfig/netpbm.pc", $templateSubsR,
+                  $netpbmPkgDir);
+
+    makeManweb($dpkgDirName, $netpbmPkgDir);
+}
+
+
+
+sub debianArchOfThisMachine() {
+
+    # A lazy implementation that handles only the most common cases
+
+    my $retval;
+
+    my $arch = qx{'arch'};
+    chomp($arch);
+
+    if ($arch eq 'x86_64') {
+        $retval = 'amd64';
+    } elsif ($arch =~ m{i.86}) {
+        $retval = 'i386';
+    } else {
+        die("Can't determine the Debian architecture classification of this " .
+            "system.  You'll have to give a -arch option");
+    }
+    return $retval;
+}
+
+
+
+sub buildToolsDir($) {
+    my ($cmdlineR) = @_;
+
+    my $retval;
+
+    if (exists($cmdlineR->{'buildtools'})) {
+        $retval = $cmdlineR->{'buildtools'};
+    } else {
+        if (-f('./debian/mkdeb')) {
+            $retval = '.';
+        } else {
+            die("The current directory does not appear to be 'buildtools' " .
+                "subdirectory of a Netpbm source tree, so you will have " .
+                "to use the -buildtools option to identify it");
+        }
+    }
+    return $retval;
+}
+
+
+
+sub netpbmPkgDir($) {
+    my ($cmdlineR) = @_;
+
+    my $retval;
+
+    if (exists($cmdlineR->{'pkgdir'})) {
+        $retval = $cmdlineR->{'pkgdir'};
+    } else {
+        my $tmpdir = $ENV{TMPDIR} || "/tmp";
+
+        my $defaultPkgDir = "$tmpdir/netpbm";
+
+        if (-d($defaultPkgDir)) {
+            $retval = $defaultPkgDir;
+        } else {
+            die("No directory '$defaultPkgDir' exists.  " .
+                "You can specify the Netpbm package directory " .
+                "(what 'make package' created), with a -pkgdir option");
+        }
+    }
+    return $retval;
+}
+
+
+
+sub arch($) {
+    my ($cmdlineR) = @_;
+
+    my $retval;
+
+    if (exists($cmdlineR->{'arch'})) {
+        $retval = $cmdlineR->{'arch'};
+    } else {
+        $retval = debianArchOfThisMachine();
+    }
+
+    return $retval;
+}
+
+
+
+###############################################################################
+#                               MAIN PROGRAM
+###############################################################################
+
+my $cmdlineR = parseCommandLine(@ARGV);
+
+my $buildTools = buildToolsDir($cmdlineR);
+
+my $netpbmPkgDir = netpbmPkgDir($cmdlineR);
+
+my $arch = arch($cmdlineR);
+
+my $release = netpbmVersion($netpbmPkgDir);
+
+my $dpkgDirName = "/tmp/netpbm-sf-$release";
+ 
+buildDpkgBuildTree($dpkgDirName, $release, $netpbmPkgDir, $arch,
+                   $buildTools);
+
+my $debFileName = 'netpbm-sf-' . $release . '_' . $arch . '.deb';
+
+system('dpkg-deb', '--build', $dpkgDirName, $debFileName) &&
+    die("dpgk-deb --build with input '$dpkgDirName' failed.");
+
+system('rm', '--recursive', $dpkgDirName);
diff --git a/buildtools/debian/postinst b/buildtools/debian/postinst
new file mode 100755
index 00000000..60836d52
--- /dev/null
+++ b/buildtools/debian/postinst
@@ -0,0 +1,5 @@
+#!/bin/sh
+set -e
+if [ "$1" = "configure" ]; then
+  ldconfig
+fi
diff --git a/buildtools/debian/postrm b/buildtools/debian/postrm
new file mode 100755
index 00000000..5f0c15e7
--- /dev/null
+++ b/buildtools/debian/postrm
@@ -0,0 +1,5 @@
+#!/bin/sh
+set -e
+if [ "$1" = "remove" ]; then
+  ldconfig
+fi