1#!/bin/bash 2# 3# This file is part of nzbget 4# 5# Copyright (C) 2015-2019 Andrey Prygunkov <hugbug@users.sourceforge.net> 6# 7# This program is free software; you can redistribute it and/or modify 8# it under the terms of the GNU General Public License as published by 9# the Free Software Foundation; either version 2 of the License, or 10# (at your option) any later version. 11# 12# This program is distributed in the hope that it will be useful, 13# but WITHOUT ANY WARRANTY; without even the implied warranty of 14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15# GNU General Public License for more details. 16# 17# You should have received a copy of the GNU General Public License 18# along with this program. If not, see <http://www.gnu.org/licenses/>. 19# 20 21# Setup strict bash error handling 22set -o nounset 23set -o errexit 24 25# Uncomment next line for debuging 26#set -x 27 28ALLTARGETS="dist i686 x86_64 armel armhf aarch64 mipsel mipseb ppc6xx ppc500 x86_64-bsd i686-ndk armhf-ndk aarch64-ndk" 29ROOT=`pwd` 30ROOTPATH=$PATH 31OUTPUTDIR=$ROOT/output 32CROSSCLANG="clang-4.0" 33 34# Configuration 35BUILD=no 36PLATFORMS="" 37TARGETS="" 38OUTPUTS="" 39REVISION="" 40BRANCH="" 41CONFIGS="" 42CLEAN=no 43PCH=no 44COREX="1" 45 46PrintUsage() 47{ 48 echo "Usage:" 49 echo " $(basename $0) [targets] [output] [revision] [reppath] [configs] [cleanup] [pch] [corex]" 50 echo " targets : all (default) $ALLTARGETS" 51 echo " output : bin installer" 52 echo " revision : head (default) work <commit-hash>" 53 echo " branch : develop (default) master tags/XXX branches/XXX" 54 echo " configs : release debug (default) release-nostrip debug-strip" 55 echo " cleanup : cleanup output directory before building" 56 echo " pch : create and use precompiled headers" 57 echo " corex : multicore make (x is a number of threads)" 58 echo 59} 60 61ParseCommandLine() 62{ 63 for PARAM in "$@" 64 do 65 case $PARAM in 66 release|release-nostrip|debug|debug-strip) 67 # using xargs to trim spaces 68 CONFIGS=`echo "$CONFIGS $PARAM" | xargs` 69 ;; 70 master|develop|tags/*) 71 BRANCH="$PARAM" 72 ;; 73 branches/*) 74 BRANCH="${PARAM:9}" 75 ;; 76 head|work|[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]*) 77 REVISION="$PARAM" 78 ;; 79 clean|cleanup) 80 CLEAN=yes 81 ;; 82 pch) 83 PCH=yes 84 ;; 85 core[1-9]) 86 COREX="${PARAM:4}" 87 ;; 88 bin|installer) 89 # using xargs to trim spaces 90 OUTPUTS=`echo "$OUTPUTS $PARAM" | xargs` 91 ;; 92 *) 93 if [[ " $ALLTARGETS " == *" $PARAM "* ]]; then 94 # using xargs to trim spaces 95 TARGETS=`echo "$TARGETS $PARAM" | xargs` 96 if [ "$PARAM" == "all" ]; then 97 PARAM=$ALLTARGETS 98 fi 99 elif [ -d toolchain/$PARAM ]; then 100 # non-standard target but the toolchain exist 101 # using xargs to trim spaces 102 TARGETS=`echo "$TARGETS $PARAM" | xargs` 103 else 104 echo "Invalid parameter: $PARAM" 105 exit 1 106 fi 107 ;; 108 esac 109 110 done 111 112 if [ "$TARGETS" == "" ]; then 113 TARGETS="$ALLTARGETS" 114 fi 115 116 if [ "$OUTPUTS" == "" ]; then 117 OUTPUTS="bin installer" 118 fi 119 120 if [ "$REVISION" == "" ]; then 121 REVISION="head" 122 fi 123 124 if [ "$BRANCH" == "" ]; then 125 BRANCH="develop" 126 fi 127 128 if [ "$CONFIGS" == "" ]; then 129 CONFIGS="release debug" 130 fi 131 132 for TARGET in $TARGETS 133 do 134 if [[ $TARGET == *-bsd ]]; then 135 PLATFORM="freebsd" 136 elif [[ $TARGET == *-ndk ]]; then 137 PLATFORM="android" 138 else 139 PLATFORM="linux" 140 fi 141 if [[ " $PLATFORMS " != *" $PLATFORM "* ]]; then 142 PLATFORMS=`echo "$PLATFORMS $PLATFORM" | xargs` 143 fi 144 done 145} 146 147PrintConfig() 148{ 149 echo "Active configuration:" 150 echo " platforms: $PLATFORMS" 151 echo " targets : $TARGETS" 152 echo " outputs : $OUTPUTS" 153 echo " revision : $REVISION" 154 echo " branch : $BRANCH" 155 echo " configs : $CONFIGS" 156 echo " cleanup : $CLEAN" 157 echo " pch : $PCH" 158 echo " cores : $COREX" 159 echo 160} 161 162UpdateFromRepository() 163{ 164 if [ ! -d nzbget ]; then 165 echo "Initial checkout" 166 git clone https://github.com/nzbget/nzbget.git 167 fi 168 169 cd nzbget 170 171 BUILDDIR=$ROOT/nzbget 172 173 cd $BUILDDIR 174 175 if [ $REVISION != "work" ]; then 176 echo "Updating to $REVISION" 177 git pull 178 git checkout $BRANCH 179 if [ $REVISION != "head" ]; then 180 git checkout $REVISION 181 fi 182 touch Makefile.in configure config.h.in 183 184 echo "Updating root certificates" 185 cd ../setup 186 curl --remote-name --time-cond cacert.pem https://curl.se/ca/cacert.pem 187 cd $BUILDDIR 188 fi 189} 190 191DetectVersionRevision() 192{ 193 VERSION=`grep "AC_INIT(nzbget, " configure.ac` 194 VERSION=`expr "$VERSION" : '.*, \(.*\),.*)'` 195 196 # Building revision name 197 B=`git branch | sed -n -e 's/^\* \(.*\)/\1/p' | sed 's/ /-/g' | sed 's/(//g' | sed 's/)//g'` 198 M=`git status --porcelain` 199 if [ "$M" != "" ]; then 200 M="M" 201 fi 202 if [ "$B" == "master" ]; then 203 REVISION="$M" 204 elif [ "$B" == "develop" ]; then 205 REVISION=`git rev-list HEAD | wc -l | xargs` 206 REVISION="${REVISION}$M" 207 else 208 REVISION=`git rev-list HEAD | wc -l | xargs` 209 REVISION="${REVISION}$M-($B)" 210 fi 211} 212 213ConstructOutputFilename() 214{ 215 BASENAME="nzbget-$VERSION" 216 if [ `expr "$VERSION" : ".*-testing"` != 0 ]; then 217 BASENAME="$BASENAME-r$REVISION" 218 fi 219} 220 221ConstructSuffix() 222{ 223 case $CONFIG in 224 release) 225 SUFFIX="" 226 ;; 227 debug) 228 SUFFIX="-debug" 229 ;; 230 debug-strip) 231 SUFFIX="-debug-strip" 232 ;; 233 release-nostrip) 234 SUFFIX="-nostrip" 235 ;; 236 esac 237 238 if [ $PLATFORM == "freebsd" ]; then 239 PLATSUFF="-bsd" 240 elif [ $PLATFORM == "android" ]; then 241 PLATSUFF="-ndk" 242 else 243 PLATSUFF="" 244 fi 245} 246 247ConstructArchParams() 248{ 249 ARCH=$TARGET 250 case $TARGET in 251 mipseb) 252 ARCH=mips 253 ;; 254 arm*) 255 ARCH=arm 256 ;; 257 ppc*) 258 ARCH=powerpc 259 ;; 260 esac 261 262 TOOLCHAIN_ROOT=$ROOT/toolchain/$TARGET$PLATSUFF 263 TOOLPATH=$TOOLCHAIN_ROOT/output/host/usr/bin 264 PATH=$TOOLPATH:$ROOTPATH 265 STAGING="$TOOLCHAIN_ROOT/output/staging" 266 case $PLATFORM in 267 linux) 268 TOOLKIND=buildroot 269 ARCH=$ARCH-linux 270 ;; 271 android) 272 TOOLKIND=ndk 273 ARCH=$ARCH-linux-android 274 if [ "$ARCH" == "arm-linux-android" ]; then 275 ARCH="arm-linux-androideabi" 276 fi 277 ;; 278 freebsd) 279 TOOLKIND=crossclang 280 ARCH=$ARCH-pc-freebsd 281 SYSROOT="$TOOLCHAIN_ROOT/sysroot" 282 ;; 283 esac 284} 285 286ConfigureTarget() 287{ 288 STRIP="" 289 if [ $CONFIG == "debug-strip" -o $CONFIG == "release" ]; then 290 STRIP="-s" 291 fi 292 293 DEBUG="" 294 if [ $CONFIG != "release" ]; then 295 DEBUG="-g" 296 fi 297 298 LUBACKTRACE="" 299 if [ -f "$STAGING/lib/libubacktrace.so.1" ] ; then 300 LUBACKTRACE="-lubacktrace" 301 fi 302 303 case "$TOOLKIND-$CONFIG" in 304 buildroot-debug|buildroot-debug-strip) 305 LDFLAGS="-static $STRIP" \ 306 CXXFLAGS="-std=c++14 -g -fasynchronous-unwind-tables" \ 307 LIBS="-lcrypto -ldl -lz -Wl,--whole-archive -lpthread -Wl,--no-whole-archive $LUBACKTRACE" \ 308 ./configure --disable-dependency-tracking --host=$ARCH --enable-debug 309 ;; 310 buildroot-release|buildroot-release-nostrip) 311 LDFLAGS="-static $STRIP" \ 312 CXXFLAGS="-std=c++14 -O2 $DEBUG" \ 313 LIBS="-lcrypto -ldl -lz -Wl,--whole-archive -lpthread -Wl,--no-whole-archive" \ 314 ./configure --disable-dependency-tracking --host=$ARCH 315 ;; 316 ndk-debug|ndk-debug-strip) 317 LDFLAGS="-static -static-libstdc++ $STRIP" \ 318 CXXFLAGS="-std=c++14 -g -fasynchronous-unwind-tables" \ 319 CXX="$ARCH-clang++" \ 320 PKG_CONFIG_LIBDIR="$STAGING/usr/lib/pkgconfig" \ 321 ./configure --disable-dependency-tracking --disable-largefile --host=$ARCH --enable-debug 322 ;; 323 ndk-release|ndk-release-nostrip) 324 LDFLAGS="-static -static-libstdc++ $STRIP" \ 325 CXXFLAGS="-std=c++14 -O2 $DEBUG" \ 326 CXX="$ARCH-clang++" \ 327 PKG_CONFIG_LIBDIR="$STAGING/usr/lib/pkgconfig" \ 328 ./configure --disable-dependency-tracking --disable-largefile --host=$ARCH 329 ;; 330 crossclang-debug|crossclang-debug-strip) 331 CXX="$CROSSCLANG" \ 332 LDFLAGS="-static $STRIP -fuse-ld=lld --target=$ARCH -lc++ -lm --sysroot=$SYSROOT" \ 333 CXXFLAGS="-g --target=$ARCH --sysroot=$SYSROOT -I$SYSROOT/usr/include/c++/v1" \ 334 PKG_CONFIG_LIBDIR="$STAGING/usr/lib/pkgconfig" \ 335 ./configure --disable-dependency-tracking --host=$ARCH --enable-debug 336 ;; 337 crossclang-release|crossclang-release-nostrip) 338 CXX="$CROSSCLANG" \ 339 LDFLAGS="-static $STRIP -fuse-ld=lld --target=$ARCH -lc++ -lm --sysroot=$SYSROOT" \ 340 CXXFLAGS="-O2 $DEBUG --target=$ARCH --sysroot=$SYSROOT -I$SYSROOT/usr/include/c++/v1" \ 341 PKG_CONFIG_LIBDIR="$STAGING/usr/lib/pkgconfig" \ 342 ./configure --disable-dependency-tracking --host=$ARCH --enable-debug 343 ;; 344 esac 345} 346 347PrecompileHeaders() 348{ 349 rm -f nzbget.h.* 350 351 OPTIM="" 352 if [ $CONFIG == "release" -o $CONFIG == "release-nostrip" ]; then 353 OPTIM="-O2" 354 fi 355 356 if [ $PCH == "yes" -a $TOOLKIND == "buildroot" ]; then 357 $ARCH-g++ -std=c++14 -DHAVE_CONFIG_H \ 358 -I. -I$STAGING/usr/include -I$STAGING/usr/include/libxml2 \ 359 -g $OPTIM daemon/main/nzbget.h -o nzbget.h.gch 360 fi 361 362 if [ $PCH == "yes" -a $TOOLKIND == "ndk" ]; then 363 $ARCH-clang++ -std=c++14 -DHAVE_CONFIG_H \ 364 -I. -I$STAGING/usr/include -I$STAGING/usr/include/libxml2 \ 365 -g $OPTIM -x c++-header daemon/main/nzbget.h -o nzbget.h.pch 366 CXXFLAGS=`sed -n 's:^CXXFLAGS =.\(.*\):\1:p' Makefile` 367 sed 's:^CXXFLAGS = :CXXFLAGS = -include-pch nzbget.h.pch :' -i Makefile 368 sed "s: CXXFLAGS+=: CXXFLAGS=$CXXFLAGS :" -i Makefile 369 fi 370} 371 372PackTarget() 373{ 374 rm -r -f $OUTPUTDIR/install 375 make DESTDIR=$OUTPUTDIR/install install 376 377 cd $OUTPUTDIR 378 rm -r -f nzbget 379 mkdir -p nzbget 380 mv install/usr/local/bin/nzbget nzbget 381 mv install/usr/local/share/doc/nzbget/* nzbget 382 mv install/usr/local/share/nzbget/webui nzbget 383 mv install/usr/local/share/nzbget/scripts nzbget 384 CONFTEMPLATE=nzbget/webui/nzbget.conf.template 385 mv install/usr/local/share/nzbget/nzbget.conf $CONFTEMPLATE 386 387 rm -r -f $OUTPUTDIR/install 388 389 # adjusting nzbget.conf 390 sed 's:^MainDir=.*:MainDir=${AppDir}/downloads:' -i $CONFTEMPLATE 391 sed 's:^DestDir=.*:DestDir=${MainDir}/completed:' -i $CONFTEMPLATE 392 sed 's:^InterDir=.*:InterDir=${MainDir}/intermediate:' -i $CONFTEMPLATE 393 sed 's:^WebDir=.*:WebDir=${AppDir}/webui:' -i $CONFTEMPLATE 394 sed 's:^ScriptDir=.*:ScriptDir=${AppDir}/scripts:' -i $CONFTEMPLATE 395 sed 's:^LogFile=.*:LogFile=${MainDir}/nzbget.log:' -i $CONFTEMPLATE 396 sed 's:^ConfigTemplate=.*:ConfigTemplate=${AppDir}/webui/nzbget.conf.template:' -i $CONFTEMPLATE 397 sed 's:^AuthorizedIP=.*:AuthorizedIP=127.0.0.1:' -i $CONFTEMPLATE 398 399 tar -czf $BASENAME-bin-$PLATFORM-$TARGET$SUFFIX.tar.gz nzbget 400 401 rm -r -f nzbget 402} 403 404BuildTarget() 405{ 406 echo "Building $TARGET ($PLATFORM $CONFIG)" 407 408 cd $BUILDDIR 409 410 ConstructArchParams 411 412 ConfigureTarget 413 414 make clean 415 416 PrecompileHeaders 417 418 make -j $COREX 419 420 PackTarget 421 422 echo "Completed build in `pwd` for $TARGET ($CONFIG)" 423} 424 425BuildInstaller() 426{ 427 echo "Creating installer for $PLATFORM $CONFIG..." 428 429 cd $OUTPUTDIR 430 431 # checking if all targets exists 432 for TARGET in $TARGETS 433 do 434 ALLEXISTS="yes" 435 if [ $TARGET != "dist" ]; then 436 if [ ! -f $BASENAME-bin-$PLATFORM-$TARGET$SUFFIX.tar.gz ]; then 437 echo "Could not find $BASENAME-bin-$PLATFORM-$TARGET$SUFFIX.tar.gz" 438 ALLEXISTS="no" 439 fi 440 fi 441 done 442 443 if [ "$ALLEXISTS" == "no" ]; then 444 exit 1; 445 fi 446 447 echo "Unpacking targets..." 448 rm -r -f nzbget 449 for TARGET in $TARGETS 450 do 451 ALLEXISTS="yes" 452 if [ "$TARGET" != "dist" ]; then 453 tar -xzf $BASENAME-bin-$PLATFORM-$TARGET$SUFFIX.tar.gz 454 mv nzbget/nzbget nzbget/nzbget-$TARGET 455 cp ../setup/unrar-$TARGET$PLATSUFF nzbget/unrar-$TARGET 456 cp ../setup/7za-$TARGET$PLATSUFF nzbget/7za-$TARGET 457 fi 458 done 459 460 # adjusting nzbget.conf 461 sed 's:^UnrarCmd=unrar:UnrarCmd=${AppDir}/unrar:' -i nzbget/webui/nzbget.conf.template 462 sed 's:^SevenZipCmd=7z:SevenZipCmd=${AppDir}/7za:' -i nzbget/webui/nzbget.conf.template 463 sed 's:^CertStore=.*:CertStore=${AppDir}/cacert.pem:' -i nzbget/webui/nzbget.conf.template 464 sed 's:^CertCheck=.*:CertCheck=yes:' -i nzbget/webui/nzbget.conf.template 465 466 INSTFILE=$BASENAME-bin-$PLATFORM$SUFFIX.run 467 468 echo "Building installer package..." 469 cp $BUILDDIR/linux/installer.sh $INSTFILE 470 cp $BUILDDIR/linux/package-info.json nzbget/webui 471 cp $BUILDDIR/linux/install-update.sh nzbget 472 cp $BUILDDIR/pubkey.pem nzbget 473 cp ../setup/license-unrar.txt nzbget 474 cp ../setup/license-7zip.txt nzbget 475 cp ../setup/cacert.pem nzbget 476 477 # adjusting update config file 478 sed "s:linux:$PLATFORM:" -i nzbget/webui/package-info.json 479 sed "s:linux:$PLATFORM:" -i nzbget/install-update.sh 480 481 # creating payload 482 cd nzbget 483 tar czf - * > ../$INSTFILE.data 484 cd .. 485 486 # creating installer script 487 sed "s:^TITLE=$:TITLE=\"$BASENAME$SUFFIX\":" -i $INSTFILE 488 sed "s:^PLATFORM=$:PLATFORM=\"$PLATFORM\":" -i $INSTFILE 489 DISTTARGETS="${TARGETS/dist/}" 490 DISTTARGETS=`echo "$DISTTARGETS" | xargs` 491 sed "s:^DISTARCHS=$:DISTARCHS=\"$DISTTARGETS\":" -i $INSTFILE 492 493 MD5=`md5sum "$INSTFILE.data" | cut -b-32` 494 sed "s:^MD5=$:MD5=\"$MD5\":" -i $INSTFILE 495 496 PAYLOAD=`stat -c%s "$INSTFILE.data"` 497 PAYLOADLEN=${#PAYLOAD} 498 499 HEADER=`stat -c%s "$INSTFILE"` 500 HEADERLEN=${#HEADER} 501 HEADER=`expr $HEADER + $HEADERLEN + $PAYLOADLEN` 502 503 TOTAL=`expr $HEADER + $PAYLOAD` 504 TOTALLEN=${#TOTAL} 505 506 HEADER=`expr $HEADER - $PAYLOADLEN + $TOTALLEN` 507 TOTAL=`expr $TOTAL - $PAYLOADLEN + $TOTALLEN` 508 509 sed "s:^HEADER=$:HEADER=$HEADER:" -i $INSTFILE 510 sed "s:^TOTAL=$:TOTAL=$TOTAL:" -i $INSTFILE 511 512 # attaching payload 513 cat $INSTFILE.data >> $INSTFILE 514 rm $INSTFILE.data 515 chmod +x $INSTFILE 516 517 rm -r nzbget 518} 519 520BuildDist() 521{ 522 echo "Building dist" 523 524 cd $BUILDDIR 525 ./configure --disable-dependency-tracking --disable-cpp-check 526 make dist 527 cp nzbget-$VERSION.tar.gz $OUTPUTDIR/$BASENAME.tar.gz 528} 529 530BuildConfig() 531{ 532 ConstructSuffix 533 534 for OUTPUT in $OUTPUTS; do 535 if [ $OUTPUT == "bin" ]; then 536 for TARGET in $TARGETS; do 537 if [ $TARGET == "dist" ]; then 538 if [ ! -f $OUTPUTDIR/$BASENAME.tar.gz ]; then 539 BuildDist 540 fi 541 else 542 BuildTarget 543 fi 544 done 545 elif [ $OUTPUT == "installer" ]; then 546 BuildInstaller 547 fi 548 done 549} 550 551FilterTargets() 552{ 553 TARGETS="" 554 for TARGET in $BUILDTARGETS 555 do 556 if [[ $TARGET == *-bsd ]]; then 557 PLAT="freebsd" 558 TARGET="${TARGET%-bsd}" 559 elif [[ $TARGET == *-ndk ]]; then 560 PLAT="android" 561 TARGET="${TARGET%-ndk}" 562 else 563 PLAT="linux" 564 fi 565 if [ $PLATFORM == $PLAT ]; then 566 TARGETS=`echo "$TARGETS $TARGET" | xargs` 567 fi 568 done 569} 570 571CleanupIfNecessary() 572{ 573 if [ $CLEAN == "yes" ]; then 574 rm -r -f $OUTPUTDIR/* 575 fi 576} 577 578##### Main script body ##### 579 580# Parsing command line 581PrintUsage 582ParseCommandLine $@ 583PrintConfig 584 585# Checkout and update from git 586UpdateFromRepository 587 588# File name format for output files 589DetectVersionRevision 590ConstructOutputFilename 591 592# Building 593mkdir -p $OUTPUTDIR 594CleanupIfNecessary 595 596BUILDTARGETS=$TARGETS 597 598for PLATFORM in $PLATFORMS; do 599 FilterTargets 600 for CONFIG in $CONFIGS; do 601 BuildConfig 602 done 603done 604 605