Page 1 of 1

Rolling your own on Mac OS X Part I (would it be a MAMP?)

Posted: Wed Oct 12, 2005 12:25 pm
by redmonkey
Rolling your own on Mac OS X Part I
(A HOWTO on compiling and installing PHP, MySQL, Apache and associated support libraries on Mac OS X.)
  1. Introduction and Prerequisites
  2. Setting up the environment
  3. Getting the archives
  4. Unpacking the archives
  5. Building zlib
  6. Building Apache
  7. Considering extra modules for PHP5
  8. Building libiconv
  9. Building gettext
  10. Building readline
  11. Building libxml2
  12. Building cURL
  13. Preparing for compiling with GD support
    1. Building libpng
    2. Building libjpeg
    3. Building freetype2
  14. Building MySQL
  15. Building Bzip2
  16. Building PHP5
  17. Editing the Apache config file
  18. Testing your handy work
  19. Notes on configuration files
  20. Just time left over for some house keeping
1. Introduction and Prerequisites

I've spent most of my afternoon dealing with an unknown quantity (more accurately described as setting up a webserver on MAC OS X). Given that my experience with MACs is limited to a short term exposure some 8 years ago, I came to the conclusion that it may be prudent to take some notes on my afternoons activities.

This document represents my notes on the problems encountered and steps taken during the setup process, all rolled together to form a (sort of) HOWTO. This document also assumes that you have some experience of working with a UNIX style command line environment.

The MAC in question is one MAC G4 with a fresh clean install of MAC OS X Server v10.2.8, as my knowledge of MACs is extremely limited I cannot guarantee how much (if any) of my notes are relevant to any other versions of MAC OS X, but my notes are offered up here to serve as a help/reference to anyone else who may find themselves in a similar situation.


2. Setting up the environment

It may seem obvious but I thought it worthy of mention, it is imperative that you have installed the Mac OS X Development Tools. The package is available on Apple's ADC site, you have to register to get to the download section but it's free to do so and you won't get far without them.

Now, being new to MAC OS X myself, two things I noticed straight away were that:
  1. The root user appears to be disabled by default
  2. The default shell is an unknown quantity to me (I'm used to the bash shell).
As much as I'm willing to embrace new things, sometimes I just feel more comfortable in my natural environment.

So, first up, as I don't particularly want to be typing 'sudo' and be prompted for a password every five minutes, let's open up a terminal window and enable to root user:

Code: Select all

shell> sudo passwd root
You will be prompted for your administrator password followed by a new passowrd for the root user and confirmation of the new password.

You can now logout, and then log back into a terminal session as root. So, about this shell, I'm sure I'll go back and investigate it at some point but certainly for the moment I wanted to make bash my default shell, all command line instructions within this document will assume you are using a bash shell, so let's make the switch:

Code: Select all

shell> niutil -createprop . /users/root shell /bin/bash
You may also want to cutomise your shell environment to suit you liking, there are plenty of turtorials and articles on this subject floating around the web. The area of customizing your shell is outwith the scope and objective of this document. That being said, there are a few customizations we do need in order to help the build process.

First of all, make sure you have '/usr/local/bin' in your PATH add the following to your ~/.profile:

Code: Select all

shell> export PATH=/usr/local/bin:$PATH
Probably the easiest thing to do for the changes to take effect is to log out from your terminal session, and then back in. Alternatively, you may source the init script.

3. Getting the archives

Old habits die hard, I tend to download all source files into the /usr/local/src directory, a directory which doesn't exist by default on MAC OS X Server, so you may want to create that as I'll be referencing it more than once within this document.

Another old habit is that I always head straight for the .tar.gz format when downloading sources archives. There is no real reason for it but again

Download zlib 1.2.3, gettext 0.14.5, libiconv 1.9.2, readline 5, libxml2 2.6.22, PHP 5.0.5, cURL 7.14.1, MySQL 4.1.14, httpd 2.0.54 (Apache), Bzip2 1.0.3, libpng 1.2.8, libjpeg v6b and FreeType 2.1.10 (version numbers are as of 12-10-2005).

The official URLs for these libraries are:
I advise to locally compare MD5 checksums, if they are listed. You do that by executing:

Code: Select all

shell> md5 'filename'
4. Unpacking the archives

With all archives in the same directory (preferably /usr/local/src), do:

Code: Select all

shell> ls *gz | xargs -n 1 tar -xzvf
5. Building zlib

I thought I'd break myself in gently, as zlib builds on almost anything with no real problems it seemed a good place to start:

Code: Select all

shell> cd zlib-1.2.3
shell> ./configure --shared && make all install
shell> cd ..
6. Building Apache

Apache is another relatively pain free source package to compile and slightly more exciting

A couple of points here, the default installation directory of Apache /usr/local/apache2 I prefer to build into a dedicated directory for each version and symlink it to /usr/local/apache.

Also, I have deliberately choosen not to attempt to build anywhere near the MAC OS X default installation of Apache for a few reasons
  1. I did not want to run the risk of a software update borking our own installation of apache.
  2. I did not want to run the risk that attempting to configure Apache through the MAC OS X GUI may break our config files
So, let's get on an build it:

Code: Select all

shell> cd httpd-2.0.54
shell> ./configure --prefix=/usr/local/apache2.0.54 --enable-mods-shared=most --enable-deflate --with-z=/usr/local && make all install
Depending on the performance specs of your machine, this may take quite sometime. While the build process churns away, may I suggest that now is a good time to grab yourself a cup of tea.

Don't forget the symlink and to change back up into the source directory:

Code: Select all

shell> ln -s /usr/local/apache{2.0.54,}
shell> cd ..
All going well, you can now start Apache and give it a quick test:

Code: Select all

shell> /usr/local/apache/bin/apachectl start
Depending on your machine's setup, you may see a message informing you that Apache could not determine the server's domain name. This is no problem, the server should still start with no issues. You should now be able to open a browser window and type 'http://localhost/' into the address bar and you will be presented with the default Apache page.

We will be editing the Apache config file once all the build work has been completed, for the moment shutdown Apache and let's move on:

Code: Select all

shell> /usr/local/apache/bin/apachectl stop
7. Considering extra modules for PHP5

The minimum requirement to building PHP5 is that you have libxml2 built and installed. However, there are many useful modules that can be compiled in to add to the many standard functions available to you from within PHP5. I'm certainly not going to be compiling with every concievable module included but I will be documenting the compiling of some of the more problematic (on MAC OS X at least) hopefully with this information it may help you to add in extra modules that you may require.

8. Building libiconv

For some odd reason, libiconv reports the wrong deployment target. This doesn't stop the build and infact I only noticed later when compiling PHP5 that it was complaining about it and subsequently not compiling the module. I got round that problem by defining the MACOSX_DEPLOYMENT_TARGET prior to configuring and building:

Code: Select all

shell> export MACOSX_DEPLOYMENT_TARGET=10.2
shell> cd libiconv-1.9.2
shell> ./configure && make all install
shell> cd ..
9. Building gettext

gettext is another seemingly pain free compile, it's also a big old boy so may take some time:

Code: Select all

shell> cd gettext-0.14.5
shell> ./configure && make all install
shell> cd ..

10. Building readline

readline required a small amount of 'hoop jumping' now is the time to crank up your text editor of choice and open the file './readline-5.0/support/shobj-conf' I'm using 'vi', if you are not using vi then you can ignore the next line:

Code: Select all

shell> vi readline-5.0/support/shobj-conf
And find the following section:

Code: Select all

# Darwin/MacOS X
darwin*|macosx*)
        SHOBJ_STATUS=unsupported
        SHLIB_STATUS=supported

        SHOBJ_CFLAGS='-fno-common'

        SHOBJ_LD='${CC}'

        SHLIB_LIBVERSION='$(SHLIB_MAJOR)$(SHLIB_MINOR).$(SHLIB_LIBSUFF)'
        SHLIB_LIBSUFF='dylib'

        case "${host_os}" in
        darwin7*)       SHOBJ_LDFLAGS=''
                        SHLIB_XLDFLAGS='-dynamiclib -arch_only `/usr/bin/arch` -install_name $(libdir)/$@ -current_version $(SHLIB_MAJOR)$(SHLIB_MINOR) -compatibility_version $(SHLIB_MAJOR) -v'
                        ;;
        *)              SHOBJ_LDFLAGS='-dynamic'
                        SHLIB_XLDFLAGS='-arch_only `/usr/bin/arch` -install_name $(libdir)/$@ -current_version $(SHLIB_MAJOR)$(SHLIB_MINOR) -compatibility_version $(SHLIB_MAJOR) -v'
                        ;;
        esac

        SHLIB_LIBS='-lncurses'  # see if -lcurses works on MacOS X 10.1
        ;;
The actual line in question we are looking for is:

Code: Select all

*)              SHOBJ_LDFLAGS='-dynamic'
Which you need to change to:

Code: Select all

*)              SHOBJ_LDFLAGS='-dynamiclib'
With that out the way, we can now compile as normal:

Code: Select all

shell> cd readline-5.0
shell> ./configure && make all install
shell> cd ..
11. Building libxml2

A relatively straight forward one:

Code: Select all

shell> cd libxml2-2.6.22
shell> ./configure --with-zlib=/usr/local && make all install
shell> cd ..
12. Building cURL

MAC OS X 10.2.8 already has cURL installed, but there is nothing wrong with bringing it up to date:

Code: Select all

shell> cd curl-7.14.1
shell> ./configure --with-ssl=/usr && make all install
shell> cd ..
13. Preparing for compiling with GD support

While access to the GD library on it's own comes in useful, the functionality of GD can be further enhanced by adding support for additional formats.

13.1 Building libpng (.png support)

Note: Despite what the INSTALL file suggests, there is no makefile.macosx, however, there is makefile.darwin.

Change into libpng's build directory, and copy the relevant Makefile:

Code: Select all

shell> cd libpng-1.2.8-config
shell> cp scripts/makefile.darwin Makefile
The Makefile needs configuring to find zlib. You have to uncomment lines 13 & 14 and comment lines 15 & 16 to read:

Code: Select all

# Where the zlib library and include files are located
ZLIBLIB=/usr/local/lib
ZLIBINC=/usr/local/include
#ZLIBLIB=../zlib
#ZLIBINC=../zlib
Now build and install:

Code: Select all

shell> make all install
shell> cd ..

13.2 Building libjpeg (.jpeg support)

A quick bit of symlinking required to build the dynamic version of libjpeg prior to compiling:

Code: Select all

shell> cd jpeg-6b/
shell> ln -s `which glibtool` ./libtool
Now configure with shared library support, then build and install:

Code: Select all

shell> ./configure --enable-shared && make all install
shell> cd ..
(Ignore the error about ltconfig: cannot guess host type; you must specify one.)

13.3 Building freetype2 (TrueType font support)

Enter freetype2's build directory:

Code: Select all

shell> cd freetype-2.1.10
By default, freetype2's support for hinting TrueType fonts is disabled. US citizens using this library for commercial purposes might be liable for patent infringement by turning it back on; those of us to which US patents don't apply, or whomever may not care, edit the file 'include/freetype/config/ftoption.h' and uncomment line 439 to read:

Code: Select all

#define TT_CONFIG_OPTION_BYTECODE_INTERPRETER
Now we can build as normal:

Code: Select all

shell> ./configure && make all install
shell> cd ..
14. Building MySQL

There are binary packages available for installing MySQL on MAC OS X. Although, from what I can gather they can throw up just as many problems as compiling your own (I'm guessing most of that is down to not reading the docs).

Also, all the binary packages I've seen so far are geared towards installing on top of the default MySQL installation that ships with MAC OS X or, if it's not doing that, it's attempting to install a (at least to me) rather starnge layout/structure.

This one is a bit more involved but all in all, if you read the docs it's pretty pain free.

In a similar vein to Apache, we will be installing MySQL into it's own discrete location and symlinking to /usr/local/mysql:

Code: Select all

shell> cd mysql-4.1.14
shell> ./configure --prefix=/usr/local/mysql4.1.14 --with-isam --without-docs --without-man --without-bench
shell> make all install
Once completed (and it takes quite some time) add the symlink to /usr/local/mysql:

Code: Select all

shell> ln -s /usr/local/mysql{4.1.14,}
Next, we need to create our config file in /etc/ and install/initialise the GRANT tables, fortunately MySQL has a handy little helper script to acheive this:

Code: Select all

shell> cp support-files/my-medium.cnf /etc/my.cnf
shell> cd /usr/local/mysql4.1.14
shell> bin/mysql_install_db --user=mysql
The next step seems to be where (for some odd reason) most people go wrong with installing MySQL. We have to give MySQL the appropriate read and write permissions for it's data directories:

Code: Select all

shell> chown -R root .
shell> chown -R mysql var
shell> chgrp -R mysql .
You should now be able to run a quick test to ensure that MySQL will at least start up:

Code: Select all

shell> share/mysql/mysql.server start
By default, MySQL installs with no root user password, as you have a database up and running, now would be a good time to set the passowrd for the root user:

Code: Select all

shell> bin/mysqladmin -u root password 'new-password'
Now we can stop the MySQL server and head back to finishing up the build process:

Code: Select all

shell> share/mysql/mysql.server stop
shell> cd /usr/local/src/
15. Building Bzip2

Last one before we actually get to build PHP5. MAC OS X 10.2.8 ships with Bzip2 but we also require the dynamic library in order to compile PHP5 with Bzip compression support

First, let's build the static libraries:

Code: Select all

shell> cd bzip2-1.0.3
shell> make all install PREFIX=/usr/local
The Bzip2 source files don't include any means to make the required dynamic library, the only support is for the UNIX standard shared 'libbz2.so' files so I had to write my own Makefile:

Code: Select all

# This Makefile builds a shared version of the library,
# libbz2.1.0.3.dylib, with install name libbz2.1.0.dylib,
# at least on MAC OS X 10.2.8 with gcc-3.1 (pre-release) it does.

SHELL=/bin/sh
CC=gcc
BIGFILES=-D_FILE_OFFSET_BITS=64
CFLAGS=-no-cpp-precomp -fpic -fPIC -Wall -Winline -O2 -fomit-frame-pointer -fno-strength-reduce
$(BIGFILES)

OBJS= blocksort.o  \
      huffman.o    \
      crctable.o   \
      randtable.o  \
      compress.o   \
      decompress.o \
      bzlib.o

all: $(OBJS)
        $(CC) -dynamiclib -install_name libbz2.1.0.dylib -o libbz2.1.0.3.dylib $
(OBJS)
        $(CC) $(CFLAGS) -o bzip2-shared bzip2.c libbz2.1.0.3.dylib

clean:
        rm -f $(OBJS) bzip2.o libbz2.1.0.3.dylib libbz2.1.0.dylib bzip2-shared

blocksort.o: blocksort.c
        $(CC) $(CFLAGS) -c blocksort.c
huffman.o: huffman.c
        $(CC) $(CFLAGS) -c huffman.c
crctable.o: crctable.c
        $(CC) $(CFLAGS) -c crctable.c
randtable.o: randtable.c
        $(CC) $(CFLAGS) -c randtable.c
compress.o: compress.c
        $(CC) $(CFLAGS) -c compress.c
decompress.o: decompress.c
        $(CC) $(CFLAGS) -c decompress.c
bzlib.o: bzlib.c
        $(CC) $(CFLAGS) -c bzlib.c
Copy the above and place it in a file (I called it Makefile-libbz2_dylib) and place that file within the root of the Bzip2 source tree /usr/local/src/bzip2-1.0.3

Now it's a simple case of building the dynamic library:

Code: Select all

shell> make -f Makefile-libbz2_dylib
Now, I must admit I got a bit lazy and did not write an install routine for the dynamic library (I may go back and clean the Makefile) so we do it manually:

Code: Select all

shell> install -m 644 libbz2.1.0.3.dylib /usr/local/lib
shell> ln -s /usr/local/lib/libbz2.1.0{.3,}.dylib
shell> ranlib /usr/local/lib/libbz2.a
shell> cd ..

16. Building PHP5

We are now ready to build PHP5 again we will be building into a discrete directory and symlinking to /usr/local/php:

Code: Select all

shell> cd php-5.0.5
shell> ./configure --prefix=/usr/local/php5.0.5 --with-mysql=/usr/local/mysql \
--with-mysqli=/usr/local/mysql/bin/mysql_config --with-zlib --with-openssl \
--with-ncurses=/usr --with-gettext=/usr/local --with-iconv=/usr/local \
--with-iconv-dir=/usr/local --with-readline=/usr/local --with-curl=/usr/local \
--with-bz2=/usr/local --with-apxs2=/usr/local/apache/bin/apxs \
--enable-exif --enable-mbstring  --enable-ftp --with-gd --with-png-dir=/usr/local \
--with-jpeg-dir=/usr/local --with-freetype-dir=/usr/local --without-pear

shell> make all install
Now, copy the base PHP5 configuration file over to the correct directory:

Code: Select all

shell> cp php.ini-recommended /usr/local/php5.0.5/lib/php.ini
Add our symlink:

Code: Select all

shell> ln -s /usr/local/php{5.0.5,}
17. Editing the Apache config file

With everything now built, we need to edit the Apache config file to include PHP support and also to enable output compression that we compiled into Apache with mod_deflate

So, grab your favourite text editor and open the file '/usr/local/apache/conf/httpd.conf'

As you scroll down through the file, it's always good to give it a quick sanity check, especially double cheking that the required modules are being loaded. The first section that you'll come across that may require editing is the LoadModule section. In particular, check that mod_deflate and the PHP5 modules are loaded, you should see three lines which look like this:

Code: Select all

LoadModule deflate_module modules/mod_deflate.so

Code: Select all

LoadModule headers_module modules/mod_headers.so

Code: Select all

LoadModule php5_module        modules/libphp5.so
If any of the above lines are commented out i.e. preceeded with a '#' character, uncomment them (remove the '#' character)

As you scroll further down, you will also see lines for ServerAdmin and ServerName. ServerAdmin should be self explanatory, if you don't know or don't have a ServerName then you should use 127.0.0.1:80

The next line we are looking is:

Code: Select all

DirectoryIndex index.html index.html.var
Find this and change it to:

Code: Select all

DirectoryIndex index.html index.html.var index.php
This will allow you to use PHP as your default index page within directories

Next, scroll right to the end of the file and add the following to enable Apache's output compression:

Code: Select all

<Location />
  <IfModule mod_deflate.c>
    # compress all html, text and css content
    AddOutputFilterByType DEFLATE text/html text/plain text/css

    # handle old browsers that do not support compression
    BrowserMatch ^Mozilla/4 gzip-only-text/html
    BrowserMatch ^Mozilla/4\.0[678] no-gzip
    BrowserMatch \bMSIE !no-gzip !gzip-only-text/html

    <IfModule mod_headers.c>
      # handle request coming via proxy
      Header append Vary User-Agent
    </IfModule>
  </IfModule>
</Location>
Lastly, add the directive so Apache knows to pass PHP files through the PHP interpreting engine.

Code: Select all

AddType application/x-httpd-php .php
AddType application/x-httpd-php-source .phps
Save and close the file

18. Testing your handy work

Everything is built and we have basic configuration files in place, all that's left to do is to run a quick test.

Much as I'm tempted to run the time honured traditional 'Hello World!' test, I think I'll refrain. Something a bit more appropriate is to display our PHP configuration within a web browser.

Turning to your text editor, open a new file and place the following line within:

Code: Select all

<?php phpinfo() ?>
Save this file as /usr/local/apache/htdocs/phpinfo.php

All that remains is to start the Apache web server:

Code: Select all

shell> /usr/local/apache/bin/apachectl start
And open up your web browser and type the location of your test script into the address bar 'http://localhost/phpinfo.php'

You can obviously now go on and test some more, remember to start your MySQL server before trying out any database testing.

19. Notes on configuration files

The configuration that we have setup should be regarded as nothing more than basic, there are some configuration options which have not as yet been set. Most notably PHP's temp directory, upload directory and session save path.

Also, the packages we have just built, have a vast array of configuration options which is far out with the scope of this document, some of these options can lead to reduced security of your server. All of the packages come with either a README or INSTALL file, I strongly recommend that you take some time to view these documents.

A short description and overview of options for most of the packages can be viewed by typing:

Code: Select all

shell> ./configure --help
from within the root of the packages source tree.

While the objective of this document is to provide you a step by step guide to building a web server, it should not be regarded as a guide to building a production class server. In other words, it's up to you to ensure that your server is secured and risk of hacking is minimised.



20. Just time left over for some house keeping

If you want to keep the source archives, you may want to move them to another directory for safe keeping; otherwise, delete them:

Code: Select all

shell> rm /usr/local/src/*.gz
You should also go into each of the extracted source archive directories and remove all the compiled binaries:

Code: Select all

shell> make clean