Skip to content

Developer guides

Arun edited this page Aug 27, 2023 · 137 revisions

Release checklist

  1. Run tests with generated outdir files
  2. Update program options and help in Wiki, if required
  3. Update auto-completion scripts, if required
  4. Update VERSION in source
  5. Update the app_version section within misc/haiku/nnn.rdef.
  6. Also, change the variety from B_APPV_DEVELOPMENT to B_APPV_FINAL.
  7. Update date in man page
  8. Review list of auto-generated packages
  9. Update CHANGELOG
  10. Create signed tag and push to GitHub
  11. Run make O_NOUG=1 upload-local (requires libgpm-dev, upx, jq) to upload source package signature and static binary
  12. Create a GitHub release and populate the release notes from CHANGELOG
  13. Revert the variety back to B_APPV_DEVELOPMENT in /misc/haiku/nnn.rdef
  14. Notify downstream package maintainers

Verify sources

The sources tarball is signed with PGP key, which you can verify as following:

$ gpg --verify nnn-<VERSION>.tar.gz.sig nnn-<VERSION>.tar.gz
gpg: Signature made ...
gpg:                using RSA key BBAD0B2F3093A7C3377A8F6BA75979F35C080412
gpg: Good signature from "Arun Prakash Jana <...>"
Primary key fingerprint: BBAD 0B2F 3093 A7C3 377A  8F6B A759 79F3 5C08 0412

make options

nnn provides several make variables to customize the features to include or exclude. This also helps in reducing the binary size further.

Compile with PCRE

POSIX regex is the default. To enable PCRE, install the PCRE development library and set O_PCRE.

On Ubuntu 18.04:

sudo apt install libpcre3-dev
make O_PCRE=1

On macOS:

brew install pcre  # if you're using Homebrew
sudo port install pcre  # if you're using MacPorts
make O_PCRE=1

Compile out readline

make O_NORL=1

Compile out mouse support

make O_NOMOUSE=1

Compile out built-in feature-limited batch renamer

make O_NOBATCH=1

Use it if you have plugin .nmv (bash script).

Compile out FIFO

make O_NOFIFO=1

Compile out session support

make O_NOSSN=1

Compile out user, group details in status bar

make O_NOUG=1

Storing and decoding user and group info adds significantly to resident memory usage.

Compile-in icons-in-terminal

make O_ICONS=1

More details here. This variable is not compatible with O_NERD=1, O_EMOJI=1 and O_NOLC=1.

Compile-in icons-nerdfont

make O_NERD=1

More details here. This variable is not compatible with O_ICONS=1, O_EMOJI=1 and O_NOLC=1.

Compile-in emojis

make O_EMOJI=1

More details here. This variable is not compatible with O_ICONS=1, O_NERD=1 and O_NOLC=1.

Compile out locale

make O_NOLC=1

Unsupported characters in file names will be replaced by ?. Operations on files work seamlessly.

Compile out X11 integration

make O_NOX11=1

Disable notifications on cp, mv, rm completion, selection sync to system clipboard and xterm title advertisement on directory change.

Compile-in Alexey Tourbin's QSORT

make O_QSORT=1

Compile-in 8 contexts

make O_CTX8=1

Warning: Saved sessions may no longer be usable when the number of contexts is switched.

Matching filters only

make O_MATCHFLTR=1

Discard filter key when there's no match.

Load directories unsorted

make O_NOSORT=1

This option is useful in type-to-nav mode. Loads dirs faster on initial entry. Any filter sorts the listing. Usable with xterm 256 colors only.

Static compilation

Install the GPM development library and set the Makefile variable O_STATIC.

On Ubuntu 16.04/18.04:

sudo apt install libgpm-dev
make O_STATIC=1 strip

On macOS: It's not possible to compile with -static on macOS at the moment. So please ignore this option if you're on macOS.

This option will not work on Mac OS X unless all libraries (including libgcc.a) have also been compiled with -static. Since neither a static version of libSystem.dylib nor crt0.o are provided, this option is not useful to most people.

Verify the binary.

file nnn
nnn: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]=1be54d27687f83cf42393dd59dba2723798956de, stripped

Optimization tips

Careful use of make variables, static compilation and upx compression can do wonders!

$ make CFLAGS+=-march=native O_NORL=1 O_NOMOUSE=1 O_NOLC=1 O_NOBATCH=1 O_NOSSN=1 O_NOFIFO=1 O_QSORT=1 O_NOUG=1 static
$ upx nnn-static
$ ls -l nnn-static
-rwxrwxr-x 1 user user 593808 Nov  2 00:45 nnn-static

# top output (/usr/bin has 1544 files)

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND                             
  31953 user      20   0    2428   2244      4 S   0.0   0.0   0:00.02 ./nnn-static -cdDEnQrux /usr/bin

Compile for MacOS

On macos the default system ncurses library is too old and can cause issues (see https://github.com/jarun/nnn/issues/1703).

Install a more up to date version from homebrew and link against it via adding the library path to $LDLIBS

$ LDLIBS="-L/opt/homebrew/opt/ncurses/lib/" make

Compile for Pi

The nnn version available as a stable Raspbian package is very out of date (v2.2), which means that the only way to get a recent version of nnn is to compile from source.

As an example, to compile nnn v3.5 for a Raspberry Pi running Raspbian Buster, get nnn-v3.5.tar.gz from the release assets, put the tarball file on the Pi, and then do the following:

Install the required dependencies

sudo apt install pkg-config libncursesw5-dev libreadline-dev

Extract the tarball ready for compilation

tar -zxvf nnn-v3.5.tar.gz
cd nnn-3.5

Compile and install to default directory (/usr/local/bin)

sudo make strip install

The above was tested on a Raspberry Pi Zero W running Buster and worked with no problems.

Cygwin instructions

Copy to Windows clipboard from Cygwin

Install plugins and use the program option -x.

External editor on Cygwin

See jarun/nnn#1200.

Compile with musl libc

In this example we will compile nnn on Ubuntu 20.04 with

Discussion thread. See this patch to save some more on terminfo.

Compilation script for Ubuntu closely following this procedure.

Install musl

sudo apt install musl musl-dev musl-tools

Get netbsd-curses and compile the shared and static libraries

git clone https://github.com/sabotage-linux/netbsd-curses
cd netbsd-curses
git checkout v0.3.2
make CC=musl-gcc CFLAGS="-O3 -Wall -fPIC" -j$(($(nproc)+1)) all
sudo mkdir /opt/nnn-libs
sudo cp libcurses/libcurses.so libterminfo/libterminfo.so /opt/nnn-libs/
make clean
make CC=musl-gcc CFLAGS=-O3 LDFLAGS=-static all-static
sudo cp libcurses/libcurses.a libterminfo/libterminfo.a /opt/nnn-libs/

Get musl-fts and compile the shared and static binaries

git clone https://github.com/void-linux/musl-fts --depth=1
cd musl-fts
./bootstrap.sh
./configure
make CC=musl-gcc CFLAGS=-O3 LDFLAGS=-static -j$(($(nproc)+1))
sudo cp .libs/libfts.a /opt/nnn-libs/
make clean
make CC=musl-gcc CFLAGS=-O3 -j$(($(nproc)+1))
sudo cp .libs/libfts.so.0.0.0 /opt/nnn-libs/libfts.so

Get pcre and compile the shared and static binaries

wget https://downloads.sourceforge.net/pcre/pcre-8.45.tar.bz2
./configure --enable-unicode-properties --enable-pcre16 --enable-pcre32
make CFLAGS=-O3 CC=musl-gcc LDFLAGS=-static
sudo cp .libs/libpcre.a /opt/nnn-libs
make CFLAGS=-O3 CC=musl-gcc
sudo cp .libs/libpcre.so.1.2.13 /opt/nnn-libs

Compile nnn

# shared
musl-gcc -O3 -DNORL -DNOMOUSE -std=c11 -Wall -Wextra -Wshadow -I/path_to/netbsd-curses/libcurses -I/path_to/musl-fts -o nnn src/nnn.c -Wl,-Bsymbolic-functions -lpthread -L/opt/nnn-libs -lcurses -lterminfo -lfts

# shared custom
musl-gcc -O3 -DNORL -DNOLC -DNOMOUSE -DNOBATCH -DNOFIFO -DTOURBIN_QSORT -DNOSSN -DNOUG -DNOX11 -std=c11 -Wall -Wextra -Wshadow -I/path_to/netbsd-curses/libcurses -I/path_to/musl-fts -o nnn src/nnn.c -Wl,-Bsymbolic-functions -lpthread -L/opt/nnn-libs -lcurses -lterminfo -lfts

# Note 1: For static compilation append `-static` to the above commands
# Note 2: To enable pcre, add `-I./pcre-8.45` and `-lpcre`

# strip the binary
strip nnn

Run

# For shared lib
export LD_LIBRARY_PATH=/opt/nnn-libs:$LD_LIBRARY_PATH

# ./nnn

Cross-compile for Android

This section applies to Linux as host, Android on arm64 target and an xterm-256color terminal.

We are going to link statically against libreadline and libncursesw so we won't need to install them separately on the phone.

For anything else, please adjust accordingly.

Preparation

  • Download ncurses
  • Download readline
  • Extract ncurses and readline
  • Setup Android's NDK and make sure you export all the necessary variables for GNU Autoconf.
  • export ANDROID_ENV to be the location where we install our cross-compiled dependencies

Cross-compile ncurses

  • cd into ncurses' directory

  • configure

    ./configure --enable-widec --enable-termcap --with-fallbacks=xterm-256color --disable-stripping --host=aarch64-linux-android --prefix=$ANDROID_ENV
    
  • make and install

    make && make install
    

Cross-compile readline

  • cd into readline's directory

  • configure

    ./configure --enable-multibyte --with-curses --disable-shared --host=aarch64-linux-android --prefix=$ANDROID_ENV
    
  • make and install

    make && make install
    

Cross-compile nnn

  • cd into nnn's directory
  • export CFLAGS="$CFLAGS -I$ANDROID_ENV/include/ncursesw -I$ANDROID_ENV/include"
  • export LDFLAGS="$LDFLAGS -L$ANDROID_ENV/lib"
  • run make

Validate

file nnn should yield something like:

nnn: ELF 64-bit LSB shared object, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /system/bin/linker64, not stripped

Get nnn-ing

Move the binary to your phone and run with your favourite terminal emulator!

Debugging nnn

To debug nnn compile the program in debug mode:

make O_DEBUG=1

The run the generated binary:

./nnn

In debug mode nnn generates additional debug information which is logged in the file nnndbg located (by priority) at:

/tmp/nnndbg or,
the directory in which nnn is run

To log extra information, use the DPRINTF_* functions.

Clone this wiki locally