configure
author "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
Sat Jun 04 19:17:26 2011 +0200 (2011-06-04)
changeset 2506 2ab553e37517
parent 2500 ba1e71fa72a9
child 2507 a5856225d851
permissions -rwxr-xr-x
configure: rationalise error messages with meaningful texts

Currently, error messages just state the obvious: a required
component is required. While in some cases, there is not much
else to say, in some other cases we could tell much more.

For example, a missing libstdc++ means no static toolchain.

Also, format error and warning messages in a similar fashion,
with a {error,warning} intro, followed by the message specified
by the caller.

Signed-off-by: "Yann E. MORIN" <yann.morin.1998@anciens.enib.fr>
     1 #!/bin/sh
     2 
     3 myname="${0##*/}"
     4 
     5 VERSION=$( cat .version )
     6 DATE=$( date +%Y%m%d )
     7 
     8 PREFIX_DEFAULT=/usr/local
     9 
    10 BINDIR_set=
    11 LIBDIR_set=
    12 DOCDIR_set=
    13 MANDIR_set=
    14 LOCAL_set=
    15 FORCE=
    16 
    17 do_quit=
    18 
    19 # Simply print the error message, and exit. Obvious, he?
    20 do_error() {
    21     printf "${myname}: ${@}\n"
    22     exit 1
    23 }
    24 
    25 # Given an option string and the following argument,
    26 # echoes the value of the option.
    27 # If --var=val => echoes val and returns 0, meaning second arg was not consumed
    28 # If --var val => echoes val and returns non null, meaning second arg was used
    29 get_optval(){
    30     case "$1" in
    31         --*=?*)
    32             printf "${1#*=}"
    33             return 0
    34             ;;
    35         *)
    36             printf "${2}"
    37             return 1
    38             ;;
    39     esac
    40 }
    41 
    42 # The set_xxx functions will set the corresponding configuration variable
    43 # They return 0 if second arg was not consumed, and non-zero if it was consumed.
    44 set_prefix() {
    45     PREFIX="$( get_optval "$1" "$2" )"
    46 }
    47 set_bindir() {
    48     BINDIR_set=1
    49     BINDIR="$( get_optval "$1" "$2" )"
    50 }
    51 set_libdir() {
    52     LIBDIR_set=1
    53     LIBDIR="$( get_optval "$1" "$2" )"
    54 }
    55 set_docdir() {
    56     DOCDIR_set=1
    57     DOCDIR="$( get_optval "$1" "$2" )"
    58 }
    59 set_mandir() {
    60     MANDIR_set=1
    61     MANDIR="$( get_optval "$1" "$2" )"
    62 }
    63 set_tool() {
    64     local var_name="${1%%=*}"
    65     var_name="${var_name#--with-}"
    66     eval ${var_name}="\$( get_optval "$1" "$2" )"
    67 }
    68 
    69 # var_list is a list of variables, each one holding a path to a
    70 # tool, either detected by ./configure, or specified by the user.
    71 var_list=""
    72 kconfig_list=""
    73 
    74 # This function adds a variable name to the above list of variable names.
    75 # $1: the name of the variable to add to the list
    76 add_to_var_list() {
    77     local v
    78     for v in ${var_list}; do
    79         [ "${v}" = "${1}" ] && return 0
    80     done
    81     var_list="${var_list} ${1}"
    82 }
    83 add_to_kconfig_list() {
    84     local k
    85     for k in ${kconfig_list}; do
    86         [ "${k}" = "${1}" ] && return 0
    87     done
    88     kconfig_list="${kconfig_list} ${1}"
    89 }
    90 
    91 # A function to test for required tools/headers/libraries
    92 # Return 0 (true) if found, !0 (false) if not found
    93 #
    94 # $*: [prog|inc|lib]=<name[ name...]>
    95 #     the name(s) of tool(s) to test for
    96 #     mandatory
    97 #       eg: prog=bash   prog="curl wget"
    98 # $*: var=<var_name>
    99 #     the name of the variable to test and set
   100 #     optional
   101 #       eg: var=bash    if ${bash} is set and non-null, use that,
   102 #                       else check for bash and set bash=$(which bash)
   103 # $*: ver=<regexp>
   104 #     for each 'prog', test if $(prog --version) matches 'regexp'
   105 #     optional
   106 #       eg: ver='^GNU bash, version [34]\.'
   107 # $*: err=<error_message>
   108 #     the error message to print if tool is missing
   109 #     optional, defaults to: '${prog}: none found'
   110 #       eg: err="'bash' 3.x or above was not found"
   111 #     Note: err may be printed by caller, not us
   112 # $*: kconfig=<var_name>
   113 #     the name of a variable to pass down to kconfig if
   114 #     the prog/inc/lib was found
   115 #     optional, defaults to none
   116 #       eg: kconfig=has_libncurses
   117 check_for() {
   118     local val
   119     local item
   120     local where
   121     local status
   122 
   123     # Note: prog/inc/lib and var/kconfig/ver/err are set here,
   124     # but declared by the caller (because it needs it)
   125     for item in "${@}"; do
   126         case "${item}" in
   127             prog=*|inc=*|lib=*|var=*|ver=*|err=*|kconfig=*)
   128                 eval ${item%%=*}=\"${item#*=}\"
   129                 ;;
   130             *)  do_error "has_or_abort: incorrect parameters: '$@'";;
   131         esac
   132     done
   133 
   134     if [ -n "${kconfig}" ]; then
   135         add_to_kconfig_list "${kconfig}"
   136     fi
   137 
   138     case "${prog}:${inc}:${lib}" in
   139         ?*::)
   140             for item in ${prog}; do
   141                 printf "Checking for '${item}'... "
   142                 if [ -n "${var}" ]; then
   143                     eval val="\${${var}}"
   144                     if [ -n "${val}" ]; then
   145                         printf "${val} (cached)\n"
   146                         add_to_var_list "${var}"
   147                         return 0
   148                     fi
   149                 fi
   150                 where="$( which "${item}" 2>/dev/null )"
   151                 if [ -z "${where}" ]; then
   152                     printf "no\n"
   153                     continue
   154                 elif [ -n "${ver}" ]; then
   155                     str=$( LC_ALL=C "${where}" --version 2>&1   \
   156                            |grep -E "${ver}"                    \
   157                            |head -n 1
   158                          )
   159                     if [ -z "${str}" ]; then
   160                         printf "no\n"
   161                         unset where
   162                         continue
   163                     fi
   164                 fi
   165                 status="${where}"
   166                 break
   167             done
   168             ;;
   169         :?*:)
   170             for item in ${inc}; do
   171                 printf "Checking for '${item}'... "
   172                 if printf "#include \"${item}\"" |gcc -x c -c - -o /dev/null >/dev/null 2>&1; then
   173                     where="${item}"
   174                     status=yes
   175                     break;
   176                 fi
   177                 printf "no\n"
   178             done
   179             ;;
   180         ::?*)
   181             for item in ${lib}; do
   182                 printf "Checking for '${item}'... "
   183                 where="$( gcc -print-file-name="${item}" )"
   184                 if [ "${where}" != "${item}" ]; then
   185                     where="$( readlink "${where}" )"
   186                     status=yes
   187                     break;
   188                 fi
   189                 printf "no\n"
   190             done
   191             ;;
   192     esac
   193 
   194     if [ -z "${status}" ]; then
   195         return 1
   196     fi
   197 
   198     printf "${status}"
   199     if [ -n "${var}" ]; then
   200         eval ${var}='"'"${where}"'"'
   201         add_to_var_list "${var}"
   202     fi
   203     if [ -n "${kconfig}" ]; then
   204         eval ${kconfig}=y
   205     fi
   206     printf "\n"
   207 }
   208 
   209 # This function checks for a tool, and aborts if not found
   210 # See check_for(), above, for how to call has_or_abort
   211 has_or_abort() {
   212     # We declare these 6 variables here, although they are
   213     # set in check_for(), called below
   214     local prog inc lib
   215     local var ver err kconfig
   216 
   217     if ! check_for "$@"; then
   218         printf " * A mandatory dependency is missing, or version mis-match\n"
   219         printf " * ${err:-${prog}${inc}${lib}: none found}\n"
   220         if [ -n "${var}" ]; then
   221             printf " * --> You can give the path to this tool using: --with-${var}=PATH\n"
   222         fi
   223         printf "\n"
   224         # Bail out if --force is not specified
   225         [ -z "${FORCE}" ] && do_error "Bailing out..."
   226         printf "<*                                          *>\n"
   227         printf "<*            FORCE in action:              *>\n"
   228         printf "<* Continuing despite missing pre-requisite *>\n"
   229         printf "<*          Prepare for breakage            *>\n"
   230         printf "<*                                          *>\n"
   231         printf "\n"
   232     fi
   233 }
   234 
   235 # This function checks for a tool, and warns if not found
   236 # See check_for(), above, for how to call has_or_abort
   237 # Note: if err is not set, then no error message is printed
   238 has_or_warn() {
   239     # We declare these 6 variables here, although they are
   240     # set in check_for(), called below
   241     local prog inc lib
   242     local var ver err kconfig
   243 
   244     if ! check_for "$@"; then
   245         printf " * An optional dependency is missing, some features will be disabled\n"
   246         printf "${err:+ * ${err}\n}"
   247         if [ -n "${var}" ]; then
   248             printf " * --> You can give the path to this tool using: --with-${var}=PATH\n"
   249         fi
   250     fi
   251 }
   252 
   253 do_help() {
   254     cat <<__EOF__
   255 \`configure' configures crosstool-NG-${VERSION} to adapt to many kind of systems.
   256 
   257 USAGE: ./configure [OPTION]...
   258 
   259 Defaults for the options are specified in brackets.
   260 
   261 Configuration:
   262   -h, --help              display this help and exit
   263       --force             force configure to continue, even in case
   264                           some pre-requisites are missing
   265 
   266 Installation directories:
   267   --prefix=PREFIX         install files in PREFIX [${PREFIX_DEFAULT}]
   268   --local                 don't install, and use current directory
   269 
   270 By default, \`make install' will install all the files in
   271 \`${PREFIX_DEFAULT}/bin', \`${PREFIX_DEFAULT}/lib' etc.  You can specify
   272 an installation prefix other than \`${PREFIX_DEFAULT}' using \`--prefix',
   273 for instance \`--prefix=\${HOME}'.
   274 
   275 For better control, use the options below.
   276 
   277 Fine tuning of the installation directories:
   278   --bindir=DIR            user executables [PREFIX/bin]
   279   --libdir=DIR            object code libraries [PREFIX/lib]
   280   --docdir=DIR            info documentation [PREFIX/share/doc]
   281   --mandir=DIR            man documentation [PREFIX/share/man]
   282 
   283 Optional Features:
   284   --with-install=PATH     Specify the full PATH to GNU install
   285   --with-make=PATH        Specify the full PATH to GNU make >= 3.80
   286   --with-grep=PATH        Specify the full PATH to GNU grep
   287   --with-sed=PATH         Specify the full PATH to GNU sed
   288   --with-bash=PATH        Specify the full PATH to bash >= 3.0
   289 __EOF__
   290 }
   291 
   292 #---------------------------------------------------------------------
   293 # Set user's options
   294 
   295 while [ $# -ne 0 ]; do
   296     case "$1" in
   297         --local)    LOCAL_set="y"; shift;;
   298         --prefix*)  set_prefix "$1" "$2" && shift || shift 2;;
   299         --bindir*)  set_bindir "$1" "$2" && shift || shift 2;;
   300         --libdir*)  set_libdir "$1" "$2" && shift || shift 2;;
   301         --docdir*)  set_docdir "$1" "$2" && shift || shift 2;;
   302         --mandir*)  set_mandir "$1" "$2" && shift || shift 2;;
   303         --with-*)   set_tool   "$1" "$2" && shift || shift 2;;
   304         --force)    FORCE=1; shift;;
   305         --help|-h)  do_help; exit 0;;
   306         # Skip, auto-stuff compatibility
   307         --build=*|--host=*|--infodir=*|--datadir=*|--sysconfdir=*|--localstatedir=*) shift;;
   308         --build|--host|--infodir|--datadir|--sysconfdir|--localstatedir)             shift 2;;
   309         *)          printf "Unrecognised option: '${1}'\n"; do_help; exit 1;;
   310     esac
   311 done
   312 
   313 # Use defaults
   314 [ -z "${PREFIX}" ] && set_prefix "" "${PREFIX_DEFAULT}"
   315 
   316 # Special case when installing locally
   317 if [ "${LOCAL_set}" = "y" ]; then
   318     set_prefix "" "$( pwd )"
   319     set_bindir "" "$( pwd )"
   320     set_libdir "" "$( pwd )"
   321     set_docdir "" "$( pwd )/docs"
   322     set_mandir "" "$( pwd )/docs"
   323 fi
   324 
   325 #---------------------------------------------------------------------
   326 # Some sanity checks, now
   327 
   328 # We check for grep and sed manually, because they are used in check_for()
   329 printf "Checking for 'grep'... "
   330 if [ -n "${grep}" ]; then
   331     printf "${grep} (cached)\n"
   332 else
   333     grep="$( which grep 2>/dev/null )"
   334     if [ -z "${grep}" ]; then
   335         printf "not found\n"
   336     else
   337         printf "${grep}\n"
   338         printf "Checking whether '${grep}' supports -E... "
   339         if echo 'foo' |"${grep}" -E 'foo' >/dev/null 2>&1; then
   340             printf "yes\n"
   341         else
   342             printf "no\n"
   343             grep=
   344         fi
   345     fi
   346 fi
   347 if [ -z "${grep}" ]; then
   348     printf "Either you are missing entirely the needed tool,\n"
   349     printf "or the version you have is too old.\n"
   350     printf "You can give the path to this tool using: --with-grep=PATH\n"
   351     do_error "Bailing out..."
   352 fi
   353 add_to_var_list grep
   354 
   355 printf "Checking for 'sed'... "
   356 if [ -n "${sed}" ]; then
   357     printf "${sed} (cached)\n"
   358 else
   359     sed="$( which sed 2>/dev/null )"
   360     if [ -z "${sed}" ]; then
   361         printf "not found\n"
   362     else
   363         printf "${sed}\n"
   364         printf "Checking whether '${sed}' supports -i and -e... "
   365         touch .ct-ng.sed.test
   366         if "${sed}" -r -i -e 's/foo/bar/' .ct-ng.sed.test >/dev/null 2>&1; then
   367             printf "yes\n"
   368         else
   369             printf "no\n"
   370             sed=
   371         fi
   372         rm -f .ct-ng.sed.test
   373     fi
   374 fi
   375 if [ -z "${sed}" ]; then
   376     printf "Either you are missing entirely the needed tool,\n"
   377     printf "or the version you have is too old.\n"
   378     printf "You can give the path to this tool using: --with-sed=PATH\n"
   379     do_error "Bailing out..."
   380 fi
   381 add_to_var_list sed
   382 
   383 # The regular list of tools we can now easily check for
   384 has_or_abort prog=bash                              \
   385              var=bash                               \
   386              ver='^GNU bash, version (3\.[1-9]|4)'  \
   387              err="'bash' 3.1 or above was not found"
   388 has_or_abort prog=cut
   389 has_or_abort prog=install var=install
   390 has_or_abort prog=make                                  \
   391              var=make                                   \
   392              ver='^GNU Make (3.[89][[:digit:]]|[4-9])'  \
   393              err="GNU 'make' 3.80 or above was not found"
   394 has_or_abort prog=gcc
   395 has_or_abort prog="awk gawk" ver='^GNU Awk' err="GNU 'awk' was not found"
   396 has_or_abort prog=bison
   397 has_or_abort prog=flex
   398 has_or_abort prog=makeinfo
   399 has_or_abort prog=automake                                                      \
   400              ver='\(GNU automake\) (1\.[[:digit:]]{2,}|[2-9][[:digit:]]*\.)'    \
   401              err="'automake' 1.10 or above was not found"
   402 has_or_abort prog=libtool                                                                           \
   403              var=libtool                                                                            \
   404              ver='\(GNU libtool.*\) (2[[:digit:]]*\.|1\.6[[:digit:]]*\.|1\.5\.[2-9][[:digit:]]+)'   \
   405              err="'libtool' 1.5.26 or above was not found"
   406 has_or_abort prog=stat
   407 has_or_abort prog="curl wget"
   408 has_or_abort prog=cvs
   409 has_or_abort prog=patch
   410 has_or_abort prog=tar
   411 has_or_abort prog=gzip
   412 has_or_abort prog=bzip2
   413 has_or_abort prog=lzma
   414 has_or_abort prog=readlink
   415 has_or_abort prog=objcopy var=objcopy
   416 has_or_abort prog=objdump var=objdump
   417 has_or_abort prog=readelf var=readelf
   418 has_or_abort prog=patch var=patch
   419 
   420 has_or_abort inc="ncurses/ncurses.h ncurses/curses.h ncurses.h curses.h"    \
   421              err="'ncurses' headers files were not found"
   422 
   423 ncurses_libs="$( for l in ncursesw ncurses curses; do   \
   424                      for x in so a dylib; do            \
   425                          printf "lib$l.$x ";            \
   426                      done;                              \
   427                  done                                   \
   428                )"
   429 has_or_abort lib="${ncurses_libs}"                  \
   430              err="The 'ncurses' library is needed fo the menuconfig frontend"
   431 
   432 stdcxx_libs="$( for x in so dylib a; do \
   433                    printf "libstdc++.$x "; \
   434                done \
   435              )"
   436 has_or_abort lib="${stdcxx_libs}" \
   437              err="The 'libstdc++' library is needed to build gcc"
   438 
   439 # Yes, we may be checking twice for libstdc++.a
   440 # The first is because we need one instance of libstdc++ (shared or static)
   441 # because it is needed for PPL; the second is because the static version is
   442 # required for static-linking, and if missing, the option is removed.
   443 has_or_warn  lib="libstdc++.a" \
   444              err="static 'libstdc++' is needed to statically link the toolchain's executables" \
   445              kconfig=has_static_libstdcxx
   446 
   447 #---------------------------------------------------------------------
   448 # Compute the version string
   449 
   450 # If this version is n hg clone, try to get the revision number
   451 # If we can't get the revision number, use date
   452 printf "\nComputing version string... "
   453 case "${VERSION}" in
   454     *+hg|hg)
   455         REVISION="$( hg id -n 2>/dev/null || true )"
   456         case "${REVISION}" in
   457             "")
   458                 VERSION="${VERSION}_unknown@$( date +%Y%m%d.%H%M%S )";;
   459             *)
   460                 VERSION="${VERSION}_$( hg id -b )@${REVISION%%+}_$( hg id -i )"
   461                 ;;
   462         esac
   463         # Arrange to have no / in the directory name, no need to create an
   464         # arbitrarily deep directory structure
   465         VERSION="$( printf "${VERSION}\n" |"${sed}" -r -e 's|/+|_|g;' )"
   466         ;;
   467 esac
   468 printf "${VERSION}\n"
   469 
   470 #---------------------------------------------------------------------
   471 # Compute and check install paths
   472 
   473 # Now we have the version string, we can build up the paths
   474 [ -z "${BINDIR_set}" ] && BINDIR="${PREFIX}/bin"
   475 [ -z "${LIBDIR_set}" ] && LIBDIR="${PREFIX}/lib"
   476 [ -z "${DOCDIR_set}" ] && DOCDIR="${PREFIX}/share/doc"
   477 [ -z "${MANDIR_set}" ] && MANDIR="${PREFIX}/share/man"
   478 
   479 # Install support files in our own sub-dir, so as not to mangle (system)
   480 # files and dirs, but only if not --local
   481 if [ -z "${LOCAL_set}" ]; then
   482     LIBDIR="${LIBDIR}/ct-ng-${VERSION}"
   483     DOCDIR="${DOCDIR}/ct-ng-${VERSION}"
   484 fi
   485 
   486 # Check that install PATHs are absolute
   487 for p in BIN LIB DOC MAN; do
   488     var="${p}DIR"
   489     eval v='"${'"${var}"'}"'
   490     case "${v}" in
   491         /*) ;;
   492         *)  do_error "'${var}' is not an absolute path: '${v}'"
   493     esac
   494 done
   495 
   496 #---------------------------------------------------------------------
   497 # That's all, folks!
   498 
   499 printf "Building up Makefile... "
   500 var_sed="$( for var_name in ${var_list}; do
   501                 eval echo 's,@@${var_name}@@,${'"${var_name}"'},g'
   502             done
   503           )"
   504 kconfig_sed="s/@@KCONFIG@@/$( for k_name in ${kconfig_list}; do
   505                                   eval printf \"${k_name}=\${${k_name}} \"
   506                               done
   507                             )/"
   508 "${sed}" -r -e "s,@@BINDIR@@,${BINDIR},g"       \
   509             -e "s,@@LIBDIR@@,${LIBDIR},g"       \
   510             -e "s,@@DOCDIR@@,${DOCDIR},g"       \
   511             -e "s,@@MANDIR@@,${MANDIR},g"       \
   512             -e "s,@@VERSION@@,${VERSION},g"     \
   513             -e "s,@@DATE@@,${DATE},g"           \
   514             -e "s,@@LOCAL@@,${LOCAL_set},g"     \
   515             -e "${var_sed}"                     \
   516             -e "${kconfig_sed}"                 \
   517          Makefile.in                            \
   518          >Makefile
   519 echo "done"
   520 
   521 cat <<__EOF__
   522 
   523 crosstool-NG configured as follows:
   524   PREFIX='${PREFIX}'
   525   BINDIR='${BINDIR}'
   526   LIBDIR='${LIBDIR}'
   527   DOCDIR='${DOCDIR}'
   528   MANDIR='${MANDIR}'
   529 
   530 Now run:
   531   make
   532 __EOF__
   533 if [ "${LOCAL_set}" != "y" ]; then
   534     printf "  make install\n"
   535 fi