#!/bin/bash -e # OpenWRT compilation script # (C) 2018 CZ.NIC, z.s.p.o. # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. BUILD_DIR="$(pwd)" SRC_DIR="$(dirname "$0")" SRC_DIR="$(cd "$SRC_DIR"; pwd)" CMD="${0}" OPENWRT_URL="https://git.openwrt.org/openwrt/openwrt.git" BRANCH=master DEBUG="" EVERYTHING="" PERL_DEBUG="" MAKE_DEBUG="" DEPTH="--depth 1" FORCE="" DEFAULT_STEPS="checkout patch_openwrt get_feeds patch_feeds gen_version configure build store_hash stats" if [ "$BUILD_DIR" == "$SRCDIR" ]; then mkdir -p build cd build BUILD_DIR="$(pwd)" fi export TMPDIR="${BUILD_DIR}/tmp" mkdir -p "$TMPDIR" [ \! -f "${SRC_DIR}"/turris-build.conf ] || . "${SRC_DIR}"/turris-build.conf [ \! -f ~/.turris-build ] || . ~/.turris-build [ \! -f ./turris-build.conf ] || . ./turris-build.conf MIRROR_UPDATED="" _report() { echo -e '\033[0;34m'"$1"'\033[0m' >&2 } _die() { echo -e '\033[0;31m'"$1"'\033[0m' >&2 exit 1 } _get_version() { # If first grep fails - version is not first non-empty, add 999 to the end # Be aware that Condition in if also outputs the results if ! grep . "${SRC_DIR}"/NEWS | head -n 1 | grep '^[0-9.]\+$'; then echo "$(grep '^[0-9.]\+$' "${SRC_DIR}"/NEWS | head -n 1).999" fi } gen_version_help="Generates Turris version package from NEWS" gen_version() { _report "Generating turris-version package" # Find the current version VERSION="$(_get_version)" # If top of the NEWS is not a version number, find previous one and add 99 # Also try to figure out where are the actual NEWS for this version if expr "$VERSION" : '999$' > /dev/null; then START=1 END="$(grep -n '^[0-9.]\+$' "${SRC_DIR}"/NEWS | head -n 1 | sed 's|:.*||')" END="$(expr $END - 1)" else START="$(grep -n '^[0-9.]\+$' "${SRC_DIR}"/NEWS | head -n 1 | sed 's|:.*||')" START="$(expr $START + 1)" END="$(grep -n '^[0-9.]\+$' "${SRC_DIR}"/NEWS | sed -n '2 s|:.*||p')" [ -n "$END" ] || END="\$" fi # Generate package mkdir -p "${BUILD_DIR}"/package/system/turris-version cat > "${BUILD_DIR}"/package/system/turris-version/Makefile << EOF # ## Copyright (C) $(date +%Y) CZ.NIC z.s.p.o. (http://www.nic.cz/) # ## This is free software, licensed under the GNU General Public License v2. # See /LICENSE for more information. # # # include \$(TOPDIR)/rules.mk PKG_NAME:=turris-version PKG_VERSION:=$VERSION PKG_MAINTAINER:=CZ.NIC <packaging@nic.cz> include \$(INCLUDE_DIR)/package.mk define Package/turris-version TITLE:=turris-version endef define Build/Prepare endef define Build/Compile endef define Package/turris-version/postinst #!/bin/sh # Danger: spaces are not ordinary spaces, but special unicode ones [ -n "\$\$IPKG_INSTROOT" ] || { create_notification -s news "$(sed -n "$START,$END p" "${SRC_DIR}"/NEWS | grep . | sed 's|^[[:blank:]]*\*[[:blank:]]*| • |')" } endef define Package/turris-version/install \$(INSTALL_DIR) \$(1)/etc echo \$(PKG_VERSION) > \$(1)/etc/turris-version endef \$(eval \$(call BuildPackage,turris-version)) EOF pushd "${BUILD_DIR}" git add "${BUILD_DIR}"/package/system/turris-version git commit -m 'turris-version: Create a package with release notes' popd } stats_help="Prints statistics regarding number of built packages" stats() { echo "Statistics of the build:" echo echo " * $(find bin/packages -name '*.ipk' | wc -l) packages built" if [ -n "$BUILD_START" ] && [ -n "$BUILD_END" ]; then BUILD_TIME="$(expr $BUILD_END - $BUILD_START)" echo " * build time $(expr $BUILD_TIME / 3600):$(expr \( $BUILD_TIME % 3600 \) / 60):$(expr $BUILD_TIME % 60)" fi } configure_help="Recreates configuration for target boards" configure() { _report "Creating default configuration" [ -n "${TARGET_BOARD}" ] || _die "No board selected!" cat "${SRC_DIR}"/configs/common/* "${SRC_DIR}"/configs/${TARGET_BOARD}/* > ./.config echo "CONFIG_DEVEL=y" >> .config echo "CONFIG_CCACHE=y" >> .config echo "CONFIG_DOWNLOAD_FOLDER=$DL_MIRROR" >> .config echo "CONFIG_VERSION_REPO=\"https://repo.turris.cz/${TARGET_BOARD}\"" >> .config echo "CONFIG_VERSION_NUMBER=\"$(_get_version)\"" >> .config if [ "$EVERYTHING" = yes ]; then echo "CONFIG_ALL_KMODS=y" >> .config echo "CONFIG_ALL=y" >> .config echo "CONFIG_IB=y" >> .config echo "CONFIG_IB_STANDALONE=y" >> .config echo "CONFIG_SDK=y" >> .config else echo "CONFIG_ALL=n" >> .config echo "CONFIG_IB=n" >> .config echo "CONFIG_IB_STANDALONE=n" >> .config echo "CONFIG_SDK=n" >> .config fi make $MAKE_DEBUG defconfig } update_mirror_help="Updates all local mirrors" update_mirror() { [ -n "$GIT_MIRROR" ] || return 0 [ -z "$MIRROR_UPDATED" ] || return 0 _report "Updating local mirrors" mkdir -p "$GIT_MIRROR" pushd "$GIT_MIRROR" if [ \! -d openwrt ]; then mkdir openwrt cd openwrt && git init --bare && git remote add --mirror=fetch origin "$OPENWRT_URL" fi cd "$GIT_MIRROR" OPENWRT_URL="$GIT_MIRROR/openwrt" for mirror in ./*; do cd "$mirror" && git fetch --all cd "$GIT_MIRROR" done popd MIRROR_UPDATED="yes" } checkout_help="Start everything from scratch - all changes deleted and fresh copy of OpenWRT gets checked out" checkout() { _report "Starting out fresh!" _report "Checking out clean OpenWRT repository" update_mirror rm -rf .git git init git remote add origin "$OPENWRT_URL" git fetch $DEPTH origin "$BRANCH" git checkout -f "origin/$BRANCH" BUILD_SETTINGS="$(cat turris-build.conf 2> /dev/null || true)" git clean -dff [ -z "$BUILD_SETTINGS" ] || echo "$BUILD_SETTINGS" > turris-build.conf git config --local commit.gpgsign false echo "/turris-build.conf" >> ./.gitignore echo "/version" >> ./.gitignore git commit -m 'gitignore: Ignore some more files' ./.gitignore [ \! -f "$SRC_DIR"/feeds.conf ] || cp "$SRC_DIR"/feeds.conf . if [ -n "$DL_MIRROR" ]; then mkdir -p "$DL_MIRROR" rm -rf dl && ln -s "$DL_MIRROR" dl fi git log -n 1 --format="%h" > version } patch_feeds_help="Apply patches to the feeds" patch_feeds() { _report "Patching feeds" pushd "$SRC_DIR"/patches for feed in *; do [ -d "$BUILD_DIR"/feeds/$feed ] || continue cd "$SRC_DIR"/patches/$feed for patch in */*.patch; do [ -f "$patch" ] || continue cd "$BUILD_DIR"/feeds/$feed git config --local commit.gpgsign false git am "$SRC_DIR"/patches/$feed/$patch done done popd } set_ccache_help="Set persistent ccache paths" set_ccache() { [ -z "$CCACHE_SET" ] || return 0 _report "Setting ccache paths" CCACHE_SET=y [ -z "$CCACHE_HOST_DIR" ] || sed -i 's|\(export CCACHE_DIR:=\).*|\1'"$CCACHE_HOST_DIR|" include/host-build.mk [ -z "$CCACHE_TARGET_DIR" ] || [ -z "$TARGET_ARCH" ] || sed -i 's|\(export CCACHE_DIR:=\).*|\1'"$CCACHE_TARGET_DIR/$TARGET_ARCH|" include/package.mk [ -z "$(git diff include/host-build.mk include/package.mk)" ] || git commit -m "include: ccache settings" include/host-build.mk include/package.mk } set_local_feeds_help="Change feed URL to their mirror counterparts" set_local_feeds() { [ -n "$GIT_MIRROR" ] || return 0 while read vcs name url rest; do if [ "$vcs" = src-git ] && [ -d "$GIT_MIRROR"/$name ]; then feed_url="$(echo "$url" | sed 's|[[:blank:]^].*||')" sed -i "s|$feed_url|file://$GIT_MIRROR/$name|" feeds.conf fi done < feeds.conf } mirror_feeds_help="Creates initial mirrors of all configured feeds" mirror_feeds() { [ -n "$GIT_MIRROR" ] || return 0 pushd "$GIT_MIRROR" cat "$SRC_DIR"/feeds.conf "$BUILD_DIR"/feeds.conf 2> /dev/null | while read vcs name url rest; do if [ "$vcs" = src-git ] && [ \! -d "$GIT_MIRROR"/$name ]; then feed_url="$(echo "$url" | sed 's|[[:blank:]^].*||')" mkdir "$name" cd "$name" && git init --bare && git remote add --mirror=fetch origin "$feed_url" && git fetch --all cd "$GIT_MIRROR" fi done popd update_mirror } patch_openwrt_help="Patch the main OpenWRT repository" patch_openwrt() { _report "Patching OpenWRT repository" pushd "$SRC_DIR"/patches/openwrt for patch in */*.patch; do cd "$BUILD_DIR" git am "$SRC_DIR"/patches/openwrt/$patch done popd set_ccache } _git_remote_hash() { pushd "$1" > /dev/null br="$(LANG=C git status --long | sed -n 's|HEAD detached from \(.*\)|\1|p')" [ -n "$br" ] || br="$(LANG=C git status --long | sed -n "s|Your branch is up to date with '\\([^']*\\)'.*|\1|p")" [ -n "$br" ] || br="$(LANG=C git status --long | sed -n "s|Your branch is ahead of '\\([^']*\\)'.*|\1|p")" [ -n "$br" ] || br=HEAD git log -n1 --pretty=%H "$br" popd > /dev/null } store_hash_help="Stores hashes of current build" store_hash() { _report "Storing hashes" mkdir -p bin { echo "Project was build from following repositories:" echo echo " * turris-build: $(_git_remote_hash "${SRC_DIR}")" echo " * openwrt: $(_git_remote_hash "${BUILD_DIR}")" for feed in feeds/*; do [ -d "$feed/.git" ] || continue echo " * $feed: $(_git_remote_hash "${feed}")" done echo } | tee bin/git-hash } get_feeds_help="Recreate configured feeds" get_feeds() { update_mirror set_local_feeds perl $PERL_DEBUG ./scripts/feeds clean -a perl $PERL_DEBUG ./scripts/feeds update -a perl $PERL_DEBUG ./scripts/feeds install -a } repatch_feeds_help="Cleanup feeds, update them and patch them" repatch_feeds() { get_feeds patch_feeds } prefetch_help="Runs make download" prefetch() { make $MAKE_DEBUG $BUILD_ARGS $OWRT_DEBUG download } build_help=" Builds everything" build() { _report "Starting real build" set_ccache BUILD_START="$(date +%s)" if [ -z "$FORCE" ]; then make $MAKE_DEBUG IS_TTY=1 LOGFILE=1 BUILD_LOG=1 $BUILD_ARGS $OWRT_DEBUG else make $MAKE_DEBUG IS_TTY=1 LOGFILE=1 BUILD_LOG=1 $BUILD_ARGS $OWRT_DEBUG || \ IGNORE_ERRORS=m make $MAKE_DEBUG IS_TTY=1 LOGFILE=1 BUILD_LOG=1 $BUILD_ARGS $OWRT_DEBUG || \ IGNORE_ERRORS=m make $MAKE_DEBUG IS_TTY=1 LOGFILE=1 BUILD_LOG=1 $BUILD_ARGS $OWRT_DEBUG -j1 V=s fi BUILD_END="$(date +%s)" } # Sets various variables to match the specified target, just a helper _set_target() { _report "Setting target as $1" case "$1" in omnia) TARGET_BOARD=omnia TARGET_ARCH=armv7l ;; turris) TARGET_BOARD=turris TARGET_ARCH=ppcspe ;; mox) TARGET_BOARD=mox TARGET_ARCH=aarch64 ;; *) echo "Invalid target board!!! Use -t [turris|omnia|mox]!!!" exit 1 ;; esac } help_help=" Displays text with help" help() { echo "Usage: $CMD [options] [command] [command] ..." echo echo "Available options are:" echo " -x Enable debug mode" echo " -e Build everything, not just minimal set" echo " -f Try hard to get stuff to compile" echo " -d Do not use shallow checkouts" echo " -t board Set target board to _board_" echo " -a \"arg1 arg2\" Set build arguments - passed directly to make" echo " -l Do not update local git mirrors" echo echo "Available commands are:" declare -F | sed -n 's|declare -f \([a-z]\)|\1|p' | while read func; do echo " $func $(eval echo \"\$${func}_help\")" done echo echo "Default commands are: $DEFAULT_STEPS" echo } [ -z "$BOARD" ] || _set_target "$BOARD" while expr x$1 : x- > /dev/null; do cmd="x$1" shift case $cmd in x-x) set -x DEBUG="yes" PERL_DEBUG="-d:Trace" MAKE_DEBUG="-n" OWRT_DEBUG="V=s" ;; x-e) EVERYTHING="yes" ;; x-d) DEPTH="" ;; x-f) FORCE="y" ;; x-t) _set_target "$1" shift ;; x-a) BUILD_ARGS="$1" shift ;; x-b) BRANCH="$1" shift ;; x-l) MIRROR_UPDATED="override" OPENWRT_URL="$GIT_MIRROR/openwrt" ;; esac done [ -n "$1" ] || set $DEFAULT_STEPS while [ -n "$1" ]; do eval "$1" shift done