Search code examples
shautotoolsautoconf

Autoconf : How to get program output in a string and check if another string is present in that


I am developing a Qt application in Python. It uses a resource file, which needs to be compiled. I am using autotools to manage compilation and installation of my projects.

Now, in order for the resource file to be usable by the application, it needs to be compiled with a certain version of the compilation program (pyrcc). I can get the version by putting the output of pyrcc -version in a variable in configure.ac. But then, I don't know how to check whether the string pyrcc5 is present in the output. If it is not present, I want to tell the user that his PyRCC programm has the wrong version, and abort configure.

Additionally, I would like to avoid the need of an extra variable for the program output, but instead do it like this (Pseudo code):

if "pyrcc5" not in output of "pyrcc -version":
    say "pyrcc has wrong version"
    exit 1

How can I do this ?


Solution

  • When writing a configure.ac for Autoconf, always remember that you are basically writing a shell script. Autoconf provides a host of macros that afford you a lot of leverage, but you can usually at least get an idea about basic "How can I do X in Autoconf?" questions by asking instead "How would I do X in a portable shell script?"

    In particular, for ...

    I would like to avoid the need of an extra variable for the program output, but instead do it like this (Pseudo code):

    if "pyrcc5" not in output of "pyrcc -version":
        say "pyrcc has wrong version"
        exit 1
    

    ... the usual tool for a portable shell script to use for such a task is grep, and, happily, the easiest way to apply it to the task does not require an intermediate variable. For example, this implements exactly your pseudocode (without emitting any extraneous messaging to the console):

    if ! pyrcc -version | grep pyrcc5 >/dev/null 2>/dev/null; then
      echo "pyrcc has wrong version"
      exit 1
    fi
    

    That pipes the output of pyrcc -version into grep, and relies on the fact that grep exits with a success status if and only if it finds any matches.

    You could, in fact, put exactly that in your configure.ac, but it would be more idiomatic to

    • Use the usual Autoconf mechanisms to locate pyrcc and grep, and to use the versions discovered that way;
    • Use the Autoconf AS_IF macro to write the if construct, instead of writing it literally;
    • Use standard Autoconf mechanisms for emitting a "checking..." message and reporting on its result; and
    • Use the standard Autoconf mechanism for outputting a failure message and terminating.

    Of course, all of that makes the above considerably more complex, but also more flexible and portable. It might look like this:

    AC_ARG_VAR([PYRCC], [The name or full path of pyrcc. Version 5 is required.])
    
    # ...
    
    AC_PROG_GREP
    AC_CHECK_PROGS([PYRCC], [pyrcc5 pyrcc], [])
    AS_IF([test "x${PYRCC}" = x],
      [AC_MSG_ERROR([Required program pyrcc was not found])])
    
    # ...
    
    AC_MSG_CHECKING([whether ${PYRCC} has an appropriate version])
    AS_IF([! pyrcc -version | grep pyrcc5 >/dev/null 2>/dev/null], [
      AC_MSG_RESULT([no])
      AC_MSG_ERROR([pyrcc version 5 is required, but ${PYRCC} is a different version])
    ], [
      AC_MSG_RESULT([yes])
    ])
    

    In addition to portability and conventional Autoconf progress messaging, that also gets the builder a way to specify a particular pyrcc executable to configure (by setting variable PYRCC in its environment), documents that in configure's help text, and exports PYRCC as a make variable.

    Oh, and I snuck in a check for pyrcc under the name pyrcc5, too, though I don't know whether that's useful in practice.

    The final result no longer looks much like the shell script fragment I offered first, I grant. But again, the pure shell script fragment could be used as is, and also, the fully Autoconfiscated version is derived directly from the pure script.