Building Zimbra v5.x on Solaris

Much of the work detailed on this page is based on previous work done by Dom Ijichi. I am very grateful to him for sharing his work in porting Zimbra 4.x to Solaris. Dom can be found as 'dijichi2' on the Zimbra Forums

Zimbra can be thought of as a whole collection of software, rather than a single software package. The Zimbra folks have written quite a bit of code themselves, most of it in Java running under Tomcat, but also some in Perl. Everything else is free open-source software (FOSS) "glued together" to form a complete mailserver environment.

It's the "glued together" part that's tricky. Although it might be possible to use existing installed copies of some of the FOSS, it's not worth the hassle - Zimbra expects config files to live in a certain place so that it can modify them itself in order to make the FOSS behave in the right way. In addition, some libraries have been compiled into the various FOSS packages so that they can all interoperate with each other in the way that Zimbra expects. In short, build it all 'their' way and your life will be much easier.

Unfortunately, 'their' way is very Linux-centric - to the point where paths and command arguments are embedded in Makefiles and often don't work on non-Linux platforms. Porting to something like Solaris, then, takes quite a bit of work, and must be redone EACH TIME they come out with a new release of software that contains any updated FOSS.

The build process can be roughly broken into three stages

  1. Prepare your build enviroment (install needed compilers, make tools, etc)
  2. Build the third-party software
  3. Either build everything into a binary package or install into a dev environment

Preparing the build environment

Do the following two steps as root

  • Download Sun Studio 12 from http://developers.sun.com/sunstudio/downloads/index.jsp [Edit: I don't think this is necessary anymore. Everything built with gcc. Try omitting this and see if it all works next time]
  • Run the prepzimdev.pl script. This script installs all Blastwave packages, sets up environment variables and creates zimbra user and group. Note that it will also try to replace Blastwave's Perl with a symlink to /usr/local/bin/perl. If you don't have a Perl at that location, you can download a packaged version of it from Sunsite. It's necessary to do this because the Blastwave Perl is linked against a different version of libDB than Zimbra wants to use, so the attempt to build the DBFile Perl module will fail. The perl on Sunsite isn't linked against any libDB
At this point, a warning is due: This build process will result in binaries that are linked against some libraries in the Blastwave packages. These are libraries not included with Solaris by default, and not included in the Zimbra ThirdParty packages. That means that if you try to run these binaries on a Solaris box not equipped with the relevant Blastwave packages, they'll fail with 'library not found' errors. The only proper fix for this would be to include all of the relevant third-party packages in the Zimbra ThirdParty build process, and use the Sun Compiler instead of gcc

Download the Zimbra source code

Do these steps as user 'zimbra' unless otherwise stated

  • Source tree and for 5.0b3 is here: http://sourceforge.net/project/showfiles.php?group_id=153217
  • The ThirdParty binaries tarball is also at the above URL - it includes the source tarballs for each third-party package that must be built, as well as copies of the Makefiles that were used for each package. However, this may not be consistently available - Zimbra is still working on their procedures around publishing their source. For future versions, you may have to use this tarball as a starting point.
  • Choose a location to unpack the tarballs. The 3rd-party build directory should be renamed to ThirdParty and moved into the Zimbra source tree - at the same level as the ZimbraBuild, ZimbraServer, etc directories.
  • Adjust the path for PERLLIB in /etc/profile. Replace /opt/zimbra/current with whatever directory you chose for the Zimbra source tree (e.g. /usr/local/src/zimbra/5.0b3)

Do the Zimbra ThirdParty Build

Note: The build process wipes out /opt/zimbra. If you have an old version in there that you want to keep, rename it to keep it around.

edit src/ZimbraBuild/rpmconf/Build/get_plat_tag.sh and change "Solaris 10...X86" to just "Solaris 10" and "SOLARISX86" to "SOLARIS10"

cd <src>/ThirdParty

There is a Makefile here that's supposed to build all Third Party packages. Of course, it doesn't work on Solaris – too many changes needed to each package. But perhaps it could be made to work. The problem isn't with the top-level Makefile, but rather with each individual package needing special care and attention instead of just a straight 'make'. However, we'll see if we can get it to work by getting each package figured out:

Edit: We now have a patch file that can patch everything under ThirdParty and allow you to do a 'make' at the top level. Download the patch zimbra-solaris-3rdparty.patch. From the directory above the ThirdParty directory, apply the patch with:

gpatch -p0 < zimbra-solaris-3rdparty.patch
For reference purposes, the information below is left here. Note: It will still be necessary to 'su' to root and run the 'make install' in the PostFix directory, unless you do your whole build process as 'root'.
  • Build MySQL:
    cd mysql
    Apply this diff to Makefile:
    38c38
    <       tar xzf $(MYSQL_CLIENT_TGZ_TARGET)
    ---
    >       tar xzf $(MYSQL_CLIENT_TGZ_TARGET))
    49c49,50
    <       -(cd $(ZIMBRA_HOME)/mysql-$(MYSQL_VERSION)/lib/mysql ; tar czvf $(MYSQL_CLIENT_TGZ_TARGET) libmysqlclient.*{so,dylib}*)
    ---
    >       mkdir $(MYSQL_ROOT)/$(BUILD_PLATFORM)
    >       -(cd $(ZIMBRA_HOME)/mysql-$(MYSQL_VERSION)/lib/mysql ; tar czvf $(MYSQL_CLIENT_TGZ_TARGET) libmysqlclient.*so* libmysqlclient.*dylib*)
    

    "make"

  • Build Sleepycat
    cd ../sleepycat
    make
  • Build libxml2
    cd ../libxml2
    Apply this diff to Makefile:
    22a23,26
    > ifeq ($(BUILD_PLATFORM), SOLARIS10)
    >       APP_CONFIGURE := $(APP_CONFIGURE) --with-iconv=/opt/csw
    > endif
    > 
    

    make

  • Build cyrus-sasl
    Modify zimbra-cyrus-sasl-build.sh with the following diff:
    36,38c36,47
    < patch -g0 -p1 < ../../sasl-link-order.patch
    < patch -g0 -p1 < ../../sasl-darwin.patch
    < patch -g0 -p1 < ../../sasl-auth-zimbra.patch
    ---
    > 
    > if [ -x /usr/bin/gpatch ]; then
    >       # Solaris
    >       gpatch -g0 -p1 < ../../sasl-link-order.patch
    >       gpatch -g0 -p1 < ../../sasl-darwin.patch
    >       gpatch -g0 -p1 < ../../sasl-auth-zimbra.patch
    > else
    >       patch -g0 -p1 < ../../sasl-link-order.patch
    >       patch -g0 -p1 < ../../sasl-darwin.patch
    >       patch -g0 -p1 < ../../sasl-auth-zimbra.patch
    > fi
    > 
    47,48c56,61
    <               echo "Where is libtoolize?"
    <               exit 1
    ---
    >               if [ -x /opt/csw/bin/libtoolize ]; then
    >                       LIBTOOLIZE=/opt/csw/bin/libtoolize
    >               else
    >                       echo "Where is libtoolize?"
    >                       exit 1
    >               fi
    64a78,88
    > # Check for Solaris
    > grep "Solaris 10" /etc/release >/dev/null 2>&1
    > if [ $? -eq 0 ]; then
    >     PRESOLOPTS="-I/opt/csw/include/libxml2"
    >     POSTSOLOPTS="--with-openssl=/opt/csw"
    > else
    >     PRESOLOPTS=""
    >     POSTSOLOPTS=""
    > fi
    > 
    > 
    79c103
    < LIBS="/opt/zimbra/libxml2/lib/libxml2.a" CFLAGS="-D_REENTRANT -g -O2" ./configure --enable-zimbra --prefix=/opt/zimbra/${src} \
    ---
    > LIBS="/opt/zimbra/libxml2/lib/libxml2.a" CFLAGS="-D_REENTRANT -g -O2" CPPFLAGS="${PRESOLOPTS}" ./configure --enable-zimbra --prefix=/opt/zimbra/${src} \
    83c107
    <             --enable-login
    ---
    >             --enable-login ${POSTSOLOPTS}
    

    'make'

  • Build openldap
    cd openldap
    Apply this diff to Makefile:
    20a21,26
    > ifeq ($(BUILD_PLATFORM), SOLARIS10)
    >       PATCH := gpatch
    > endif
    > PATCH ?= patch
    > 
    > 
    34,36c40,42
    <       patch -p1 < ../ITS5037.patch; \
    <       patch -p1 < ../ITS5052.patch; \
    <       patch -p1 < ../init-null.patch; \
    ---
    >       $(PATCH) -p1 < ../ITS5037.patch; \
    >       $(PATCH) -p1 < ../ITS5052.patch; \
    >       $(PATCH) -p1 < ../init-null.patch; \
    

    make

  • Build Aspell:
    cd aspell
    Apply this diff to Makefile:
    9a10,15
    > ifeq ($(BUILD_PLATFORM),SOLARIS10)
    >       CC=/opt/csw/gcc3/bin/gcc
    >       CXX=/opt/csw/gcc3/bin/g++
    >       export CC CXX
    > endif
    > 
    32c38
    <       export PATH=$(ZIMBRA_HOME)/aspell-$(ASPELL_VERSION)/bin:$$PATH
    ---
    >       PATH=$(ZIMBRA_HOME)/aspell-$(ASPELL_VERSION)/bin:$$PATH; export PATH
    

    make

  • Build clamav:
    cd clamav
    Apply this diff to Makefile:
    30c30
    <       chmod -R a+w $(CLAMAV_ROOT)/builds/$(BUILD_PLATFORM)
    ---
    >       chmod -R a+w $(P4_ROOT)/ThirdPartyBuilds/$(BUILD_PLATFORM)/clamav
    

    make

  • Build Apache:
    cd apache-httpd
    make
  • Build php. Unfortunately, the libxml that got built earlier produces errors when linked into PHP, somehow related to its static build. So to get this working, we'll have to link against the libxml2 in /opt/csw. That means that PHP won't run on any machine that doesn't have a libxml.so.2 library installed. Blah.
    cd php
    Apply diff to Makefile
    17a18,20
    > ifeq ($(BUILD_PLATFORM), SOLARIS10)
    >       LIBXML2 := --with-libxml-dir=/opt/csw
    > endif
    40c43
    <       chmod -R a+w $(PHP_ROOT)/builds/$(BUILD_PLATFORM)
    ---
    >       chmod -R a+w $(P4_ROOT)/ThirdPartyBuilds/$(BUILD_PLATFORM)/php
    

    make

  • Build Postfix
    cd PostFix
    Apply this diff to Makefile:
    69a70,85
    > MYSQLDIR := /opt/zimbra/mysql-$(MYSQL_VERSION)/lib
    > ifeq ($(BUILD_PLATFORM), SOLARIS10)
    >       PCRE_DEF := -DHAS_PCRE
    >       PCRE_INCLUDE := -I/opt/csw/include
    >       PCRE_LIB := -L/opt/csw/lib -R/opt/csw/lib -lpcre
    >       PATCH := gpatch
    >       DBLIB := -L/opt/zimbra/sleepycat-4.2.52.6/lib -R/opt/zimbra/sleepycat-4.2.52.6/lib
    >       SASLLIB := -L/opt/zimbra/cyrus-sasl-$(SASL_VERSION)/lib -R/opt/zimbra/cyrus-sasl-$(SASL_VERSION)/lib
    >       LDAPLIB := -L/opt/zimbra/openldap-$(LDAP_VERSION)/lib -R/opt/zimbra/openldap-$(LDAP_VERSION)/lib
    >       MYSQLLIB := -L$(MYSQLDIR) -R$(MYSQLDIR) -L$(MYSQLDIR)/mysql -R$(MYSQLDIR)/mysql
    > endif
    > PATCH ?= patch
    > SASLLIB ?= -L/opt/zimbra/cyrus-sasl-$(SASL_VERSION)/lib
    > LDAPLIB ?= -L/opt/zimbra/openldap-$(LDAP_VERSION)/lib
    > MYSQLLIB ?= -L$(MYSQLDIR)
    > 
    81,83c97,99
    <       patch -g0 -p1 < ../postfix-ldap-sasl.patch; \
    <       patch -g0 -p1 < ../postfix-zimbra-bdb.patch; \
    <       patch -g0 -p1 < ../postfix-main-cf-zimbra.patch; \
    ---
    >       $(PATCH) -g0 -p1 < ../postfix-ldap-sasl.patch; \
    >       $(PATCH) -g0 -p1 < ../postfix-zimbra-bdb.patch; \
    >       $(PATCH) -g0 -p1 < ../postfix-main-cf-zimbra.patch; \
    106,109c122
    <       AUXLIBS='-L/opt/zimbra/cyrus-sasl-$(SASL_VERSION)/lib \
    <       $(DBLIB) -ldb -L/opt/zimbra/openldap-$(LDAP_VERSION)/lib $(PCRE_LIB) \
    <       -lldap -llber -L/opt/zimbra/mysql-$(MYSQL_VERSION)/lib \
    <       -L/opt/zimbra/mysql-$(MYSQL_VERSION)/lib/mysql \
    ---
    >       AUXLIBS='$(SASLLIB) $(DBLIB) -ldb $(LDAPLIB) $(PCRE_LIB) -lldap -llber $(MYSQLLIB) \
    

    make
    The Make will fail when it tries to do a make install, so at this point:
    su - root
    cd <path to src>/ThirdParty/PostFix
    make install
    make tar

  • Build rrdtool
    cd rrdtool
    make
  • Build snmp
    cd snmp
    Apply this diff to Makefile:
    34a35
    >       --with-perl-modules="LIB=/opt/zimbra/zimbramon/lib" \
    
    [Edit: This is the wrong path. The Perl build (next step below) tars up all of its modules into a tarball, but the build placed the modules into a different path, so the SNMP modules would have been missed in the tarball. I will have to revise this once I get everything working]

    make

  • Build Perl. This has thankfully improved substantially over 4.5.x:
    cd Perl
    Apply this diff to MyConfig.pm.template file
    45c45
    <   'urllist' => [q[http://inside.zimbra.com/public/software/shared/CPAN/],],
    ---
    >   'urllist' => [q[ftp://ftp.perl.org/pub/CPAN/],],
    

    Apply this diff to the Makefile:

    118c118
    < JAVA_HOME             := /usr/local/java
    ---
    > JAVA_HOME             ?= /usr/local/java
    

    make
    A few tests will probably fail, but the Makefile does a 'force install' on each module, so they get installed anyway. Check the file /tmp/ThirdParty-Perllibs.log and look for "NOT OK" to find failed tests. If none are critical, it's probably safe to ignore

  • Re-tar Apache:
    cd apache-httpd
    make tar

At this point, we've done every package listed in ThirdParty/Makefile, which means that a 'make' at the ThirdParty level should also succeed. However, several packages aren't included in that makefile for some reason. We'll start building those by hand

  • Build memcached:
    cd memcached
    Apply this diff to Makefile:
    9a10,14
    > SOLPATCH := 
    > ifeq ($(BUILD_PLATFORM), SOLARIS10)
    >       SOLPATCH := gpatch -p0 < ../solaris.libevent.patch
    > endif
    > 
    23a29
    >       $(SOLPATCH); \
    

    Place this patch file, solaris.libevent.patch, into the same dir as the Makefile
    'make'

  • Build nginx:
    cd nginx
    Apply this patch to Makefile:
    10a11
    > LD_OPT := 
    11a13,18
    > ifeq ($(BUILD_PLATFORM), SOLARIS10)
    >         CFLAGS := "-g -O2 -I/opt/csw/include -L/opt/csw/lib"
    >       LD_OPT := "-L/opt/csw/lib -R/opt/csw/lib"
    > endif
    > 
    > 
    26c33
    <       CFLAGS=$(CFLAGS) ./configure \
    ---
    >       CFLAGS=$(CFLAGS) LINK=$(LINK) ./configure \
    30a38
    >            --with-ld-opt=$(LD_OPT) \
    36c44
    <       mkdir -p $(P4_ROOT)/ThirdPartyBuilds/$(BUILD_PLATFORM)
    ---
    >       mkdir -p $(P4_ROOT)/ThirdPartyBuilds/$(BUILD_PLATFORM)/nginx
    

    make

Not done yet because they aren't in the 3rd-Party Makefile: amavisd, jetty, mrtg, slf4j, tcmalloc