Have I said nice things about Kate recently? Not enough, so let me gush a little about Kate as an “IDE” and using it, with the Build Plugin, as a tool for editing locally and building remotely.

I work on a codebase that has very specific platform requirements. These requirements are difficult to reproduce in a normal host – or, if you have some modern rolling distro like openSUSE, well-nigh-impossible. That’s the situation where Docker shows up, since a Docker container can be whatever specific platform is needed.

So I have a Docker, with the special compilation environment over here, and the host machine, running a recent version of Kate over there. How can I make them work together?

Sharing Directories with Docker

When starting a Docker container with docker run, you can bind-mount locations into the container. So for a builder-container, where you want to have the source code available inside, a convenient way to do it is to bind-mount the source directory in the host, to a location – the same location – in the container.

Something like this:

docker run \
    -v /home/me/src/myproject:/home/me/src/myproject:rw \
    --name myproject \
    myprojectimage \
    /bin/sh

The --name argument is slightly-important. Docker comes up with a creative random name of the container if you don’t give one explicitly, and that makes it harder to connect to the running container.

I should note that my approach is “leave the container running, and connect to it for compilation”, not “start a new container for every build”. Your mileage may vary, and it’s easy enough to bung some commands to start a container and run make in it, in a shell script and use that.

Configuring the Build-in-Docker

The codebase I’m on uses CMake as meta-buildsystem, which leads to the usual (?) convention: there’s a build/ dir underneath the sources, CMake is run there, and then the build proceeds there as well:

# Do this in the container
mkdir /home/me/src/myproject/build
cd /home/me/src/myproject/build
cmake ..

When doing a build like this, Qt’s moc will generate files in (subdirectories-of) the build/ directory; other sources might be generated there as well. Compiler errors might reference absolute paths (e.g. /home/me/src/myproject/main.cc) or might reference relative paths (e.g. ../main.cc).

Depending on the exact way Docker is run from the host, the build directory may or may not be visible. For me, it isn’t, and for various reasons I can’t create the same build/ path in the host. So instead, I create a similar path that leads to the same relative paths back to the source directory:

# Do this in the host
mkdir /home/me/src/myproject/build_

Setting up Kate-in-Host

This is the main course: using Kate as an IDE, running the build inside the Docker container.

First, we need to enable the Build Plugin. Kate comes with a bunch of plugins that provide extra search functionality, IDE functionality, better LaTeX support, .. it’s quite extensive. Go to SettingsConfigure Kate.. and choose the Plugins pane (module? I don’t really know what those icons-in-a-column should be called, each of which calls up its own set of tabs). Tick the box in front of the Build Plugin.

Kate Plugin List, with *Build Plugin* checked
Kate Plugin List, with *Build Plugin* checked

Unfortunately, the Build Plugin doesn’t initialize quite right when enabled the first time. Quit Kate, then start it again.

Once it’s back, there is a Build button at the bottom of the window. Click on it to open up the tool view for the plugin. There are target sets, and there’s a top-level “name of the target set” and “working directory” – since this is laid out in a two-column table it looks a bit strange.

Kate Plugin List, with *Build Plugin* checked
Kate Plugin List, with *Build Plugin* checked

The Kate Documentation for the Build Plugin is reasonably extensive.

  • Optionally, click on the T: Target Set label to change the name of the set.
  • Click on the Dir: label to change the directory where the build happens. This is needed because otherwise the build happens either where Kate was started, or the directory where the current file is. I haven’t got a clear answer on that.
  • Tick the box in front of build to make it the default target to build.
  • Click on the make command to edit it.
  • Fill in the command to run the build in the container. I use Docker’s run command, with the name of the container to attach to. -a is a flag to preserve stdin, out, and error. The make command changes directory to the actual build-directory, and -j is tuned to the available CPU power.
    docker run -a myproject \
        make -C /home/me/src/myproject/build -j4
    

There’s a little cog-like icon with tooltip Build selected target. Click on the build line to select it, then hit the cog and see what happens.

Personally I like the KDevelop key-binding of F8 for “build the thing”, so I open the Build menu (top of the Kate window), right-mouse-click on the menu entry Build Default Target, pick Configure Shortcut.. and bind F8 to it. By default, that key is bound to “switch to next view”, but I don’t use split views.

O noes, Ninja

The Build Plugin parses the output of the build command – e.g. make. The Build Plugin also knows how to deal with Ninja. However – and thanks to Christoph Cullmann for helping figure this out – Kate uses a trick to separate the Ninja output from compiler output (with make, this is apparently not needed). The environment variable NINJA_STATUS gets special treatment from Kate. The variable needs to be passed in to the container, so for a ninja build this is the Docker command (where -e NINJA_STATUS means “pass the value of the environment variable in to the container”).

docker run -a myproject \
    -e NINJA_STATUS \
    make -C /home/me/src/myproject/build -j4

Takeaway

With just a few steps, building a weird-ass codebase in a container can be a lot more pleasant by editing it outside the container with modern tools, and “remote build” is supported by Kate quite well.

If you wonder why I’m not using KDevelop, well, two things: it actually has less documentation on custom and remote builds, and two, it crashes just trying to read the weird-ass codebase. I have yet to debug the latter.