Skip to content

Instantly share code, notes, and snippets.

@equalsraf
Last active October 8, 2017 09:44
Show Gist options
  • Save equalsraf/c9827e78893ca60a963ae133fe4b29ea to your computer and use it in GitHub Desktop.
Save equalsraf/c9827e78893ca60a963ae133fe4b29ea to your computer and use it in GitHub Desktop.
Try to build neovim in haiku

TLDR; it did not work, apparently the major blocker is libuv support

1. dependencies (i.e. nvim's third-party/)

Haiku already has some deps, lets use its packages. But for libvterm, etc we need to use third-party

mkdir .deps
cd .deps
cmake ../third-party/ -DUSE_BUNDLED_LUAJIT=NO -DUSE_BUNDLED_LIBUV=NO -DUSE_BUNDLED_LUAROCKS=YES -DUSE_BUNDLED_LUAJIT=NO -DUSE_BUNDLED_JEMALLOC=NO
make

Right now luarocks fails to build because it cant find the lua headers (but they are installed)

Checking Lua includes... lua.h not found (looked in //include, //include/lua/5.1, //include/lua5.1)
  • it seems the luajit.pc from the haiku packages reports the wrong path, but I dont know how to edit the read-only file in /boot/system/develop/lib/pkgconfig

We can not use our luajit from third-party because it fails to build ``

lj_alloc.c:255:2: error: #error "NYI: need an equivalent of MAP_32BIT for this 64 bit OS"
 #error "NYI: need an equivalent of MAP_32BIT for this 64 bit OS"

You can work around this one by adding an || defined(__HAIKU__) to the corresponding ifdef, assuming this is correct (I have no idea really!!!). This will allow luajit to build.

With this workaround luarocks still fails to build, you get

Your version of Lua does not support io.popen,
which is required by LuaRocks. Please check your Lua installation.

Related issue luarocks/luarocks#348

For now lets settle for cmake ../third-party/ -DUSE_BUNDLED_LUAJIT=NO -DUSE_BUNDLED_LIBUV=NO -DUSE_BUNDLED_LUAROCKS=NO -DUSE_BUNDLED_LUAJIT=NO -DUSE_BUNDLED_JEMALLOC=NO and use system packages for everything else.

2. Build lpeg

3. Build lua-mpack

Its easier to use an older version of lua-mpack, before it was split into multiple repos

git clone https://github.com/libmpack/libmpack
git checkout 1.0.4
cd bindings/lua
make USE_SYSTEM_LUA=yes CFLAGS=-std=c99

This will create mpack.so, you will need this later too.

4. Prepare lua environment

Now pick a directory to put those lua .so modules. For example I used ~/Code/neovim/build, and export the following variable

export LUA_CPATH=~/Code/neovim/build/?.so

If you open luajit now you should be able to

> require('mpack')
> require('lpeg')

So as long as that environment variable is set it should work. This is needed because I have not figured out where to put those modules in haiku (... and I'm to lazy to package them).

5. Build neovim

mkdir build
cd build
cmake ..
make

Currently this is failling

[ 50%] Building C object src/nvim/CMakeFiles/nvim.dir/api/private/dispatch.c.o
In file included from /boot/system/develop/headers/posix/sys/socket.h:12:0,
                 from /boot/system/develop/headers/uv-unix.h:30,
                 from /boot/system/develop/headers/uv.h:62,
                 from /boot/home/Code/neovim/src/nvim/os/fs_defs.h:4,
                 from /boot/home/Code/neovim/src/nvim/buffer_defs.h:109,
                 from /boot/home/Code/neovim/src/nvim/normal.h:6,
                 from /boot/home/Code/neovim/src/nvim/ex_cmds_defs.h:8,
                 from /boot/home/Code/neovim/src/nvim/ex_eval.h:5,
                 from /boot/home/Code/neovim/src/nvim/globals.h:8,
                 from /boot/home/Code/neovim/src/nvim/vim.h:303,
                 from /boot/home/Code/neovim/src/nvim/api/private/dispatch.c:12:
/boot/system/develop/headers/posix/sys/uio.h:12:16: error: redefinition of 'struct iovec'
 typedef struct iovec {
                ^
In file included from /boot/system/develop/headers/msgpack.h:22:0,
                 from /boot/home/Code/neovim/src/nvim/api/private/dispatch.c:8:
/boot/system/develop/headers/msgpack/vrefbuffer.h:19:8: note: originally defined here
 struct iovec {
        ^
src/nvim/CMakeFiles/nvim.dir/build.make:1258: recipe for target 'src/nvim/CMakeFiles/nvim.dir/api/private/dispatch.c.o' failed
make[2]: *** [src/nvim/CMakeFiles/nvim.dir/api/private/dispatch.c.o] Error 1
CMakeFiles/Makefile2:2446: recipe for target 'src/nvim/CMakeFiles/nvim.dir/all' failed
make[1]: *** [src/nvim/CMakeFiles/nvim.dir/all] Error 2
Makefile:151: recipe for target 'all' failed
make: *** [all] Error 2

The relevant bit from the msgpack headers is

#if defined(unix) || defined(__unix) || defined(__APPLE__)
#include <sys/uio.h>
#else
struct iovec {
    void  *iov_base;
    size_t iov_len;
};
#endif

So the messagepack headers consider haiku is not posix compatible. This happens both with the haiku package and our version from third-party.

So I removed the system package for message pack and edited the header in ../.deps/usr/include/msgpack/vrefbuffer.h to add || defined(__HAIKU__), sidestepping that issue.

Retrying moves along, but fails with

[  0%] Building C object src/nvim/CMakeFiles/nvim.dir/os/fs.c.o
/boot/home/Code/neovim/src/nvim/os/fs.c: In function 'os_readv':
/boot/home/Code/neovim/src/nvim/os/fs.c:519:47: warning: conversion to 'size_t {aka long unsigned int}' from 'int' may change the sign of the result [-Wsign-conversion]
     ptrdiff_t cur_read_bytes = readv(fd, iov, (int)iov_size);
                                               ^
In file included from /boot/home/Code/neovim/src/nvim/os/fs.c:25:0:
/boot/home/Code/neovim/src/nvim/os/fs.c: In function 'os_translate_sys_error':
/boot/home/Code/neovim/src/nvim/os/fs.c:1199:17: warning: integer overflow in expression [-Woverflow]
   STATIC_ASSERT(-ENOMEM == UV_ENOMEM, "Need to translate error codes");
                 ^
/boot/home/Code/neovim/src/nvim/assert.h:65:60: note: in definition of macro 'STATIC_ASSERT_STATEMENT'
 # define STATIC_ASSERT_STATEMENT(cond, msg) _Static_assert(cond, msg)
                                                            ^
/boot/home/Code/neovim/src/nvim/os/fs.c:1199:3: note: in expansion of macro 'STATIC_ASSERT'
   STATIC_ASSERT(-ENOMEM == UV_ENOMEM, "Need to translate error codes");
   ^
[  0%] Building C object src/nvim/CMakeFiles/nvim.dir/os/input.c.o
[  0%] Building C object src/nvim/CMakeFiles/nvim.dir/os/mem.c.o
[  0%] Building C object src/nvim/CMakeFiles/nvim.dir/os/pty_process_unix.c.o
/boot/home/Code/neovim/src/nvim/os/pty_process_unix.c: In function 'pty_process_spawn':
/boot/home/Code/neovim/src/nvim/os/pty_process_unix.c:55:13: warning: implicit declaration of function 'forkpty' [-Wimplicit-function-declaration]
   int pid = forkpty(&master, NULL, &termios, &ptyproc->winsize);
             ^
/boot/home/Code/neovim/src/nvim/os/pty_process_unix.c: In function 'init_termios':
/boot/home/Code/neovim/src/nvim/os/pty_process_unix.c:174:3: warning: implicit declaration of function 'cfsetspeed' [-Wimplicit-function-declaration]
   cfsetspeed(termios, 38400);
   ^
/boot/home/Code/neovim/src/nvim/os/pty_process_unix.c:211:17: error: 'VREPRINT' undeclared (first use in this function)
   termios->c_cc[VREPRINT] = 0x1f & 'R';
                 ^
/boot/home/Code/neovim/src/nvim/os/pty_process_unix.c:211:17: note: each undeclared identifier is reported only once for each function it appears in
/boot/home/Code/neovim/src/nvim/os/pty_process_unix.c:212:17: error: 'VWERASE' undeclared (first use in this function)
   termios->c_cc[VWERASE]  = 0x1f & 'W';
                 ^
/boot/home/Code/neovim/src/nvim/os/pty_process_unix.c:213:17: error: 'VLNEXT' undeclared (first use in this function)
   termios->c_cc[VLNEXT]   = 0x1f & 'V';
                 ^
src/nvim/CMakeFiles/nvim.dir/build.make:3082: recipe for target 'src/nvim/CMakeFiles/nvim.dir/os/pty_process_unix.c.o' failed

The forkpty() function seems to be missing. The symbol itself seems to be in libbsd.so, and there is an extern declaration in posix/bsd/pty.h. I was expecting to find a util.h header like in other BSDs, but there is none.

A quick workaround diff was this. Notice that the include for libutil.h does not change the warning for forkpty. For now I just commented the missing symbols, we would need to add a platform check in config/CMakelists.txt and config/config.h.in to wrap those properly.

diff --git a/src/nvim/os/pty_process_unix.c b/src/nvim/os/pty_process_unix.c
index ee3ab96a8..1e6228976 100644
--- a/src/nvim/os/pty_process_unix.c
+++ b/src/nvim/os/pty_process_unix.c
@@ -12,9 +12,9 @@
 #include <sys/ioctl.h>
 
 // forkpty is not in POSIX, so headers are platform-specific
-#if defined(__FreeBSD__) || defined (__DragonFly__)
+#if defined(__FreeBSD__) || defined (__DragonFly__) || defined(__HAIKU__)
 # include <libutil.h>
-#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
+#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__) 
 # include <util.h>
 #else
 # include <pty.h>
@@ -171,7 +171,7 @@ static void init_termios(struct termios *termios) FUNC_ATTR_NONNULL_ALL
   termios->c_cflag = CS8|CREAD;
   termios->c_lflag = ISIG|ICANON|IEXTEN|ECHO|ECHOE|ECHOK;
 
-  cfsetspeed(termios, 38400);
+//  cfsetspeed(termios, 38400);
 
 #ifdef IUTF8
   termios->c_iflag |= IUTF8;
@@ -208,9 +208,9 @@ static void init_termios(struct termios *termios) FUNC_ATTR_NONNULL_ALL
   termios->c_cc[VSTART]   = 0x1f & 'Q';
   termios->c_cc[VSTOP]    = 0x1f & 'S';
   termios->c_cc[VSUSP]    = 0x1f & 'Z';
-  termios->c_cc[VREPRINT] = 0x1f & 'R';
-  termios->c_cc[VWERASE]  = 0x1f & 'W';
-  termios->c_cc[VLNEXT]   = 0x1f & 'V';
+//  termios->c_cc[VREPRINT] = 0x1f & 'R';
+//  termios->c_cc[VWERASE]  = 0x1f & 'W';
+//  termios->c_cc[VLNEXT]   = 0x1f & 'V';
   termios->c_cc[VMIN]     = 1;
   termios->c_cc[VTIME]    = 0;
 }

After this it fails to link because it cant find -lutil. This is not unexpected, we need to link against libbsd instead of libutil. After that you get a lot of missing symbols starting with __stack this is a known issue, in some systems building with stack protection does not work, it seems to be the case here (I have not checked this deeper). Here is a dirty diff to confirm this

qdiff --git a/CMakeLists.txt b/CMakeLists.txt
index df29774d4..d23700f91 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -239,7 +239,7 @@ if(UNIX)
   check_c_compiler_flag(-fstack-protector HAS_FSTACK_PROTECTOR_FLAG)
 
   if(HAS_FSTACK_PROTECTOR_STRONG_FLAG)
-    add_definitions(-fstack-protector-strong)
+#    add_definitions(-fstack-protector-strong)
   elseif(HAS_FSTACK_PROTECTOR_FLAG)
     add_definitions(-fstack-protector --param ssp-buffer-size=4)
   endif()
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt
index e2f1f1663..424160f51 100644
--- a/src/nvim/CMakeLists.txt
+++ b/src/nvim/CMakeLists.txt
@@ -375,7 +375,7 @@ list(APPEND NVIM_LINK_LIBRARIES
 if(UNIX)
   list(APPEND NVIM_LINK_LIBRARIES
     m
-    util
+    bsd
   )
 endif()

Still some missing symbols

[  0%] Linking C executable ../../bin/nvim
CMakeFiles/nvim.dir/os/fs.c.o: In function `os_exepath':
/boot/home/Code/neovim/src/nvim/os/fs.c:214: undefined reference to `uv_exepath'
CMakeFiles/nvim.dir/os/mem.c.o: In function `os_get_total_mem_kib':
/boot/home/Code/neovim/src/nvim/os/mem.c:14: undefined reference to `uv_get_total_memory'
CMakeFiles/nvim.dir/shada.c.o: In function `msgpack_read_uint64':
/boot/home/Code/neovim/src/nvim/shada.c:3231: undefined reference to `be64toh'
collect2: error: ld returned 1 exit status

A similar issue is luvit/luv#229 but if that is the case, there is some problem with the libuv library. We can actually implement fallbacks for this in neovim, a full patch would require platform function checks, the quick hack is

diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c
index 78627f870..c261a96c9 100644
--- a/src/nvim/os/fs.c
+++ b/src/nvim/os/fs.c
@@ -211,7 +211,11 @@ int os_nodetype(const char *name)
 int os_exepath(char *buffer, size_t *size)
   FUNC_ATTR_NONNULL_ALL
 {
+#ifdef __HAIKU__
+  return UV_ENOENT;
+#else
   return uv_exepath(buffer, size);
+#endif
 }
 
 /// Checks if the given path represents an executable file.
diff --git a/src/nvim/os/mem.c b/src/nvim/os/mem.c
index eccb3c97e..77152b959 100644
--- a/src/nvim/os/mem.c
+++ b/src/nvim/os/mem.c
@@ -10,6 +10,11 @@
 /// Get the total system physical memory in KiB.
 uint64_t os_get_total_mem_kib(void)
 {
+#ifdef __HAIKU__
+  // FIXME(@equalsraf): I believe this was the default fallback in Vim
+  return 0x1fffff;
+#else
   // Convert bytes to KiB.
   return uv_get_total_memory() / 1024;
+#endif
 }

The be64toh is actually a macro available from bsd/endian.h. But it is not being included in neovim, neovim/neovim#4755 has a full example for this type of check. It is not working as intended though because haiku has an endian.h that does not define the macro, but it seems to import it some other way - so the configuration check for be64toh succeeds but the actual build fails. I have not been able to fix this check so I broke it instead, forcing the use of the builtin version

diff --git a/config/CMakeLists.txt b/config/CMakeLists.txt
index c3643db20..7bbcf1c93 100644
--- a/config/CMakeLists.txt
+++ b/config/CMakeLists.txt
@@ -74,7 +74,7 @@ endif()
 check_include_files("endian.h" HAVE_ENDIAN_H)
 check_include_files("sys/endian.h" HAVE_SYS_ENDIAN_H)
 
-set(ENDIAN_INCLUDE_FILE "endian.h")
+set(ENDIAN_INCLUDE_FILE "XXXXXXXXXX")
 if(HAVE_SYS_ENDIAN_H AND NOT HAVE_ENDIAN_H)
   set(ENDIAN_INCLUDE_FILE "sys/endian.h")
 endif()

And now we have one more error

[100%] Built target printargs-test
runtime_loader: /boot/system/lib/libuv.so.1.0.0: Could not resolve symbol 'uv__io_check_fd'
resolve symbol "uv__io_check_fd" returned: -2147478780
runtime_loader: /boot/system/lib/libuv.so.1.0.0: Troubles relocating: Symbol not found

this seems related :)

So it seems someone has been working on libuv support for haiku. But that last PR was not merged. The system pkgs are broken. I tried build libuv from that PR but still got a lot of missing symbols.

Other pitfalls

  • make sure all lua modules link against the same version of lua, usually 5.1 or luajit
  • robcsi reported the pthread check was failling, but I did not bump into this issue
  • my notes are step by step, but you might have to restart the build by removing CMakeCache.txt for some changes

Next steps

  1. Work on porting libuv for haiku
  2. submit haiku fix for msgpack headers, or work it out in haiku packages
  3. Open tracking issue in neovim/neovim for haiku support
  4. Open upstream issues in dependencies and/or fix haiku packages (luajit, luarocks, etc)
  5. (maybe) package lua modules e.g. lpeg, bitops, mpack. But its always better to get luarocks working, because we need it for tests anyway.
  6. Some of the dirty patches above probably deserve an issue in neovim/neovim (that be64toh seems very strange)
@robcsi
Copy link

robcsi commented Oct 8, 2017

There was also a problem with the unibilium on HaikuOS. The devel package couldn't be deployed, it's recipe was broken. I've fixed and pushed that to the HaikuPorts repo.
It should now be possible to build it from the repo.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment