Cross kompilácia nginx, aleb pokus o najpomalší configure skript

30.06.2014 | 14:00 | Mirecove dristy | Miroslav Bendík

NGINX je síce krásny webserver no jeho kompilácia nie je ani zďaleka taká sranda ako by sa mohlo na prvý pohľad zdať.

Na rozdiel od väčšiny softvéru NGINX nepoužíva žiaden existujúci build systém. V balíku síce nájdeme configure skript, ktorého použitie sa na prvý pohľad nijak zvlášne neodlišuje od autotools. Jeho veľkosť (okolo 2kB) je však podozrivo malá ;)

Po letmom nahliadnutí do súboru môžme vidieť, že jeho autorom je Igor Sysoev. Na rozdiel od automaticky generovaného configure vyzerá skutočne elegantne.

Samotná funkcionalita je skrytá v adresári auto. Zisťovanie prítomností jednotlivých systémových balíkov (alebo ako to nazvať) je v súbore auto/feature.

Spúšťanie testov má na starosti riadok if sh -c $NGX_AUTOTEST >> $NGX_AUTOCONF_ERR 2>&1; then. V premennej $NGX_AUTOTEST bash príkaz (zvyčajne spúšťajúci len obyčajnú binárku skompilovanú pomocou gcc). Pri cross kompilácii však nie je možné priamo spustiť binárku pre inú platformu. V prípade autotools je cross kompilácia riešená dosť šialeným spôsobom (configure skripty fakt nie sú tak veľké len tak zo srandy), tu sú skripty malé a elegantné, nie sú však prispôsobené na cross kompiláciu.

Ak máme prístup cez SSH na dané zariadenie môžme použiť malý trik so spúšťaním príkazov cez SSH. Najskôr vytvoríme súbor auto/run, ktorý je prakticky kópiou súboru z tohto tutoriálu.

#!/bin/bash
basedir=$(dirname $(readlink -f $0))
keyfile=${basedir}/remote-ssh-key
logfile=${basedir}/run.txt
verbose=

if [ -f "${basedir}/remote" ] ; then
  remote=$(<${basedir}/remote)
else
  echo -n "Vzdialeny stroj (username@192.168.1.1): "
  read remote
  echo "$remote" > ${basedir}/remote
fi

if [ "$1" = "-v" ] ; then
  verbose=1
  shift
fi

if [ -z "$1" ] ; then
  echo "Usage: $0 COMMAND ARG..."
  exit 1
fi

set -e -u

if [ ! -f $keyfile ] ; then
  echo "Generovanie kluca $keyfile" >> ${logfile}
  ssh-keygen -f ${keyfile} -N ""
  echo "Prenos kluca na vzdialeny system (zadajte prosim heslo)" >> ${logfile}
  scp -q ${keyfile}.pub ${remote}:/tmp
  echo "Pridanie kluca do authorized_keys (zadajte prosim heslo)" >> ${logfile}
  ssh -q ${remote} "mkdir -p ~/.ssh; chmod 700 ~ ~/.ssh; cat /tmp/remote-ssh-key.pub >> ~/.ssh/authorized_keys;"
fi

if [ -x "$1" ] ; then
  if [ -n "$verbose" ] ; then
     echo "Copying $1 to $remote" >&2
  else
     echo "$(date) Copying $1 to $remote" >> ${logfile}
  fi
  scp -q -i ${keyfile} "$1" ${remote}:/tmp
  remotename="/tmp/$(basename $1)"
  shift
  if [ -n "$verbose" ] ; then
     echo "Vzdialene spustenie: ${remotename} $@" >&2
  else
     echo "$(date) Vzdialene spustenie: ${remotename} $@" >> ${logfile}
  fi
  ssh -q -i ${keyfile} ${remote} "${remotename} $@"
else
  if [ -n "$verbose" ] ; then
     echo "Vzdialene spustenie: $@" >&2
  else
     echo "$(date) Vzdialene spustenie: $@" >> ${logfile}
  fi
  ssh -q -i ${keyfile} ${remote} "$@"
fi

Potom už stačí len na pár miestach nahradiť sh -c príkazom auto/run, ktorý vykoná test na vzdialenom stroji (nechce sa mi to celé rozpisovať, prikladám patch pre nginx 1.6.0).

Nakoniec stačí už len spustiť príkazy configure (dlhá pauza lebo sa všetko spúšťa cez ssh) a make (ukážka pre ARM).

$buildhost = "/home/mirec/buildroot-armhf/output/host"
$sysroot = "$buildhost/usr/arm-buildroot-linux-gnueabihf/sysroot"


export PKG_CONFIG="$buildhost/usr/bin/pkg-config"
export PKG_CONFIG_LIBDIR="$sysroot/usr/lib/pkgconfig"
export PKG_CONFIG_SYSROOT_DIR="$sysroot"
export MAKEFLAGS=" -j3"
export cc=$buildhost/usr/bin/arm-cortex_a8-linux-gnueabi-gcc
export cpp=$buildhost/usr/bin/arm-cortex_a8-linux-gnueabi-cpp
export cflags="-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64  -pipe -Os "
export ldflags=""

./configure \
--with-cc=$cc \
--with-cpp=$cpp \
--with-cc-opt=$cflags \
--with-ld-opt=$ldflags \
--crossbuild=arm-buildroot-linux-gnueabihf