# -*-sh-*- ############################################### ### ### Configuration ### # name of the "control" files CONTROL="dune.module" ############################################### ### ### check for environment variables ### if test -z $GREP; then GREP=grep fi if test -z "$SED"; then SED=sed fi # SunOS [e]grep does not seem to comprehend character classes. Set up # some variables to spell them out UPPER=ABCDEFGHIJKLMNOPQRSTUVWXYZ LOWER=abcdefghijklmnopqrstuvwxyz ALPHA="$UPPER$LOWER" DIGIT=0123456789 ALNUM="$ALPHA$DIGIT" space=" " formfeed="" newline=" " cr=" " tab=" " vtab="" # $SPACE will unfortunately not work since grep will not accept an # embedded newline. Instead one can often get away with using $BLANK SPACE="$space$formfeed$newline$cr$tab$vtab" BLANK="$space$tab" NOBLANK="^$space$tab" # # read parameters from a $CONTROL file # # parameters: # $1 file to read # PARSER_TRIM="awk '{gsub(/^[ \\t]+|[ \\t]+$/,\"\");printf(\"%s\", \$0);}'" parse_control() { # check file existence if test ! -f "$1" -o "$(basename "$1")" != "$CONTROL"; then echo "ERROR: '$1' is no $CONTROL file" >&2 exit 1 fi # reset information handling module="" module_inst="no" # read parameters from control file local name="$($GREP Module: "$1" | cut -d ':' -f2 | eval $PARSER_TRIM)" if test "x$name" = "x"; then echo "ERROR: $CONTROL files $1 does not contain a Module entry" >&2 exit 1 fi # create and check variable name from module name export module=$(fix_variable_name $name) if ! check_modname "$module"; then echo "ERROR: $CONTROL files $1 contains an invalid Module entry" >&2 exit 1 fi # read dune.module file local deps="$($GREP "^[BLANK]*Depends:" "$1" | cut -d ':' -f2 | eval $PARSER_TRIM)" local sugs="$($GREP "^[BLANK]*Suggests:" "$1" | cut -d ':' -f2 | eval $PARSER_TRIM)" local vers="$($GREP "^[BLANK]*Version:" "$1" | cut -d ':' -f2 | eval $PARSER_TRIM)" local main="$($GREP "^[BLANK]*Maintainer:" "$1" | cut -d ':' -f2 | eval $PARSER_TRIM)" # check whether the module is installed. # - installed modules can be found via pkg-config # - pkg-config --var=prefix should be the same as $path # # the path contains a different sub structure # for installed and source modules # - installed module: ${path}/lib/dunecontrol/${name}/dune.module # and there is a file ${path}/lib/pkgconfig/${name}.pc # - source module: ${path}/dune.module # and there is a file ${path}/${name}.pc.in local path="$(canonicalpath "$1")" if pkg-config $name; then local prefix="$(pkg-config --variable=prefix $name)" local pkgpath=$(canonicalname "$prefix/lib/dunecontrol/$name") if test x"$pkgpath" = x"$path"; then path="$prefix" module_inst="yes" fi fi # avoid multiple definition of the same module if eval test "x\$HAVE_$module" != "x"; then # make sure we don't stumble over the same module twice if eval test "\$PATH_$module" = "$path"; then return fi local old_mod_inst eval old_mod_inst=\$INST_$module case "$old_mod_inst$module_inst" in # multiple local modules are an error # multiple installed modules are an error nono|yesyes) echo "ERROR: multiple definition of module $name" >&2 echo "previous defined in:" >&2 if eval test x\$INST_$module = "xyes"; then echo " $(eval echo \$PATH_$module)/lib/dunecontrol/$name/$CONTROL" >&2 else echo " $(eval echo \$PATH_$module)/$CONTROL" >&2 fi echo "redefined in:" >&2 if test "$module_inst" = "yes"; then echo " $path/lib/dunecontrol/$name/$CONTROL" >&2 else echo " $path/$CONTROL" >&2 fi exit 1 ;; # installed modules are superseded by locally built modules noyes) return ;; # local modules supersede installed modules yesno) superseded_modules="$superseded_modules $path" true # do nothing, ignore the previously found module ;; esac fi # set status variables export HAVE_$module=yes export PATH_$module="$path" export VERS_$module="$vers" export NAME_$module="$name" export MAIN_$module="$main" export DEPS_$module="$deps" export INST_$module="$module_inst" for name in $deps; do mod=$(fix_variable_name $name) export NAME_$mod="$name" done export SUGS_$module="$sugs" for name in $sugs; do mod=$(fix_variable_name $name) export NAME_$mod="$name" done # update list of modules if test "$module_inst" = "yes"; then export INSTMODULES="$INSTMODULES$module " else export LOCALMODULES="$LOCALMODULES$module " fi } # Uses the current compiler to extract information about the # multiarch triplets and sets the export variable MULTIARCH_LIBDIR # according to it. # If not compiler is specified then cc or gcc is used. extract_multiarch_pkg_config_path(){ local my_cxx_compiler if test "x$MULTIARCH_LIBDIR" != "x"; then return fi set +e #error in the multiarch detection should not be fatal. $(which cc &>/dev/null) if test $? -eq "0"; then my_cxx_compiler=cc else my_cxx_compiler=gcc fi multiarch=$($my_cxx_compiler --print-multiarch 2>/dev/null) if test $? -gt 0; then for i in "target=" "Target:"; do multiarch=$($my_cxx_compiler -v 2>&1| $GREP "$i" | sed "s/.*$i[$BLANK]*\([a-z0-9_-]*\)/\1/" | $SED "s/-[a-z]*-linux-gnu/-linux-gnu/") if test -n "$multiarch"; then break; fi done fi set -e # set to old value. export MULTIARCH_LIBDIR="lib/$multiarch" # create PKG_CONFIG_PATH for installed dune modules for i in $MULTIARCH_LIBDIR lib64 lib32 lib; do if test -d "$PREFIX_DIR/$i/pkgconfig"; then export PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$PREFIX_DIR/$i/pkgconfig" fi done } # # try to setup the control path # setup_control_path() { if test -z "$DUNE_CONTROL_PATH"; then DUNE_CONTROL_PATH=. # try pkg-config locations if ! pkg-config dune-common; then # try usual locations of installed modules for i in /usr/local/lib/dunecontrol/ /usr/lib/dunecontrol/; do if test -d $i; then DUNE_CONTROL_PATH=$DUNE_CONTROL_PATH:"$i" fi done for i in `echo $PKG_CONFIG_PATH | tr ':' ' '`; do if test -d "$i/../dunecontrol"; then DUNE_CONTROL_PATH=$DUNE_CONTROL_PATH:"$i/../dunecontrol" fi done else NEW_DUNE_CONTROL_DIR=$(pkg-config dune-common --variable=prefix)/lib/dunecontrol # There might be old version of DUNE lying around, that do not contain # lib/dunecontrol, yet. To prevent failur at a later stage of dunecontrol # we check that the directory really exists. if test -d "$NEW_DUNE_CONTROL_DIR"; then DUNE_CONTROL_PATH=$DUNE_CONTROL_PATH:$NEW_DUNE_CONTROL_DIR fi fi fi # try to read DUNE_CONTROL_PATH from OPTS file if test -n "$DUNE_OPTS_FILE"; then DUNE_CONTROL_PATH="$(. $DUNE_OPTS_FILE; eval echo $DUNE_CONTROL_PATH)" fi # canonicalize path local TMP="" # foreach dir in $@ while read dir; do TMP=$TMP:"$(canonicalname "$dir")" done <<EOF $(echo $DUNE_CONTROL_PATH | sed -e 's/:\+/:/g' | tr ':' '\n') EOF # sort+uniq path DUNE_CONTROL_PATH="$(echo $TMP | tr ':' '\n' | sort -u | tr '\n' ':' | sed -e 's/^://' -e 's/:$//')" # safe result export DUNE_CONTROL_PATH } # # search for modules in each directory in DUNE_CONTROL_PATH # find_modules_in_path() { setup_control_path if test -z "$FOUND_MODULES"; then # foreach dir in $@ while read dir; do if test -d "$dir"; then while read m; do test -n "$m" && parse_control "$m" done <<EOFM $(find -H "$dir" -name $CONTROL | $GREP -v 'dune-[-_a-zA-Z]/dune-[-a-zA-Z_]*-[0-9]\{1,\}.[0-9]\{1,\}/') EOFM else parse_control "$dir" fi done <<EOF $(echo $DUNE_CONTROL_PATH | sed -e 's/:\+/:/g' | tr ':' '\n') EOF export MODULES="$LOCALMODULES$INSTMODULES" export FOUND_MODULES="$MODULES" else export MODULES="$FOUND_MODULES" fi } # # sort $MODULES according to the dependencies # sort_modules() { # reset lists export SORTEDMODULES="" export REVERSEMODULES="" export SORTEDMODULES_SUB="" # handle each modules passed as parameter for m in "$@"; do # did we find a module file for this module? if eval test x\$HAVE_$m != x; then _sort_module $m MAIN else echo "ERROR: could not find module $(eval echo \$NAME_$m)" >&2 exit 1 fi done # save result export MODULES="$SORTEDMODULES" # setup list of SUGS/DEPS and the INFO list export SORTEDMODULES_INFO="" export SORTEDMODULES_DEPS="" export SORTEDMODULES_MAIN="" export SORTEDMODULES_SUGS="" local mode for m in $MODULES; do eval mode=\$MODE_$m SORTEDMODULES_INFO="$SORTEDMODULES_INFO $m[$mode]" eval SORTEDMODULES_$mode=\"\$SORTEDMODULES_$mode $m\" done export SORTEDMODULES_INFO export SORTEDMODULES_DEPS export SORTEDMODULES_SUGS export SORTEDMODULES_MAIN # clean up temporary variables for m in $MODULES; do export MODE_$m="" export SORT_DONE_$m="" export SORT_DEPS_DONE_$m="" export SORT_SUGS_DONE_$m="" done } # strip any leading spaces, tabs, or newlines _ltrim() { local val="$1" local tab=" " local nl=" " while :; do case $val in " "*|"$tab"*|"$nl"*) val=${val#?} ;; *) break ;; esac done # if this is used inside `...` or $(...), any trailing newlines will be # stripped, no matter what we do. Setting a variable to the result would # work around this, but is not a common idiom. printf "%s" "$val" } _check_deps() { local module="$1" local mode="$2" local depmode="$3" local report="ERROR" local requires="requires" local required="required" local dependency="dependency" if test "x$mode" = "xSUGS"; then report="WARNING" requires="suggests" required="suggested" dependency="suggestion" fi eval deps=\$${mode}_$module #initially remove leading space deps=$(_ltrim "$deps") while test -n "$deps"; do #the end of the name is marked either by space or opening parenthesis name="${deps%%[ (]*}" #remove the name and adjacent whitespace deps=$(_ltrim "${deps#"$name"}") #check whether there is a dependency version case "$deps" in '('*) deps="${deps#(}" depver="${deps%%)*}" deps="${deps#*)}" ;; *) depver= ;; esac #remove any leading whitespace for the next iteration deps=$(_ltrim "$deps") dep=$(fix_variable_name $name) if ! check_modname $dep; then echo "ERROR: invalid module name '$name' ($dependency of '$module')" >&2 exit 1 fi if eval test x\$HAVE_$dep != "x"; then eval ver=\$VERS_$dep if test "$SKIPVERSIONCHECK" != "yes" && ! check_version "$ver" "$depver"; then echo "$report: version mismatch." >&2 echo " $modname $requires '$name $depver'," >&2 echo " but only '$name' = '$ver' is available." >&2 if test "x$mode" = "xDEPS"; then exit 1 else echo "Skipping '$name'!" >&2 continue fi fi _sort_module $dep $depmode else # perhaps this module is installed, # then it should be handled via pkg-config if ! pkg-config $name; then echo "$report: could not find module '$name'," >&2 echo " module is also unknown to pkg-config." >&2 echo " Maybe you need to adjust PKG_CONFIG_PATH!" >&2 echo " '$name' is $required by $modname" >&2 if test "x$mode" = "xDEPS"; then exit 1 else echo "Skipping '$name'!" >&2 continue fi else eval ver=$(pkg-config $name --modversion) if test "$SKIPVERSIONCHECK" != "yes" && ! check_version "$ver" "$depver"; then echo "$report: version mismatch." >&2 echo " $modname $requires '$name $depver'," >&2 echo " but only '$name' = '$ver' is installed." >&2 if test "x$mode" = "xDEPS"; then exit 1 else echo "Skipping '$name'!" >&2 continue fi fi # update module list parse_control $(pkg-config $name --variable=prefix)/lib/dunecontrol/$name/dune.module _sort_module $dep $depmode fi fi done } # # recursive part of sort_modules # evaluate dependencies of one module # # parameters: # $1 name of the modules # $2 parser mode: # DEPS: search for dependencies # SUSG: search for suggestions (DEPS of SUGS are handled as SUGS) # MAIN: primary invocation of a DEPS search, # MAIN modules are not added to the list of DEPS/SUGS # _sort_module() { local module="$1" local mode="$2" test -n "$mode" local modname="" eval modname=\$NAME_$module local deps="" local name="" local dep="" local ver="" local depver="" shift 1 if ! check_modname $module; then echo "ERROR: invalid module name $module" >&2 exit 1 fi depmode=$(test $mode = SUGS && echo SUGS || echo DEPS) if eval test "x\$SORT_${depmode}_DONE_$module" != "xyes"; then # stop any recursion export SORT_${depmode}_DONE_$module=yes # resolve dependencies _check_deps $module DEPS $depmode # it might happen that the DEPS are actually SUGS # resolve suggestions _check_deps $module SUGS SUGS # remember mode of the module if eval test "x\$MODE_$module" = xSUGS -o "x\$MODE_$module" = x; then export MODE_$module=$mode fi # topological list of the module and its dependencies/suggestions if eval test "x\$SORT_DONE_$module" != "xyes"; then export SORT_DONE_$module=yes export SORTEDMODULES="$SORTEDMODULES $module" export REVERSEMODULES="$module $REVERSEMODULES" fi fi } # # load the $CONTROL file, skip all control variables # and run a command # # parameters: # $1 command to execute # $2 full path of the $CONTROL file # eval_control() { local command="$1" local file="$2" shift 2 if test -f "$file"; then # open subshell ( set -e # load functions defined in $file # if $command is not defined in $file, # then the default implementation will be executed eval "$($GREP -v "^[-$ALNUM]\{1,\}:" "$file")" # execute $command $command ) || false else echo "ERROR: could not find $file" >&2 exit 1 fi } # # fix a value such that it is suitable for a variable name # # parameters: # $1 value # fix_variable_name() { echo ${@//[[:punct:]]/_} } # # fix a value such that it is suitable for a variable name and assign it # # parameters: # $1 name of variable # $2 value # fix_and_assign() { local name="$1" if ! check_modname $name; then echo "ERROR: error in assignment. $name is not a valid variabel name." >&2 fi shift 1 export $name=$(fix_variable_name $@) } # # make sure the module name fits the naming convention # (we try to assign the name and report upon failure) # # parameters: # $1 module name # check_modname() { # magic pattern match, see http://www.linuxmisc.com/9-unix-questions/67d307ca51f16ed4.htm [ -n "${1##*[!A-Za-z0-9_]*}" ] && [ -n "${1##[!A-Za-z_]*}" ] } # # compare a sub part of the version string # # parameters: # $1 version # $2 part # # parts: # 1: major # 2: minor # 3: revision # get_sub_version() { #it would be nice to give the part to awk via a "-v FIELD=$2" #command line argument. Unfortunately, SunOS does not support this. #Worse, we cannot use awks int() function here, since under SunOS it #will always return 0 for string input. echo $1 | cut -d. -f"$2" | sed 's/[^0-9].*$//;s/^$/0/' } # # compare two versions # # parameters: # $1 version1 # $2 version1 # # return: # 0: equal # 1: v1 > v2 # 2: v1 < v2 # compare_versions() { local v1="$1" local v2="$2" for i in 1 2 3; do compare_sub_version $v1 $v2 $i || return 0 done echo "eq" } compare_sub_version() { # compare sub version number local sub1=`get_sub_version $1 $3` local sub2=`get_sub_version $2 $3` if test $sub1 -gt $sub2; then echo "gt" return 1 fi if test $sub1 -lt $sub2; then echo "lt" return 1 fi return 0 } check_version() { if test -z "$2"; then # if no constraint is given, check_version is true return 0 fi local v=$1 local PATTERN="^ *\([<>=]*\) *\([0-9.]*\)\(.*\)$" if test x != `echo "$2" | sed -e "s/$PATTERN/x/"`; then echo "ERROR: invalid version constraint $2" >&2 exit 1 fi local op=`echo "$2" | sed -e "s/$PATTERN/\1/"` local v2=`echo "$2" | sed -e "s/$PATTERN/\2/"` local rest=`echo "$2" | sed -e "s/$PATTERN/\3/" -e 's/ //g'` local result=1 local rel=`compare_versions $v $v2` case $rel$op in "eq<="|"eq="|"eq>="|\ "gt>="|"gt>"|\ "lt<="|"lt<") result=0 ;; esac if test -z "$rest"; then return $result fi PATTERN="\([|&]\{2\}\)\(.*\)$" if test xx != x`echo "$rest" | sed -e "s/$PATTERN/x/"`; then echo "ERROR: invalid version constraint '$rest'" >&2 exit 1 fi op=`echo "$rest" | sed -e "s/$PATTERN/\1/"` v2=`echo "$rest" | sed -e "s/$PATTERN/\2/"` if eval "test $result -eq 0" $op "check_version \"$v\" \"$v2\""; then return 0 fi return 1 }