tmux on Solaris

In the last month my work is somewhat related to Solaris and since I really got used to tmux I kind of miss it. Unfortunately it turns out Solaris is not the happy Linux land I am used to. One does not simply  dowload, ./configure and make install stuff in Solaris. Not without   the proper spells 🙂 So here is an attempt to document my experience to build static tmux binary, that doesn’t require libevent or ncurses shared libraries. I used a VM I had with gcc installed from openCSW.

First thing libevent, download and unpack it. Then:

$ cd libevent-2.0.21-stable
$ ./configure --prefix=/tmp/tmux-install
$ make && make install

Next goes ncurses,  download  and unpack. Then:

$ export AR=gar
$ ./configure --prefix=/tmp/tmux-install --without-cxx-binding
$ make && make install

And finally we can compile tmux itself. This is abit trickier , as it seems tmux doesn’t directly support Solaris. Download and unpack.  You need to apply the following patch:

diff -ur tmux-1.8/client.c tmux-1.8-patched/client.c
--- tmux-1.8/client.c	Sun Mar 17 16:03:37 2013
+++ tmux-1.8-patched/client.c	Mon Nov 18 22:29:59 2013
@@ -33,6 +33,39 @@
 
 #include "tmux.h"
 
+/* BEGIN SOLARIS 11 FIX */
+#ifndef LOCK_SH
+#define LOCK_SH 1 /* shared lock */
+#define LOCK_EX 2 /* exclusive lock */
+#define LOCK_NB 4 /* don’t block when locking */
+#define LOCK_UN 8 /* unlock */
+#endif
+int flock(int fd, int cmd);
+void cfmakeraw(struct termios *termios_p);
+int
+flock(int fd, int cmd)
+{
+    struct flock f;
+    memset(&f, 0, sizeof (f));
+    if (cmd & LOCK_UN)
+        f.l_type = F_UNLCK;
+    if (cmd & LOCK_SH)
+        f.l_type = F_RDLCK;
+    if (cmd & LOCK_EX)
+        f.l_type = F_WRLCK;
+    return fcntl(fd, (cmd & LOCK_NB) ? F_SETLK : F_SETLKW, &f);
+}
+void
+cfmakeraw(struct termios *termios_p)
+{
+    termios_p->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
+    termios_p->c_oflag &= ~OPOST;
+    termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
+    termios_p->c_cflag &= ~(CSIZE|PARENB);
+    termios_p->c_cflag |= CS8;
+}
+/* END SOLARIS 11 FIX */
+
 struct imsgbuf	client_ibuf;
 struct event	client_event;
 struct event	client_stdin;
diff -ur tmux-1.8/server-client.c tmux-1.8-patched/server-client.c
--- tmux-1.8/server-client.c	Tue Mar 26 21:22:31 2013
+++ tmux-1.8-patched/server-client.c	Mon Nov 18 22:34:13 2013
@@ -25,7 +25,20 @@
 #include 
 #include 
 #include 
+#include 
 
+#ifndef timersub
+# define timersub(a, b, result)						\
+	do {								\
+		(result)->tv_sec = (a)->tv_sec - (b)->tv_sec;		\
+		(result)->tv_usec = (a)->tv_usec - (b)->tv_usec;        \
+		if ((result)->tv_usec < 0) { \ + --(result)->tv_sec;				\
+			(result)->tv_usec += 1000000;			\
+		}                                                       \
+	} while (0)
+#endif
+
 #include "tmux.h"
 
 void	server_client_check_focus(struct window_pane *);

Use gpatch, obviuosly patch in Solaris carries some braindead Unix legacy which I don’t even want to know about:

$ gpatch -p1 < ../tmux-1.8-solaris.patch

Then we setup the CPP/LDFLAGS, ./configure and make:

$ export LIBEVENT_CFLAGS=-I/tmp/tmux-install/include
$ export LIBEVENT_LIBS="-lsendfile /tmp/tmux-install/lib/libevent.a -L/tmp/tmux-install/include"
$ CPPFLAGS="-D_XPG6" LDFLAGS="-D_XPG6" ./configure --prefix=/tmp/tmux-install/
$ make

Thats it 🙂 In the tmux source directory we have a tmux binary that depends only on system libraries so you can copy it to other Solaris boxes and use it there.

$ ldd tmux
        libxnet.so.1 =>  /lib/libxnet.so.1
        libsocket.so.1 =>        /lib/libsocket.so.1
        libnsl.so.1 =>   /lib/libnsl.so.1
        libcurses.so.1 =>        /lib/libcurses.so.1
        libsendfile.so.1 =>      /lib/libsendfile.so.1
        librt.so.1 =>    /lib/librt.so.1
        libresolv.so.2 =>        /lib/libresolv.so.2
        libc.so.1 =>     /lib/libc.so.1
        libmp.so.2 =>    /lib/libmp.so.2
        libmd.so.1 =>    /lib/libmd.so.1
        libscf.so.1 =>   /lib/libscf.so.1
        libaio.so.1 =>   /lib/libaio.so.1
        libdoor.so.1 =>  /lib/libdoor.so.1
        libuutil.so.1 =>         /lib/libuutil.so.1
        libgen.so.1 =>   /lib/libgen.so.1
        libm.so.2 =>     /lib/libm.so.2