開発メモ

Qtを使ったプログラムのMakefileをautoconf/automake(所謂autotools)を使って生成する方法に関するメモ. 以前に参考にしたサイトが消えてしまったようなので,自分用の備忘録として記す.

問題点

Qtのsignal/slotを利用したプログラムをコンパイルするには,moc(Meta Object Compiler)によってソースファイルを自動生成しなければならない.

mocはQt付属のソースファイル自動生成コマンド.通常,Q_OBJECTマクロを含むクラスのヘッダファイル(XXXX.h)から,moc_XXXX.cppというファイルが生成される.

Qt付属のqmakeコマンドを利用すれば,mocの呼び出しまですべて自動でやってくれるMakefileを作れる. しかし,autoconf/automakeとqmakeを組み合わせることはできない.

では,どうやって解決するか?

解決策

moc

該当するヘッダファイルを含むMakefile.amに以下の記述を加える.

moc_%.cpp: %.h
        moc $< -o $@

ただし,mocコマンドがどこにインストールされているかは環境によって異なるので注意が必要. 特に,システムにQt3とQt4が混在しているならば,どちらのバージョンのmocを使用するか,明示的に指定しなければならない. mocコマンドの部分を変数にしておいて,configure時にmocのパスをチェックした方が良い.

続いて,自動生成されるソースファイルの記述. ビルドターゲットがxxxxで,Q_OBJECTを含むヘッダとしてaaaa.h, bbbb.h, cccc.hが存在する場合,

nodist_xxxx_SOURCES = \
    moc_aaaa.cpp \
    moc_bbbb.cpp \
    moc_cccc.cpp

として,自動生成ファイルが配布物(make distの対象)に含まれないようにする.

ついでに,

CLEANFILES = $(nodist_XXXX_SOURCES)

としておいて,make cleanによって自動生成ファイルが削除されるようにしておけばなお良いだろう.

pkg-configの利用

mocが利用できるようになっただけではまだコンパイルできない. Qtのライブラリやヘッダファイルのパスを指定しなければならない. Qtはpkg-configに対応しているので,これを利用すれば簡単にQtの設定をチェックできる(自前でQtをインストールした場合は除く).

まずは,自分のシステムにQtが正しくインストールされているか確認. 以下のオプションによって,pkg-configが認識できるライブラリの一覧が表示される.

$ pkg-config --list-all

ほとんどの環境において,Qt3は"qt-mt"という名前で登録されている. Qt4はモジュールごとに認識されるので(QtCore, QtGui, QtSql, QtNetwork, QtScript, QtTest, QtAssistantClientなど),必要に応じてモジュールを指定しなければならない.

pkg-config関連の処理をconfigure.acに書けば良いのだが,M4マクロを用意しておく方が再利用できて便利. 細かい話は取っ払って,実際に使用しているM4マクロを張り付けておく. http://autoconf-archive.cryp.to/bnv_have_qt.html をベースに独自に書き直したもので,大抵の32bit環境のLinuxディストリビューション,FreeBSD, MacOSXに対応可能だが,汎用性は低く,十分なものではない. (注:以下のQt4用マクロは,QtCore,QtGui,QtNetworkしかチェックしていません.) 出来れば,ちゃんと書き直した方が良い.

AC_DEFUN([AX_QT3],
[
  AC_REQUIRE([AC_PROG_CXX])

  AC_MSG_CHECKING(for Qt3)

  QT3_REQUIRED_VERSION=ifelse([$1], ,3.3.0,$1)
  have_qt3="no"

  AC_PATH_PROG(PKG_CONFIG, pkg-config, no)
  if test "x$PKG_CONFIG" = "xno"; then
    AC_MSG_ERROR(You have to install pkg-config to compile $PACKAGENAME-$VERSION.)
  fi

  PKG_CHECK_MODULES(Qt3,
                    qt-mt >= $QT3_REQUIRED_VERSION,
                    have_qt3="yes",
                    have_qt3="no")
  if test "$have_qt3" = "no"; then
    PKG_CHECK_MODULES(Qt3,
                      qt >= $QT3_REQUIRED_VERSION,
                      have_qt3="yes",
                      have_qt3="no")
  fi

  if test "$have_qt3" = "no"; then
    AC_MSG_ERROR([The Qt library >= [$QT3_REQUIRED_VERSION] could not be found.])
  fi

  QT3_CFLAGS=$($PKG_CONFIG --cflags qt-mt)
  QT3_CXXFLAGS="$QT3_CFLAGS"
  QT3_CPPFLAGS=""
  QT3_LDFLAGS=$($PKG_CONFIG --libs-only-L qt-mt)
  QT3_LDADD="$($PKG_CONFIG --libs-only-other qt-mt)$($PKG_CONFIG --libs-only-l qt-mt)"
  AC_MSG_NOTICE([set QT3_CXXFLAGS... $QT3_CXXFLAGS])
  AC_MSG_NOTICE([set QT3_LDFLAGS... $QT3_LDFLAGS])
  AC_MSG_NOTICE([set QT3_LDADD... $QT3_LDADD])
  AC_SUBST(QT3_CFLAGS)
  AC_SUBST(QT3_CXXFLAGS)
  AC_SUBST(QT3_CPPFLAGS)
  AC_SUBST(QT3_LDFLAGS)
  AC_SUBST(QT3_LDADD)

  # check the path to moc
  QT3_MOC=""

  AC_ARG_WITH([qt3-moc],
    [  --with-qt3-moc=PATH     Qt3's moc utilitiy to be used (optional)])
  if test x$with_qt3_moc != x && test -x "$with_qt3_moc" ; then
    QT3_MOC="$with_qt3_moc"
  fi
  if test x$QT3_MOC = x ; then
    for qt3_path_tmp in /usr/qt/3 /usr/lib/qt3 /usr/share/qt3 /usr/lib/qt-3.3 /opt/local/lib/qt3 /opt/local /usr/local /usr ; do
      if test -x "${qt3_path_tmp}/bin/moc" ; then
        QT3_MOC="${qt3_path_tmp}/bin/moc"
        break;
      fi
    done
  fi
  if test x$QT3_MOC = x ; then
    have_qt3=no
    AC_MSG_ERROR([You must specify the path to Qt3's moc command.])
  fi

  AC_MSG_NOTICE([set QT3_MOC... $QT3_MOC])
  AC_SUBST(QT3_MOC)
])

AC_DEFUN([AX_QT4],
[
  AC_REQUIRE([AC_PROG_CXX])

  QT4_REQUIRED_VERSION=ifelse([$1], ,4.1.0,$1)

  AC_PATH_PROG(PKG_CONFIG, pkg-config, no)
  if test "x$PKG_CONFIG" = "xno"; then
    AC_MSG_ERROR(You have to install pkg-config to compile $PACKAGENAME-$VERSION.)
  fi

  PKG_CHECK_MODULES(Qt4,
                    QtCore >= $QT4_REQUIRED_VERSION
                    QtGui >= $QT4_REQUIRED_VERSION
                    QtNetwork >= $QT4_REQUIRED_VERSION,
                    have_qt4="yes",
                    have_qt4="no")
  if test "$have_qt4" = "no"; then
    AC_MSG_ERROR(
      [The QtCore, QtGui or QtNetwork library >= [$QT4_REQUIRED_VERSION] could not be found.])
  fi

  QT4_CFLAGS=$($PKG_CONFIG --cflags QtCore QtGui QtNetwork)
  QT4_CXXFLAGS="$QT4_CFLAGS"
  QT4_CPPFLAGS=""
  QT4_LDFLAGS=$($PKG_CONFIG --libs-only-L QtCore QtGui QtNetwork)
  QT4_LDADD="$($PKG_CONFIG --libs-only-other QtCore QtGui QtNetwork)$($PKG_CONFIG --libs-only-l QtCore QtGui QtNetwork)"
  AC_MSG_NOTICE([set QT4_CXXFLAGS... $QT4_CXXFLAGS])
  AC_MSG_NOTICE([set QT4_LDFLAGS... $QT4_LDFLAGS])
  AC_MSG_NOTICE([set QT4_LDADD... $QT4_LDADD])
  AC_SUBST(QT4_CFLAGS)
  AC_SUBST(QT4_CXXFLAGS)
  AC_SUBST(QT4_CPPFLAGS)
  AC_SUBST(QT4_LDFLAGS)
  AC_SUBST(QT4_LDADD)

  # check the path to moc
  QT4_MOC=""

  AC_ARG_WITH([qt4-moc],
    [  --with-qt4-moc=PATH     Qt4's moc utilitiy to be used (optional)])
  if test x$with_qt4_moc != x && test -x "$with_qt4_moc" ; then
    QT4_MOC="$with_qt4_moc"
  fi
##    AC_CHECK_PROG(QT4_MOC, [moc], [moc])
  if test x$QT4_MOC = x ; then
      if test -x "/usr/local/bin/moc-qt4" ; then
        QT4_MOC="/usr/local/bin/moc-qt4"
      fi
  fi
  if test x$QT4_MOC = x ; then
    for qt4_path_tmp in /usr/qt/4 /usr/lib/qt4 /usr/share/qt4 /opt/local /usr/local /usr ; do
      if test -x "${qt4_path_tmp}/bin/moc" ; then
        QT4_MOC="${qt4_path_tmp}/bin/moc"
        break;
      fi
    done
  fi
  if test x$QT4_MOC = x ; then
    have_qt4=no
    AC_MSG_ERROR([You must specify the path to Qt4's moc command.])
  fi

  AC_MSG_NOTICE([set QT4_MOC... $QT4_MOC])
  AC_SUBST(QT4_MOC)
])

以上の内容を,パッケージトップディレクトリのacinclude.m4に書いておく(無ければ作る). あるいは,qt.m4などのファイルに保存して,パッケージ内の適当な場所に置いておく(普通はconfigure.acと同じ場所?パッケージトップのMakefile.amに ACLOCAL_AMFLAGS=-I m4と書いておけば,パッケージトップのm4ディレクトリに置けるようになる).

マクロが用意できれば,続いてconfigure.acにマクロ呼び出しの記述を追加. マクロの引数として,要求するQtのバージョンを指定する.

AX_QT3(3.3.0)
if test x$have_qt3 != xyes ; then
   AC_MSG_ERROR([The Qt3 library could not be found.])
fi
AX_QT4(4.3.0)
if test x$have_qt4 != xyes ; then
   AC_MSG_ERROR(
     [The QtCore, QtGui, QtOpenGL or QtNetwork library could not be found.])
fi

以上で,configureによるQtの自動検出が可能になる. インストールパスの指定は出来ないので,標準以外の場所にインストールされたQtを指定することは出来ない. mocのパスは"--with-qt3-moc"または"--with-qt4-moc"オプションによって指定できる.

最後に,ソースディレクトリのMakefile.amに変数を追加(以下は,Qt4の場合)

moc_%.cpp: %.h
        $(QT4_MOC) $< -o $@

xxxx_CPPFLAGS = $(QT4_CPPFLAGS)
xxxx_CXXFLAGS = $(QT4_CXXFLAGS)
xxxx_LDFLAGS = $(QT4_LDFLAGS)
xxxx_LDADD = $(QT4_LDADD)

トップ   編集 凍結 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2016-03-14 (月) 14:51:37 (1923d)
SourceForge.JP
Creative Commons License
RoboCup tools by Hidehisa Akiyama is licensed under a Creative Commons 表示-非営利 2.1 日本 License.