Desperately need help with mingw64 and gtk-3.0 for cross compilation from Linux (WSL/Ubuntu) to Windows

I’ve been using WSL 2 with Ubuntu.

So far, so good

The following works.
In the WSL/Ubuntu terminal:

$ x86_64-w64-mingw32-gcc -g -o hello hello.c

In CMD:

C:\Users\michiel>hello.exe
Hello world!

And this also works.
In the WSL/Ubuntu terminal:

$ gcc -o test main.c `pkg-config --libs --cflags gtk+-3.0`
$ ./test

This opens a basic (gtk) gui example.

The problem

$ x86_64-w64-mingw32-gcc -o main.exe main.c `pkg-config --libs --cflags gtk+-3.0`

output:

In file included from /usr/lib/x86_64-linux-gnu/glib-2.0/include/glibconfig.h:9,
                 from /usr/include/glib-2.0/glib/gtypes.h:32,
                 from /usr/include/glib-2.0/glib/galloca.h:32,
                 from /usr/include/glib-2.0/glib.h:30,
                 from /usr/include/gtk-3.0/gdk/gdkconfig.h:13,
                 from /usr/include/gtk-3.0/gdk/gdk.h:30,
                 from /usr/include/gtk-3.0/gtk/gtk.h:30,
                 from main.c:1:
/usr/include/glib-2.0/glib/gtypes.h: In function ‘_GLIB_CHECKED_ADD_U64’:
/usr/include/glib-2.0/glib/gmacros.h:738:31: error: static assertion failed: "Expression evaluates to false"
  738 | #define G_STATIC_ASSERT(expr) _Static_assert (expr, "Expression evaluates to false")
      |                               ^~~~~~~~~~~~~~
/usr/include/glib-2.0/glib/gtypes.h:463:3: note: in expansion of macro ‘G_STATIC_ASSERT’
  463 |   G_STATIC_ASSERT(sizeof (unsigned long long) == sizeof (guint64));
      |   ^~~~~~~~~~~~~~~
In file included from /usr/include/glib-2.0/gio/gio.h:46,
                 from /usr/include/gtk-3.0/gdk/gdkapplaunchcontext.h:28,
                 from /usr/include/gtk-3.0/gdk/gdk.h:32,
                 from /usr/include/gtk-3.0/gtk/gtk.h:30,
                 from main.c:1:
/usr/include/glib-2.0/gio/gcredentials.h: At top level:
/usr/include/glib-2.0/gio/gcredentials.h:75:1: error: unknown type name ‘uid_t’
   75 | uid_t            g_credentials_get_unix_user      (GCredentials    *credentials,
      | ^~~~~
/usr/include/glib-2.0/gio/gcredentials.h:79:52: error: unknown type name ‘uid_t’; did you mean ‘pid_t’?
   79 |                                                    uid_t           uid,
      |                                                    ^~~~~
      |                                                    pid_t

I’ve also tried:

$ x86_64-w64-mingw32-gcc -o main.exe main.c `x86_64-w64-mingw32-pkg-config --libs --cflags gtk+-3.0`

Same result.

And I’ve installed more recent versions of the deb packages (than distributed by ubuntu for now): mingw-w64_8_ and mingw-w64-tools_8_ . This too gave the same result.

I installed MSYS2 and tried to change the PKG_CONFIG_PATH env variable but failed in doing so succesfully. I’m also not sure if this is the right course of action.

Can some kind spirit please help me with this frustrating issue?

Hello, @michiel.kerremans!

Plain pkg-config should go with gcc; for the mingw-w64 cross-compiler, instead, you have to use mingw-w64-pkg-config.

I am not an Ubuntu user, but I believe that the right package is Ubuntu – Details of package pkg-config-mingw-w64-x86-64 in bionic

Thank you for your support.

This is why I tried x86_64-w64-mingw32-pkg-config from the mingw-w64-tools package (I also tried a more recent version as well using the deb package directly), but this gives the same result as pkg-config, that is with export PKG_CONFIG_PATH=/usr/lib/x86_64-linux-gnu/pkgconfig.

I might need to add another location to the PKG_CONFIG_PATH env variable, but I’m clueless as to which one and what exactly should be at that location.

In the output there’s referencing to unix user credentials, maybe I need another library or something for windows?

Kind Regards

Extra Information

$ export PKG_CONFIG_PATH=/mnt/c/msys64/mingw64/lib/pkgconfig
$ x86_64-w64-mingw32-pkg-config --libs --cflags gtk+-3.0

output:

-DLIBDEFLATE_DLL -I/mingw64/include/gtk-3.0 -I/mingw64/include -I/mingw64/include/pango-1.0 -I/mingw64/include/harfbuzz -I/mingw64/include/pango-1.0 -I/mingw64/include/fribidi -I/mingw64/include -I/mingw64/include/atk-1.0 -I/mingw64/include/cairo -I/mingw64/include -I/mingw64/include/freetype2 -I/mingw64/include/harfbuzz -I/mingw64/include -I/mingw64/include/pixman-1 -I/mingw64/include/gdk-pixbuf-2.0 -I/mingw64/include/libpng16 -I/mingw64/include -I/mingw64/include/webp -I/mingw64/include -I/mingw64/include/glib-2.0 -I/mingw64/lib/glib-2.0/include -I/mingw64/include -L/mingw64/lib -lgtk-3 -lgdk-3 -lz -lgdi32 -limm32 -lshell32 -lole32 -Wl,-luuid -lwinmm -ldwmapi -lsetupapi -lcfgmgr32 -lhid -lwinspool -lcomctl32 -lcomdlg32 -lpangowin32-1.0 -lpangocairo-1.0 -lpango-1.0 -lharfbuzz -latk-1.0 -lcairo-gobject -lcairo -lgdk_pixbuf-2.0 -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lintl

If I use PKG_CONFIG_PATH=/usr/lib/x86_64-linux-gnu/pkgconfig:/mnt/c/msys64/mingw64/lib/pkgconfig, it gives me the same bad result as for PKG_CONFIG_PATH=/usr/lib/x86_64-linux-gnu/pkgconfig without the addition.

But for just PKG_CONFIG_PATH=/mnt/c/msys64/mingw64/lib/pkgconfig, x86_64-w64-mingw32-pkg-config does give the msys64 directories and files, which is good I guess.

However, when I now run:

x86_64-w64-mingw32-pkg-config --modversion gtk+-3.0
x86_64-w64-mingw32-gcc -o main.exe main.c `x86_64-w64-mingw32-pkg-config --libs --cflags gtk+-3.0`

I get:

main.c:1:10: fatal error: gtk/gtk.h: No such file or directory
    1 | #include <gtk/gtk.h>
      |          ^~~~~~~~~~~
compilation terminated.

So the problem persists in that now the compiler cannot find gtk.h.

1 Like

Yes, /usr/lib/x86_64-linux-gnu/pkgconfig is the path for native Linux libraries. mingw libraries are instead found under /usr/x86_64-w64-mingw32/lib/pkgconfig. See for example the contents of libgpg-error-mingw-w64-dev.

Anyway, looks like Ubuntu provides very few mingw packages: Ubuntu – Package Search Results -- mingw. Basically, it gives you the mingw-w64 cross-compiler and a few fundamental libraries, nothing more. So you’re left with building GTK and all the dependencies yourself. That’s a huge task!

Fedora provides many pre-built mingw packages instead, GTK included: mingw-gtk3 - Fedora Packages

The problem with mounting an MSYS2 bundle under /mnt is that pkg-config is not prepared for that, and thus returns wrong paths.

The easiest way would be to use MSYS2 directly, use Fedora packages or even some project like MXE which automates the task of cross-building many libraries from source.

As you’re on Windows, the best option is really to use MSYS2 or gvsbuild

1 Like

I’ve managed to solve the issues by using the mxe setup.
However, I would like to share the solutions here for others.
My next reply will do so.

1 Like

The following works with WSL (Ubuntu).

Install mxe with gtk3 for Windows, in /mxe.

mxe.bash

#!/bin/bash

sudo apt -y install libssl-dev libtool-bin flex bison \
  gperf intltool p7zip-full python-is-python3
git clone https://github.com/mxe/mxe.git /mxe
git config --global --add safe.directory /mxe
make -C /mxe MXE_TARGETS='x86_64-w64-mingw32.static' cc gtk3

Install gtk3 for Linux.

gtk.bash

#!/bin/bash

deb="deb http://archive.ubuntu.com/ubuntu focal-updates main"
! grep "$deb" /etc/apt/sources.list >/dev/null \
  && echo "$deb" | sudo tee -a /etc/apt/sources.list
sudo apt update
sudo apt -y upgrade
sudo apt -y install libgtk-3-dev
echo $'\n'"pkg-config --modversion gtk+-3.0"
printf '> %s\n' "`pkg-config --modversion gtk+-3.0`"
echo $'\n'"pkg-config --libs --cflags gtk+-3.0"
printf '> %s\n' "`pkg-config --libs --cflags gtk+-3.0`" ""

I’ve also included echo and printf commands here to print the gtk version and libraries.

My Bash script with commands and exports.

gcc.bash

#!/bin/bash

mkdir -p /gcc/
export PATH=/mxe/usr/bin:"$PATH"
export GCC="-I/gcc/ -L/gcc/ -pthread"
export GTK="`pkg-config --cflags --libs gtk+-3.0`"
export GTKWIN="-mwindows `x86_64-w64-mingw32.static-pkg-config --cflags --libs gtk+-3.0`"

gcc-win(){
  x86_64-w64-mingw32.static-gcc "$@"
}

pkg-config-win(){
  x86_64-w64-mingw32.static-pkg-config "$@"
}

gcc-lib(){
  cp "$1".h "$1".c /gcc/
  gcc -c /gcc/"$1".c -o /gcc/"$1".o
  ar rcs /gcc/"lib$1.a" /gcc/"$1".o
  gcc-win -c /gcc/"$1".c -o /gcc/"$1-win".o
  ar rcs /gcc/"lib$1-win.a" /gcc/"$1-win".o
}

gcc-lib can be used to quickly add a single library in /gcc/.
Sourcing this script creates /gcc (if non-existent) and the script’s exports assume that new libraries are placed in /gcc/.

How to use the commands.

You can use the following test .c files:

gtktest.c

#include <gtk/gtk.h>

static void
print_hello (GtkWidget *widget,
             gpointer   data)
{
  g_print ("Hello World\n");
}

static void
activate (GtkApplication *app,
          gpointer        user_data)
{
  GtkWidget *window;
  GtkWidget *button;
  GtkWidget *button_box;

  window = gtk_application_window_new (app);
  gtk_window_set_title (GTK_WINDOW (window), "Window");
  gtk_window_set_default_size (GTK_WINDOW (window), 200, 200);

  button_box = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
  gtk_container_add (GTK_CONTAINER (window), button_box);

  button = gtk_button_new_with_label ("Hello World");
  g_signal_connect (button, "clicked", G_CALLBACK (print_hello), NULL);
  g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_widget_destroy), window);
  gtk_container_add (GTK_CONTAINER (button_box), button);

  gtk_widget_show_all (window);
}

int
main (int    argc,
      char **argv)
{
  GtkApplication *app;
  int status;

  app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
  g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
  status = g_application_run (G_APPLICATION (app), argc, argv);
  g_object_unref (app);

  return status;
}

sqltest.c

#include <sqlite3.h>
#include <stdio.h>

int main(void) {
  printf("%s%s\n", "SQLITE3 VERSION: ", sqlite3_libversion());
  return 0;
}

We’ll compile the sqlite amalgamation file and add the library with gcc-lib.

The SQLite Amalgamation

sqlite-amalgamation-3410200.zip
(2.50 MiB) C source code as an amalgamation, version 3.41.2.

Contents of my ~/gtk/:

  • mxe.bash
  • gtk.bash
  • gcc.bash
  • gtktest.c
  • sqltest.c
  • sqlite3.c
  • sqlite3.h

Install everything with the following commands (provided that you’re in ~/gtk/):

(the first command takes quite a while…)

bash mxe.bash
ls /mxe
bash gtk.bash
. gcc.bash
echo $GCC
echo $GTK
echo $GTKWIN
. gcc.bash
gcc-lib sqlite3
ls /gcc

Now you can easily (cross-)compile the .c files.

. gcc.bash
gcc gtktest.c -o gtktest $GCC $GTK
./gtktest

This opens a GTK GUI prompt with a ‘Hello World’ button you can click.

. gcc.bash
gcc-win gtktest.c -o gtktest.exe $GTKWIN
cp *.exe /mnt/c/users/michiel/gtk/

Then in CMD (Windows):

gtk\gtktest.exe

This opens the same GTK GUI prompt in Windows.

. gcc.bash
gcc sqltest.c -o sqltest -lsqlite3 -ldl $GCC
./sqltest

This prints your Sqlite version (using sqlite in ansi C).

. gcc.bash
gcc-win sqltest.c -o sqltest.exe -lsqlite3-win $GCC
cp *.exe /mnt/c/users/michiel/gtk/

Then in CMD (Windows):

gtk\sqltest.exe

Does the same in CMD.

Good luck!

This is as idiotproof as I, the idiot, can make it.
:smiley:

Thanks to @lb90 for the guidance.

2 Likes

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.