#! /bin/sh
#
# opkhelper
# src/opkbuild
# Build opkg packages.
#
# Copyright (C) 2012 Patrick "P. J." McDermott
#
# 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 .
. @@LIBDIR@@/opkhelper/controlfields
. @@LIBDIR@@/opkhelper/architecture
. @@LIBDIR@@/opkhelper/archive
print_usage()
{
cat <.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Written by P. J. McDermott.
EOF
}
error()
{
[ ${#} -eq 1 ] && printf 'opkbuild: [%s] Error\n' "${1}" >&2
if ${dbg}; then
printf 'opkbuild: Starting debugging shell...\n' >&2
/bin/sh
fi
cd ..
rm -Rf tmp 2> /dev/null
exit 1
}
opts=$(getopt -n "${0}" -o 'r:a:p:ds:V' -- "${@}")
if [ ${?} -ne 0 ]; then
print_usage "${0}" >&2
exit 1;
fi
eval set -- "${opts}"
while true; do
case "${1}" in
-r)
uid0_cmd=${2}
shift 2
;;
-a)
host_arch=${2}
shift 2
;;
-p)
host_platform=${2}
shift 2
;;
-d)
dbg=true
shift
;;
-s)
status_override=${2}
shift 2
;;
-V)
print_version
exit 0
;;
--)
shift
break
;;
*)
print_usage "${0}" >&2
exit 1
;;
esac
done
if [ -z "${uid0_cmd}" ]; then
uid0_cmd=fakeroot
fi
${uid0_cmd} true
if [ ${?} -ne 0 ]; then
printf 'opkbuild: Error running command to gain UID 0\n' >&2
exit 1
fi
if [ -z "${dbg}" ]; then
dbg=false
fi
# Sanity checks.
printf 'opkbuild: Checking for sanity...\n'
if [ ! -f format -o ! -f build -o ! -f control ]; then
printf 'Error: Current working directory is not a source package.\n' >&2
exit 1
fi
if [ "$(cat format)" != '1.0' ]; then
printf 'Error: Source package is of an incompatible version.\n' >&2
exit 1
fi
# Attempt to detect the build architecture tuple.
build_arch=$(opkg print-architecture | sed -n \
's/^arch \([^ -][^ -]*-[^ -][^ -]*-[^ -][^ -]*\) [0-9][0-9]*$/\1/p')
if [ -z "${build_arch}" ]; then
printf 'opkbuild: Error: No installable architecture found\n' >&2
exit 1
elif [ $(echo "${build_arch}" | wc -l) -gt 1 ]; then
printf 'opkbuild: Error: Multiple installable architectures found\n' >&2
exit 1
fi
# If a host architecture is not specified, natively build.
if [ -z "${host_arch}" ]; then
host_arch="${build_arch}"
fi
# Attempt to detect the host platform.
# If there no config files to copy, build platform-independent packages.
if [ ! -f config ]; then
host_platform=''
# If a host platform was not specified ...
elif [ -z "${host_platform}" ]; then
host_platform=$(opkg print-architecture | \
sed -n 's/^arch \([^ -][^ -]*\) [0-9][0-9]*$/\1/p' | \
grep -v 'all')
# ... and there are config files and zero installable platforms, fail.
if [ -z "${host_platform}" ]; then
printf 'opkbuild: Error: %s\n' \
'Building platform-dependent package and no platforms detected' >&2
exit 1
# ... and there are config files and multiple installable platforms, request
# explicit selection.
elif [ $(echo "${host_platform}" | wc -l) -gt 1 ]; then
printf 'opkbuild: Error: %s\n' \
'Multiple platforms found while detecting host' >&2
exit 1
fi
# ... and there are config files and one installable platform, build for it.
fi
# Resolve status override file path.
pkg_dir="${PWD}"
cd "$(dirname "${status_override}")"
status_override="${PWD}/$(basename "${status_override}")"
cd "${pkg_dir}"
# Make work area.
printf 'opkbuild: Making work area...\n'
mkdir tmp
cd tmp
# Get source package name and version.
printf 'opkbuild: Reading source package control fields...\n'
srcpkg=$(oh_get_field Source)
version=$(oh_get_field Version)
export OH_SRCPKG="${srcpkg}"
export OH_PKGVER=${version}
# Set environment variables for the build architecture.
export OH_BUILD_ARCH_DIST="${build_arch}"
IFS=- read OH_BUILD_ARCH_CPU OH_BUILD_ARCH_KERNEL OH_BUILD_ARCH_LIBS <&2
exit 1
fi
# Look up GNU architecture name and set toolchain environment variables.
export OH_HOST_ARCH_GNU="$(sed -n \
"s/^${OH_HOST_ARCH_DIST}[ \\t][ \\t]*\\(.*\\)$/\\1/p" \
"@@DATADIR@@/opkhelper/archtab")"
if [ -z "${OH_HOST_ARCH_GNU}" ]; then
printf 'opkbuild: Error: "%s" not found in architecture table.\n' \
"${OH_HOST_ARCH_DIST}" >&2
exit 1
fi
# NB: This is written for GNU Binutils and GCC and won't work for, e.g., LLVM.
export AR="${OH_HOST_ARCH_GNU}-ar"
export AS="${OH_HOST_ARCH_GNU}-as"
export CC="${OH_HOST_ARCH_GNU}-gcc"
export CPP="${OH_HOST_ARCH_GNU}-cpp"
export CXX="${OH_HOST_ARCH_GNU}-g++"
export LD="${OH_HOST_ARCH_GNU}-ld"
export NM="${OH_HOST_ARCH_GNU}-nm"
export OBJCOPY="${OH_HOST_ARCH_GNU}-objcopy"
export OBJDUMP="${OH_HOST_ARCH_GNU}-objdump"
export RANLIB="${OH_HOST_ARCH_GNU}-ranlib"
export READELF="${OH_HOST_ARCH_GNU}-readelf"
export SIZE="${OH_HOST_ARCH_GNU}-size"
export STRINGS="${OH_HOST_ARCH_GNU}-strings"
export STRIP="${OH_HOST_ARCH_GNU}-strip"
# Set build flags.
if [ -f "@@DATADIR@@/opkhelper/buildflags/${OH_HOST_ARCH_CPU}" ]; then
. @@DATADIR@@/opkhelper/buildflags/${OH_HOST_ARCH_CPU}
fi
# Check build dependencies.
oh-checkbuilddeps -s "${status_override}" || error "${srcpkg}-src"
printf '\n'
# Build *-src package.
printf 'opkbuild: Attempting to build package "%s"...\n' "${srcpkg}-src"
printf 'opkbuild: Installing files for package "%s"...\n' "${srcpkg}-src"
${uid0_cmd} mkdir -p ${srcpkg}-src.data/usr/src/${srcpkg}_${version} ||
error "${srcpkg}-src"
for file in ../*; do
case ${file} in
../tmp)
;;
../*)
${uid0_cmd} cp -R ${file} \
${srcpkg}-src.data/usr/src/${srcpkg}_${version} ||
error "${srcpkg}-src"
;;
esac
done
( ${uid0_cmd} oh-gencontrol -s;) || error "${srcpkg}-src"
( ${uid0_cmd} oh-buildopk -s;) || error "${srcpkg}-src"
( ${uid0_cmd} rm -Rf ${srcpkg}-src.data;) || error "${srcpkg}-src"
printf 'opkbuild: Package "%s" complete!\n\n' "${srcpkg}-src"
# Build other binary packages.
for binpkgdir in ../*.pkg/; do
binpkg=${binpkgdir#'../'}
binpkg=${binpkg%'.pkg/'}
export OH_BINPKG="${binpkg}"
# Check architecture.
oh_is_buildable "${binpkg}"
if [ ${?} -eq 0 ]; then
printf 'opkbuild: Attempting to build package "%s"...\n' "${binpkg}"
# Copy or extract software sources to src.
if [ -d ../src ]; then
printf 'opkbuild: Copying sources into work area...\n'
cp -Rp ../src src || error "${binpkg}"
else
printf 'opkbuild: Extracting sources into work area...\n'
oh_archive_extract_source
case ${?} in
1)
printf 'opkbuild: Error: No source archive found\n' >&2
error
;;
2)
printf 'opkbuild: Error: Multiple source archives found\n' \
>&2
error
;;
3)
printf 'opkbuild: Error: %s\n' \
'Unsupported archive compression format detected' >&2
error
;;
4)
printf 'opkbuild: Error: %s\n' \
'No directories found in source archive' >&2
error
;;
5)
printf 'opkbuild: Error: %s\n' \
'Multiple top-level directories found in source archive' >&2
error
;;
6)
printf 'opkbuild: Error: %s\n' \
'Failed to extract source archive' >&2
error
;;
7)
printf 'opkbuild: Error: %s\n' \
'Failed to move extracted sources' >&2
error
;;
esac
fi
# Make installation directory.
# TODO: Maybe this should be an FHS-compliant filesystem hierarchy.
mkdir dest || error "${binpkg}"
# Apply patches.
oh-applypatches
# Copy platform config files.
oh-copyconfig || error "${binpkg}"
# Build the package.
${uid0_cmd} ../build ${binpkg} || error "${binpkg}"
printf 'opkbuild: Package "%s" complete!\n\n' "${binpkg}"
# Clean up everything except the build stamps.
for file in *; do
case ${file} in
*.buildstamp)
;;
*)
${uid0_cmd} rm -Rf ${file} || error "${binpkg}"
;;
esac
done
fi
done
# Clean up tmp.
cd ..
rm -Rf tmp