Categories
Uncategorized

Glade & Gtk on Windows with MSYS2

This post will detail my attempts to get a simple “Hello World” Glade/Gtk program working on Windows. I’m not an expert but I’m hoping it will provide the kind of help I was looking for when I tried to do this. I’ve cobbled this together from a bunch of articles and my own fumblings.

In fact I thought it might be fun to give you a walk through of what I did, what issues I hit and how I solved them. Maybe later I’ll try to write a proper tutorial.

First Steps

Initially I was following this guide as far as creating my simple Gtk program. I was doing so because having used Glade 2 on a work project I quickly found there were significant differences in Glade 3 – notably that it no longer generates template code for you. So I was looking for a “hello world” I could adapt once I’d figured out the basics.

Installing MSYS2

Next I installed MSYS2 – I just followed the steps from the website. That was straightforward.

I updated the package manager:

pacman -Syuu

This involved re-starting the MSYS2 window a one point, there was a message to this effect.

Installing the Development Tools

Obviously we need a compiler:

pacman -S base-devel mingw-w64-x86_64-toolchain

and we need gtk3 and glade:

pacman -S mingw-w64-x86_64-gtk3 mingw-w64-x86_64-glade3

Also, just because they’re generally useful:

pacman -S git vim

I added this to my ~/.bashrc –

alias vi=vim

Obviously you need to either log out and in again, or also run in the terminal to pick this up.

Finally I created a shortcut for the MSYS2 terminal

Compiling the Template

So part of the first step on our guide is to create a set of template files. I quickly realised that for what I wanted the template was my “hello world”. The only difference is the hello world guide shows you how to use Glade to create the UI itself.

So I tried to compile the template using the makefile.  I hit the following problems.

Problem #1 GCC not on path

Simple enough, I added this line to my .bashrc

export PATH=$PATH:/mingw64/bin

Problem #2 undefined references to gtk functions

gcc -o template_app main.o -pthread `pkg-config --cflags --libs gtk+-3.0`
Package gtk+-3.0 was not found in the pkg-config search path.
Perhaps you should add the directory containing `gtk+-3.0.pc'
to the PKG_CONFIG_PATH environment variable
No package 'gtk+-3.0' found
main.o: In function `main':
C:\msys64\home\paul\Projects\gtk\template/src/main.c:8: undefined reference to `gtk_init_abi_check'
C:\msys64\home\paul\Projects\gtk\template/src/main.c:10: undefined reference to `gtk_builder_new'
C:\msys64\home\paul\Projects\gtk\template/src/main.c:11: undefined reference to `gtk_builder_add_from_file'
C:\msys64\home\paul\Projects\gtk\template/src/main.c:13: undefined reference to `gtk_widget_get_type'
C:\msys64\home\paul\Projects\gtk\template/src/main.c:13: undefined reference to `gtk_builder_get_object'
C:\msys64\home\paul\Projects\gtk\template/src/main.c:13: undefined reference to `g_type_check_instance_cast'
C:\msys64\home\paul\Projects\gtk\template/src/main.c:14: undefined reference to `gtk_builder_connect_signals'
C:\msys64\home\paul\Projects\gtk\template/src/main.c:16: undefined reference to `g_object_unref'
C:\msys64\home\paul\Projects\gtk\template/src/main.c:18: undefined reference to `gtk_widget_show'
C:\msys64\home\paul\Projects\gtk\template/src/main.c:19: undefined reference to `gtk_main'
main.o: In function `on_window_main_destroy':
C:\msys64\home\paul\Projects\gtk\template/src/main.c:27: undefined reference to `gtk_main_quit'
collect2.exe: error: ld returned 1 exit status
make: *** [makefile:25: all] Error 1

Note the message about PKG_CONFIG_PATH. Another addition to my .bashrc

export PKG_CONFIG_PATH=/mingw64/lib/pkgconfig:/mingw64/share/pkgconfig

Problem #3 – undefined reference to WinMain

gcc -o  main.o -pthread `pkg-config --cflags --libs gtk+-3.0`
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/6.3.0/../../../../x86_64-w64-mingw32/lib/../lib/libmingw32.a(lib64_libmingw32_a-crt0_c.o): In function `main':
C:/repo/mingw-w64-crt-git/src/mingw-w64/mingw-w64-crt/crt/crt0_c.c:18: undefined reference to `WinMain'
collect2.exe: error: ld returned 1 exit status
make: *** [makefile:25: all] Error 1

I spent a fair bit of time on this. I was convinced this was something specific to Windows (remember the guide I was following was Linux based) because of the “WinMain” part. However it turned out to be a cut and paste error. I’d copied the makefile by pasting into vim, which recognised the first line as a comment and pasted all subsequent lines as comments. I should have first switched into paste mode. Rather than re-do it I chose instead to edit it and remove the ‘#’s as appropriate. I missed one and had commented out TARGET= line. This makes sense if you look at the gcc command line above. It should be something like

gcc -o template_app.exe  main.o -pthread  ...

but since our exe name is missing it’s treating the main.o as the target exe, which is our object file and has the WinMain function inside.

This isn’t something you’re likely to hit if you download the file or cut and paste carefully, but I provide the details for completeness sake.

Problem #4 – seems to work… but it won’t close

So now I have a template_app.exe that I can run from my MSYS2 terminal and I get a GUI window. But if I try to close it it remains open. I have to kill the process from task manager.
I also tried the hello world app and the ‘Hello’ button appears but nothing happens if I press it.
This is probably the first genuine Windows specific issue. Functions in DLLs in Windows have to be declared to be visible externally aka ‘exported’. Glib (which Gtk is built on) has a macro for this, G_MODULE_EXPORT. So we need to declare any callback functions using this macro. e.g. on_window_main_destroy():

G_MODULE_EXPORT void on_window_main_destroy()
{
...
}

Similarly in Hello World:

G_MODULE_EXPORT void on_btn_hello_clicked()
{
...
}

G_MODULE_EXPORT is defined specific to the platform you’re compiling on which means on Linux it will (usually) equate to nothing, meaning you can safely add it to your code and it’ll be cross-platform.
(See this link for more)

Almost there?

So now we should have an executable we can run from our msys2 terminal and it looks good and functions correctly. Though if it’s the template app it doesn’t do much, and hello world doesn’t do a lot more.

So we’re good right? Well not exactly. You see you might want to share your program or install it on another machine, or just not run it from the terminal. i.e. you might want your program to be ‘standalone’. So I tried this, running the exe file using a Windows command prompt (but I could also have done it by double-clicking it in explorer).
I hit a new series of problems.

Problem #5 missing DLLs

My first attempt I got a series of popup errors like this:

It helpfully tells me which dll is missing. All I need to do is make sure this is on the PATH or in the current directory. I had already created a directory called ‘standalone’ to do my tests in, so I copied the missing dlls there.

I’ll save you a bit of time. I hit this problem repeatedly because what would happen is that I would only get errors for the first few dlls. I would dutifully copy them across and try again only to see new errors for new dlls. I probably should have carried on doing this so that I ended up with only those dlls that I really needed. In the end though I did this in my msys2 terminal

cp /mingw64/bin/*dll .

where the current directory was my standalone directory.

/mingw64/bin is equivalent to C:\msys64\mingw64\bin if you’re copying using Windows tools.

Problem #6 – GdkPixBuf error

Next I got this error:

(template_app.exe:9792): GdkPixbuf-WARNING **: Cannot open pixbuf loader module file 'C:\msys64\home\paul\Projects\gtk\standalone\lib\gdk-pixbuf-2.0\2.10.0\loaders.cache': No such file or directory

This likely means that your installation is broken.
Try running the command
  gdk-pixbuf-query-loaders > C:\msys64\home\paul\Projects\gtk\standalone\lib\gdk-pixbuf-2.0\2.10.0\loaders.cache
to make things work again for the time being.

(template_app.exe:9792): Gtk-CRITICAL **: gtk_widget_show: assertion 'GTK_IS_WIDGET (widget)' failed

So this looks like it has something to do with the GUI itself. If you looked at the layout of the template files you’ll recall we had the XML file, window_main.glade, in a sub-directory called glade, also that this gets loaded dynamically to create the UI. So we need to copy the glade directory so we can still find the XML file to load.

Problem #7 GdkPixBuf error continued

So copying the glade directory only fixed part of the problem, I still got most of the same errors as above. Looking at it I can see that it’s looking for files under my current directory in lib\gdk-pixbuf-2.0\2.10.0\loaders.cache. So I copied these from /mingw64/lib i.e.

cd ~/Projects/gtk/standalone
cp -R /mingw64/lib/gdk* .

Problem #8 – missing icons

Now I get the window for the app appearing but I also get this:

(template_app.exe:12800): Gtk-WARNING **: Could not find the icon 'window-minimize-symbolic-ltr'. The 'hicolor' theme
was not found either, perhaps you need to install it.
You can get a copy from:
        http://icon-theme.freedesktop.org/releases

This is referring to missing icons:

The solution is to copy over the icons:

cd ~/Projects/gtk/standalone
mkdir icons
cp -R /mingw64/share/icons icons

please note that once again I’m being lazy. I’m copying all the system icons rather than the few I actually need.

Problem #9 – console in the background

Now everything works but a Windows command prompt/console appears in the background.

To fix this add -mwindows to the LDFLAGS line in the makefile

LDFLAGS=$(PTHREAD) $(GTKLIB) -mwindows

This means re-compiling but after that you’re done.

All Done?

So that’s it. I now have a program that works and the contents of a directory that constitutes the deliverable should I wish to share my app.

There are a few outstanding issues (I won’t call these problems) to work out which I’ll leave as an exercise for the reader:

  • figure out the minimum set of dlls and icons to distribute
  • package the directory in some way – a zip file would be low-tech, an MSI or similar would be better
  • clarify and comply with the license situation. Gtk is LGPL so I think you’re ok so long as you provide the license details and a link to the original source.