#!/usr/bin/env bash
-# Script to copy a toolchain from given source to given
-# destination directory.
+#
+# Script for various external toolchain tasks, refer to
+# the --help output for more information.
+#
+# Copyright (C) 2012 Jo-Philipp Wich <jow@openwrt.org>
+#
+# 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 2 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
CC=""
CXX=""
c: ld-* lib{anl,c,cidn,crypt,dl,m,nsl,nss_dns,nss_files,resolv,util}
rt: librt-* librt
pthread: libpthread-* libpthread
- cpp: libstdc++
+ stdcpp: libstdc++
gcc: libgcc_s
ssp: libssp
gfortran: libgfortran
test_uclibc() {
local sysroot="$("$CC" $CFLAGS -print-sysroot 2>/dev/null)"
- if [ -d "$sysroot" ]; then
+ if [ -d "${sysroot:-$TOOLCHAIN}" ]; then
local lib
- for lib in "$sysroot"/{lib,usr/lib,usr/local/lib}/ld-uClibc*.so*; do
+ for lib in "${sysroot:-$TOOLCHAIN}"/{lib,usr/lib,usr/local/lib}/ld-uClibc*.so*; do
if [ -f "$lib" ] && [ ! -h "$lib" ]; then
return 0
fi
local inc
local sysroot="$("$CC" "$@" -muclibc -print-sysroot 2>/dev/null)"
for inc in "include" "usr/include" "usr/local/include"; do
- local conf="$sysroot/$inc/bits/uClibc_config.h"
+ local conf="${sysroot:-$TOOLCHAIN}/$inc/bits/uClibc_config.h"
if [ -f "$conf" ]; then
case "$feature" in
lfs) grep -q '__UCLIBC_HAS_LFS__ 1' "$conf"; return $?;;
find_libs() {
- local spec="$(echo "$LIB_SPECS" | sed -ne "s#^[[:space:]]*$1:##p")"
+ local spec="$(echo "$LIB_SPECS" | sed -ne "s#^[[:space:]]*$1:##ip")"
if [ -n "$spec" ] && probe_cpp; then
local libdir libdirs
}
find_bins() {
- local spec="$(echo "$BIN_SPECS" | sed -ne "s#^[[:space:]]*$1:##p")"
+ local spec="$(echo "$BIN_SPECS" | sed -ne "s#^[[:space:]]*$1:##ip")"
if [ -n "$spec" ] && probe_cpp; then
local sysroot="$("$CPP" -print-sysroot)"
local bindir bindirs
for bindir in $(
- echo "$sysroot/bin";
- echo "$sysroot/usr/bin";
- echo "$sysroot/usr/local/bin";
- echo "$TOOLCHAIN/bin";
- echo "$TOOLCHAIN/usr/bin";
- echo "$TOOLCHAIN/usr/local/bin";
+ echo "${sysroot:-$TOOLCHAIN}/bin";
+ echo "${sysroot:-$TOOLCHAIN}/usr/bin";
+ echo "${sysroot:-$TOOLCHAIN}/usr/local/bin";
"$CPP" $CFLAGS -v -x c /dev/null 2>&1 | \
sed -ne 's#:# #g; s#^COMPILER_PATH=##p'
); do
}
+wrap_bin_cc() {
+ local out="$1"
+ local bin="$2"
+
+ echo '#!/bin/sh' > "$out"
+ echo 'for arg in "$@"; do' >> "$out"
+ echo ' case "$arg" in -l*|-L*|-shared|-static)' >> "$out"
+ echo -n ' exec "'"$bin"'" '"$CFLAGS"' ${STAGING_DIR:+' >> "$out"
+ echo -n '-idirafter "$STAGING_DIR/usr/include" ' >> "$out"
+ echo -n '-L "$STAGING_DIR/usr/lib" ' >> "$out"
+ echo '-Wl,-rpath-link,"$STAGING_DIR/usr/lib"} "$@" ;;' >> "$out"
+ echo ' esac' >> "$out"
+ echo 'done' >> "$out"
+ echo -n 'exec "'"$bin"'" '"$CFLAGS"' ${STAGING_DIR:+' >> "$out"
+ echo '-idirafter "$STAGING_DIR/usr/include"} "$@"' >> "$out"
+
+ chmod +x "$out"
+}
+
+wrap_bin_ld() {
+ local out="$1"
+ local bin="$2"
+
+ echo '#!/bin/sh' > "$out"
+ echo -n 'exec "'"$bin"'" '"$CFLAGS"' ${STAGING_DIR:+' >> "$out"
+ echo -n '-L "$STAGING_DIR/usr/lib" ' >> "$out"
+ echo '-rpath-link "$STAGING_DIR/usr/lib"} "$@"' >> "$out"
+
+ chmod +x "$out"
+}
+
+wrap_bin_other() {
+ local out="$1"
+ local bin="$2"
+
+ echo '#!/bin/sh' > "$out"
+ echo 'exec "'"$bin"'" "$@"' >> "$out"
+
+ chmod +x "$out"
+}
+
wrap_bins() {
if probe_cc; then
mkdir -p "$1" || return 1
for cmd in "${CC%-*}-"*; do
if [ -x "$cmd" ]; then
local out="$1/${cmd##*/}"
+ local bin="$cmd"
+
+ if [ -x "$out" ] && ! grep -q STAGING_DIR "$out"; then
+ mv "$out" "$out.bin"
+ bin='$(dirname "$0")/'"${out##*/}"'.bin'
+ fi
- echo '#!/bin/sh' > "$out"
case "${cmd##*/}" in
*-*cc|*-*cc-*|*-*++|*-*++-*|*-cpp)
- echo -n 'exec "'"$cmd"'" '"$CFLAGS"' ' >> "$out"
- echo -n '${STAGING_DIR:+-idirafter ' >> "$out"
- echo -n '"$STAGING_DIR/usr/include" ' >> "$out"
- echo -n '-L "$STAGING_DIR/usr/lib" ' >> "$out"
- echo -n '-Wl,-rpath-link,' >> "$out"
- echo '"$STAGING_DIR/usr/lib"} "$@"' >> "$out"
+ wrap_bin_cc "$out" "$bin"
;;
*-ld)
- echo -n 'exec "'"$cmd"'" ${STAGING_DIR:+' >> "$out"
- echo -n '-L "$STAGING_DIR/usr/lib" ' >> "$out"
- echo -n '-rpath-link ' >> "$out"
- echo '"$STAGING_DIR/usr/lib"} "$@"' >> "$out"
+ wrap_bin_ld "$out" "$bin"
;;
*)
- echo "exec '$cmd' \"\$@\"" >> "$out"
+ wrap_bin_other "$out" "$bin"
;;
esac
- chmod +x "$out"
fi
done
}
+print_config() {
+ local mktarget="$1"
+ local mksubtarget
+
+ local target="$("$CC" $CFLAGS -dumpmachine)"
+ local cpuarch="${target%%-*}"
+ local prefix="${CC##*/}"; prefix="${prefix%-*}-"
+ local config="${0%/scripts/*}/.config"
+
+ # if no target specified, print choice list and exit
+ if [ -z "$mktarget" ]; then
+ # prepare metadata
+ if [ ! -f "${0%/scripts/*}/tmp/.targetinfo" ]; then
+ "${0%/*}/scripts/config/mconf" prepare-tmpinfo
+ fi
+
+ local mktargets=$(
+ sed -ne "
+ /^Target: / { h };
+ /^Target-Arch: $cpuarch\$/ { x; s#^Target: ##p }
+ " "${0%/scripts/*}/tmp/.targetinfo" | sort -u
+ )
+
+ for mktarget in $mktargets; do
+ case "$mktarget" in */*)
+ mktargets=$(echo "$mktargets" | sed -e "/^${mktarget%/*}\$/d")
+ esac
+ done
+
+ if [ -n "$mktargets" ]; then
+ echo "Available targets:" >&2
+ echo $mktargets >&2
+ else
+ echo -e "Could not find a suitable OpenWrt target for " >&2
+ echo -e "CPU architecture '$cpuarch' - you need to " >&2
+ echo -e "define one first!" >&2
+ fi
+ return 1
+ fi
+
+ # bail out if there is a .config already
+ if [ -f "${0%/scripts/*}/.config" ]; then
+ echo "There already is a .config file, refusing to overwrite!" >&2
+ return 1
+ fi
+
+ case "$mktarget" in */*)
+ mksubtarget="${mktarget#*/}"
+ mktarget="${mktarget%/*}"
+ ;; esac
+
+
+ echo "CONFIG_TARGET_${mktarget}=y" > "$config"
+
+ if [ -n "$mksubtarget" ]; then
+ echo "CONFIG_TARGET_${mktarget}_${mksubtarget}=y" >> "$config"
+ fi
+
+ if test_feature "softfloat"; then
+ echo "CONFIG_SOFT_FLOAT=y" >> "$config"
+ else
+ echo "# CONFIG_SOFT_FLOAT is not set" >> "$config"
+ fi
+
+ if test_feature "ipv6"; then
+ echo "CONFIG_IPV6=y" >> "$config"
+ else
+ echo "# CONFIG_IPV6 is not set" >> "$config"
+ fi
+
+ if test_feature "locale"; then
+ echo "CONFIG_BUILD_NLS=y" >> "$config"
+ else
+ echo "# CONFIG_BUILD_NLS is not set" >> "$config"
+ fi
+
+ echo "CONFIG_DEVEL=y" >> "$config"
+ echo "CONFIG_EXTERNAL_TOOLCHAIN=y" >> "$config"
+ echo "CONFIG_TOOLCHAIN_ROOT=\"$TOOLCHAIN\"" >> "$config"
+ echo "CONFIG_TOOLCHAIN_PREFIX=\"$prefix\"" >> "$config"
+ echo "CONFIG_TARGET_NAME=\"$target\"" >> "$config"
+
+ local lib
+ for lib in C RT PTHREAD GCC STDCPP SSP GFORTRAN; do
+ local file
+ local spec=""
+ local llib="$(echo "$lib" | sed -e 's#.*#\L&#')"
+ for file in $(find_libs "$lib"); do
+ spec="${spec:+$spec }$(echo "$file" | sed -e "s#^$TOOLCHAIN#.#")"
+ done
+ if [ -n "$spec" ]; then
+ echo "CONFIG_PACKAGE_lib${llib}=y" >> "$config"
+ echo "CONFIG_LIB${lib}_FILE_SPEC=\"$spec\"" >> "$config"
+ else
+ echo "# CONFIG_PACKAGE_lib${llib} is not set" >> "$config"
+ fi
+ done
+
+ local bin
+ for bin in LDD LDCONFIG; do
+ local file
+ local spec=""
+ local lbin="$(echo "$bin" | sed -e 's#.*#\L&#')"
+ for file in $(find_bins "$bin"); do
+ spec="${spec:+$spec }$(echo "$file" | sed -e "s#^$TOOLCHAIN#.#")"
+ done
+ if [ -n "$spec" ]; then
+ echo "CONFIG_PACKAGE_${lbin}=y" >> "$config"
+ echo "CONFIG_${bin}_FILE_SPEC=\"$spec\"" >> "$config"
+ else
+ echo "# CONFIG_PACKAGE_${lbin} is not set" >> "$config"
+ fi
+ done
+
+ # inflate
+ make -C "${0%/scripts/*}" defconfig
+ return 0
+}
+
+
probe_cc() {
if [ -z "$CC" ]; then
local bin
while [ -n "$1" ]; do
arg="$1"; shift
case "$arg" in
- -l|--libs)
- [ -n "$1" ] || {
- echo "No library given, specify one of:"$(echo "$LIB_SPECS" | sed -ne 's#:.*$##p') >&1
- exit 1
- }
- FINDLIB="$1"; shift
- ;;
- -b|--bins)
- [ -n "$1" ] || {
- echo "No binary given, specify one of:"$(echo "$BIN_SPECS" | sed -ne 's#:.*$##p') >&1
- exit 1
- }
- FINDBIN="$1"; shift
- ;;
-
--toolchain)
[ -d "$1" ] || {
echo "Toolchain directory '$1' does not exist." >&2
--print-target)
if probe_cc; then
- CC="${CC##*/}"
- echo "${CC%-*}"
- exit 0
+ exec "$CC" $CFLAGS -dumpmachine
fi
echo "No C compiler found in '$TOOLCHAIN'." >&2
exit 1
exit $?
;;
+ --config)
+ if probe_cc; then
+ print_config "$1"
+ exit $?
+ fi
+ echo "No C compiler found in '$TOOLCHAIN'." >&2
+ exit 1
+ ;;
+
-h|--help)
me="$(basename "$0")"
echo -e "\nUsage:\n" >&2
echo -e " Create wrapper scripts for C and C++ compiler, " >&2
echo -e " linker, assembler and other key executables in " >&2
echo -e " the directory given with --wrap.\n" >&2
+ echo -e " $me --toolchain {directory} --config {target}" >&2
+ echo -e " Analyze the given toolchain and print a suitable" >&2
+ echo -e " .config for the given target. Omit target " >&2
+ echo -e " argument to get a list of names.\n" >&2
echo -e " $me --help" >&2
echo -e " Display this help text and exit.\n\n" >&2
echo -e " Most commands also take a --cflags parameter which " >&2
esac
done
-exit 0
+exec $0 --help