2

I was working on a bash function to help me to compile packages:

make_package() {
        local PACKAGE_NAME=$1
        local PACKAGE_VERSION=$2
        local PACKAGE_INSTALL_DIR=$3
        local PACKAGE_CONFIGURE_PARAMETERS=$4

        echo "Make ${PACKAGE_NAME}-${PACKAGE_VERSION}"

        local BUILD_DIRECTORY=build/${PACKAGE_NAME}-${PACKAGE_VERSION}_build
        if [ -d ${BUILD_DIRECTORY} ]; then
                rm -rf ${BUILD_DIRECTORY}/*
        else
                mkdir -p ${BUILD_DIRECTORY}
        fi

        cd ${BUILD_DIRECTORY} && \
        ../../${PACKAGE_NAME}-${PACKAGE_VERSION}/configure $4 --prefix=`pwd`/../$3 && \
        make && \
        make install && \
        cd ../../
        if [ $? -ne 0 ]; then
                echo "Make ${PACKAGE_NAME} error!"
                exit 1
        fi
}

It was working fine for things like

make_package "popt" "1.16" "arm_sdk" "--host=arm-linux-gnueabihf"
make_package "ncurses" "5.6" "arm_sdk" "--host=arm-linux-gnueabihf --without-ada"

But I'm stuck at:

make_package "OpenIPMI" "2.0.28" "--host=arm-linux-gnueabihf LDFLAGS=\"-L`pwd`/build/arm_sdk/lib\" CPPFLAGS=\"-I`pwd`/build/arm_sdk/include -I`pwd`/build/arm_sdk/include/ncurses\""

The problem comes from the:

CPPFLAGS=\"-I`pwd`/build/arm_sdk/include -I`pwd`/build/arm_sdk/include/ncurses\"

Because of this I get an error:

configure: error: unrecognized option: `-I/home/me/build/arm_sdk/include/ncurses"'

So I'm stuck here... Is there a way to pass such configure arguments as a parameter to a function in bash?

kostr22
  • 163

1 Answers1

1

The shell parses quotes (and escapes etc) before expanding parameters (and variables etc). As a result, putting quotes in the value of a parameter, as you're doing in your fourth argument, doesn't do anything useful. See BashFAQ #50: "I'm trying to put a command in a variable, but the complex cases always fail!", and many previous questions.

Usually, people are trying to store multiple arguments in a variable, and the answer is to use an array; but you can't pass an array as an argument, so that won't work for you. What you can do instead is pass multiple arguments, so $4 is the first package configuration argument, $5 is the second, etc. So you'd run it something like this:

make_package "OpenIPMI" "2.0.28" --host=arm-linux-gnueabihf LDFLAGS="-L$PWD/build/arm_sdk/lib" CPPFLAGS="-I$PWD/build/arm_sdk/include -I$PWD/build/arm_sdk/include/ncurses"

Note that I replaced use of the pwd command with references to the variable $PWD -- this doesn't require creating a new process each time, so it's more efficient. If you do want to use the pwd command, I recommend using $(pwd) instead of backticks, because it's generally more readable and doesn't have the same syntactic weirdnesses that backticks have.

To extract and use the arguments in your function, use something like this:

# Store arguments starting at $4 in an array:
local package_configure_parameters=("${@:4}")
...

...
../../"${package_name}-${package_version}/configure" "${package_configure_parameters[@]}" --prefix="$PWD/../$package_install_dir" &&
...

See all those parentheses, brackets, quotes etc I used in defining and referencing the array? Those are all strictly required for it to work right. I also added quotes around the other variable references, which probably isn't necessary, but is a good idea. shellcheck.net is good at pointing out things like this. And I lowercased the variable names, which is generally a good practice to avoid tripping over any of the all-caps names with special functions (like $PWD). Lower- or mixed-case names are safer unless you want some special meaning.

Arrays are a bash (and zsh and...) feature, but not available in all shells. For completeness, if you needed to do this in a portable or non-bash script, you could capture $1 through $3 as variables (as you already do), then use shift to remove them from the function's argument list and use "$@" to get the config parameters:

make_package() {
    local package_name="$1"
    local package_version="$2"
    local package_install_dir="$3"
    shift 3    # Remove everything but the package config params from the arg list

    ...
    ../../"${package_name}-${package_version}/configure" "$@" --prefix="$PWD/../$package_install_dir" &&
    ...