PublicNotes on Nostr: ### Using the OpenWRT SDK ``` #!/bin/bash set -e SCRIPT_DIR="$( cd -- "$( dirname -- ...
### Using the OpenWRT SDK
```
#!/bin/bash
set -e
SCRIPT_DIR="$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
# Check and install libncurses5-dev and libncursesw5-dev libraries
install_ncurses_libraries() {
if ! dpkg -s libncurses5-dev libncursesw5-dev >/dev/null 2>&1; then
echo "Installing libncurses5-dev and libncursesw5-dev packages..."
sudo apt-get update
sudo apt-get install -y libncurses5-dev libncursesw5-dev
else
echo "libncurses5-dev and libncursesw5-dev are already installed."
fi
}
install_go() {
# First check if go is in /usr/local/go/bin
if [ -x "/usr/local/go/bin/go" ]; then
# Add to PATH if not already there
if [[ ":$PATH:" != *":/usr/local/go/bin:"* ]]; then
export PATH=$PATH:/usr/local/go/bin
# Add to ~/.bashrc if not already there
if ! grep -q "/usr/local/go/bin" ~/.bashrc; then
echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc
fi
fi
echo "Go is already installed."
echo "Go version: $(/usr/local/go/bin/go version)"
return 0
fi
# If go is not installed, proceed with installation
echo "Installing Go..."
sudo apt install -y pigz # For multi-core unpack
wget https://go.dev/dl/go1.23.4.linux-amd64.tar.gz
sudo rm -rf /usr/local/go
sudo tar -I pigz -C /usr/local -xf go1.23.4.linux-amd64.tar.gz
export PATH=$PATH:/usr/local/go/bin
# Add to ~/.bashrc if not already there
if ! grep -q "/usr/local/go/bin" ~/.bashrc; then
echo 'export PATH=$PATH:/usr/local/go/bin' >> ~/.bashrc
fi
rm go1.23.4.linux-amd64.tar.gz
# Verify Go installation
if ! /usr/local/go/bin/go version &> /dev/null; then
echo "Failed to install Go. Please install manually."
exit 1
fi
echo "Go version: $(/usr/local/go/bin/go version)"
}
# Add this function to manage Python dependencies
setup_python_environment() {
local sdk_path=$1
if [ ! -f "${sdk_path}/staging_dir/host/bin/opkg-make-index" ]; then
echo "Installing opkg-make-index..."
mkdir -p "${sdk_path}/staging_dir/host/bin"
wget https://raw.githubusercontent.com/shr-project/opkg-utils/master/opkg-make-index -O "${sdk_path}/staging_dir/host/bin/opkg-make-index"
chmod +x "${sdk_path}/staging_dir/host/bin/opkg-make-index"
else
echo "opkg-make-index is already installed."
fi
}
# Add this function to check feeds status
check_feeds() {
local sdk_path=$1
# Check if feeds directory exists and has content
if [ -d "${sdk_path}/feeds" ] && [ "$(ls -A ${sdk_path}/feeds)" ]; then
# Check if package index exists and is recent (less than 1 day old)
if [ -f "${sdk_path}/feeds/packages.index" ]; then
local file_age=$(( $(date +%s) - $(stat -c %Y "${sdk_path}/feeds/packages.index") ))
local day_seconds=86400
if [ ${file_age} -lt ${day_seconds} ]; then
echo "Feeds are up to date, skipping update..."
return 0
fi
fi
fi
return 1
}
# Check if the required argument is provided
if [ $# -ne 1 ]; then
echo "Usage: $0 <model>"
exit 1
fi
MODEL=$1
VERSION=23.05.3
SDKDIR=/tmp/openwrt-sdk
# Set platform variables based on model
case $MODEL in
"gl-mt300n-v2")
PLATFORM="ramips"
SUBTARGET="mt76x8"
;;
"gl-ar300m")
PLATFORM="ath79"
SUBTARGET="generic"
;;
"gl-mt3000"|"gl-mt6000")
PLATFORM="mediatek"
SUBTARGET="filogic"
;;
"gl-e750")
VERSION="snapshot"
PLATFORM="ath79"
SUBTARGET="nand"
;;
"archer_mr200")
PLATFORM="ramips"
SUBTARGET="mt7620"
;;
*)
echo "Unsupported model. Supported models: gl-mt300n-v2, gl-ar300m, gl-mt3000, gl-mt6000, gl-e750, archer_mr200"
exit 1
;;
esac
SDK_ARCHIVE="openwrt-sdk-${VERSION}-${PLATFORM}-${SUBTARGET}_gcc-12.3.0_musl.Linux-x86_64.tar.xz"
DOWNLOAD_URL="https://downloads.openwrt.org/releases/${VERSION}/targets/${PLATFORM}/${SUBTARGET}/${SDK_ARCHIVE}";
SDK_PATH="${SDKDIR}/openwrt-sdk-${VERSION}-${PLATFORM}-${SUBTARGET}_gcc-12.3.0_musl.Linux-x86_64"
# Install dependencies
install_ncurses_libraries
install_go
# Prepare SDK directory
if [ ! -d "${SDKDIR}" ] ; then
mkdir -p "${SDKDIR}"
fi
# Download and extract SDK
if [ ! -f "${SDKDIR}/${SDK_ARCHIVE}" ]; then
echo "Downloading SDK..."
(cd "${SDKDIR}" && curl -O "${DOWNLOAD_URL}")
fi
echo "Extracting SDK..."
tar -I "xz -T0" -xf "${SDKDIR}/${SDK_ARCHIVE}" -C "${SDKDIR}"
# Change to SDK directory
cd "${SDK_PATH}"
# Setup python environment with correct SDK path
setup_python_environment "${SDK_PATH}"
echo "Script dir: $SCRIPT_DIR"
cp "${SCRIPT_DIR}"/feeds.conf "${SDK_PATH}"/feeds.conf
# Update feeds
echo "Updating feeds..."
"${SDK_PATH}"/./scripts/feeds update -a
"${SDK_PATH}"/./scripts/feeds install -a
# Configure and build
echo "Configuring SDK..."
make defconfig
echo "Building golang first..."
make package/feeds/custom/golang/compile V=sc
echo "Building all TollGate modules..."
MODULES=(
"merchant"
"valve"
"whoami"
"crowsnest"
"tollgate-module-relay-go"
)
echo "Building all TollGate modules..."
for module in "${MODULES[@]}"; do
echo "Building ${module}..."
make package/feeds/custom/${module}/compile V=sc
done
# Find all built packages and print their paths
BUILT_PACKAGES_DIR=$(find "${SDK_PATH}/bin/packages" -name "tollgate-module-*.ipk" -exec dirname {} \; | head -n 1)
echo -e "\nUploading packages to blossom and creating nostr event..."
# Run the aggregate info script for all packages
python3 "${SCRIPT_DIR}/aggregate_info.py" "${BUILT_PACKAGES_DIR}" "${SCRIPT_DIR}/feeds.conf"
noscl publish "$(cat note.md)"
# List all built packages
echo "Built packages:"
find "${BUILT_PACKAGES_DIR}" -name "tollgate-module-*.ipk" -exec ls -l {} \;
```
I learnt that there is this thing called the openwrt SDK for compiling just the binaries that we care about without needing to compile the entire operating system. When I take a proper look at the above script, it looks like its building the binaries in the openwrt directory, but it isn't immediately obvious to me that it actually uses the SDK.
Below is some content I found on the internet regarding the SDK. Am I doing it wrong? How can I change my script to use the SDK instead? Please help me to understand the difference and the trade-offs between the different ways of building custom feeds for OpenWRT.
```
# Building applications for an [OpenWrt](https://trac.gateworks.com/wiki/OpenWrt) Target[](https://trac.gateworks.com/wiki/OpenWrt/SDK#BuildingapplicationsforanOpenWrtTarget "Link to this section")
There are several ways you can use an [OpenWrt](https://trac.gateworks.com/wiki/OpenWrt) Software Development Kit (SDK) or Toolchain to compile your own applications outside of the [OpenWrt](https://trac.gateworks.com/wiki/OpenWrt) buildroot :
- use prebuilt [OpenWrt](https://trac.gateworks.com/wiki/OpenWrt) toolchain to build applications (ie from [http://dev.gateworks.com/openwrt/latest/](http://dev.gateworks.com/openwrt/latest/))
- use prebuilt [OpenWrt](https://trac.gateworks.com/wiki/OpenWrt) SDK to build an [OpenWrt](https://trac.gateworks.com/wiki/OpenWrt) package (ie from [http://dev.gateworks.com/openwrt/latest/](http://dev.gateworks.com/openwrt/latest/))
- use toolchain in your [OpenWrt](https://trac.gateworks.com/wiki/OpenWrt) buildroot staging_dir tree (what you may need to do if your running your own firmware with a different lib/kernel config than Gateworks pre-built images)
The point of using the [OpenWrt](https://trac.gateworks.com/wiki/OpenWrt) toolchain or SDK is that it can be pre-built and installed on a host that does not have the [OpenWrt](https://trac.gateworks.com/wiki/OpenWrt) buildroot.
Note: Custom programming can be achieved through shell scripts on the Gateworks boards (most examples on the Gateworks wiki are shell commands). C code can be used when desired.
## [OpenWrt](https://trac.gateworks.com/wiki/OpenWrt) Prebuilt Toolchain[](https://trac.gateworks.com/wiki/OpenWrt/SDK#OpenWrtPrebuiltToolchain "Link to this section")
If you are using pre-built firmware from [http://dev.gateworks.com/openwrt](http://dev.gateworks.com/openwrt) then you can use the pre-built toolchain there to build your own code.
The steps involved:
1. Download prebuilt toolchain/SDK, the toolchain contains the compiler and standard libraries only.
2. Uncompress it.
3. Add it to your path (optional)
4. Use the toolchain cross compiler to cross compile your code.
Examples:
- Example, if you wanted to build a hello-world for [OpenWrt](https://trac.gateworks.com/wiki/OpenWrt) 14.08 for the laguna (cns3xxx) platform:
$ wget http://dev.gateworks.com/openwrt/14.08/cns3xxx/OpenWrt-Toolchain-cns3xxx-for-arm_v6k-gcc-4.6-linaro_uClibc-0.9.33.2_eabi.tar.bz2
$ tar xvf OpenWrt-Toolchain-cns3xxx-for-arm_v6k-gcc-4.6-linaro_uClibc-0.9.33.2_eabi.tar.bz2
$ PATH=$PWD/OpenWrt-Toolchain-cns3xxx-for-arm_v6k-gcc-linaro_uClibc-0.9.32_eabi/toolchain-arm_v6k_gcc-linaro_uClibc-0.9.32_eabi/bin:$PATH
$ cat << EOF > hello-world.c
#include <stdio.h>
int main (int argc, char** argv)
{
printf("Hello World\n");
return 0;
}
EOF
$ arm-openwrt-linux-uclibcgnueabi-gcc hello-world.c -o hello-world
$ file hello-world
hello-world: ELF 32-bit LSB executable, ARM, version 1 (SYSV), dynamically linked (uses shared libs), not stripped
- Example [OpenWrt](https://trac.gateworks.com/wiki/OpenWrt) 16.02 for the Ventana (imx6) platform:
# download toolchain
wget http://dev.gateworks.com/openwrt/16.02/imx6/Gateworks-Toolchain-imx6_gcc-5.2.0_musl-1.1.12_eabi.Linux-x86_64.tar.bz2
# extract toolchain
tar xvf Gateworks-Toolchain-imx6_gcc-5.2.0_musl-1.1.12_eabi.Linux-x86_64.tar.bz2
# add toolchain to path
PATH=$PWD/Gateworks-Toolchain-imx6_gcc-5.2.0_musl-1.1.12_eabi.Linux-x86_64/toolchain-arm_cortex-a9+neon_gcc-5.2.0_musl-1.1.12_eabi/bin:$PATH
# create a simple program
cat << EOF > hello-world.c
#include <stdio.h>
int main (int argc, char** argv)
{
printf("Hello World\n");
return 0;
}
EOF
# compile your program
arm-openwrt-linux-gcc hello-world.c -o hello-world
Note: The prebuilt toolchain may have some issue if the script arm-openwrt-linux-uclibcgnueabi-wrapper.sh is used (with regard to paths having whitespace).
### Venice Notes[](https://trac.gateworks.com/wiki/OpenWrt/SDK#VeniceNotes "Link to this section")
Gateworks has not published a Toolchain / SDK and thus it should be built with the [OpenWrt](https://trac.gateworks.com/wiki/OpenWrt) instructions on the [OpenWrt/building](https://trac.gateworks.com/wiki/OpenWrt/building) page.
This results in a toolchain in ./staging_dir and for 24.01 imx8m the toolchain will be toolchain-aarch64_cortex-a53_gcc-12.3.0_musl
Once the toolchain is there, use the following commands to compile a Hello World:
# configure toolchain
export TOOLCHAIN=toolchain-aarch64_cortex-a53_gcc-12.3.0_musl
export STAGING_DIR=$PWD/staging_dir
export ARCH=arm64
export CROSS_COMPILE=aarch64-openwrt-linux-
export PATH=$PATH:$STAGING_DIR/$TOOLCHAIN/bin
cat << EOF > helloworld.c
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
printf("hello world!\n");
return 0;
}
EOF
${CROSS_COMPILE}gcc helloworld.c -o helloworld
This builds a dynamically linked helloworld which you can inspect as:
$ file helloworld
helloworld: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-musl-aarch64.so.1, with
debug_info, not stripped
${CROSS_COMPILE}objdump -x helloworld | grep NEEDED
NEEDED libgcc_s.so.1
NEEDED libc.so
You can then copy this executable and run this on a board with [OpenWrt](https://trac.gateworks.com/wiki/OpenWrt) 24.01 installed
```
### Answer
Your script is essentially using the OpenWrt SDK already—it downloads (or locates) the “openwrt-sdk-…tar.xz” archive, extracts it, places custom feeds configuration, and then calls “make defconfig” plus “make package/…/compile” on individual packages. That’s all consistent with building inside the SDK, rather than the entire OpenWrt buildroot. So you’re not “doing it wrong” per se; it’s more that the SDK can still feel like a full build system because a lot of the core build steps (e.g., compiler, musl, etc.) are prepackaged in it.
## How the SDK Differs from the Full Buildroot
The full buildroot is the complete OpenWrt source tree for building everything (kernel, root filesystem, user packages, etc.) all at once. The SDK is a stripped-down version of that buildroot including:
• Compiler toolchains and libraries (precompiled)
• Scripts and makefiles to handle package configuration and compilation
Since the compiler and most dependencies are already built when you use the SDK, you only compile your custom feeds or packages. By contrast, the full buildroot does everything from scratch, which can be overkill if you only want custom packages.
## How the SDK Differs from a Prebuilt Toolchain
A prebuilt toolchain is basically just the cross-compiler and associated libraries. Using the prebuilt toolchain alone means you manually run something like:
arm-openwrt-linux-gcc helloworld.c -o helloworld
You avoid all the OpenWrt-specific makefiles, feed structures, packaging steps, etc. In other words, you just cross-compile your application. If you want to generate OpenWrt .ipk files or use the normal feeds mechanism, you have to set up more of the environment yourself.
## What Your Script Is Doing
1. Downloads and extracts the SDK to /tmp/openwrt-sdk
2. Installs Python dependencies (opkg-make-index, etc.)
3. Copies feeds.conf into the SDK
4. Runs scripts/feeds update -a and scripts/feeds install -a
5. Calls make defconfig to configure the SDK
6. Compiles golang, then compiles your custom modules
Those are the normal steps when using the SDK approach. You’re effectively letting the SDK handle compilation and packaging of your custom feeds. That targets only your needed packages, without building the entire firmware image.
## Suggested Tweaks for a More Standard “SDK-Only” Flow
You could simplify the script by letting the user manually pick packages or select them via menuconfig. For example:
```bash
#!/bin/bash
set -e
# 1. Download the SDK
SDKDIR=/tmp/openwrt-sdk
mkdir -p "$SDKDIR"
wget -O "$SDKDIR"/sdk.tar.xz "https://example.org/openwrt-sdk.tar.xz";
tar -I "xz -T0" -xf "$SDKDIR"/sdk.tar.xz -C "$SDKDIR"
# 2. Move into the extracted SDK
cd "$SDKDIR"/openwrt-sdk-*
# 3. Copy or create your feeds.conf
cp /path/to/feeds.conf ./feeds.conf
./scripts/feeds update -a
./scripts/feeds install -a
# 4. Configure the SDK (optional menuconfig or defconfig)
make defconfig
# 5. Compile a specific package
make package/feeds/custom/my-package/compile V=s
```
When you’re done, any generated .ipk files appear in bin/packages/<arch>/custom/ (or a similarly named feed directory). Then you can install or share those packages as you like.
## Trade-Offs
1. Full Buildroot
• Pros: Build an entire customized image (kernel, rootfs, packages) in one place.
• Cons: Much larger downloads, more disk space required, longer builds.
2. SDK
• Pros: Lightweight compared to the full buildroot, includes everything needed to build packages (.ipk) in the normal OpenWrt manner.
• Cons: Still has overhead compared to a simple compiler toolchain. Not as small as a bare cross-compiler.
3. Prebuilt Toolchain
• Pros: Easiest way to cross-compile if all you need is raw binaries. Fast and minimal download.
• Cons: You have to handle packaging or any OpenWrt feed integration yourself.
In your case, using the SDK is perfectly suitable for building custom feeds or packages. You get the best of both worlds: you don’t waste time recompiling the entire OS, but still follow all the typical OpenWrt packaging and feeds steps. That is precisely what your script does—you are indeed using the SDK. If you ever want to build a full custom firmware image with kernel changes, you’d switch to the full buildroot. If you only wanted a bare cross-compiler, you’d pick the prebuilt toolchain. But for custom feed packages, you’re in good shape with your current approach.