Mac OS X Unleashed

Mac OS X Unleashed

By John Ray and William C. Ray

File Locations, and Fighting with Installers

For this example, you will need the netpbm package, available from http://download.sourceforge.net/netpbm/netpbm-9.12.tgz. The easy solution is

lynx -dump http://download.sourceforge.net/netpbm/netpbm-9.12.tgz > netpbm-9.12.tgz

The file should be 2057293 bytes in length. Uncompress it, untar it, and check whether it wants configure or make:

[localhost:~/Documents] software% gunzip netpbm-9.12.tgz
[localhost:~/Documents] software% tar -xf netpbm-9.12.tar
[localhost:~/Documents/netpbm-9.12] software% ls

     COPYRIGHT.PATENT          README.VMS                pbmplus.h
     GNUmakefile               amiga                     pgm
     GPL_LICENSE.txt           compile.h                 pnm
     HISTORY                   configure                 ppm
     Makefile                  empty_depend              scoptions
     Makefile.common           installosf                shhopt
     Makefile.config.djgpp     libopt.c                  stamp-date
     Makefile.config.in        libtiff                   stamp-date.amiga
     Makefile.depend           magic                     testgrid.pbm
     Netpbm.programming        make_merge.sh             testimg.ppm
     README                    mantocat                  urt
     README.CONFOCAL           mkinstalldirs             version.h
     README.DJGPP              netpbm.lsm                vms
     README.JPEG               pbm                       zgv_bigmaxval.patch

There's a configure file, so run it. This one is going to make some guesses, and ask you some questions. Pick the options shown in the following example, because they're necessary to get the rest of the example to work:

[localhost:~/Documents/netpbm-9.12] software% ./configure

     ./configure: Command not found.

Hold on, problem number one—that wasn't the expected behavior. The file configure is right here in the directory with you, yet you're getting a command not found error. It could be ./configure isn't executable, but in this case, it's a less obvious, more common problem:

[localhost:~/Documents/netpbm-9.12] software% head ./configure

      #!/bin/perl -w

      use strict;

      # This program generates Makefile.config, which is included by all of the
      # Netpbm makefiles.  You run this program as the first step in building
      # Netpbm.  (The second step is 'make').

      # This program is only a convenience.  It is supported to create
      # Makefile.config any way you want.  In fact, an easy way is to copy
      .
      .
      .

The problem is OS X doesn't have Perl as /bin/perl, it's /usr/bin/perl. Fire up vi (or your favorite text editor) and change that first line to #!/usr/bin/perl -w.

[localhost:~/Documents/netpbm-9.12] software% head ./configure

     #!/usr/bin/perl -w

     use strict;
     .
     .
     .

Now try again:

[localhost:~/Documents/netpbm-9.12] software% ./configure

     Which of the following best describes your platform?
     1) GNU/Linux
     2) Solaris or SunOS
     3) AIX
     4) Tru64
     5) Irix
     6) Windows (Cygwin or DJGPP)
     7) BeOS
     8) NetBSD
     9) none of these are even close

     Your choice ==> 1

     Enter the installation directory (the prefix on all installation
     paths for 'make install').  This is not built into any programs;
     It is used only by 'make install'.

     install prefix (/usr/local/netpbm)=>

     Do you want static-linked Netpbm libraries or shared?

     static or shared (shared)=> static

     Can't exec "ginstall": No such file or directory at ./configure line 195.

     We have created the file 'Makefile.config'.  You can now
     proceed to enter the 'make' command.

     Note, however, that we have only made a rough guess at your
     configuration, and you may want to look at Makefile.config and
     edit it to your requirements and taste before doing the make.

The results of the configure are better, but there's an ominous complaint in there about can't exec ginstall. To get things working will take editing that Makefile.config and making a few changes—mostly to patch things back to standard locations, where Linux tends to store them. Fire up vi and look through Makefile.config for lines that look similar to the following; then change them until they're exactly as shown in the following listings:

Now you're ready to try the make:

[localhost:~/Documents/netpbm-9.12] software% make

     make -C pbm -f /Users/software/Documents/netpbm-9.12/pbm/Makefile all
     ln -s ../pbmplus.h pbmplus.h
     ln -s ../version.h version.h
../stamp-date
     gcc -c -I../shhopt -pedantic -O3 -Wall -Wno-uninitialized -o atktopbm.o ../pbm/atktopbm.c
     make[1]: gcc: Command not found
     make[1]: *** [atktopbm.o] Error 127
     make: *** [pbm] Error 2

Again, not the output we wanted! This time, it's complaining that it can't find the compiler. cc is the standard name for a C compiler, but gcc is the GNU C Compiler, and many software packages are written to take advantage of special features that the GNU compiler provides. Apple has been nice enough to provide the GNU compiler with the development tools, but has named it cc, instead of gcc. The error for this program could be fixed by modifying the Mak e file.config file again to call cc instead of gcc, but this problem will crop up frequently, and many installers won't know that they can use the special gcc features unless the compiler is called gcc. Let's fix it by creating an alias (symbolic link) named gcc instead, and pointing it at the cc compiler:

[localhost:~/Documents/netpbm-9.12] software% pushd /usr/local/bin

     /usr/local/bin ~/Documents/netpbm-9.12
[localhost:/usr/local/bin] software% which cc

     /usr/bin/cc
[localhost:/usr/local/bin] software% ln -s /usr/bin/cc ./gcc
[localhost:/usr/local/bin] software% popd

     ~/Documents/netpbm-9.12

Try the make again:

[localhost:~/Documents/netpbm-9.12] software% make

make -C pbm -f /Users/software/Documents/netpbm-9.12/pbm/Makefile all
gcc -c -I../shhopt -pedantic -O3 -Wall -Wno-uninitialized  -o atktopbm.o ../pbm/atktopbm.c
In file included from /usr/include/machine/types.h:30,
                 from /usr/include/sys/types.h:70,
                 from /usr/include/stdio.h:64,
                 from ../pbm/atktopbm.c:13:
/usr/include/ppc/types.h:75: warning: ANSI C does not support `long long'
/usr/include/ppc/types.h:76: warning: ANSI C does not support `long long'
In file included from ../pbm/pbmplus.h:115,
                 from ../pbm/pbm.h:7,
                 from ../pbm/atktopbm.c:15:
/usr/include/stdlib.h:181: warning: ANSI C does not support `long long'
/usr/include/stdlib.h:183: warning: ANSI C does not support `long long'
gcc -c -I../shhopt -pedantic -O3 -Wall -Wno-uninitialized   -o libpbm1.o ../pbm/libpbm1.c
.
.
.
gcc -o pgmkernel pgmkernel.o -lm `../libopt libpgm.a ../pbm/libpbm.a`
make -C ppm -f /Users/software/Documents/netpbm-9.12/ppm/Makefile all
ln -s ../pbmplus.h pbmplus.h
ln -s ../pbm/pbm.h pbm.h
ln -s ../pbm/libpbm.h libpbm.h
ln -s ../pbm/pbmfont.h pbmfont.h
ln -s ../pgm/pgm.h pgm.h
ln -s ../pgm/libpgm.h libpgm.h
gcc -c -I../shhopt -I/usr/local/include -pedantic -O3 -Wall -Wno-uninitialized     -o 411toppm.o /Users/software/Documents/netpbm-9.12/ppm/411toppm.c
/Users/software/Documents/netpbm-9.12/ppm/411toppm.c:60: header file 'malloc.h' not found
cpp-precomp: warning: errors during smart preprocessing, retrying in basic mode
make[1]: *** [411toppm.o] Error 1
make: *** [ppm] Error 2

Did I mention I picked this install because it wasn't easy? Those error messages are just gcc being pedantic about the code. The C programming language has gone through a few revisions, and some programs still don't adhere to the most recent standards. The warnings won't hurt anything, but the error at the bottom of the output will. A few lines above the error is the complaint header file malloc.h not found. This is the actual source of the error. If you were to read the code looking for occurrences of malloc.h (grep might help with this), you'd find there are comments detailing the ambiguities of different Unix flavors and their oddball malloc.h implementations. In Apple's case, its that malloc.h isn't where the source expects it to be. You've got a choice of fixing all the code to point to /usr/include/sys/malloc.h, instead of /usr/include/malloc.h, or cheating a little and making it available somewhere that the makefile already has the compiler looking. We're going to take the cheating route, and make a link to /usr/include/sys/malloc.h in /usr/local/include/malloc.h, where the compiler should be able to find it. There's actually another option, adding a path to the places that the compiler will search for header files, but it turns out that fix will break something else later on, so stick with our cheat:

[localhost:~/Documents/netpbm-9.12] software% pushd /usr/include

     /usr/include ~/Documents/netpbm-9.12

[localhost:/usr/include] software% find ./ -name malloc.h -print

     .//objc/malloc.h
     .//sys/malloc.h
[localhost:/usr/include] software% popd

     ~/Documents/netpbm-9.12

[localhost:~/Documents/netpbm-9.12] software% pushd /usr/local/include

     /usr/local/include ~/Documents/netpbm-9.12

[localhost:/usr/local/include] software% ln -s /usr/include/sys/malloc.h ./
[localhost:/usr/local/include] software% popd

     ~/Documents/netpbm-9.12

And, back to make again:

[localhost:~/Documents/netpbm-9.12] software% make

make -C pbm -f /Users/software/Documents/netpbm-9.12/pbm/Makefile all
make -C pbmtoppa all
cd ../../pbm ; make libpbm.a
make[3]: `libpbm.a' is up to date.
make -C pgm -f /Users/software/Documents/netpbm-9.12/pgm/Makefile all
cd ../pbm ; make libpbm.a
make[2]: `libpbm.a' is up to date.
make -C ppm -f /Users/software/Documents/netpbm-9.12/ppm/Makefile all
gcc -c -I../shhopt -I/usr/local/include -pedantic -O3 -Wall -Wno-uninitialized     -o 411toppm.o /Users/software/Documents/netpbm-9.12/ppm/411toppm.c
In file included from /usr/include/machine/types.h:30,
                 from /usr/include/sys/types.h:70,
                 from /usr/include/stdio.h:64,
                 from /Users/software/Documents/netpbm-9.12/ppm/411toppm.c:58:
/usr/include/ppc/types.h:75: warning: ANSI C does not support `long long'
/usr/include/ppc/types.h:76: warning: ANSI C does not support `long long'
.
.
.
gcc  -o ppmtojpeg ppmtojpeg.o `../libopt libppm.a ../pbm/libpbm.a ../pgm/libpgm.a`   -L/usr/local/lib -ljpeg
/usr/bin/ld: table of contents for archive: /usr/local/lib/libjpeg.a is out of date; rerun

      ccc.gif
    ranlib(1) (can't load from it)
make[1]: *** [ppmtojpeg] Error 1
make: *** [ppm] Error 2

Well, at least this time it not only tells us what the error is, but how to fix it…

[localhost:~/Documents/netpbm-9.12] software% ranlib /usr/local/lib/libjpeg.a
[localhost:~/Documents/netpbm-9.12] software% make

.
.
.
gcc -c parallel.c -o parallel.o -pedantic -O3 -Wall -Wno-uninitialized -I. -Iheaders -I../

      ccc.gif
   ../shhopt -I/usr/local/include
/usr/include/sys/socket.h:175: undefined type, found `u_char'
/usr/include/sys/socket.h:176: undefined type, found `u_char'
/usr/include/sys/socket.h:186: undefined type, found `u_short'
.
.
.
parallel.c:1790: sizeof applied to an incomplete type
parallel.c:1764: warning: unused variable `nameEntry'
make[2]: *** [parallel.o] Error 1
make[1]: *** [all] Error 2
make: *** [ppm] Error 2

This one is tough—tough enough that this would be where most people would throw up their hands and decide they don't need the software that badly. It hasn't complained that there's a file missing, but it's complaining about undefined types. It's bad to have undefined things in programs, and there doesn't seem to be anything missing to have caused things to be undefined. Still, it's not like doing some poking around is going to do anything worse than waste a bit of time, and you never know when you might get lucky, so let's press ahead. First, find the file that it's complaining about:

[localhost:~/Documents/netpbm-9.12] software% find ./ -name parallel.c -print

.//ppm/ppmtompeg/parallel.c

Looking at this file, we see

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/times.h>
#include <time.h>
#include <netinet/in.h>
#include <unistd.h>
#include <netdb.h>

The make process complained that there were undefined things in socket.h, and the only thing included before socket.h that could have defined them is types.h. types.h almost certainly lives in /usr/include/sys, based on the angle brackets surrounding the include filename in parallel.c. Searching in /usr/include/sys/types.h for the undefined u_char type, we find

#ifndef _POSIX_SOURCE
typedef unsigned char   u_char;
typedef unsigned short  u_short;
typedef unsigned int    u_int;
typedef unsigned long   u_long;
typedef unsigned short  ushort;         /* Sys V compatibility */
typedef unsigned int    uint;           /* Sys V compatibility */
#endif

Interestingly, the type is defined, but there's a cryptic #ifndef POSIX_SOURCE...#endif surrounding the definition. If you were a programmer, the problem would be almost immediately obvious at this point. Because you're probably not a programmer, the most information you can get is that if something named POSIX_SOURCE is not defined, the needed u_char type is defined. Presumably, if POSIX_SOURCE is defined, u_char doesn't get defined here. Armed with this knowledge, if you search in parallel.c again, you'll find the following lines:

#define _POSIX_SOURCE
#define _POSIX_C_SOURCE 2

What do you know! Right there in parallel.c, it's shooting itself in the foot. Let's see what happens if we just comment that out, and have at it again. It already doesn't work, the most that can go wrong is that it still doesn't work, right? Fire up your editor again, and change those lines so they look like this:

/* #define _POSIX_SOURCE */
/* #define _POSIX_C_SOURCE 2 */

And, make again:

[localhost:~/Documents/netpbm-9.12] software% make

     .
     .
     .
     gcc  -o pnmtopng pnmtopng.o `../libopt libpnm.a ../ppm/libppm.a ../pgm/libpgm.a ..

      ccc.gif
   /pbm/libpbm.a `         -L/lib, -lz -L/usr/local/lib -lpng -lm
     /usr/bin/ld: warning -L: directory name (/lib,) does not exist
     /usr/bin/ld: table of contents for archive: /usr/local/lib/libpng.a is out of date;                   rerun ranlib(1) (can't load from it)
     make[1]: *** [pnmtopng] Error 1
     make: *** [pnm] Error 2

You've already seen that one before:

[localhost:~/Documents/netpbm-9.12] software% ranlib /usr/local/lib/libpng.a
[localhost:~/Documents/netpbm-9.12] software% make

.
.
.
make -C ../../pnm libpnm.a
make[3]: `libpnm.a' is up to date.
make -C ../../ppm libppm.a
make[3]: `libppm.a' is up to date.
make -C ../../pgm libpgm.a
make[3]: `libpgm.a' is up to date.
make -C ../../pbm libpbm.a
make[3]: `libpbm.a' is up to date.
gcc  -o pnmtofiasco binerror.o cwfa.o getopt.o getopt1.o params.o `../../libopt codec/libfiasco_codec.a input/libfiasco_input.a output/libfiasco_output.a

      ccc.gif
    lib/libfiasco_lib.a `  `../../libopt ../../pnm/libpnm.a ../../ppm/libppm.a ../../pgm/libpgm.a ../../pbm/libpbm.a

      ccc.gif
    ` -lm
/usr/bin/ld: archive: codec/libfiasco_codec.a has no table of contents, add one with

      ccc.gif
    ranlib(1) (can't load from it)
/usr/bin/ld: archive: input/libfiasco_input.a has no table of contents, add one with

      ccc.gif
    ranlib(1) (can't load from it)
/usr/bin/ld: archive: output/libfiasco_output.a has no table of contents, add one with

      ccc.gif
    ranlib(1) (can't load from it)
/usr/bin/ld: archive: lib/libfiasco_lib.a has no table of contents, add one with ranlib(1)

      ccc.gif
    (can't load from it)
make[2]: *** [pnmtofiasco] Error 1
make[1]: *** [all] Error 2
make: *** [pnm] Error 2

That's getting a little boring! Don't you wish it would just run ranlib for you, instead of telling you it needs to be run? Actually, the installers are supposed to take care of that stuff for you. Like the install not creating the needed directories, it also seems to have trouble ranlibing things, so for some things you have to do it by hand:

[localhost:~/Documents/netpbm-9.12] software% ranlib codec/libfiasco_codec.a

     ranlib: can't open file: codec/libfiasco_codec.a (No such file or
     directory)

Oops! That wasn't expected. Something else you don't (usually) need to know about make is it might be recursively making things in subdirectories. The path shown in an error might not be the relative path from your location, but the relative path from wherever make is currently operating. In this case, we can just find the directories by name, and ranlib them that way:

software% find ./ -name libfiasco_codec.a -print

      .//pnm/fiasco/codec/libfiasco_codec.a

software% find ./ -name libfiasco_input.a -print

      .//pnm/fiasco/input/libfiasco_input.a

software% find ./ -name libfiasco_output.a -print

      .//pnm/fiasco/output/libfiasco_output.a

software% find ./ -name libfiasco_lib.a -print

     .//pnm/fiasco/lib/libfiasco_lib.a

software% ranlib .//pnm/fiasco/codec/libfiasco_codec.a
software% ranlib .//pnm/fiasco/input/libfiasco_input.a
software% ranlib .//pnm/fiasco/output/libfiasco_output.a
software% ranlib .//pnm/fiasco/lib/libfiasco_lib.a

And, make again:

[localhost:~/Documents/netpbm-9.12] software% make

.
.
.
                 from ../../pnm/pnmtopalm/pnm.h:7,
                 from ../../pnm/pnmtopalm/pnmtopalm.c:12:
/usr/include/stdlib.h:181: warning: ANSI C does not support `long long'
/usr/include/stdlib.h:183: warning: ANSI C does not support `long long'
gcc  -o pnmtopalm pnmtopalm.o palmcolormap.o `../../libopt ../../pnm/libpnm.a ../../ppm

      ccc.gif
   /libppm.a ../../pgm/libpgm.a ../../pbm/libpbm.a ` 
[localhost:~/Documents/netpbm-9.12] software%

Hard to believe, but it just finished the compile. Now you can do a make install, and you'll be all set. netpbm installs its applications into /usr/local/netpbm/bin/; its man pages and so on go into directories in /usr/local/netpbm. Because of this you'll again need to extend your path: set path=($path /usr/local/netpbm/bin/), and your MANPATH: setenv MANPATH {$MANPATH}:/usr/local/netpbm/man/.

Finally, if you'd like to see whether it works, find something like a JPEG file, and try out the following:

jpegtopnm < ~/Pictures/<oldfile>.jpg | pnminvert | ppmtojpeg > ~/Pictures/<newfile>.jpg

Take a look at the new file in your Pictures directory. The netpbm package is a large collection of programs that perform very specific graphics manipulations. They can be chained together in arbitrary combinations to create arbitrarily complex graphics manipulations. We'll cover a few of the things it can do in Chapter 18, "Advanced Unix Shell Use: Configuration and Programming (Shell Scripting)." The number of uses is almost unlimited, so you really should read through the man pages for more ideas.

Share ThisShare This

Informit Network