Trying qmake and CMake

Until this week I was not familiar with qmake and CMake because I am a fairly satisfied user of autotools. I have not forgotten how strange it was when I first learned it, when there was no decent documentation, but things are much better now. I feel at home with it and I like how other systems and distros expect the standard “configure;make all install” steps. I am definitely biased against the use of other build systems.

However, these days I have to deal with code that uses qmake and CMake and I can’t just be stubbornly ignorant. So I tried an experiment. I created branches of a little (but real-world) project that uses Qt and an extra library via pkg-config: qlom with qmake, and qlom with cmake. The master branch uses non-recursive autotools.

I was not impressed. Please do add comments to correct me. I’d particular like patches that make my errors crystal clear and prove that it’s all much better than I think. I am capable of admitting error and changing my mind when appropriate.

Bad Documentation. Weird Syntax

Just like autotools, neither were easy to get started with. The documentation is fragmented, unclear, and incomplete. I found qmake easier than CMake, but that’s probably just because qmake does much less. Nevertheless, CMake has a real problem with documentation and in general, as a widely-used open-source project, it deserves a better infrastructure.

They both suffer from one major problem shared by autotools: They have evolved over enough time that Google will happily return out-of-date examples and documentation, making the syntax seem more varied than it really is. I wish that autotools could force me not to use deprecated syntax. I don’t know if qmake and CMake can.

As with autotools there’s a heavy dose of arbitrariness:

  • File names: autotools’s configure.ac and Makefile.am seem more logical than SomeProject.pro (qmake) or CMakeLists.txt (CMake)
  • Syntax: m4 (used by autotools) is a crappy language, but at least it’s a mature one that’s used outside of autotools. I understand the wish to have no dependencies, but “invent a programming language” is always a bad design decision.
    And autotools don’t require anything but make when building from a tarball. qmake and CMake seem to require that they are installed even when building from a tarball. I would have liked to see Python used because it’s easily available on all machines that would create source tarballs.
    CMake’s non-case-sensitive function names and keywords are personally annoying to me, because I like code to have a consistent style.

No Respect For pkg-config

I am dismayed that CMake expects people to write code for “Find” modules for each library they might use, while having poor support for the generic pkg-config solution. A project’s list of dependencies is data, not an excuse to write code. More code means more problems.

In fact, after several days of trying, I still can’t figure out how to use pkg-config with cmake, so my glom_cmake branch is not finished yet.

Most libraries provide the simple .pc files these days. The autotools PKG_CHECK_MODULES() macro makes it very easy to check for several dependencies at once. CMake feels too much like the bad old 90s when we suffered fragile copy-paste-hacked config scripts, custom m4, macros and verbose build files with separate CFLAGS and LIBS variables for each dependency, and inconsistent release-version and API-version checking.

I understand that pkg-config is not popular on Windows or MacOS, and that those are awkward platforms to work with, but:

  • The real solution to poor dependency information on Windows and MacOS is to encourage the use of pkg-config, so it can fix the problem there like it fixed the problem for Linux. That’s entirely possible for the cross-platform libraries that are typically open source. And pkg-config would be easy to port.
  • The platform-specific libraries on Windows and MacOs don’t need any cross-platform support in the build system.

CMake’s use of scripts just spreads the chaos to Linux instead of keeping things simple on Linux and improving the other platforms too.

No Configure Stage

With qmake, I really miss having a proper configure stage, with the resulting config.h so my code can use ifdefs. I like seeing a list of documented build options from configure –help, which neither qmake or cmake offer.

CMake can generate a config.h, at least. However,

  • There are no default checks, so you must specify the common stuff always, making the build file more verbose.
  • You can’t just generate the config.h.in, as you can with autoheader when using autotools. There’s no reason to specify the defines in both CMakeFiles.txt/configure.ac and config.h.in.
  • Arbitrarily, the config.h.in uses “#cmakedefine SOMETHING 1” instead of #undef SOMETHING as in autotools (now deprecated, unnecessary) config.h.in files. For anything other than booleans, there’s an undocumented syntax such as #cmakedefine “@PACKAGE_NAME@”.

Install is an Afterthought

Both CMake and qmake require explicit extra syntax to actually install the built executable. With autotools you get this for free when using the regular bin_PROGRAMS to specify the executable name, though libraries do need more explicit instructions to install the correct headers in the correct place.

  • With qmake, this typically means that paths are hard-coded in the build files. That way lies pain.
  • With CMake, it’s easier, but you have to do “make -DCMAKE_INSTALL_PREFIX=/opt/mystuff” instead of autotool’s simpler ./configure –prefix=/opt/mystuff. autotools lists that option via “configure –help”.

Also, qmake and CMake have no make distcheck for making source tarball releases.

This makes sense slightly because CMake (and maybe qmake) aim to support Windows, Mac, and Linux equally, and Windows has no real convention for installation of built-from-source binaries. CMake (and maybe qmake) generate convenient Visual Studio and X-Code project files, for instance. But the end results it that Linux and Linux conventions are not fully supported, so they feel like major regressions compared to autotools.

(note: removed my nonsense with the TODO about the location of .o files.)

Summary

In summary, I think:

  • qmake would only be used by Trolltech (now called Qt Development Frameworks) for their own projects, out of habit, or by users of Qt who are so unaware of other systems that they would just do whatever Qt’s developers recommend.
  • CMake isn’t simpler, so it doesn’t solve autotool’s steep learning curve. It makes many thinks worse than autotools and its documentation is disconcertingly vague and incomplete. It’s cross-platform dependency checking adds complication without solving the real problem. The best CMake experience is probably with a large monolithic project rather than a large dependency tree of modules. But I like modularity and reuse.

I understand the wish to support Windows and Mac-specific build systems such as Visual Studio and X-Code. I just don’t like how qmake and cmake do that, and for me it’s not worth making things worse on Linux. Still, I’ll have to use these in some existing projects, so I’m glad that I’m more familiar with them now.

53 thoughts on “Trying qmake and CMake

  1. Hi,
    You say:
    > when there was no decent documentation, but things are much better now.
    Which documentation of autotools would you recommend?

  2. The autotools book (available online and in print) is fairly useful, though of course not perfect:
    http://sources.redhat.com/autobook/

    There’s a lot of stuff online. I like to think that my own simple how-to documents made the common cases easier for impatient people. I should check if they need updating:
    http://www.openismus.com/documents/linux/automake/automake.shtml
    http://www.openismus.com/documents/linux/using_libraries/using_libraries.shtml
    http://www.openismus.com/documents/linux/building_libraries/building_libraries.shtml

    autotools itself has also become more consistent and simpler and therefore easier to understand and document.

  3. The fact that you did not found the pkgconfig support made me wonder how much you did investigate:
    http://www.cmake.org/cmake/help/cmake2.6docs.html#module:FindPkgConfig

    As to the reason for the Find*.cmake, you said it later cmake intend to support equally linux and windows, and windows does not have pkg-config, hence the need for a fallback.

    Then on the point of the programmation language, I have never seen the use of m4 outside autoconf, it might exists independentely, but what the point of a programmation language that is used only for one purpose ?

    I also fail to see how cmake is not modular, you can not go on making affirmation without proof (especially since cmake is used in many modular environment…)

  4. Personally, I’ve never been so happy with a change in my development tools as I was with the change from autotools to cmake… But I’m only an application developer, and for me, as a mere user of about fifty dependent libraries for a cross-platform application, cmake made life a lot easier. I found http://cmake.org/cmake/help/cmake-2-8-docs.html pretty complete… And when I started to learn cmake, the book was helpful, too, but that would be rather out of date by now. By now, I wouldn’t want to go back.41

  5. I think with regards CMake you’re just experiencing the big differences between the tools. I moved a large (modular) project from autotools to CMake, and although the initial problems were a bit painful the end result was definitely worth it.

    Albert has already pointed out how easy it is to use pkg-config in CMake, I’d also throw in that cpack can also create your source packages easily and although the default file name isn’t terribly useful it’s easily changed. There is also a kind of configure stage (that’s when you call cmake; you can use ccmake to inspect it and reconfigure it).

    I’ve found building out of tree much easier with cmake (which was a big win for us), but also in the longer run people have felt much happier modifying and adapting the various build scripts than under autotools: I think the conversion is much harder on the “expert” autotools users tbh.

    I would encourage you to keep up with cmake for a little bit before forming too hard an impression; I suspect most of the hype around it is generated by people who never really got [modern] autotools in the first place, but I found it worth the effort.

  6. That’s exactly how I feel about them as well. I’ve spent half a day implementing stuff in qmake (and failing) which would have taken like one or two lines in autotools. Not to mention the massive problems if you have many subprojects – recursive qmake sucks even more than recursive automake ;)

    You might find those two links interesting, I stumbled upon them while looking for a solution. Seems they at least know about the problems with qmake.

    http://labs.trolltech.com/blogs/2009/10/12/to-make-or-not-to-make-qmake-and-beyond
    http://labs.trolltech.com/blogs/2009/10/12/to-make-or-not-to-make-qmake-and-beyond

  7. Hi

    Sorry, I just could not resist in posting a comment. In large, I found it an interesting read, exactly because I’m an active user of cmake and I have always tried to stay away from autotools.

    I tried to learn autotools, but everytime I tried, I failed miserably. When I moved to cmake, it took me a day and things were going smoothly. Your mileage varied – fair enough
    Just a couple of points (I’ll leave out qmake as I’m not familiar with it):

    >> File names: autotools’s configure.ac and Makefile.am seem more logical than SomeProject.pro (qmake) or CMakeLists.txt (CMake)
    How so? I don’t get this point. There is a build-system, and it’s present through one single file. Why is there a split in the autotools? That seems illogical to me. The filenames differ, but that’s just a matter of taste/what you are used to

    >> Syntax: m4 (used by autotools) is a crappy language, but at least it’s a mature one that’s used outside of autotools. I understand the wish to have no dependencies, but “invent a programming language” is always a bad design decision.
    That is sort of true, and I’m not particularly fond of the cmake language. But it’s very simple to learn, so I don’t think that’s too much of an issue. On the same hand, when writing autotools scripts, you have to know multiple languages which to me seems like an even worse problem.

    >> pkg-config
    Well, a lot of packages actually don’t ship a .pc file. Gnome is very consistent in doing so, but a lot of software isn’t. There are a number of things I dislike about pkg-config actually, but that’s off-topic here.
    But on the cmake side: there are two scripts distributed with cmake: FindPkgConfig.cmake, UsePkgConfig.cmake. Have you checked those out?

    >> config.h issue, # There are no default checks, so you must specify the common stuff always, making the build file more verbose.
    I’ve now coded multiple projects and never had the need of such repetitive checks, what checks are you referring to here?

    >> (install) With CMake, it’s easier, but you have to do “make -DCMAKE_INSTALL_PREFIX=/opt/mystuff” instead of autotool’s simpler ./configure –prefix=/opt/mystuff. autotools lists that option via “configure –help”.
    (you ment cmake -DCMAKE…. right?) Now I really don’t get that point… have you tried ccmake? A very nice gui to set all your configs. Besides, in cmake, the install prefix is just a variable like cflags or anything else, so setting it by -DNAME=value is very consistent.

    >> there’s an undocumented syntax such as #cmakedefine “@PACKAGE_NAME@”.
    That’s not true. I got that from the docu under configure_file. It’s right there.
    On the other side, I agree that cmake’s docu is not the best. But lets be fair – you stated too that you had a hard time learning autotools (and I failed). That docu isn’t really better either. I guess it’s a matter of getting used to it

  8. I couldn’t figure out which command cmake would eventually generate to compile the code. It is all hidden away from the user, but that makes it difficult to trace compiler/linker-related errors, or to just compile stuff manually (say, for a simple test). What did I miss?

  9. murrayc: I did use it for some of my own projects and I tried to use it at this work-project (Qt based, basically to get setup.exe and RPM for free) but had to abandon it because we need to have as few external dependencies as possible. Also I found that Qt + CMake is a bit esoteric, but this may be the documentation issue you also mentioned.

    For me it’s autotools when on Unix/cygwin/mingw, CMake if we need to be portable (as in Linux and Windows with MSVC) and don’t have other constraints and qmake if we have to deal with Qt.

  10. Like Pavel said, scons is very nice. Escpecially the bit where it’s just a Python library – the learning curve for most people is measured in minutes, not hours.

  11. I’ve had similar experiences with CMake – I started a little project with it, and ended up having to do so much hacking on CMake to make everything work that I ended up just scrapping the whole thing and starting again with Autotools… As long as you don’t use recursion, Autotools is actually a very good system, despite what an extremely vocal minority try to make everyone believe…

    I’ve stayed away from SCons too, having not once been able to get a project that uses it to build… I’ve tried five or six projects over three or four SCons versions, but they all seem to fail with syntax errors in various python files, or complains that I need a version of SCons that is two or three point releases ahead of the one in Ubuntu…

  12. Hi,

    try this to use pkgconfig. i walked away from qmake to cmake because of
    cross platfrom/cross compiler issues. boost and openmp is a mess when
    using three different compilers and two different operating systems.

    cmake_minimum_required(VERSION 2.6)
    find_package(PkgConfig REQUIRED)
    pkg_check_modules(gtk REQUIRED gtk+-2.0)
    IF(gtk_FOUND)
    message(STATUS “gtk found”)
    message(STATUS ${gtk_LDFLAGS})
    message(STATUS ${gtk_CFLAGS})
    ENDIF(gtk_FOUND)
    add_executable(test test.cpp)

    cheers

  13. Gregor, I encourage you to actually look at the problem I was having.

    Your is just another overly-simple incomplete example that doesn’t actually do any linking or including.

  14. well then its like this:

    cmake_minimum_required(VERSION 2.6)
    find_package(PkgConfig REQUIRED)
    pkg_check_modules(gtk REQUIRED gtk+-2.0)

    include_directories(${gtk_CFLAGS})
    add_executable(test test.cpp)
    target_link_libraries(test ${gtk_LDFLAGS})

    1. Gregor, using include_directories() there apparently still seems wrong, though I don’t know what CMake really wants us to do. Using include_directories() ends up losing spaces from the CFLAGS. I think that’s the same problem that I remember back when I wrote this blog entry.

  15. I use cmake for most of what I do and am quite happy with it. But seriously, a single page for the official documentation? Splitting it into multiple pages would make it a lot friendlier.

  16. Murray, saying that autotools only requires make is a bit untrue.

    It requires make, a posix shell, and most projects end up using loads of custom commands, perl scripts and other cruft that makes people trying to build software out of the Linux/Unix world a pain in the arse. This is actually worse than requiring just python, as python is way easier to find and install in non unix systems.

    I mean, if you become an expert and you target to Linux and just Linux, autotools can be awesome with enough experience, but it makes life _really_ hard for beginners, documentation might be better than when you started, but so many things about it are as non obvious as the ones you just found with CMake.

    Yet nor waf, cmake, qmake or scons are able to compete in many areas with autotools :/

  17. About the “No configure stage” paragraph: read the docs before saying something is undocumented ;) the @VAR@ syntax is documented, as is the standard syntax ${VAR}. See e.g. the man page, which is the same as the online doc, search for configure_file.

  18. Not to mention, with autotools you have to learn a few languages, not just an invented one, but Make (with automake magic), autoconf, and eventually M4 if you want to extend things. With CMake at least you just have to learn one :-)

  19. Oh actually since you only mention #cmakedefine it seems that you believed that that was the only way to configure something? If that was the case: no, you can configure absolutely any text file, you can use the ${VAR} syntax anywhere.

    I’d be surprised if there were still anything significant that cmake lacks compared to autotools, but to find stuff it’s true that you may have to look at existing cmake code or ask for help, as documentation is not always extensive (that said, as i mentioned, part of what you didnt find was actually in the man page).

  20. You can actually do quite a lot with qmake (which allows you to define functions etc.), but official documentation is only available for basic stuff. Otherwise I agree with your analysis.

    The main problem of qmake (in my opinion) is the limitation of one target per .pro file, which really gets in your way quite often.

    If you want to see a custom build system built on qmake (seperate .pri files for library dependencies, checking of dependencies, multi-directory builds, a useful make install), take a look at http://bazaar.launchpad.net/%7Eigotu2gpx/igotu2gpx/0.3/files/181 :-).

  21. I think you underestimate how bizarre and complicated autotools is for a beginner. I routinely see patches coming in for various projects that are complete except for modification to the build system to support them–this is because so many people can’t figure out autotools.

    Cmake may not be perfect and I find parts of it annoying, but it is easy to learn the basics.

  22. Benoit, yes, sorry, I was looking here,
    http://www.itk.org/Wiki/CMake_HowToDoPlatformChecks (from the cmake developers, I believe.)
    It is indeed mentioned here:
    http://www.cmake.org/cmake/help/cmake-2-8-docs.html#command:configure_file
    It would have been helpful if that wiki had linked to the relevant reference documentation, and even more helpful if the reference documentation gave more hints about how to use things.

    It’s not cmake’s fault at all, but google is bad at returning relevant results when searching for cmake stuff. For instance, when searching for “cmake configure_check”, that second link is nowhere in the first few results, if at all. Even using site:cmake.org will return mailing list archives first.

  23. I found exactly the same thing when dealing with CMake for MySQL builds on Windows (and when porting MySQL Cluster to Windows). MySQL uses autotools on UNIX/Linux but CMake on Win32/Win64.

    I found the CMake book to be pretty useless and the error messages coming out of CMake to be even more useless.

    At least with automake you can look at the resulting Makefile.

    The only advantage for CMake? It can produce VisualStudio project files, which is useful for Windows devs.

  24. murrayc,
    Have your read on LWN before posting?

    In my experience, cmake’s learning curve is fine (compared to autotools). For a simple “hello world” program. All you need is just one line in CMakeLists.txt.
    add_executable(hello hello.cpp)

    I found cmake is especially handy for people like me who are too lazy to read documentation.
    Because of cmake’s genius design, all I need to do is search “keyword file:CMakeLists.txt” on google code.

  25. chen, this sounds very scary to me: ‘Because of cmake’s genius design, all I need to do is search “keyword file:CMakeLists.txt” on google code.’ With regard to build scripts, I wouldn’t want to rely on other projects using the same lib as I do and simply hope that they “got it right”. Also, Google never forgets. So what are the chances you get an old CMakeList.txt with deprecated commands?

  26. Chen,
    > In my experience, cmake’s learning curve is fine (compared to autotools). For a simple “hello world” program. All you need is just one line in CMakeLists.txt.

    Yes, I agree that that is nice and a valuable part of the learning curve. A simple “PROGRAMS = test” would probably work in a Makefile.am, I suppose, though you’d still need a configure.ac, and that demands some reading.

    However, my post talks about how awkward it is to do anything after that simple hello world.

  27. michael,
    My point is an example is always helpful. For cmake, finding an example is easier because all you need search is just one file.

    I did not say copying&hacking code is good or bad.

    As for the “deprecated commands”, an old project has more deprecated things.

    murrayc,
    I did read your post. If “cmake is awkward to do anything after simple hello world” (compared with autotools), why some top KDE guy highly recommened cmake?

    Following is quoted from KDE mailing list,
    “Aaron Seigo asked for some help to port some of kdesktop’s components into krunner so that kdesktop could finally be killed off in the KDE 4 tree. This is the sort of task that I would not have attempted to tackle in the KDE 3.x tree, not because the code was any harder, but because the build system was so difficult to deal with.”
    http://mail.kde.org/pipermail/dot-stories/2007-February/001050.html

  28. I’d just like to say that I agree with your post. I actually _became_ an autotools user after trying SCons and CMake for a while. SCons I didn’t mind, but I didn’t want a compile-time dependency on Python (which was annoying for the Windows/MingW part of my build), so I switched to CMake, but couldn’t STAND it! The language is just so completely awful, and getting it to do simple things is like pulling teeth if you’re not familiar with it.

    Certainly m4 is not a common or even particularly nice language, but the thing I like about autotools and what ultimately made me decide to stick to it, is that there is some comfort in knowing that you’re basically just throwing some macros together to create a standard shell script. Also, autotools being an old, old unix tool, just *knows* so much about *nix and where things are supposed to go and how to build a proper release, it seems wasteful not to take advantage of that implicit knowledge.

    One major problem I had recently was a library build that uses libtool, there has been some major change in libtool between major versions 1 and 2 such that for a while producing tarballs on newer systems would break and not work on older systems, and conversely producing a tarball on too-old a system would break on newer systems. That was a pretty bad situation, but I finally figured out that to deal with it I have to ensure that the build system used to create the release must have a new enough version of libtool, or if an older version of libtool is installed on the target system, to re-run libtool on that system. Pain in that ass, that is, _shrug_.

  29. Long, long ago I made a simple project with autotools and I thought it was pretty kludgy. From there on out I tried Jam, then SCons, then CMake, and I finally went back to autotools and I’m now satisfied. There’s a lot of room for improvement from where autotools is, but the alternatives are worse for most projects. Note that I spent a couple years with Jam and SCons before giving them up, and I’ve only used autotools for couple months but I still like it better.

  30. Actually, http://sources.redhat.com/autobook/ seems to be considered deprecated: I remember joining #gnu on the freenode irc network in hope someone would help me understand some problems faced with the autotools and that’s where I was advised to forget about the autobook. In that aspect, maybe the book should reworked or maybe simply pulled.

    Then I googled a bit and found this excellent tutorial by Alexandre Duret-Lutz: http://www.lrde.epita.fr/~adl/autotools.html
    As I didn’t take the time to read http://www.freesoftwaremagazine.com/books/autotools_a_guide_to_autoconf_automake_libtool carefully, I can’t tell whether it’s useful or not.

    I disagree with “I understand that pkg-config is not popular on Windows or MacOS, and that those are awkward platforms to work with”. No they’re not awkward platforms to work with — they just don’t satisfy the many assumptions made by the autotools. What’s awkward for instance is putting hope in the autotools when building non open source projects.

    I was asked to use the autotools on a closed source project with an existing directory hierarchy: like “bin/$platform-$arch/” directories for the binaries or “lib/$compiler/” directories for some static libraries or “build/$buildsystem/$platform-$arch” for the intermediate files like object files. I had to put a level of shell scripting and GNU makefiles on top of the autotools: for instance to make it automatically change directory to “build/autotools/linux-x86_64” before calling “../../../configure” etc. And how to move the binaries to the “bin/linux-x86_64” directory without issuing “make install” anyway? That’s definitely not the scenario emphasized in all the autotools tutorials found out there and it was a major headache to force the autotools into doing what was expected.

    I’m sorry my comment doesn’t help you using CMake though :)

  31. Many open source developers’ idea of “cross-platform” is “supports Linux and FreeBSD, with experimental support for Solaris”. That isn’t even close to being cross-platform.

    Supporting non-POSIX environments may not be important to you. Ain’t nothing wrong with that. If you’re liking it, and it’s paying your bills, then that’s cool. CMake is solving problems you don’t have, and probably feels like “all pain and no gain” to you. If you’re only building on Linux and close cousins, and you’ve already made the effort to learn autotools, there is no benefit to CMake.

    There are a lot of developers who need to build on both POSIX and non-POSIX (especially Windows) systems. Running a POSIX-emulation layer on the non-POSIX system (e.g. Cygwin) may be undesirable or impossible. Tools like CMake that abstract platform differences, and integrate with native build tools (e.g. Microsoft compilers), are solving a real world problem that autotools simply does not address.

Leave a Reply

Your email address will not be published. Required fields are marked *