Local web development on MacOS X Lion

Lion no longer creates personal web sites by default. To create one manually, enter the following:

mkdir ~/Sites
echo "<html><body><h1>My site works</h1></body></html>" > ~/Sites/index.html.en

PHP is not enabled in Lion. To enable it, do:

sudo vi /etc/apache2/httpd.conf

Uncomment line 111 that reads:

#LoadModule php5_module libexec/apache2/libphp5.so

to

LoadModule php5_module libexec/apache2/libphp5.so

Edit the launchd config file for Apache:

sudo vi /System/Library/LaunchDaemons/org.apache.httpd.plist  

Remove the following:

<string>-D</string>
<string>WEBSHARING_ON</string>

Restart Apache:

sudo launchctl unload -w /System/Library/LaunchDaemons/org.apache.httpd.plist 
sudo launchctl load -w /System/Library/LaunchDaemons/org.apache.httpd.plist 

To turn on Apache, go to System Preferences > Sharing and enable Web Sharing.

In Safari, navigate to your web site with the following address:

http://<your local host>/

It should say:

It works!

Now try your user home directory:

http://<your local host>/~<your short user name>

It should say:

My site works!

Now try PHP. Create a PHP info file with:

echo "<?php echo phpinfo(); ?>" > ~/Sites/info.php

And test it by entering the following into Safari’s address bar:

http://<your local host>/~<your short user name>/info.php

You should see your PHP configuration information. This will be important for setting up MySQL later.

Download MySQL from http://www.mysql.com/downloads/mysql/. You want the Mac OS X ver. 10.6 (x86, 64-bit), DMG Archive. Open the archive mysql-5.5.14-osx10.6-x86_64.dmg. Install only the mysql-5.5.14-osx10.6-x86_64.pkg package. Ignore everything else.

Create the launchd config file for MySQL:

sudo vi /Library/LaunchDaemons/com.mysql.mysql.plist  

Use the following content:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
  <dict>
    <key>KeepAlive</key>
    <true/>
    <key>Label</key>
    <string>com.mysql.mysqld</string>
    <key>ProgramArguments</key>
    <array>
    <string>/usr/local/mysql/bin/mysqld_safe</string>
    <string>--user=mysql</string>
    </array>
  </dict>
</plist>

Create a config file for MySQL that matches the Apple PHP build:

sudo vi /etc/my.conf  

Use the following content:

[client]
socket=/var/mysql/mysql.sock
[mysqld]
socket=/var/mysql/mysql.sock

Start MySQL:

sudo launchctl load -w /Library/LaunchDaemons/com.mysql.mysql.plist 

Download DBD::mysql from http://search.cpan.org/~capttofu/DBD-mysql-4.019/lib/DBD/mysql.pm

Extract the archive with:

tar zxvf DBD-mysql-4.019.tar.gz

Move into the directory:

cd DBD-mysql-4.019

First, fix the MySQL client library according to instructions in:

http://probably.co.uk/problems-installing-dbdmysql-on-os-x-snow-leopard.html

For Lion, type:

sudo install_name_tool -id /usr/local/mysql-5.5.14-osx10.6-x86_64/lib/libmysqlclient.18.dylib /usr/local/mysql-5.5.14-osx10.6-x86_64/lib/libmysqlclient.18.dylib

Next, build DBD::mysql with:

perl Makefile.PL --mysql_config=/usr/local/mysql/bin/mysql_config --testsocket=/var/mysql/mysql.sock --testuser=root
make
make test
sudo make install

If you want to add modules to PHP, I suggest the following site:

http://michaelgracie.com/2011/07/21/plugging-mcrypt-into-php-on-mac-os-x-lion-10-7/

I can’t explain it any better.

 

Unix executable inquiry tools

Once again today I found myself struggling to remember a certain obscure Unix command to inquire about what files were linked to an executable. That means it’s time to post to Etreblog again. So, for the record:

Utility Description
file
Display handy information about a file or library. MacOS X just tells the architectures while Linux provides some additional info.
ar t
List source files inside a static library
ldd
Print shared library dependencies. Not on MacOS X.
otool
Like ldd for MacOS X, only much more powerful.

Darwin versions for open-source development

I’m trying to support Intel in 10.4 and PPC in 10.2. I found the following table from Wikipedia very helpful:

Date Darwin release Mac OS X release
March 16, 1999 Darwin 0.1 Mac OS X Server 1.0
April 5, 2000 Darwin 1.0
April 13, 2000 Darwin 1.0.2 Mac OS X DP4
Darwin 1.2.1 Mac OS X public beta
April 13, 2001 Darwin 1.3.1 Mac OS X 10.0 to 10.0.4
October 2, 2001 Darwin 1.4.1 Mac OS X 10.1
Darwin 5.1 Mac OS X 10.1.1
Darwin 5.2 Mac OS X 10.1.2
Darwin 5.3 Mac OS X 10.1.3
Darwin 5.4 Mac OS X 10.1.4
Darwin 5.5 Mac OS X 10.1.5
September 23, 2002 Darwin 6.0.1 Mac OS X 10.2
October 28, 2002 Darwin 6.0.2 Mac OS X 10.2
Darwin 6.1 Mac OS X 10.2.1
Darwin 6.2 Mac OS X 10.2.2
Darwin 6.3 Mac OS X 10.2.3
Darwin 6.4 Mac OS X 10.2.4
Darwin 6.5 Mac OS X 10.2.5
Darwin 6.6 Mac OS X 10.2.6
Darwin 6.7 Mac OS X 10.2.7
Darwin 6.8 Mac OS X 10.2.8
October 24, 2003 Darwin 7.0 Mac OS X 10.3
Darwin 7.1 Mac OS X 10.3.1
Darwin 7.2 Mac OS X 10.3.2
Darwin 7.3 Mac OS X 10.3.3
Darwin 7.4 Mac OS X 10.3.4
Darwin 7.5 Mac OS X 10.3.5
Darwin 7.6 Mac OS X 10.3.6
Darwin 7.7 Mac OS X 10.3.7
Darwin 7.8 Mac OS X 10.3.8
April 15, 2005 Darwin 7.9 Mac OS X 10.3.9
April 29, 2005 Darwin 8.0 Mac OS X 10.4
May 16, 2005 Darwin 8.1 Mac OS X 10.4.1
July 12, 2005 Darwin 8.2 Mac OS X 10.4.2
October 31, 2005 Darwin 8.3 Mac OS X 10.4.3
January 10, 2006 Darwin 8.4 Mac OS X 10.4.4
February 14, 2006 Darwin 8.5 Mac OS X 10.4.5
April 3, 2006 Darwin 8.6 Mac OS X 10.4.6
August 7, 2006 Darwin 8.7 Mac OS X 10.4.7
September 29, 2006 Darwin 8.8 Mac OS X 10.4.8

Enumerate interfaces

I’m going to delete this code, but I may want to use it at some point in the future. This code will enumerate all the network interfaces and display various information about each.

  struct ifaddrs * ifap;

  if(getifaddrs(& ifap))
    throw Error(__FILE__, __LINE__, errno,
      "Couldn't query IP addresses");

  struct ifaddrs * intf = ifap;

  while(intf->ifa_next)
    {
    std::string name;
    std::string ifname;
    std::string address;
    std::string netmask;

    char buf[NI_MAXHOST];

    buf[0] = 0;

    if(getnameinfo(intf->ifa_addr, sizeof(*(intf->ifa_addr)),
      buf, sizeof(buf), 0, 0, NI_NUMERICHOST))
      buf[0] = 0;

    buf[NI_MAXHOST - 1] = 0;

    if(intf->ifa_name)
      ifname = intf->ifa_name;

    address = buf;  

    buf[0] = 0;

    if(getnameinfo(intf->ifa_netmask, sizeof(*(intf->ifa_netmask)),
      buf, sizeof(buf), 0, 0, NI_NUMERICHOST))
      buf[0] = 0;

    buf[NI_MAXHOST - 1] = 0;

    netmask = buf;

    if(!address.empty())
      {
      struct hostent * host = 0;

      struct in_addr sin;

      if(!inet_pton(AF_INET, address.c_str(), & sin))
        host = gethostbyaddr(& sin, sizeof(sin), AF_INET);
      else
        {
        struct in6_addr sin6;

        if(!inet_pton(AF_INET6, address.c_str(), & sin6))
          host = gethostbyaddr(& sin, sizeof(sin), AF_INET6);
        }

      if(host)
        name = host->h_name;

      ES::debugLog(
        "%s: %s (%s) \"%s\"",
        ifname.c_str(), address.c_str(), netmask.c_str(), name.c_str());
      }

    intf = intf->ifa_next;
    }

  freeifaddrs(ifap);

That is all well and good. However, I have found a better way. Just call CSCopyMachineName. I should be able to lookup machinename.local and get a plausible IP address.

What is my IP address?

Pound for pound, I think the Apple Mailing List site may be the most useful site for programmers looking for answers. One would think that something as generic as C code to find local IP addresses on Unix should have tons of examples on the Internet. Well, I couldn’t find them. I did, however, find exactly what I was looking for in this post on the Apple Mailing List site. This isn’t the first time this has happened.

I have seen some scary stuff come out of Apple. But I think the people posting on the mailing lists tend to know what they are talking about.

The answer to my query is a nice little function called getifaddrs.

What? Didn’t that link work? You must not have Bwana installed.

Re-entrant routines in MacOS X

To quote (paraphrase, actually) Marc Majka from the Apple darwin-dev mailing list:

– alias_getbyname alias_getent alias_setent alias_endent
– bootp_getbyether bootp_getbyip
– bootparams_getbyname bootparams_getent bootparams_setent bootparams_endent
– getfsbyname getfsspec getfsfile getfsent setfsent endfsent
– initgroups getgrnam getgrgid getgrent setgrent endgrent
– gethostbyaddr gethostbyname gethostbyname2 gethostent sethostent endhostent
– getipnodebyname getipnodebyaddr
– innetgr getnetgrent setnetgrent endnetgrent
– getnetbyaddr getnetbyname getnetent setnetent endnetent
– prdb_getbyname prdb_get prdb_set prdb_end
– getprotobyname getprotobynumber getprotoent setprotoent endprotoent
– getrpcbyname getrpcbynumber getrpcent setrpcent endrpcent
– getservbyport getservbyname getservent setservent endservent
– getpwnam getpwuid getpwent setpwent endpwent

They all cache returned data in per-thread storage. The threads correctly release the cached structures on subsequent calls. Memory is reclaimed when threads exit by a destructor routine. For those with an interest in seeing the implementation, see the lu_utils.[ch] files and any one of the lu_*.c routines in the Libinfo project (e.g. lu_host.c)

Open Source Universal Binaries

I would like to get Tor running on my Macbook. Unfortunately, the developers haven’t figured out how to build Universal Binaries for MacOS X yet. I’m not waiting for them. I had earlier hacked together an Intel Privoxy, so Tor shouldn’t be too hard.

The Tor configure fails because I don’t have libevent. Libevent looks very interesting. It could be a candidate for my “good” category of OSS. I might want to incorporate libevent into some shareware. I had been just linking all my libraries statically. Now that I have Universal Binaries to worry about, perhaps I should bite the bullet and figure out how to distribute dynamic libraries inside my .app packages. I also don’t want to just install it on my system because I need to test my yet-to-be-developed scheme for distributing dynamic libraries. I think it is a good idea to develop my software in the same environment in which it will be run. Yeah. I’m a wacko. Maybe when all this is done, I’ll fix my hacked-up Privoxy and submit patches to the offical Tor and Privoxy people. They seem to need to help.

Luckily, Apple has a nice technote on how to build Universal Binary configure-based open source software. It would be even nicer if it worked. Apple’s instructions will not create Universal Binary dynamic libraries.

This guy seems to know what he’s talking about. He thinks I need to download new versions of autoconf, automake, and libtool. I’m not a Linux guy so I would prefer not to muck around with my system. I keep looking and find this post. He claims to have gotten it working. He also says you can install autoconf, automake, and libtool in /usr/local. OK, I’ll do that.

I download, configure, and install autoconf, automake, and libtool. No problems.

Next, I go into my libevent directory and run:

autoreconf -fvi

This may not be necessary. See the next post.

Now, in theory, make should forward those “-arch” arguments on to the linker. I’m ready to re-configure. I setup some handy aliases in my bash profile for configuring and building Universal Binaries. You have to modify CFLAGS to specify that you want both the ppc and 386 architectures built. You have to add the new isysroot thingy. Finally, you have to disable the default dependency tracking to handle the new split personality nature of the object files. Here are my aliases:

alias uconfigure="env CFLAGS=\"-isysroot /Developer/SDKs/MacOSX10.4u.sdk -arch i386 -arch ppc\" ./configure --prefix=/Programming/Libraries --disable-dependency-tracking"
alias umake="env CFLAGS=\"-isysroot /Developer/SDKs/MacOSX10.4u.sdk -arch i386 -arch ppc\" make"

Note that I am going to install any Universal Binaries into /Programming/Libraries. That way, the system won’t see them. The only way they’ll work is if I figure out how to put them inside a .app bundle. (I hope that works or I’ll have to re-do all this.)

This is all similar to Apple’s instructions. Apple also had us munging up the LDFLAGS, turning off optimization, and turning on debug. I had read somewhere (I forget where, hence the need for this blog) that you don’t have to mess with LDFLAGS. Also, I’ll let the makefile handle optiization and debugging.

It all works. I can now build a Universal Binary libevent and Tor. Next, I’ll fix the official Tor and Privoxy packages. That will take more work. Plus I like to run Privoxy all the time. Tor messes with Privoxy’s config file. I need to figure out a way to switch between them. That’s for later.

I can now build Universal Binary dynamic libraries from OSS. I can easily install them into a hidden, but usable location. I’ve learned about libevent. Overall, a productive tangent.

PS: Today is 10-05-2006 and the blog has come in handy. I forgot how to check the executable type of a file. The above link the Apple technote helped, but, for the record, it is:

file