antek's tech blog - cmakeZola2019-03-02T00:00:00+00:00https://anadoxin.org/blog/tags/cmake/atom.xmlIs it worth using make?2019-03-02T00:00:00+00:002019-03-02T00:00:00+00:00Unknownhttps://anadoxin.org/blog/is-it-worth-using-make.html/<p>You may think you've created a nice and tidy Makefile, which tracks dependencies and works across many different operating systems, but ask yourself these questions (and answer honestly):</p>
<h4 id="which-compiler-does-your-makefile-support">Which compiler does your Makefile support?</h4>
<p>Is it <code>GCC</code>? Or <code>Clang</code>? Some of their options are pretty similar, so it may not be very hard to make your Makefile work for both. But does it support e.g. Visual Studio?</p>
<h4 id="does-your-makefile-support-out-of-source-build">Does your Makefile support out-of-source build?</h4>
<p>Polluting the source tree with autogenerated files is often not a very good idea. It makes source code versioning harder, even if you use <code>.gitignore</code>, you can't use a different partition to store your compiled object files, you can't easily clean your build (nothing is easier than simply removing the build directory with <code>rm -rf</code>), you can't use a read-only partition to store your source, etc.</p>
<h4 id="does-your-makefile-support-windows-at-all">Does your Makefile support Windows at all?</h4>
<p>Windows often uses a different set of rules when it comes to building software. More than that, it uses its own compiler (Visual Studio), with different switches and different options. You may want to target only MinGW (which basically is GCC for Windows), but in this case you still won't be able to run your clever scripts embedded into Makefile rules (<code>grep</code>, <code>sed</code>, <code>if</code>, <code>test</code> -- nothing is supported). You won't even have the <code>make</code> tool installed there, so there will be nothing that could interpret your Makefile. You might want to target <code>MSYS2</code> environment so you will have support for <code>make</code> command and whole binutils package, but how many Windows users are using <code>MSYS2</code>? I think not too many.</p>
<h4 id="is-your-makefile-a-gnu-makefile-or-bsd-makefile">Is your Makefile a GNU makefile, or BSD makefile?</h4>
<p>You don't simply create a Makefile. What interpreter do you want to use? A GNU make, or a BSD make? Or maybe Watcom make, nmake, Borland make, Sun dmake, Sun DevPro make? If you want to see what it really takes to support lots of different Makefile dialects, operating systems and compilers, you can look at <a href="https://github.com/madler/zlib">zlib</a>'s repository, and check how they're handling things. Using Makefile is anything but easy. Still, you can get away with simply requiring to use the GNU make, which is more popular than BSD make (but requires to use <code>gmake</code> instead of <code>make</code> on BSD systems).</p>
<h4 id="does-your-makefile-support-cleaning-the-project-from-all-autogenerated-artifacts">Does your Makefile support cleaning the project from all autogenerated artifacts?</h4>
<p>If you're using git, you can maybe sometimes get away with <code>git clean -fd</code>. But if you're not using out-of-source builds, you have to give users the ability to clean the project tree so they can perform a clean re-build of the project, because there are situations that will need this functionality.</p>
<h4 id="do-you-support-a-situation-when-the-compiler-sdk-will-be-upgraded-on-the-system">Do you support a situation when the compiler/SDK will be upgraded on the system?</h4>
<p>When was the last time you've run <code>apt-get update</code> or <code>pacman -Syu</code>? Yesterday? Did you remember if GCC was updated? Because if it was updated, chances are that some object files need to be recompiled. Does your Makefile support detection when a file will need to be recompiled? You can get away with this by allowing the user to clean the build and do a clean re-compile, this would be enough for most cases.</p>
<h4 id="do-you-track-the-dependencies-on-the-libraries-installed-in-the-system">Do you track the dependencies on the libraries installed in the system?</h4>
<p>So in your project you're using zlib to uncompress some files. What happens when you update <code>zlib</code> to a new version? Some of your object files will have old definitions of structs and function signatures, which may not reflect what's really going on in current version's zlib. You need to perform a clean build to be sure every object file will be up-to-date with system libraries. Or you risk some random issues popping up from time to time in the <em>runtime</em>.</p>
<h4 id="do-you-support-setting-a-release-debug-build-of-your-project">Do you support setting a Release/Debug build of your project?</h4>
<p>If you put a variable in your Makefile that needs to be toggled to get a Debug or Release build, you're making it harder for the people to use your project during development, because this change will pop up every time they'll use <code>git status</code>. It will be harder for them to switch branches. If you don't support Release/Debug targets at all, then you're making it even harder.</p>
<h4 id="does-your-makefile-support-passing-custom-cflags-or-ldflags">Does your Makefile support passing custom CFLAGS or LDFLAGS?</h4>
<p>It's important if you want to add e.g. fuzzing support to your project. Or maybe you want to use the zlib version installed in some directory, not the system zlib. Or maybe 100 other reasons. Thing is, people expect this and it's a good idea to have this possibility.</p>
<h4 id="are-you-using-thirdparty-libraries-in-your-project">Are you using thirdparty libraries in your project?</h4>
<p>How do you perform library discovery to check if it's available in the system? Does the build simply stops on <code>missing file f_foobar.h file</code>? Or maybe you actually check if the library headers are installed? Are you using <code>pkg-config</code> as a discovery tool? Are you sure you don't need to add an explicit linkage to <code>pthreads</code> like on some Fedora versions? Are you sure your <code>ninja</code> builder is installed as <code>ninja</code>, not as <code>ninja-build</code> as on some Linux distributions? Are you sure that a library you want to use is installed in <code>/usr/include</code>, not in <code>/usr/local/include</code> as on some BSD systems? Or maybe it's a completely different path, maybe it was installed by <code>brew</code> and user is running macOS?</p>
<h4 id="i-don-t-want-to-use-cmake-because-the-project-is-small-and-it-s-not-worth-it">I don't want to use CMake, because the project is small and it's not worth it.</h4>
<p>Did you know that a minimal fully functional CMake script that supports <em>all</em> of the points from this list takes only 2 lines?</p>
<pre><code>cmake_minimum_required(VERSION 3.5)
add_executable(app main.cpp)
</code></pre>
<p>So "Makefile is less complicated" argument doesn't seem to be true.</p>
<h4 id="what-if-someone-just-wants-to-use-eclipse-xcode-visual-studio-codeblocks-etc">What if someone just wants to use Eclipse, Xcode, Visual Studio, CodeBlocks, etc?</h4>
<p>With your build system they have to use whatever setup you have. And people prefer to use their setups, because they like them. They may have inferior knowledge, they may require indoctrination and enlightenment, sure, but for now they simply want to try to compile your project and that's it.</p>
<h4 id="does-your-makefile-support-showing-the-full-command-line-used-to-compile-a-compilation-unit">Does your Makefile support showing the full command line used to compile a compilation unit?</h4>
<p>Sometimes it's required to debug 'unresolved symbol' linker errors. Or sometimes the user will want to preprocess a compilation unit instead of compiling it. It will require some Makefile hacking in order to do this. You can check how easy it is to run a preprocessor for a selected C++ source file when using CMake: <a href="/blog/generating-preprocessed-sources-in-cmake-projects.html">here</a>. OTOH, fortunately the default usage of make will take care of this point correctly, since it will output full command line that was used to produce an object file, but some people change the Makefile to hide this info and produce only <code>CC file.o</code>. And that's fine, unless there's a problem during compilation.</p>
<h1 id="summary">Summary</h1>
<p>Did you know? Using Makefile generators like <code>CMake</code> and <code>Meson</code> will implement every item on this list automatically without you even knowing about it. Well, maybe point 3 (Windows + Visual Studio support) can require some additional effort, but it'll still be less than when writing pure Makefiles. There is no need to rant about the impossibility of debugging the resulting Makefiles; you debug your source CMake's or Meson's build script, not the resulting Makefiles.</p>
<p>Also, as a bonus, your script will allow itself to be copied and pasted without issues, which is not always true for Makefiles (as they require using tab characters to indent lines, and some tools expand tabs to spaces).</p>
Generating preprocessed sources in CMake projects2018-11-21T00:00:00+00:002018-11-21T00:00:00+00:00Unknownhttps://anadoxin.org/blog/generating-preprocessed-sources-in-cmake-projects.html/<p>Hi,</p>
<p>It appears you can use CMake to quickly generate preprocessed source of your chosen <code>.cpp</code> file without modifying the <code>CMakeLists.txt</code> project file. This trick works only when your generator is <code>make</code> -- meaning, it won't work with the <code>ninja</code> builder.</p>
<p>But still, if you're using <code>make</code> as your generator, try the following.</p>
<p>First, create a sample source code (<code>~/dev/project/test.cpp</code>):</p>
<pre data-lang="cpp" class="language-cpp "><code class="language-cpp" data-lang="cpp">#include <iostream>
using namespace std;
int main() {
cout << "hello world\n";
return 0;
}
</code></pre>
<p>Then, create your <code>CMakeLists.txt</code> file with nothing but just a standard set of commands (<code>~/dev/project/CMakeLists.txt</code>):</p>
<pre data-lang="cmake" class="language-cmake "><code class="language-cmake" data-lang="cmake">cmake_minimum_required(VERSION 3.5)
project(cpptest)
add_executable(cpptest test.cpp)
</code></pre>
<p>Next step is to create your build directory:</p>
<pre data-lang="nothing" class="language-nothing "><code class="language-nothing" data-lang="nothing">$ cd ~/dev/project
$ ls
CMakeLists.txt test.cpp
$ mkdir build && cd build
$ cmake ..
-- The C compiler identification is GNU 8.2.1
-- The CXX compiler identification is GNU 8.2.1
-- Check for working C compiler: /bin/cc
-- Check for working C compiler: /bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /bin/c++
-- Check for working CXX compiler: /bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/antek/dev/project/build
</code></pre>
<p>Now you can issue <code>make</code> in order to build the project, but also you can do:</p>
<pre data-lang="nothing" class="language-nothing "><code class="language-nothing" data-lang="nothing">$ make test.cpp.i
Preprocessing CXX source to CMakeFiles/cpptest.dir/test.cpp.i
</code></pre>
<p>This way CMake will use proper build flags, include directories, proper dependency management, etc, when generating the preprocessed source file. This should work in your own CMake-based project without any modifications.</p>
<p>G.</p>
CMake support for Qt5's external resources2015-05-03T00:00:00+00:002015-05-03T00:00:00+00:00Unknownhttps://anadoxin.org/blog/cmake-support-for-qt5s-external-resources.html/<p>When writing a Qt5 application there is often a need to include graphical
resources inside the application binary. As Qt is a portable framework, it
doesn't use platform-specific solutions for resource storage like the Resource
section in PE files on Windows systems. Qt has its own mechanism which is
possible for use with the help of the <code>rcc</code> tool.</p>
<p>Normally the <code>rcc</code> tool will generate <code>c++</code> source files which contain selected
resources as simple arrays, together with some control structs. Your build
system takes this autogenerated source file, compiles it to a normal object file
with your C++ compiler, and links it into the final executable. CMake supports
that without any problem.</p>
<p>The problem started when I wanted to create an application which loads a plugin.
I wanted the plugin to use Qt5 code, but also I wanted to put some resources
into the plugin itself, not to the host application that loads the plugin. This
resulted in a problem, because the resources linked to the plugin shared object
are not registered to the Qt Resource subsystem, which results in inability to
load them through normal loading mechanisms, like <code>QPixmap(":/resource.jpg")</code>.</p>
<p>Fortunately Qt's <code>rcc</code> tool also supports external resources, which are compiled
binaries, that are meant to be put in an external <code>*.rcc</code> file instead of linked
into the application binary. It's possible to generate this kind of resources by
adding the <code>-binary</code> option to <code>rcc</code>:</p>
<pre><code>$ rcc res.qrc -o res.rcc -binary
$ file res.rcc
res.rcc: Qt Binary Resource file
</code></pre>
<p>Normally I am using a combo of CMake and Ninja to manage the build process, and
unfortunately CMake doesn't support generation of external resource files. CMake
seems to support <code>qt5_add_resources</code> function, but it's designed to generate
source files that are later linked into the application. Even if forcing this
function to pass the <code>-binary</code> option to <code>rcc</code> tool, which is possible, the
result is that the linker tries to link also these binary resource files, which
obviously is not a good idea.</p>
<p>However, I've managed to create a small CMake script that should add support for
this. My function is based on original <code>qt5_add_resources</code> in the sense that it
tries to parse the <code>qrc</code> file to extract the external file references. These
file references are added to a list of dependencies, so CMake knows that it has
to rebuild the <code>rcc</code> file if any of the referenced resource files will change.
It rebuilds the <code>rcc</code> file also when the <code>qrc</code> file will change.</p>
<p>The function works in both <code>make</code> and <code>ninja</code> generators. It has been tested on
gcc only, and I have no idea if it will work on Visual Studio or not.</p>
<p>You can use this support in your projects by checking out this repository on
GitHub:</p>
<ul>
<li><a href="https://github.com/antekone/qt5-external-resources-cmake">https://github.com/antekone/qt5-external-resources-cmake</a></li>
</ul>
<p>This repository contains a small example application that will help you understand how the
CMake function should be called and how to load an external resource from your
application.</p>