[GUIDE] How to build lbrynet on NetBSD [Step by step]

I can’t edit posts on this forum, so you might find later updates of this guide here. If you have any issues following the instructions, feel free to comment below.

This has been tested on NetBSD 10.0 amd64.

WARNING: At the time of writing, the latest lbry-sdk release is v0.113.0, which needs Python 3.7 due to a bug. Python 3.7 is EOL. lbry-sdk requires older dependencies & they might have vulnerabilities. Please use security measures to protect your system if that’s important to you.

I figured it would be a good idea to keep lbry-sdk or lbrynet dependencies independent of the system /usr/local. This way we don’t have to mess with anything already installed and removal would be easier (if you desire to do so later). So after building from source, installations will go to /usr/local/lbdeps and they’ll have -Wl,R or -Wl,rpath linking option added to them so that setting LD_LIBRARY_PATH environment variable is not necessary every time using them. So we need to build from sources. Don’t worry. These instructions are written so that almost anyone can follow.

I tried to make this as easy as possible. The other alternative would be to manually go through revisions in NetBSD packages source code for multiple packages, which might be even harder to follow. But let me know if this can be made easier.

If this sounds a bit hard to follow, you can download a compiled binary copy of lbrynet for NetBSD.

For laptops: If your machine is getting very hot during builds, you might try some tips from this tuning NetBSD article. Modern machines usually take care of heat management by themselves, but in my experience NetBSD hasn’t been good. e.g. [acpifan(4) says that it “does not support controlling the fan”]. So this might still be inadequate. If it still overheats, try cleaning the insides (if you are allowed/able to) or place a table fan towards the machine’s hottest place.

Step 0: Basic prep

You should have pkgin to install packages. If you don’t have it already:

#~ Login as root or run su, then edit .profile and uncomment
#~ the export PKG_PATH line. Then run: pkg_add pkgin
#~ Or to do this manually instead, run:
# PKG_PATH=https://cdn.netbsd.org/pub/pkgsrc/packages/NetBSD/$(uname -m)/$(uname -r)/All pkg_add pkgin
# pkgin update

I’ll use doas. sudo might also work. No matter which one you use, be sure to configure it for your nonroot user first. Also, my shell is bash.

I have done something like this (feel free to adapt to your liking):

# pkgin install doas bash
# echo 'permit nopass setenv { PATH=$PATH } :wheel as root' > /usr/pkg/etc/doas.conf
# usermod -G wheel nonrootusername
#~ change shell to bash
# chsh -s /usr/pkg/bin/bash nonrootusername
#~ logout (and make sure you are logged in as the nonroot user)
# exit

NOTE: If you use doas, the setenv {...} part is important because by default doas doesn’t pass $PATH to root shell, so commands may fail.

Here are some basic packages needed:

$ doas pkgin install git-base gnupg2 gmake libtool-base pkgconf \
autoconf automake
#~ If it's not already installed, install latest Python 3 available
$ PYLATEST=$(pkgin se '^python3' | sort -t. -n -k1,1 -k2,2 -k3,3 -k4,4 | \
sed -ne 's/\(^py.*[0-9]\)\-.*/\1/gp' | tail -n1)
$ find /usr/pkg/bin -name 'python3\.[0-9][2]' -type f &>/dev/null \
|| doas pkgin install $PYLATEST
#~ If we can just execute "python3" it'll be Useful later for
#~ running commands and scripts.
$ PYFOUND=$(find /usr/pkg/bin -name 'python3\.[0-9][2]' -type f | tail -n1)
$ [ $PYFOUND ] && doas ln -s $PYFOUND /usr/pkg/bin/python3
#~ If it's not already installed, install a version of GCC
#~ To keep it consistent with pkgsrc, we can use GCC version
#~ used to build python3
$ gcc --version &>/dev/null || doas pkgin install "gcc$(python3 -VV | \
sed -ne 's/.*GCC \([0-9]*\)\..*/\1/p')"

Prepare dir for sources:

$ cd ~
$ mkdir lbrepos

Step 1: Building OpenSSL 1.x from source

lbrynet 0.113.0 requires Python cryptography==2.5, for which, we need OpenSSL 1.x. 1.1.1w is the latest 1.x version as of writing this.

$ cd ~/lbrepos
#~ OpenSSL 1.1.1w is latest atm. Later versions might also work, but not tested.
$ git clone --depth 1 -b OpenSSL_1_1_1w https://github.com/openssl/openssl
$ cd openssl
$ ./config -fPIC -shared --prefix=/usr/local/lbdeps
$ gmake  # GNU Make is gmake on NetBSD
$ doas gmake all install_sw

If you get a “sh: gmake: not found” error meesage, it is possible that doas.conf is not exactly how I mentioned above and doas is resetting your $PATH to a value which does not include /usr/pkg/bin. You might fix doas.conf to pass the $PATH (recommended) or set MAKE, i.e. doas gmake MAKE=/usr/pkg/bin/gmake all install_sw. First fix is recommended because you’ll get more errors like this. e.g. One other gmake command and doas b2 ... commands might cause issues. Fixing them manually would be a chore.

Step 2: Install Python 3.7

We’re going to use a separate sqlite install for python to use to get around an error I faced. Relax, we’re going to use amalgamation autoconf source code to make this super easy:

$ cd ~/lbrepos
#~ SQLite 3.46.0 is used here. Later versions might also work, but not tested.
$ curl -LO https://sqlite.org/2024/sqlite-autoconf-3460000.tar.gz
$ tar -xvf sqlite-autoconf-3460000.tar.gz
$ cd sqlite-autoconf-3460000
$ ./configure --prefix=/usr/local/lbdeps
$ gmake
$ doas gmake install

To test (optional):

$ echo .version | /usr/local/lbdeps/bin/sqlite3
#~ It should say "SQLite version 3.46.0"
$ echo .dbconfig | /usr/local/lbdeps/bin/sqlite3 | grep load_extension
#~ In the above output "load_extension" should be "on" if you want to use it
#~ with "--enable-loadable-sqlite-extensions" python configuration option.

Let’s install Python 3.7:

$ cd ~/lbrepos
$ PYVER=3.7.17
$ curl -LO https://www.python.org/ftp/python/$PYVER/Python-$PYVER.tar.xz.asc
$ curl -LO https://www.python.org/ftp/python/$PYVER/Python-$PYVER.tar.xz
#~ Got the gpg fingerprint below from https://www.python.org/downloads/ under
#~ "OpenPGP Public Keys" heading, which also links to https://keybase.io/nad/
$ gpg2 --keyserver hkps://keys.openpgp.org --recv-keys 2D347EA6AA65421D FB9921286F5E1540
$ gpg2 --verify Python-$PYVER.tar.xz.asc
#~ If it says 'Good signature from "Ned Deily (Python release
#~ signing key) <nad@python.org>"' then it's a good copy.
#~ If it doesn't say above, discard the copy and download again.

$ tar -xvf Python-$PYVER.tar.xz
$ cd Python-$PYVER

#~ For "No module named '_ctypes'" error we need libffi and --with-system-ffi etc.
#~ https://stackoverflow.com/questions/55867213/building-python3-7-3-from-source-missing-ctypes
#~ PKG_CONFIG_PATH might be needed which is also covered later
#~ https://github.com/pyenv/pyenv/issues/1183#issuecomment-421401095
$ doas pkgin install libffi

Now to build:

#~ You can add "--enable-optimizations" to the following. It will take some
#~ extra time to build, but resulting python "can significantly enhance the 
#~ execution speed of Python programs" (https://dnmtechs.com/understanding-the-purpose-of-enable-optimizations-flag-in-python-3-compilation/)
$ ./configure --enable-shared --enable-loadable-sqlite-extensions \
--with-system-ffi --with-ensurepip=install --prefix=/usr/local/lbdeps \
--with-openssl=/usr/local/lbdeps \
CFLAGS="-I/usr/local/lbdeps/include -I/usr/local/include/xorg \
-I/usr/local/include" \
LDFLAGS="-L/usr/local/lbdeps/lib -Wl,-R/usr/local/lbdeps/lib \
-L/usr/X11R7/lib -Wl,-R/usr/X11R7/lib -L/usr/local/lib \
-Wl,-R/usr/local/lib -L/usr/pkg/lib -Wl,-R/usr/pkg/lib" \
PKG_CONFIG_PATH="/usr/local/lbdeps/lib/pkgconfig:/usr/pkg/lib/pkgconfig"
$ gmake
$ gmake test  # optional
$ doas gmake altinstall

Test:

$ /usr/local/lbdeps/bin/python3.7 --version
Python 3.7.17
$ /usr/local/lbdeps/bin/python3.7 -c \
'import sqlite3; print(sqlite3.sqlite_version)'
3.46.0
$ /usr/local/lbdeps/bin/python3.7 -c \
'import ssl; print(ssl.OPENSSL_VERSION)'
OpenSSL 1.1.1w  11 Sep 2023

Step 3: Prepare lbry-sdk venv

$ cd ~/lbrepos
$ git clone --depth 1 -b v0.113.0 https://github.com/lbryio/lbry-sdk.git
$ cd lbry-sdk
$ /usr/local/lbdeps/bin/python3.7 -m venv lbry-venv
$ source lbry-venv/bin/activate

This will add a (lbry-venv) prefix to your shell prompt. It means you are in a venv with python 3.7 being the default python. The bug I mentioned at the beginning is the reason why we need to follow the build process in a python 3.7 venv. Don’t exit this venv unless the guide tells you later.

$ pip install --upgrade pip  # upgrade pip to get rid of messages
$ python --version  # it should say "Python 3.7.17"

Step 4: libtorrent Python Bindings

Without quitting venv:

$ cd ~/lbrepos
#~ Used 1.84.0 here. Later versions might also work, but not tested.
$ curl -LO https://github.com/boostorg/boost/releases/download/boost-1.84.0/boost-1.84.0.tar.xz
$ tar -xvf boost-1.84.0.tar.xz
$ cd boost-1.84.0
#~ Very IMPORTANT for building libtorrent
$ export BOOST_ROOT=$PWD  # the directory with directories like libs, more, status
$ export BOOST_BUILD_PATH=$BOOST_ROOT/tools/build

Build b2 from source to be used later on:

$ cd "$BOOST_BUILD_PATH"
$ ./bootstrap.sh
#~ So that we can use b2 binary that we just built without installing
#~ on system
$ export PATH="$BOOST_BUILD_PATH:$PATH"
#~ The following output should not show b2 from /usr/local, but from
#~ our ~/lbrepos directory
$ which b2
/home/username/lbrepos/boost-1.84.0/tools/build/b2

Now create ~/user-config.jam and put:

using python : 3.7 : /usr/local/lbdeps/bin/python3.7
  : /usr/local/lbdeps/include/python3.7m
  : /usr/local/lbdeps/lib/python3.7 ;
using gcc : libtorrent : g++
  : <cxxflags>-fext-numeric-literals <compileflags>-fPIC
  <compileflags>-I/usr/local/lbdeps/include
  <linkflags>-L/usr/local/lbdeps/lib
  <linkflags>-Wl,-R/usr/local/lbdeps/lib
  <linkflags>-Wl,-rpath=/usr/pkg/gcc10/lib ;

When gcc --version is run on my system it shows gcc (nb3 20231008) 10.5.0, so I ran pkgin pkg-content gcc10 | grep '\/gcc.*\/lib\/libstdc++.so$' | xargs dirname which returned /usr/pkg/gcc10/lib. So added <linkflags>-Wl,-rpath=/usr/pkg/gcc10/lib above. If you have a different version, change it accordingly in above file.

We need to make sure that running doas b2 finds this same .jam file, we need to have the same file as /root/user-config.jam:

$ doas ln -s /home/$USER/user-config.jam /root/user-config.jam

Let’s build boost libraries needed and install them:

$ cd "$BOOST_ROOT"
$ b2 --with-system --with-python
$ doas b2 --with-system --with-python \
install --prefix=/usr/local/lbdeps

Now to libtorrent python bindings:

$ cd ~/lbrepos
#~ tar download has all submodules populated - more convenient
#~ libtorrent version 2.0.6 is reuired by lbry-sdk 0.113.0
$ curl -LO https://github.com/arvidn/libtorrent/releases/download/v2.0.6/libtorrent-rasterbar-2.0.6.tar.gz
$ tar -xvf libtorrent-rasterbar-2.0.6.tar.gz
$ cd libtorrent-rasterbar-2.0.6

We need a fix for a rule "version.boost-build" unknown error. We also need some NetBSD specific changes. Save this in a file called myfix.patch:

diff --git a/Jamfile b/Jamfile
index a8c476b..c3593cd 100644
--- a/Jamfile
+++ b/Jamfile
@@ -22,6 +22,8 @@ ECHO "CXXFLAGS =" $(CXXFLAGS) ;
 ECHO "LDFLAGS =" $(LDFLAGS) ;
 ECHO "OS =" [ os.name ] ;
 
+jam-version = [ modules.peek : JAM_VERSION ] ;
+
 if $(BOOST_ROOT)
 {
 	ECHO "building boost from source directory: " $(BOOST_ROOT) ;
@@ -163,10 +165,11 @@ rule linking ( properties * )
 		# which only works on ELF targets with gcc
 		result += <linkflags>-Wl,--export-dynamic <linkflags>-rdynamic ;
 	}
-	else
+	else if [ version.version-less $(jam-version) : 1990 0 ]
 	{
-		# backtraces don't work with visibility=hidden, so we only add that in
-		# the else-block
+		# the visibility feature was introduced in boost-1.69. This was close to
+		# when the verisoning scheme changed from year to (low) version numbers.
+		# in boost-1.70
 		result += <visibility>hidden ;
 	}
 
@@ -301,11 +304,11 @@ rule building ( properties * )
 	}
 
 	local VERSION = [ feature.get-values <cxxstd> : $(properties) ] ;
-	if ! $(VERSION) || $(VERSION) < 14
-	{
-		ECHO "libtorrent requires at least C++14. Specify cxxstd=14 or higher" ;
-		result += <build>no ;
-	}
+	#if ! $(VERSION) || $(VERSION) < 14
+	#{
+	#	ECHO "libtorrent requires at least C++14. Specify cxxstd=14 or higher" ;
+	#	result += <build>no ;
+	#}
 
 	if <toolset>msvc in $(properties) || <toolset>intel-win in $(properties)
 	{
@@ -920,7 +923,7 @@ lib torrent
 
 	: # default build
 	<threading>multi
-	<cxxstd>14
+	#<cxxstd>14
 	<c++-template-depth>512
 
 	: # usage requirements
@@ -940,8 +943,10 @@ rule install-paths ( properties * )
 	# package.paths was introduced in boost-1.70 (2018.02)
 	# however, boost build's versioning scheme changed in boost-1.71 to version
 	# 4.0
-	local boost-build-version = [ SPLIT_BY_CHARACTERS [ version.boost-build ] : "-" ] ;
-	if [ version.version-less [ SPLIT_BY_CHARACTERS $(boost-build-version[1]) : "." ] : 2018 03 ]
+	# so, if versions are 4.0+ we want to use package.paths, but if it's a year,
+	# say 2018, that means it's old and we use the fallback below. Any version <
+	# 1990 is considered the 4.0 and later numbering scheme.
+	if [ version.version-less 1990 0 : $(jam-version) ]
 	{
 		import option ;
 		import property ;
diff --git a/bindings/python/Jamfile b/bindings/python/Jamfile
index 6a4e461..730d820 100644
--- a/bindings/python/Jamfile
+++ b/bindings/python/Jamfile
@@ -291,7 +291,7 @@ my-python-extension libtorrent
 	<toolset>msvc:<cxxflags>/wd4268
 	: # default-build
 	<warnings>all
-	<cxxstd>14
+	#<cxxstd>14
 	: # usage-requirements
 	<suppress-import-lib>false
 	;
@@ -344,7 +344,7 @@ install stage_module
 	: libtorrent
 	: <location>.
 	<install-type>PYTHON_EXTENSION
-	: <cxxstd>14
+	: #<cxxstd>14
 	;
 
 install stage_dependencies
@@ -354,7 +354,7 @@ install stage_dependencies
 	: <location>dependencies
 	<install-dependencies>on
 	<install-type>SHARED_LIB
-	: <cxxstd>14
+	: #<cxxstd>14
 	;
 
 explicit stage_module ;
diff --git a/src/platform_util.cpp b/src/platform_util.cpp
index 505c9c9..75556ca 100644
--- a/src/platform_util.cpp
+++ b/src/platform_util.cpp
@@ -40,7 +40,7 @@ POSSIBILITY OF SUCH DAMAGE.
 
 #if TORRENT_HAS_PTHREAD_SET_NAME
 #include <pthread.h>
-#ifdef TORRENT_BSD
+#if defined(TORRENT_BSD) && !defined(__NetBSD__)
 #include <pthread_np.h>
 #endif
 #endif
@@ -105,7 +105,11 @@ namespace libtorrent {
 		TORRENT_UNUSED(name);
 #if TORRENT_HAS_PTHREAD_SET_NAME
 #ifdef TORRENT_BSD
+#if defined(__NetBSD__)
+		pthread_setname_np(pthread_self(), name, nullptr);
+#else
 		pthread_set_name_np(pthread_self(), name);
+#endif
 #else
 		pthread_setname_np(pthread_self(), name);
 #endif

Now apply the patch:

$ patch -p1 < myfix.patch

Build + install libtorrent and then libtorrent python bindings:

$ b2 variant=release library-path=/usr/local/lbdeps/lib
$ doas b2 variant=release library-path=/usr/local/lbdeps/lib \
install --prefix=/usr/local/lbdeps
#~ Install Python module
$ python setup.py build_ext --b2-args="toolset=gcc-libtorrent \
variant=release libtorrent-link=shared boost-link=shared \
library-path=/usr/local/lbdeps/lib" install

Confirm if libraries (.so files) are taken from /usr/local/lbdeps:

$ ldd $VIRTUAL_ENV/lib/python3.7/site-packages/*/libtorrent.so
...
	-ltorrent-rasterbar.2.0.6 => /usr/local/lbdeps/lib/libtorrent-rasterbar.so.2.0.6
	-lboost_system.1.84.0 => /usr/local/lbdeps/lib/libboost_system.so.1.84.0
	-lstdc++.9 => /usr/lib/libstdc++.so.9
	-lm.0 => /usr/lib/libm.so.0
	-lc.12 => /usr/lib/libc.so.12
	-lgcc_s.1 => /usr/lib/libgcc_s.so.1
	-lpthread.1 => /usr/lib/libpthread.so.1
	-lssl.1.1 => /usr/local/lbdeps/lib/libssl.so.1.1
	-lcrypto.1.1 => /usr/local/lbdeps/lib/libcrypto.so.1.1
	-lutil.7 => /usr/lib/libutil.so.7
	-lboost_python37.1.84.0 => /usr/local/lbdeps/lib/libboost_python37.so.1.84.0

libboost_python37.so, libtorrent-rasterbar.so, libboost_system.so, libssl.so, libcrypto.so should be from /usr/local/lbdeps. If the output does not show the paths like above, check the user-config.jam file to see if the paths are correctly set. You might have to repeat some of the commands.

Step 5: Using lbrynet

We need to build coincurve 15.0.0 from source because it doesn’t allow builds on NetBSD by default:

$ cd ~/lbrepos
$ git clone --depth 1 -b v15.0.0 https://github.com/ofek/coincurve
$ cd coincurve

#~ Allow to be built on NetBSD
$ sed -i'.bak' -e "s/OpenBSD'\]/OpenBSD', 'NetBSD'\]/" setup.py

#~ install it
$ pip install -U -e .

Before building lbrynet, let’s mod some files for NetBSD:

$ cd ~/lbrepos/lbry-sdk
$ sed -i'.bak' -e "s/'linux' in sys/'linux' or 'bsd' in sys/" \
lbry/conf.py
$ sed -i'.bak' -e \
's/if d\["os_system"\] == "Linux":/if d\["os_system"\] == "Linux" or d\["os_system"\] == "NetBSD":/' \
lbry/extras/system_info.py

To build lbrynet:

$ gmake install

Now test with:

$ lbrynet --version
lbrynet 0.113.0

The lbrynet that you used above is not a binary. If you run cat $(which lbrynet) you will see that it’s just a python script. So it requires to have the whole lbry-sdk source code to be present. You will notice that it has the lbry-sdk source path in its first line (shebang line). The official lbry-sdk project provides a single binary which is more convenient. There are instructions on that below.

If you don’t want to go the extra mile of creating a single lbrynet binary, then you should keep the ~/lbrepos/lbry-sdk in that place and you can copy and use ~/lbrepos/lbry-sdk/lbry-venv/bin/lbrynet anywhere you want on the system. As long as the the lbry-sdk source is on the directory mentioned in its first line, it should work. For example, you can use the file with FastLBRY GTK by copying it as ...FastLBRY-GTK/flbry/lbrynet.

Before starting lbrynet daemon, you might want to change the default wallet servers because those don’t often work. Working servers might change in future. For now I have it working like this below. Optionally, uncomment and set download_dir to save downloaded content in your preferred place.

You can save something like below as ~/.local/share/lbry/lbrynet/daemon_settings.yml:

blockchain_name: lbrycrd_main
#download_dir: /home/user/Downloads/LBRY_Downloads
lbryum_servers:
- c-hub1.odysee.com:50001
- a-hub1.odysee.com:50001
save_blobs: true
save_files: false
share_usage_data: true
tcp_port: 3333
udp_port: 4444
use_upnp: true

You may find the need to login to lbrynet before using it. This login is different from your browser sessions like in Odysee.com. So even if you are already logged in to odysee.com, you’ll have to login to lbrynet separately, since your wallet, channels etc. will not be available otherwise.

To do that without LBRY Desktop is a bit harder. There is a script (also posted here) for this purpose. Don’t forget to read the comments at the beginning, esp. the warnings. To continue:

  • Run /path/to/lbrynet start, let it run for some time until it initializes.
  • Save the file as signin-lbrynet.py.
  • Then on another terminal run python3 signin-lbrynet.py and follow the on screen instructions. If successful, it will sync and make available the wallets and channels, so I keep it running until “Sync” related messages stop appearing in ~/.local/share/lbry/lbrynet/lbrynet.log.
  • Then when done, go back to the shell where you started lbrynet and press Ctrl+C to stop it.

Step 6: Creating a single lbrynet binary (optional, but convenient)

We’ll have to do this with PyInstaller. PyInstaller dropped support for python 3.7 from 6.x. 5.13.2 is the last 5.x version. We can’t install with pip because it doesn’t have NetBSD support. So we’d have to patch for NetBSD & build from source.

$ cd ~/lbrepos
$ git clone --depth 1 -b v5.13.2 https://github.com/pyinstaller/pyinstaller
$ cd pyinstaller

Save the following file as netbsdpi.patch:

diff --git a/PyInstaller/compat.py b/PyInstaller/compat.py
index 6bd3e4b..b9edace 100644
--- a/PyInstaller/compat.py
+++ b/PyInstaller/compat.py
@@ -56,11 +56,12 @@
 is_aix = sys.platform.startswith('aix')
 is_freebsd = sys.platform.startswith('freebsd')
 is_openbsd = sys.platform.startswith('openbsd')
+is_netbsd = sys.platform.startswith('netbsd')
 is_hpux = sys.platform.startswith('hp-ux')
 
 # Some code parts are similar to several unix platforms (e.g. Linux, Solaris, AIX).
 # Mac OS is not considered as unix since there are many platform-specific details for Mac in PyInstaller.
-is_unix = is_linux or is_solar or is_aix or is_freebsd or is_hpux or is_openbsd
+is_unix = is_linux or is_solar or is_aix or is_freebsd or is_hpux or is_openbsd or is_netbsd
 
 # Linux distributions such as Alpine or OpenWRT use musl as their libc implementation and resultantly need specially
 # compiled bootloaders. On musl systems, ldd with no arguments prints 'musl' and its version.
diff --git a/PyInstaller/depend/bindepend.py b/PyInstaller/depend/bindepend.py
index 332d25d..708590b 100644
--- a/PyInstaller/depend/bindepend.py
+++ b/PyInstaller/depend/bindepend.py
@@ -856,6 +856,8 @@ def findLibrary(name):
                 paths.append('/usr/local/lib/hpux64')
         elif compat.is_freebsd or compat.is_openbsd:
             paths.append('/usr/local/lib')
+        elif compat.is_netbsd:
+            paths.append('/usr/pkg/lib')
         lib = _which_library(name, paths)
 
     # Give up :(
@@ -863,7 +865,7 @@ def findLibrary(name):
         return None
 
     # Resolve the file name into the soname
-    if compat.is_freebsd or compat.is_aix or compat.is_openbsd:
+    if compat.is_freebsd or compat.is_aix or compat.is_openbsd or compat.is_netbsd:
         # On FreeBSD objdump does not show SONAME, and on AIX objdump does not exist, so we just return the lib we
         # have found.
         return lib
diff --git a/PyInstaller/depend/utils.py b/PyInstaller/depend/utils.py
index 84f43ad..f2810fb 100644
--- a/PyInstaller/depend/utils.py
+++ b/PyInstaller/depend/utils.py
@@ -328,7 +328,10 @@ def load_ldconfig_cache():
     if ldconfig is None:
         # If `ldconfig` is not found in $PATH, search for it in some fixed directories. Simply use a second call instead
         # of fiddling around with checks for empty env-vars and string-concat.
-        ldconfig = find_executable('ldconfig', '/usr/sbin:/sbin:/usr/bin:/usr/sbin')
+        if compat.is_netbsd:
+            ldconfig = find_executable('ldd', '/usr/sbin:/sbin:/usr/bin:/usr/sbin')
+        else:
+            ldconfig = find_executable('ldconfig', '/usr/sbin:/sbin:/usr/bin:/usr/sbin')
 
         # If we still could not find the 'ldconfig' command...
         if ldconfig is None:
diff --git a/bootloader/wscript b/bootloader/wscript
index 7d2c94a..b501ba3 100644
--- a/bootloader/wscript
+++ b/bootloader/wscript
@@ -48,6 +48,7 @@
     'linux': 'Linux',
     'freebsd': 'FreeBSD',
     'openbsd': 'OpenBSD',
+    'netbsd': 'NetBSD',
     'win32': 'Windows',
     'darwin': 'Darwin',
     'sunos': platform.system(),  # FIXME: inhibits cross-compile
@@ -657,7 +658,7 @@ def configure(ctx):
     else:
         # Mac OS X and FreeBSD do not need libdl.
         # https://stackoverflow.com/questions/20169660/where-is-libdl-so-on-mac-os-x
-        if ctx.env.DEST_OS not in ('darwin', 'freebsd', 'openbsd'):
+        if ctx.env.DEST_OS not in ('darwin', 'freebsd', 'openbsd', 'netbsd'):
             ctx.check_cc(lib='dl', mandatory=True)
             # libdl to be thread-safe requires libpthread!
             ctx.check_cc(lib='pthread', mandatory=True)
@@ -665,7 +666,7 @@ def configure(ctx):
             # On FreeBSD if python has threads: libthr needs to be loaded in the main process, so the bootloader needs
             # to be link to thr.
             ctx.check_cc(lib='thr', mandatory=True)
-        elif ctx.env.DEST_OS == 'hpux' and sysconfig.get_config_var('HAVE_PTHREAD_H'):
+        elif (ctx.env.DEST_OS == 'hpux' or ctx.env.DEST_OS == 'netbsd') and sysconfig.get_config_var('HAVE_PTHREAD_H'):
             ctx.check_cc(lib='pthread', mandatory=True)
         ctx.check_cc(lib='m', mandatory=True)
 

To apply patch:

$ patch -p1 < netbsdpi.patch

Now continue:

$ cd bootloader
$ python ./waf all
$ cd ..

#~ PyInstaller/bootloader should have a "NetBSD-64bit" dir with
#~ binaries
$ ls PyInstaller/bootloader/NetBSD-*
run   run_d

#~ install deps
$ python -m pip install -U -e . setuptools wheel
#~ clean if previously you built it
$ python setup.py clean
$ pip install .
$ pyinstaller --version
5.13.2

Now to create it as single binary file:

$ cd ~/lbrepos/lbry-sdk
#~ We set the library path because pyinstaller might have problems
#~ finding libpython3.7.so and show a "OSError: Python library not
#~ found" error otherwise
$ LD_LIBRARY_PATH=/usr/local/lbdeps/lib pyinstaller --onefile \
--strip --collect-all coincurve --name lbrynet lbry/extras/cli.py

We need --collect-all coincurve because for some reason pyinstaller does not include coincurve in the binary and without it shows a ModuleNotFoundError. --strip is optional here to keep the file size low. It gets rid of information from the binary file that is needed for debugging (important for developers and troubleshooting, not so much for average users). A file lbry-sdk/dist/lbrynet should be created with file size around 9MiB (~13MiB not stripped).

You can install it to system:

$ doas mkdir -p /usr/local/bin/
$ doas cp dist/lbrynet /usr/local/bin/

For FastLBRY GTK, you can just symlink from it. For example:

$ ln -s /usr/local/bin/lbrynet ~/Repos/FastLBRY-GTK/flbry/

Now you can run deactivate from the venv to quit out of it.

You are now ready to keep using it. If everything went as expected, you can now delete (if you wish) /usr/local/lbdeps dir and the single dist/lbrynet file should still work. You can copy the file somewhere else and also delete (if you wish) ~/lbrepos dir.

Removal (optional)

If you don’t like the outcomes of something and decide to remove everything you built, just delete the two output directories ~/lbrepos and /usr/local/lbdeps. Easy. Doing all the hard work to keep lbrynet related installations separate from usual /usr/local dir has this benefit. You might also want to remove ~/user-config.jam and /root/user-config.jam. Also look into the usual files/dirs that lbrynet creates, such as, ~/.local/share/lbry and the path you set on download_dir on daemon_settings.yml.

License: This guide is made available under CC0 1.0 Universal. Feel free to use it, modify it, relicense it, without asking for permission.