Wednesday, August 22, 2012

Build CouchDB 1.2 on Solaris 11 (SPARC)

I want to play a little bit with Document-oriented DB. The first try was MongoDB, however, building MongoDB on SPARC is a horrible experience: MongoDB is written for x86/x64; in addition, it uses scons as its build tool and scons doesn't work with IPS-based Solaris Studio 12.3 (I need hack scons to make it work), in fact in MongoDB's source code, it never consider other compilers but VC and GCC. Therefore, I decided to try CouchDB. Allthough CouchDB has a lot of dependencies, but they are friendly for porting.

1)  ICU (International Components for Unicode)
This is easy on Solaris 11:
# pkg install developer/icu (this will also cause library/icu to be installed)
Note: the ICU library 4.6 is built with Sun CC, so the C++ code that will link to it also should be built with Sun CC.


2) Build Erlang
Solaris 11 11/11 IPS repository provides Erlang 5.6.5, this is too old. CouchDB 1.1.x or later requires Erlang >= 5.7.3. Although Erlang website says they do daily build for Solaris Sparc (may be because Ericsson was Sun's shop), but why don't they publish the binary package for Solaris? Fortunately, the build procedure is not that difficult:

- Grab the source code from Erlang website. I chose 14B04 which version is 5.8.5.

- ./configure --prefix=/opt/local  (I use default gcc-45 from Solaris 11 IPS repository, since it is said erlang uses some GCC features (label vars?).
Ignore configure warnings unless configure fails.

- fix erts/emulator/drivers/common/inet_drv.c:
ifreq.ifr_hwaddr.sa_data would cause compiling error because ifreq does not have that member. Since Solaris 11 has defined both  SIOCGIFHWADDR and SIOCGENADDR, we only need SIOCGENADDR.
//#ifdef SIOCGIFHWADDR
//          if (ioctl(desc->s, SIOCGIFHWADDR, (char *)&ifreq) < 0)
//              break;
//          buf_check(sptr, s_end, 1+2+IFHWADDRLEN);
//          *sptr++ = INET_IFOPT_HWADDR;
//          put_int16(IFHWADDRLEN, sptr); sptr += 2;
//          /* raw memcpy (fix include autoconf later) */
//          sys_memcpy(sptr, (char*)(&ifreq.ifr_hwaddr.sa_data), IFHWADDRLEN);
//          sptr += IFHWADDRLEN;
//#elif defined(SIOCGENADDR)
#ifdef SIOCGENADDR


- After gmake install, prepend /opt/local/bin to PATH.


3) Build SpiderMonkey 1.8.5
- Download source code from here.
- It's interesting that Mozilla's project need autoconf-2.13, so I had to build this old version.
Get the source from GNU webiste, then:
./configure --prefix=/usr/local --program-suffix=-2.13

- Run autoconf in SpiderMonkey's source tree: to generate configure script.
 cd  js-1.8.5/js/src
 /usr/local/bin/autoconf-2.13


- This time I used Sun CC from Solaris Studio 12.3 which is freely available.
   CC=cc CXX=CC ./configure

- gmake; sudo gmake install  (in /usr/local)


4) Build CouchDB 1.2
Before proceeding, I need to fix something:

 - apache-couchdb-1.2.0/src/couchdb/priv/Makefile.in:
    replace "-Wall -Werror" with "-v"  because I use Sun CC.

 - cd /usr/local/lib; ln -s libmozjs185.so.1.0 libmozjs185-1.0.so
(because configure.ac always choose libmozjs185-1.0 instead of libmozjs185 due to existence of  libmozjs185-1.0.a)

- apache-couchdb-1.2.0/src/snappy/google-snappy/snappy-stubs-internal.h:
solaris does not have byteswap.h, I replaced it with byteorder.h and defined a few macros.
...
#else
//#include
#include
#define bswap_16(x) BSWAP_16(x)
#define bswap_32(x) BSWAP_32(x)
#define bswap_64(x) BSWAP_64(x)
....


- configure
 ./configure CC=cc CXX=CC LDFLAGS="-R /usr/local/lib" --with-erlang=/opt/local/lib/erlang/usr/include --with-js-lib=/usr/local/lib/ --with-js-include=/usr/local/include/js/ --prefix=/opt/couchdb1.2

- gmake

- Run test:
  $ export PATH=/usr/perl5/5.12/bin:$PATH
  $ gmake check   
Wait for a while, all tests should be successful.

- sudo gmake install

-  create a script couchdb.sh in /opt/couchdb1.2/bin (since I don't want the couchdb output to be at arbitrary place).
#!/usr/bin/bash
BIN_DIR=$(dirname $0)
cd $BIN_DIR
./couchdb -o ../var/log/couchdb.stdout -e ../var/log/couchdb.stderr ${1+"$@"}

- modify /opt/couchdb1.2/etc/couchdb/default.ini, change bind_address to let couchdb accessible from anywhere
  bind_address  = 0.0.0.0

- start couchdb: /opt/couchdb1.2/bin/couchdb.sh -b

Now, enjoy CouchDB!

UPDATE (Sept 2012):

 - I also tested Erlang 15B01 and latest 15B02, erts/emulator/drivers/common/inet_drv.c has already been fixed. But for building couchdb, we need to add something to /opt/local/lib/erlang/usr/include/erl_driver.h:
 #if defined(__sun)
#include <unistd.h>    /* for ssize_t */
#endif

- Running couchdb testsuite in browser (Erlang 14B04 and 15B01) caused erlang process crash. I posted the core dump analysis and temporary workaround in erlang mailing list. Using 15B02 doesn't have this problem, but still should be careful when the Erlang application on Solaris reloads crypto.so, see discussions here. One solution might be adding "-z nodelete" LDFLAGS in lib/crypto/c_src/sparc-sun-solaris2.11/Makefile.