#!@@SHELL@@ # # 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 @@SHELL@@ fi cd .. rm -Rf tmp 2> /dev/null exit 1 } source_only=false binary_only=false opts=$(getopt -n "${0}" -o 'Sbr:a:p:ds:V' -- "${@}") if [ ${?} -ne 0 ]; then print_usage "${0}" >&2 exit 1; fi eval set -- "${opts}" while true; do case "${1}" in -S) source_only=true shift ;; -b) binary_only=true shift ;; -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 ${source_only} && ${binary_only}; then printf 'opkbuild: Error: Cannot combine -S and -b\n' >&2 exit 1 fi 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. 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 build platform. build_platform=$(opkg print-architecture | sed -n \ 's/^arch \([^ -][^ -]*\) [0-9][0-9]*$/\1/p' | \ grep -v 'all') if [ -z "${build_platform}" ]; then printf 'opkbuild: Error: No build platforms found\n' >&2 exit 1 elif [ $(echo "${build_platform}" | wc -l) -gt 1 ]; then printf 'opkbuild: Error: Multiple build platforms found\n' >&2 exit 1 fi # If there no config files to copy, build platform-independent packages. if [ ! -f config ]; then host_platform='' # If a host platform was not specified, natively configure. elif [ -z "${host_platform}" ]; then host_platform="${build_platform}" 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 archtab_bre='[ \t][ \t]*\([^ \t][^ \t]*[ \t][ \t]*[^ \t][^ \t]*\)' # TODO: kbuild doesn't have standardized architecture names. For example, IA-32 # is known as "x86" in Linux and "i386" in BusyBox. So we should support a # comma-separated list of possible values and try to find one in src/arch once # the software source code is copied into the work area. # TODO: Ideally, we should have a tool like debhelper's dh_auto_configure that # detects the build system in use and configures the build automatically, # including cross building options. # Look up build GNU and kbuild architecture names. archtab_row_build="$(sed -n \ "s/^${OH_BUILD_ARCH_DIST}${archtab_bre}\$/\\1/p" \ "@@DATADIR@@/opkhelper/archtab")" if [ -z "${archtab_row_build}" ]; then printf 'opkbuild: Error: "%s" not found in architecture table.\n' \ "${OH_BUILD_ARCH_DIST}" >&2 exit 1 fi read OH_BUILD_ARCH_GNU OH_BUILD_ARCH_KBUILD <&2 exit 1 fi read OH_HOST_ARCH_GNU OH_HOST_ARCH_KBUILD <}" # Check build dependencies. oh-checkbuilddeps -s "${status_override}" || error "${srcpkg}-src" printf '\n' # TODO: This should maybe go in the library. if ! ${binary_only}; then # 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" fi # TODO: This should maybe go in the library. if ! ${source_only}; then # 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 *stamp) ;; *) ${uid0_cmd} rm -Rf ${file} || error "${binpkg}" ;; esac done fi done fi # Clean up tmp. cd .. rm -Rf tmp