Need help porting Neovim to OpenWrt

I’m trying to make an OpenWrt package for Neovim (which I was surprised didn’t exist). I know it’s fairly easy to build Neovim directly under OpenWrt, as shown in this guide, so I came up with this Makefile for the package.

    include $(TOPDIR)/rules.mk

    PKG_NAME:=neovim
    PKG_VERSION:=0.11.5
    PKG_RELEASE:=1

    PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
    PKG_SOURCE_URL:=https://codeload.github.com/neovim/neovim/tar.gz/v$(PKG_VERSION)?
    PKG_HASH:=c63450dfb42bb0115cd5e959f81c77989e1c8fd020d5e3f1e6d897154ce8b771

    PKG_MAINTAINER:=
    PKG_LICENSE:=Apache-2.0
    PKG_LICENSE_FILES:=LICENSE

    PKG_BUILD_PARALLEL:=1
    PKG_BUILD_FLAGS:=

    include $(INCLUDE_DIR)/package.mk
    include $(INCLUDE_DIR)/cmake.mk

    define Package/neovim
      SECTION:=utils
      CATEGORY:=Utilities
      TITLE:=Hyperextensible Vim-based text editor
      URL:=https://github.com/neovim/neovim
      DEPENDS+=luajit
    endef

    define Package/neovim/description
      Neovim is a Vim-based text editor engineered for extensibility and usability,                                             to encourage new applications and contributions.
    endef

    define Package/neovim/install
    │       $(INSTALL_DIR) $(1)/usr/bin
    │       $(INSTALL_BIN) $(PKG_BUILD_DIR)/nvim $(1)/usr/bin/
    endef

    $(eval $(call BuildPackage,neovim))

The build fails, though, with the following error.

!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
Neovim doesn't support in-tree builds.  It's recommended that you
use a build/ subdirectory:
    mkdir build
    cd build
    cmake <OPTIONS> ..

Make sure to cleanup some CMake artifacts from this failed build
with:
    rm -rf CMakeFiles CMakeCache.txt
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

CMake Error at cmake/PreventInTreeBuilds.cmake:19 (message):
  Stopping build.
Call Stack (most recent call first):
  cmake/PreventInTreeBuilds.cmake:23 (PreventInTreeBuilds)
  CMakeLists.txt:35 (include)

I tried running make manually from the source directory, and Neovim builds successfully that way. If I’m not mistaken, the default compile function of the OpenWrt build system, $(Build/Compile/Default), should do the exact same thing — run makein the source directory, but there’s clearly something else going on.

I’m also looking for a clean way to pass an argument to make when cmake is involved, e.g. make CMAKE_BUILD_TYPE=RelWithDebInfo.

could be the reason.

Yes, but I’d like to figure out what makes it an in-tree build when the $(Build/Compile/Default)function is used (as opposed to calling makein the build directory from CLI) and what would be the clean workaround.

You can set “CMAKE_BINARY_DIR” or “CMAKE_BINARY_SUBDIR” (See https://github.com/openwrt/openwrt/blob/master/include/cmake.mk - Patch Fix)

And for params https://openwrt.org/docs/guide-developer/creating-a-cmake-package-in-openwrt#passing_cmake_options

Will be nice to see neovim as openwrt package :slight_smile:

1 Like

Thank you. With that I got to the point of realizing there are dependencies of Neovim entirely missing from the OpenWrt package feeds (e.g., tree-sitter). By default, Neovim builds its own dependencies, though. Of those, luajitwill fail to build for OpenWrt, so the best way forward I see is to let Neovim build some of its dependencies and take luajitfrom OpenWrt. For that, I tried to circumvent the cmakepart of the build system and use a build template from the Neovim documentation by removing include $(INCLUDE_DIR)/cmake.mkfrom the package Makefile and creating a custom Build/Compilesection with tree-sitter as something to try this on.

define Build/Compile
       cmake -S cmake.deps -B .deps -G tree-sitter \
       -D CMAKE_BUILD_TYPE=MinSizeRel \
       -DUSE_BUNDLED=OFF -DUSE_BUNDLED_TS=ON && \
       cmake --build .deps && \
       cmake -B build -G Ninja -D CMAKE_BUILD_TYPE=MinSizeRel && \
       cmake --build build
endef

However, the idea failed outright. Hopefully, someone with a better understanding of the OpenWrt build system will be interested in making it work.

For now, I’ve settled on the following solution. The guide I mentioned above worked well enough for building Neovim on the OpenWrt box itself with a few additional steps. Before building gettext as one of the depencencies, I had to install the libiconv-fullpackage and run export am_cv_func_iconv_works=yes(the latter possibly being an aarch64-specific fix not required for other platforms). I also used CMAKE_BUILD_TYPE=Releaseto not bloat the nvim binary and I built from the latest release tar.gz rather than the main git branch of Neovim.

After that, I bundled the nvim binary along with its runtime at /usr/share/neovimin thefilesdirectory of the OpenWrt build root to incorporate into new images, which I build from source every time.

So far it’s been working great even with LazyVim plugins, granted I use a rather beefy router (BPI-R4).

Yeah i have the same router :wink: i spent last days to figure it somehow out, but every time i fixed one step i came to the next :confused: i do not really like the idea to compile it directly inside openwrt. And it annoys me much more that it compiles inside openwrt but not in the build system :smiley:

1 Like

Ideally, we’d make all of the build dependencies of Neovim available as OpenWrt packages and not rely on bundled versions. So far I found that the existing luajit package builds just fine, luvrequired changing the minimum cmake version to 3.5 in the source CmakeLists.txt. tree-sitteris unavailable, but may be easy to port. Its libraries compiled just fine in the OpenWrt build system, and I managed to create a proper package for tree-sitter-cli(which is nice to have regardless) with this Makefile:

include $(TOPDIR)/rules.mk

PKG_NAME:=tree-sitter
PKG_VERSION:=0.25.10
PKG_RELEASE:=1

PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
PKG_SOURCE_URL:=https://codeload.github.com/tree-sitter/tree-sitter/tar.gz/v$(PKG_VERSION)?
PKG_HASH:=ad5040537537012b16ef6e1210a572b927c7cdc2b99d1ee88d44a7dcdc3ff44c

PKG_MAINTAINER:=
PKG_LICENSE:=MIT
PKG_LICENSE_FILES:=LICENSE

PKG_BUILD_DEPENDS:=rust/host
PKG_BUILD_PARALLEL:=1
PKG_BUILD_FLAGS:=
MAKE_PATH:=cli

include $(INCLUDE_DIR)/package.mk
include $(TOPDIR)/feeds/packages/lang/rust/rust-package.mk

define Package/tree-sitter-cli
  SECTION:=utils
  CATEGORY:=Utilities
  TITLE:=CLI tool for creating and testing Tree-sitter parsers
  URL:=https://github.com/tree-sitter/tree-sitter
  DEPENDS:=$(RUST_ARCH_DEPENDS)
endef

define Package/ctpv/description
  The Tree-sitter CLI allows you to develop, test, and use Tree-sitter grammars from the command line.
endef

$(eval $(call RustBinPackage,tree-sitter-cli))
$(eval $(call BuildPackage,tree-sitter-cli))

TheMAKE_PATH:=cliline could be the only difference between tree-sitterand tree-sitter-clihere, but I didn’t test packaging the actual libraries yet.

That leavesgettext,unibiliumand utf8proc, which are also not available as OpenWrt packages. lpegis available, but Neovim failed to find it for some reason. All of those happen to be build-time dependencies (i.e., PKG_BUILD_DEPENDS:= luv lpege.t.c.) and are not required on runtime.

Also, in the build guide for Neovim on OpenWrt, some stub libraries are created to link against. Apparently, those are build-time only as well. The binary is only linked to the real ones.

root@home-rt-edge-1 plugins # ldd /usr/bin/nvim
	/lib/ld-musl-aarch64.so.1 (0x7fa7c40000)
	libutil.so => /lib/ld-musl-aarch64.so.1 (0x7fa7c40000)
	libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x7fa7c0f000)
	libc.so => /lib/ld-musl-aarch64.so.1 (0x7fa7c40000)
1 Like

I’ve been chipping away at Neovim’s dependencies and got tree-sitter fully ported (CLI tool and library) andlpegpatched. Theluvpackage got a bugfix recently. So three down, three to go (gettext, unibilium and utf8proc). Hopefully, it won’t take me too long to create a full commit series to have Neovim in the OpenWrt repo.

So I finished porting the missing dependencies only to find out that Neovim’s build process starts using the code it has built, including the actual nvim binary (which, in case of cross-compiling, won’t run on the build host). Meaning, the whole chain of dependencies will have to be built as /hostpackages, then Neovim as /host to bootstrap the final build for the target architecture (see explanation). This is what some OpenWrt packages do, but I’m starting to question if it’ll fly for Neovim in the official repo since there’s not a lot of target system with resources to spare on running an IDE-like editor anyway. Those are probably capable of building Neovim locally. Or, at the very least, are x86 or aarch64 based, so an Alpine container can be used on a PC or Mac to build for them.

1 Like