Index
Contents
This page is targeted at those who want to develop Qt applications in the FreeSurfer code tree.
1. Usual Workflow of Qt Developers
If you are new to Qt programming, please start with the official documentation from Qt site.
(optionally) design the user interface using Qt Designer. This generates .ui files
(optionally) write the Qt Resource file which is an XML specification of the binary files needed by the application. This has .qrc extension.
- Code the .cpp and .h files
Generate a Qt project file with qmake -project command line. This has .pro extension.
Generate Makefile using qmake command line
Make using make
1.1. Workflow in FreeSurfer Tree
Unfortunately, at this moment, this workflow is not possible in FreeSurfer because there is no straightforward way of transferring configuration details from Autotools to Qt Project files. The build system follows the Autotools way where one writes Makefile.am file which configure script reads and generates Makefile. So, the first 4 steps of the workflow is the same and these are the subsequent steps
(step 5) Write Makefile.am using the generated .pro file and instructions in this page.
(step 6) Execute make and make install
In fact, Step 4 ( generating .pro file ) is optional if one is comfortable with writing Makefile.am from the start. This is outlined below.
2. Writing Makefile.am for a Qt Application
This is not much different from the .pro file and freeview/freeview.pro is used as a reference file. The following diagram gives a graphical overview of the Qt build system.
Taken from Qt Developer Site
Makefile.am should account for the intermediate files produced. That's probably the only additional thing one would write compared to .pro file. The following is a skeleton Makefile.am of freeview which you can copy to your Qt binary directory and make appropriate changes.
if ENABLE_QT_APPS include $(top_srcdir)/build-aux/autotroll.mk bin_PROGRAMS = freeview BUILT_SOURCES = ui_MainWindow.h \ ..... moc_BrushProperty.cpp \ ..... qrc_freeview.cpp freeview_SOURCES = $(BUILT_SOURCES) \ Annotation2D.cpp \ ..... QVTKWidget.cxx \ QVTKPaintEngine.cxx \ BrushProperty.h \ ..... if HAVE_MAC_OSX AM_CXXFLAGS=\ -fno-strict-aliasing \ -Wno-deprecated \ -Wno-unused \ -Wno-uninitialized \ -Wno-return-type \ -Wno-reorder \ -Wno-sign-compare \ -I$(top_srcdir)/include \ $(GL_CFLAGS) \ $(VTK_COCOA_CXXFLAGS) \ -I$(top_srcdir)/vtkfsio \ -I$(top_srcdir)/vtkutils \ $(ITK_CFLAGS) -DHAVE_ITK_LIBS \ $(VXL_CFLAGS) freeview_CXXFLAGS = $(QT_CXXFLAGS) $(AM_CXXFLAGS) freeview_CPPFLAGS = $(QT_CPPFLAGS) $(AM_CPPFLAGS) freeview_LDFLAGS = $(QT_LDFLAGS) $(OS_LDFLAGS) -framework Cocoa -framework IOKit freeview_LDADD = $(QT_LIBS) \ $(addprefix $(top_builddir)/, $(LIBS_MGH)) \ $(top_builddir)/vtkfsio/libvtkfsio.a \ $(top_builddir)/vtkutils/libvtkutils.a \ $(VTK_COCOA_LIBS) $(VTK_VERDICT_LIB) -lvtkGraphics \ $(VTK_EXPAT_LIB) $(VTK_FREETYPE_LIB) \ $(VTK_TIFF_LIB) $(VTK_JPEG_LIB) \ $(VTK_METAIO_LIB) $(VTK_PNG_LIB) $(VTK_Z_LIB) \ $(VTK_SQLITE_LIB) \ -lvtkImaging -lvtkFiltering \ -lvtkCommon -lvtksys -lvtkGenericFiltering \ -lvtkexoIIc -lvtkNetCDF \ -lvtkVolumeRendering -lvtkRendering -lvtkftgl \ -lvtkWidgets -lvtkHybrid \ -lvtkIO -lvtkDICOMParser $(VTK_MPEG2ENCODE_LIB) # need to create a bundle for Macs install-exec-hook:freeview mkdir -p $(DESTDIR)$(bindir)/Freeview.app mkdir -p $(DESTDIR)$(bindir)/Freeview.app/Contents mkdir -p $(DESTDIR)$(bindir)/Freeview.app/Contents/MacOS mkdir -p $(DESTDIR)$(bindir)/Freeview.app/Contents/Resources mkdir -p $(DESTDIR)$(bindir)/Freeview.app/Contents/Resources/English.lproj # mkdir -p $(DESTDIR)$(bindir)/Freeview.app/Contents/Frameworks cp $(top_builddir)/freeview/Info.plist $(DESTDIR)$(bindir)/Freeview.app/Contents echo -n 'APPL????' > $(DESTDIR)$(bindir)/Freeview.app/Contents/PkgInfo cp $(top_builddir)/freeview/freeview $(DESTDIR)$(bindir)/Freeview.app/Contents/MacOS/freeview.bin echo "#!/bin/tcsh -ef" > $(DESTDIR)$(bindir)/freeview # echo "source \$$FREESURFER_HOME/bin/tcl_setup" \ >> $(DESTDIR)$(bindir)/freeview echo "source \$$FREESURFER_HOME/bin/qt_setup" \ >> $(DESTDIR)$(bindir)/freeview echo "exec $(DESTDIR)$(bindir)/Freeview.app/Contents/MacOS/freeview.bin \$$*" >> $(DESTDIR)$(bindir)/freeview chmod a+x $(DESTDIR)$(bindir)/freeview # ./mac_package_dylibs.sh $(WXWIDGETS_DIR)lib $(DESTDIR)$(bindir)/Freeview.app/Contents/Frameworks $(DESTDIR)$(bindir)/Freeview.app/Contents/Mac OS/freeview.bin if [[ -f /usr/pubsw/bin/chrpath ]]; then \ /usr/pubsw/bin/chrpath -d $(DESTDIR)$(bindir)/Freeview.app/Contents/MacOS/freeview.bin; fi uninstall-hook: rm -f $(DESTDIR)$(bindir)/freeview rm -rf $(DESTDIR)$(bindir)/Freeview.app else AM_CXXFLAGS=\ -fno-strict-aliasing \ -Wno-deprecated \ -Wno-unused \ -Wno-uninitialized \ -Wno-return-type \ -Wno-reorder \ -Wno-sign-compare \ -I$(top_srcdir)/include \ $(GL_CFLAGS) \ $(VTK_CXXFLAGS) \ -I$(top_srcdir)/vtkfsio \ -I$(top_srcdir)/vtkutils \ $(ITK_CFLAGS) -DHAVE_ITK_LIBS \ $(VXL_CFLAGS) freeview_CXXFLAGS = $(QT_CXXFLAGS) $(AM_CXXFLAGS) freeview_CPPFLAGS = $(QT_CPPFLAGS) $(AM_CPPFLAGS) freeview_LDFLAGS = $(QT_LDFLAGS) $(OS_LDFLAGS) freeview_LDADD = $(QT_LIBS) \ $(addprefix $(top_builddir)/, $(LIBS_MGH)) \ $(top_builddir)/vtkfsio/libvtkfsio.a \ $(top_builddir)/vtkutils/libvtkutils.a \ $(VTK_LIBS) $(VTK_VERDICT_LIB) -lvtkGraphics \ $(VTK_EXPAT_LIB) $(VTK_FREETYPE_LIB) \ $(VTK_TIFF_LIB) $(VTK_JPEG_LIB) \ $(VTK_METAIO_LIB) $(VTK_PNG_LIB) $(VTK_Z_LIB) \ $(VTK_SQLITE_LIB) \ -lvtkImaging -lvtkFiltering \ -lvtkCommon -lvtksys -lvtkGenericFiltering \ -lvtkexoIIc -lvtkNetCDF \ -lvtkVolumeRendering -lvtkRendering -lvtkftgl \ -lvtkWidgets -lvtkHybrid \ -lvtkIO -lvtkDICOMParser $(VTK_MPEG2ENCODE_LIB) # put a wrapper around the bin, used to setup tcltktixblt,vtk,kww enviro vars # and if the OS is MACOSX have a different install-hook to create a bundle install-exec-hook:freeview cp $(top_builddir)/freeview/freeview $(DESTDIR)$(bindir)/freeview.bin echo "#!/bin/tcsh -ef" > $(DESTDIR)$(bindir)/freeview echo "source \$$FREESURFER_HOME/bin/tcl_setup" \ >> $(DESTDIR)$(bindir)/freeview echo "source \$$FREESURFER_HOME/bin/vtk_setup" \ >> $(DESTDIR)$(bindir)/freeview echo "source \$$FREESURFER_HOME/bin/qt_setup" \ >> $(DESTDIR)$(bindir)/freeview echo "freeview.bin \$$argv" >> $(DESTDIR)$(bindir)/freeview chmod a+x $(DESTDIR)$(bindir)/freeview if [[ -f /usr/pubsw/bin/chrpath ]]; then \ /usr/pubsw/bin/chrpath -d $(DESTDIR)$(bindir)/freeview.bin; fi uninstall-hook: rm -f $(DESTDIR)$(bindir)/freeview.bin endif .... endif
2.1. Explanation
if ENABLE_QT_APPS include $(top_srcdir)/build-aux/autotroll.mk
if ENABLE_QT_APPS is a necessary guard that ensures that configure script continues if it can't find Qt.
The excellent Autotroll is made use of to seamlessly use Autotools to build Qt applications. In summary, it does the hardwork of populating relevant variables by calling qmake on a sample Qt project.
bin_PROGRAMS = freeview
This is the name of your binary. freeview in this case.
BUILT_SOURCES = ui_MainWindow.h \ ..... moc_BrushProperty.cpp \ ..... qrc_freeview.cpp
BUILT_SOURCES variable takes care of the accounting of intermediate files produced in the above diagram. As you can notice, all of moc_, ui_ and qrc_ files are accounted. For example, if your source file has MainWindow.ui file generated by the Qt Designer, you'll include it as ui_MainWindow.h in BUILT_SOURCES variable in your Makefile.am
freeview_SOURCES = $(BUILT_SOURCES) \ Annotation2D.cpp \ ..... QVTKWidget.cxx \ QVTKPaintEngine.cxx \ BrushProperty.h \ .....
All your source files .cpp and .h files go here along with the BUILT_SOURCES variable.
freeview_CXXFLAGS = $(QT_CXXFLAGS) $(AM_CXXFLAGS) freeview_CPPFLAGS = $(QT_CPPFLAGS) $(AM_CPPFLAGS) freeview_LDFLAGS = $(QT_LDFLAGS) $(OS_LDFLAGS) freeview_LDADD = $(QT_LIBS) \ .... install-exec-hook:freeview cp $(top_builddir)/freeview/freeview $(DESTDIR)$(bindir)/freeview.bin echo "#!/bin/tcsh -ef" > $(DESTDIR)$(bindir)/freeview echo "source \$$FREESURFER_HOME/bin/tcl_setup" \ >> $(DESTDIR)$(bindir)/freeview echo "source \$$FREESURFER_HOME/bin/vtk_setup" \ >> $(DESTDIR)$(bindir)/freeview echo "source \$$FREESURFER_HOME/bin/qt_setup" \ >> $(DESTDIR)$(bindir)/freeview echo "freeview.bin \$$argv" >> $(DESTDIR)$(bindir)/freeview chmod a+x $(DESTDIR)$(bindir)/freeview if [[ -f /usr/pubsw/bin/chrpath ]]; then \ /usr/pubsw/bin/chrpath -d $(DESTDIR)$(bindir)/freeview.bin; fi
This is if we detect Linux x86 or x86_64. Note that the Qt information is captured in the variables starting with QT_ variables -- QT_CXXFLAGS, QT_CPPFLAGS, QT_LDFLAGS and QT_LIBS. Also, we rename the binary to binary.bin and write a script named binary which calls binary.bin and sets up various shared library paths. Since freeview needs Qt, VTK and Tcl, we call tcl_setup, vtk_setup and qt_setup before invoking freeview.bin.
2.2. Special considerations for MacOSX
if HAVE_MAC_OSX AM_CXXFLAGS=\ ... $(VTK_COCOA_CXXFLAGS) \ ... freeview_CXXFLAGS = $(QT_CXXFLAGS) $(AM_CXXFLAGS) freeview_CPPFLAGS = $(QT_CPPFLAGS) $(AM_CPPFLAGS) freeview_LDFLAGS = $(QT_LDFLAGS) $(OS_LDFLAGS) -framework Cocoa -framework IOKit freeview_LDADD = $(QT_LIBS) \ $(addprefix $(top_builddir)/, $(LIBS_MGH)) \ $(top_builddir)/vtkfsio/libvtkfsio.a \ $(top_builddir)/vtkutils/libvtkutils.a \ $(VTK_COCOA_LIBS) $(VTK_VERDICT_LIB) -lvtkGraphics \ $(VTK_EXPAT_LIB) $(VTK_FREETYPE_LIB) \ $(VTK_TIFF_LIB) $(VTK_JPEG_LIB) \ ....
We have a separate logic if we detect MacOSX. This is due to a few reasons: if the Qt application uses VTK, a separate Cocoa enabled static VTK library only seems to work with Qt. This separate VTK is detected at configure time and the information is there in VTK_COCOA_CXXFLAGS and VTK_COCOA_LIBS variables. Also, the binary_LDFLAGS need the -framework Cocoa -framework IOKit argument ( and possibly more, depending on the application). install-exec-hook takes care of packaging the Qt application as a Mac Application bundle.
There is a bug in 4.7.1 Cocoa version of Qt in which the items in the menu don't work. The workaround is to simply copy the following directory to the Contents/Resources of the new app.
if [[ -d /usr/pubsw/packages/qt/current/lib/qt_menu.nib ]]; then \ cp -rv /usr/pubsw/packages/qt/current/lib/qt_menu.nib $(DESTDIR)$(bindir)/Freeview.app/Contents/Resources; fi
3. Odds and Ends
Out of all these possible modules in Qt, only core, gui and opengl are enabled in configure.in. If you want to include additional Qt modules for compilation, append to the AT_WITH_QT variable. For example, if you want the sql module, change AT_WITH_QT([opengl]) to AT_WITH_QT([opengl sql]) in dev/configure.in
Qt is installed in the path /usr/pubsw/packages/qt/current/ in the NMR center. There you can find directories like demos/, examples/ etc. which has more Qt examples. qmake is in /usr/pubsw/packages/qt/current/bin. Also, the MacOSX version is not installed as a framework ( --no-framework option ) but as a bunch of shared libraries.
If the linker complains of "undefined symbols" even if you are linking everything correctly, it might be due to the lack of moc_<foo>.cpp file in the BUILT_SOURCES automake variable. Note that these moc_ files are produced by the qmake automatically but since we are going the autotools route, they have to be explicitly specified in Makefile.am