Improve work around for Qt-4.3.2.
[autotroll.git] / build-aux / autotroll.m4
blob75aad19ff5bcbb3bc088f581f12622d12fb1badb
1 # Build Qt apps with the autotools (Autoconf/Automake).
2 # M4 macros.
3 # This file is part of AutoTroll.
4 # Copyright (C) 2006  Benoit Sigoure <benoit.sigoure@lrde.epita.fr>
6 # AutoTroll is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; either version 2
9 # of the License, or (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
19 # USA.
21  # ------------- #
22  # DOCUMENTATION #
23  # ------------- #
25 # Disclaimer: Never tested with anything else than Qt 4.2! Feedback welcome.
26 # Simply invoke AT_WITH_QT in your configure.ac. AT_WITH_QT can take
27 # arguments which are documented in depth below. The default arguments are
28 # equivalent to the default .pro file generated by qmake.
30 # Invoking AT_WITH_QT will do the following:
31 #  - Add a --with-qt option to your configure
32 #  - Find qmake, moc and uic and save them in the make variables $(QMAKE),
33 #    $(MOC), $(UIC).
34 #  - Save the path to Qt in $(QT_PATH)
35 #  - Find the flags to use Qt, that is:
36 #     * $(QT_DEFINES): -D's defined by qmake.
37 #     * $(QT_CFLAGS): CFLAGS as defined by qmake (C?!)
38 #     * $(QT_CXXFLAGS): CXXFLAGS as defined by qmake.
39 #     * $(QT_INCPATH): -I's defined by qmake.
40 #     * $(QT_CPPFLAGS): Same as $(QT_DEFINES) + $(QT_INCPATH)
41 #     * $(QT_LFLAGS): LFLAGS defined by qmake.
42 #     * $(QT_LDFLAGS): Same thing as $(QT_LFLAGS).
43 #     * $(QT_LIBS): LIBS defined by qmake.
45 # You *MUST* invoke $(MOC) and/or $(UIC) where necessary. AutoTroll provides
46 # you with Makerules to ease this, here is a sample Makefile.am to use with
47 # AutoTroll which builds the code given in the chapter 7 of the Qt Tutorial:
48 # http://doc.trolltech.com/4.2/tutorial-t7.html
50 # -------------------------------------------------------------------------
51 # include $(top_srcdir)/build-aux/autotroll.mk
53 # ACLOCAL_AMFLAGS = -I build-aux
55 # bin_PROGRAMS = lcdrange
56 # lcdrange_SOURCES =  $(BUILT_SOURCES) lcdrange.cpp lcdrange.h main.cpp
57 # lcdrange_CXXFLAGS = $(QT_CXXFLAGS) $(AM_CXXFLAGS)
58 # lcdrange_CPPFLAGS = $(QT_CPPFLAGS) $(AM_CPPFLAGS)
59 # lcdrange_LDFLAGS  = $(QT_LDFLAGS) $(LDFLAGS)
60 # lcdrange_LDADD    = $(QT_LIBS) $(LDADD)
62 # BUILT_SOURCES = lcdrange.moc.cpp
63 # -------------------------------------------------------------------------
65 # Note that your MOC, UIC and QRC files *MUST* be listed manually in
66 # BUILT_SOURCES. If you name them properly (eg: .moc.cc, .qrc.cc, .ui.cc -- of
67 # course you can use .cpp or .cxx or .C rather than .cc) AutoTroll will build
68 # them automagically for you (using implicit rules defined in autotroll.mk).
70 m4_pattern_forbid([^AT_])dnl
71 m4_pattern_forbid([^_AT_])dnl
73 # AT_WITH_QT([QT_modules], [QT_config], [QT_misc])
74 # ------------------------------------------------
75 # Enable Qt support and add an option --with-qt to the configure script.
77 # The QT_modules argument is optional and defines extra modules to enable or
78 # disable (it's equivalent to the QT variable in .pro files). Modules can be
79 # specified as follows:
81 # AT_WITH_QT   => No argument -> No QT value.
82 #                                Qmake sets it to "core gui" by default.
83 # AT_WITH_QT([xml])   => QT += xml
84 # AT_WITH_QT([+xml])  => QT += xml
85 # AT_WITH_QT([-gui])  => QT -= gui
86 # AT_WITH_QT([xml -gui +sql svg])  => QT += xml sql svg
87 #                                     QT -= gui
89 # The QT_config argument is also optional and follows the same convention as
90 # QT_modules. Instead of changing the QT variable, it changes the CONFIG
91 # variable, which is used to tweak configuration and compiler options.
93 # The last argument, QT_misc (also optional) will be copied as-is the .pro
94 # file used to guess how to compile Qt apps. You may use it to further tweak
95 # the build process of Qt apps if tweaking the QT or CONFIG variables isn't
96 # enough for you.
97 AC_DEFUN([AT_WITH_QT],
98 [ AC_REQUIRE([AC_CANONICAL_HOST])
99   AC_REQUIRE([AC_CANONICAL_BUILD])
100   AC_REQUIRE([AC_PROG_CXX])
102   test x"$TROLL" != x && echo 'ViM rox emacs.'
104 dnl Memo: AC_ARG_WITH(package, help-string, [if-given], [if-not-given])
105   AC_ARG_WITH([qt],
106               [AS_HELP_STRING([--with-qt],
107                  [Path to Qt @<:@Look in PATH and /usr/local/Trolltech@:>@])],
108               [QT_PATH=$withval], [QT_PATH=])
110   # Find Qt.
111   AC_ARG_VAR([QT_PATH], [Path to the Qt installation])
112   if test -d /usr/local/Trolltech; then
113     # Try to find the latest version.
114     tmp_qt_paths=`echo /usr/local/Trolltech/*/bin | tr ' ' '\n' | sort -nr \
115                                               | xargs | sed 's/  */:/g'`
116   fi
118   # Find qmake.
119   AC_ARG_VAR([QMAKE], [Qt Makefile generator command])
120   AC_PATH_PROGS([QMAKE], [qmake qmake-qt4 qmake-qt3], [missing],
121                 [$QT_DIR:$QT_PATH:$PATH:$tmp_qt_paths])
122   if test x"$QMAKE" = xmissing; then
123     AC_MSG_ERROR([Cannot find qmake in your PATH. Try using --with-qt.])
124   fi
126   # Find moc (Meta Object Compiler).
127   AC_ARG_VAR([MOC], [Qt Meta Object Compiler command])
128   AC_PATH_PROGS([MOC], [moc moc-qt4 moc-qt3], [missing],
129                 [$QT_PATH:$PATH:$tmp_qt_paths])
130   if test x"$MOC" = xmissing; then
131     AC_MSG_ERROR([Cannot find moc (Meta Object Compiler) in your PATH. Try using --with-qt.])
132   fi
134   # Find uic (User Interface Compiler).
135   AC_ARG_VAR([UIC], [Qt User Interface Compiler command])
136   AC_PATH_PROGS([UIC], [uic uic-qt4 uic-qt3 uic3], [missing],
137                 [$QT_PATH:$PATH:$tmp_qt_paths])
138   if test x"$UIC" = xmissing; then
139     AC_MSG_ERROR([Cannot find uic (User Interface Compiler) in your PATH. Try using --with-qt.])
140   fi
142   # Find rcc (Qt Resource Compiler).
143   AC_ARG_VAR([RCC], [Qt Resource Compiler command])
144   AC_PATH_PROGS([RCC], [rcc], [false], [$QT_PATH:$PATH:$tmp_qt_paths])
145   if test x"$UIC" = xfalse; then
146     AC_MSG_WARN([Cannot find rcc (Qt Resource Compiler) in your PATH. Try using --with-qt.])
147   fi
149   # If we don't know the path to Qt, guess it from the path to qmake.
150   if test x"$QT_PATH" = x; then
151     QT_PATH=`dirname "$QMAKE"`
152   fi
153   if test x"$QT_PATH" = x; then
154     AC_MSG_ERROR([Cannot find the path to your Qt install. Use --with-qt.])
155   fi
156   AC_SUBST([QT_PATH])
158   # Get ready to build a test-app with Qt.
160   # Look for a writable temporary directory.
161   AC_ARG_VAR([TMPDIR], [A temporary directory with write access @<:@/tmp@:>@])
162   if test x"$TMPDIR" = x || test ! -d "$TMPDIR" || test ! -w "$TMPDIR"; then
163     echo "$as_me:$LINENO: no TMPDIR or bad TMPDIR ($TMPDIR)" \
164       >&AS_MESSAGE_LOG_FD
165     for i in /tmp /var/tmp; do
166       if test -d "$i" && test -w "$i"; then
167         TMPDIR=$i
168         export TMPDIR
169         echo "$as_me:$LINENO: setting TMPDIR=$TMPDIR" >&AS_MESSAGE_LOG_FD
170         break
171       fi
172     done
173   fi
175   # Kludge!!  QMake has a very strange behavior.  For instance, if you
176   # install Qt under your $HOME and run QMake somewhere else under your
177   # $HOME, it will try to be clever and produce Makefiles with relative
178   # include paths.  In order to avoid this, we will test QMake from a
179   # temporary directory (usually /tmp).  Note that this problem was only
180   # observed with Qt 4.
181   my_configure_pwd=`pwd`
182   my_tmpdir="$TMPDIR/conftest$$.dir"
183   test -d "$my_tmpdir" || mkdir "$my_tmpdir"
184   if test -w "$my_tmpdir" && cd "$my_tmpdir"
185   then
186     :
187   else
188     AC_MSG_ERROR([Cannot cd to or write in $my_tmpdir])
189   fi
190   cat >conftest.h <<_ASEOF
191 #include <QObject>
193 class Foo: public QObject
195   Q_OBJECT;
196 public:
197   Foo();
198   ~Foo() {}
199 public slots:
200   void setValue(int value);
201 signals:
202   void valueChanged(int newValue);
203 private:
204   int value_;
206 _ASEOF
208   cat >conftest.cpp <<_ASEOF
209 #include "conftest.h"
210 Foo::Foo()
211   : value_ (42)
213   connect(this, SIGNAL(valueChanged(int)), this, SLOT(setValue(int)));
216 void Foo::setValue(int value)
218   value_ = value;
221 int main()
223   Foo f;
225 _ASEOF
226   if $QMAKE -project; then :; else
227     AC_MSG_ERROR([Calling $QMAKE -project failed.])
228   fi
230   # Find the .pro file generated by qmake.
231   pro_file='conftest.dir.pro'
232   test -f $pro_file || pro_file=`echo *.pro`
233   if test -f "$pro_file"; then :; else
234     AC_MSG_ERROR([Can't find the .pro file generated by Qmake.])
235   fi
237 dnl Tweak the value of QT in the .pro if have been the 1st arg.
238 m4_ifval([$1], [_AT_TWEAK_PRO_FILE([QT], [$1])])
240 dnl Tweak the value of CONFIG in the .pro if have been given a 2nd arg.
241 m4_ifval([$2], [_AT_TWEAK_PRO_FILE([CONFIG], [$2])])
243 m4_ifval([$3],
244 [ # Add the extra-settings the user wants to set in the .pro
245   echo "$3" >>"$pro_file"
248   echo "$as_me:$LINENO: Invoking $QMAKE on $pro_file" >&AS_MESSAGE_LOG_FD
249   sed 's/^/| /' "$pro_file" >&AS_MESSAGE_LOG_FD
251   if $QMAKE; then :; else
252     AC_MSG_ERROR([Calling $QMAKE failed.])
253   fi
255   # Qmake from Qt-4.3.2 generates Makefile with slashes instead of backslashes
256   # on mingw and this lead to an error (see #96). The followind sed call is a
257   # work around this issue.
258   case $host_os in
259      *mingw*|*cygwin*)
260         # We substitute only slashes with a leading non whitespace to avoid
261         # conversion of slashes used in windows tool options. Fortunately all
262         # path are relative...
263         perl -i -p -e 's,\.\./\.\./\.\.,/cygdrive/c,g' Makefile Makefile.Release Makefile.Debug
264         ;;
265   esac
267   # Try to compile a simple Qt app.
268   AC_CACHE_CHECK([whether we can build a simple Qt app], [at_cv_qt_build],
269   [at_cv_qt_build=ko
270   : ${MAKE=make}
272   if $MAKE >&AS_MESSAGE_LOG_FD 2>&1; then
273     at_cv_qt_build='ok, looks like Qt 4'
274   else
275     echo "$as_me:$LINENO: Build failed, trying to #include <qobject.h> \
276 instead" >&AS_MESSAGE_LOG_FD
277     sed 's/<QObject>/<qobject.h>/' conftest.h > tmp.h && mv tmp.h conftest.h
278     if $MAKE >&AS_MESSAGE_LOG_FD 2>&1; then
279       at_cv_qt_build='ok, looks like Qt 3'
280     else
281       # Sometimes (such as on Debian) build will fail because Qt hasn't been
282       # installed in debug mode and qmake tries (by default) to build apps in
283       # debug mode => Try again in release mode.
284       echo "$as_me:$LINENO: Build failed, trying to enforce release mode" \
285             >&AS_MESSAGE_LOG_FD
287       _AT_TWEAK_PRO_FILE([CONFIG], [+release])
289       sed 's/<qobject.h>/<QObject>/' conftest.h > tmp.h && mv tmp.h conftest.h
290       if $MAKE >&AS_MESSAGE_LOG_FD 2>&1; then
291         at_cv_qt_build='ok, looks like Qt 4, release mode forced'
292       else
293         echo "$as_me:$LINENO: Build failed, trying to #include <qobject.h> \
294 instead" >&AS_MESSAGE_LOG_FD
295         sed 's/<QObject>/<qobject.h>/' conftest.h > tmp.h && mv tmp.h conftest.h
296         if $MAKE >&AS_MESSAGE_LOG_FD 2>&1; then
297           at_cv_qt_build='ok, looks like Qt 3, release mode forced'
298         else
299           at_cv_qt_build=ko
300           echo "$as_me:$LINENO: failed program was:" >&AS_MESSAGE_LOG_FD
301           sed 's/^/| /' conftest.h >&AS_MESSAGE_LOG_FD
302           echo "$as_me:$LINENO: failed program was:" >&AS_MESSAGE_LOG_FD
303           sed 's/^/| /' conftest.cpp >&AS_MESSAGE_LOG_FD
304         fi # if make with Qt3-style #include and release mode forced.
305       fi # if make with Qt4-style #include and release mode forced.
306     fi # if make with Qt3-style #include.
307   fi # if make with Qt4-style #include.
308   ])dnl end: AC_CACHE_CHECK(at_cv_qt_build)
310   if test x"$at_cv_qt_build" = xko; then
311     AC_MSG_ERROR([Cannot build a test Qt program])
312   fi
313   QT_VERSION_MAJOR=`echo "$at_cv_qt_build" | sed 's/^[^0-9]*//'`
314   AC_SUBST([QT_VERSION_MAJOR])
316   # This sed filter is applied after an expression of the form: /^FOO.*=/!d;
317   # It starts by removing the beginning of the line, removing references to
318   # SUBLIBS, removing unnecessary whitespaces at the beginning, and prefixes
319   # all variable uses by QT_.
320   qt_sed_filter='s///;
321                  s/$(SUBLIBS)//g;
322                  s/^ *//;
323                  s/\$(\(@<:@A-Z_@:>@@<:@A-Z_@:>@*\))/$(QT_\1)/g'
325   # Find the Makefile (qmake happens to generate a fake Makefile which invokes
326   # a Makefile.Debug or Makefile.Release). We we have both, we'll pick the
327   # Makefile.Release. The reason is that the main difference is that release
328   # uses -Os and debug -g. We can override -Os by passing another -O but we
329   # usually don't override -g.
330   if test -f Makefile.Release; then
331     at_mfile='Makefile.Release'
332   else
333     at_mfile='Makefile'
334   fi
335   if test -f $at_mfile; then :; else
336     cd "$my_configure_pwd"
337     AC_MSG_ERROR([Cannot find the Makefile generated by qmake.])
338   fi
340   # Find the DEFINES of Qt (should have been named CPPFLAGS).
341   AC_CACHE_CHECK([for the DEFINES to use with Qt], [at_cv_env_QT_DEFINES],
342   [at_cv_env_QT_DEFINES=`sed "/^DEFINES@<:@^A-Z@:>@*=/!d;$qt_sed_filter" $at_mfile`])
343   AC_SUBST([QT_DEFINES], [$at_cv_env_QT_DEFINES])
345   # Find the CFLAGS of Qt (We can use Qt in C?!)
346   AC_CACHE_CHECK([for the CFLAGS to use with Qt], [at_cv_env_QT_CFLAGS],
347   [at_cv_env_QT_CFLAGS=`sed "/^CFLAGS@<:@^A-Z@:>@*=/!d;$qt_sed_filter" $at_mfile`])
348   AC_SUBST([QT_CFLAGS], [$at_cv_env_QT_CFLAGS])
350   # Find the CXXFLAGS of Qt.
351   AC_CACHE_CHECK([for the CXXFLAGS to use with Qt], [at_cv_env_QT_CXXFLAGS],
352   [at_cv_env_QT_CXXFLAGS=`sed "/^CXXFLAGS@<:@^A-Z@:>@*=/!d;$qt_sed_filter" $at_mfile`])
353   AC_SUBST([QT_CXXFLAGS], [$at_cv_env_QT_CXXFLAGS])
355   # Find the INCPATH of Qt.
356   AC_CACHE_CHECK([for the INCPATH to use with Qt], [at_cv_env_QT_INCPATH],
357   [at_cv_env_QT_INCPATH=`sed "/^INCPATH@<:@^A-Z@:>@*=/!d;$qt_sed_filter" $at_mfile`])
358   AC_SUBST([QT_INCPATH], [$at_cv_env_QT_INCPATH])
360   AC_SUBST([QT_CPPFLAGS], ["$at_cv_env_QT_DEFINES $at_cv_env_QT_INCPATH"])
362   # Find the LFLAGS of Qt (Should have been named LDFLAGS)
363   AC_CACHE_CHECK([for the LDFLAGS to use with Qt], [at_cv_env_QT_LDFLAGS],
364   [at_cv_env_QT_LDFLAGS=`sed "/^LFLAGS@<:@^A-Z@:>@*=/!d;$qt_sed_filter" $at_mfile`])
365   AC_SUBST([QT_LFLAGS], [$at_cv_env_QT_LDFLAGS])
366   AC_SUBST([QT_LDFLAGS], [$at_cv_env_QT_LDFLAGS])
368   AC_MSG_CHECKING([whether host operating system is Darwin])
369   at_darwin="no"
370   case $host_os in
371     darwin*)
372       at_darwin="yes"
373       ;;
374   esac
375   AC_MSG_RESULT([$at_darwin])
377   # Find the LIBS of Qt.
378   AC_CACHE_CHECK([for the LIBS to use with Qt], [at_cv_env_QT_LIBS],
379   [at_cv_env_QT_LIBS=`sed "/^LIBS@<:@^A-Z@:>@*=/!d;$qt_sed_filter" $at_mfile`
380    if test x$at_darwin = xyes; then
381      # Fix QT_LIBS: as of today Libtool (GNU Libtool 1.5.23a) doesn't handle
382      # -F properly. The "bug" has been fixed on 22 October 2006
383      # by Peter O'Gorman but we provide backward compatibility here.
384      at_cv_env_QT_LIBS=`echo "$at_cv_env_QT_LIBS" \
385                              | sed 's/^-F/-Wl,-F/;s/ -F/ -Wl,-F/g'`
386    fi
387   ])
388   AC_SUBST([QT_LIBS], [$at_cv_env_QT_LIBS])
390   cd "$my_configure_pwd" || echo 'WTF!'
391   rm -rf "$my_tmpdir"
394 # AT_REQUIRE_QT_VERSION(QT_version)
395 # ---------------------------------
396 # Check (using qmake) that Qt's version "matches" QT_version.
397 # Must be run AFTER AT_WITH_QT. Requires autoconf 2.60.
398 AC_DEFUN([AT_REQUIRE_QT_VERSION],
399 [ AC_PREREQ([2.60])
400   if test x"$QMAKE" = x; then
401     AC_MSG_ERROR([\$QMAKE is empty. \
402 Did you invoke AT@&t@_WITH_QT before AT@&t@_REQUIRE_QT_VERSION?])
403   fi
404   AC_CACHE_CHECK([for Qt's version], [at_cv_QT_VERSION],
405   [echo "$as_me:$LINENO: Running $QMAKE --version:" >&AS_MESSAGE_LOG_FD
406   $QMAKE --version >&AS_MESSAGE_LOG_FD 2>&1
407   qmake_version_sed=['/^.*\([0-9]\.[0-9]\.[0-9]\).*$/!d;s//\1/']
408   at_cv_QT_VERSION=`$QMAKE --version 2>&1 | sed "$qmake_version_sed"`])
409   if test x"$at_cv_QT_VERSION" = x; then
410     AC_MSG_ERROR([Cannot detect Qt's version.])
411   fi
412   AC_SUBST([QT_VERSION], [$at_cv_QT_VERSION])
413   AS_VERSION_COMPARE([$QT_VERSION], [$1],
414     [AC_MSG_ERROR([This package requires Qt $1 or above.])])
417 # _AT_TWEAK_PRO_FILE(QT_VAR, VALUE)
418 # ---------------------------
419 # @internal. Tweak the variable QT_VAR in the .pro.
420 # VALUE is an IFS-separated list of value and each value is rewritten
421 # as follows:
422 #   +value  => QT_VAR += value
423 #   -value  => QT_VAR -= value
424 #    value  => QT_VAR += value
425 AC_DEFUN([_AT_TWEAK_PRO_FILE],
426 [ # Tweak the value of $1 in the .pro file for $2.
428   qt_conf=''
429   for at_mod in $2; do
430     at_mod=`echo "$at_mod" | sed 's/^-//; tough
431                                   s/^+//; beef
432                                   :ough
433                                   s/^/$1 -= /;n
434                                   :eef
435                                   s/^/$1 += /'`
436     qt_conf="$qt_conf
437 $at_mod"
438   done
439   echo "$qt_conf" | sed 1d >>"$pro_file"