How to create a GUI app using libui-ng on Windows?

well, the state of project is slightly lower than my usual bar for github projects, but i didn’t have much time lately so why not.
Uploaded it to GitHub - konovod/nappgui-cr: Crystal wrapper for NAppGUI

progress so far

изображение

3 Likes

Thank you very much.
I enjoyed running lowlevel_example.cr and highlevel_example.cr !

What I really didn’t understand was which linker option to use for each OS. Especially on Windows.

Thanks to @konovod uploading his nappgui-cr project to GitHub, I now know how to write the link flag on Windows.

@[Link("#{__DIR__}/../../core")]

However, this does not work on Linux. Is there a good way to cross-platform?

https://github.com/crystal-lang/crystal/blob/master/src/compiler/crystal/codegen/link.cr

Looking at the source code of crystal above, I see the following

  • On Linux and MacOS, you specify the flags for the GNU ld linker.
  • On Windows, on the other hand, you specify the options for MSVC linker.

I do not know much about static languages, but my conclusion is simple. These two linkers are not compatible in their flags. So, it is easier to use macros to set different flags for different operating systems.

  {% if flag?(:windows) %}
    @[Link("#{__DIR__}/../../libui")]
  {% else %}
    @[Link(ldflags: "-L #{__DIR__}/../../ -lui")]
  {% end %}
  lib LibUI

This works, but there may be a better way to write it.

Distribution of shared libraries remains a challenge. In the case of Ruby, I wrote a Rake task to download so, dlls, dylib to the vendor directory. In the case of Crystal, postinstall mechanism is one option.

scripts:.
  postinstall: crystal run download.cr

but I am not sure if this is really a good idea. Technically, the shared library is a binary file, so it should be in a generic location like /usr/lib, not ./lib/libui-ng/ in the project. But libui-ng is a portable library for hobbyists, and should work immediately after shards install if possible.

If you do not want the terminal screen to pop up when app.exe starts, add
--link-flags=/SUBSYSTEM:WINDOWS.

Thanks again HertzDevil and konovod.

Finally, I was able to run libui-ng on Windows and other platforms in the same way.
Passing a Proc to a C function is difficult, but I think I was able to implement according to the API reference. This is the first time I used Box.

Link to Prototype

1 Like

I now know the cross-platform compilation options for building an app with static libraries.

module UIng
  {% if flag?(:windows) %}
    @[Link("User32")]
    @[Link("Gdi32")]
    @[Link("Comctl32")]
    @[Link("UxTheme")]
    @[Link("Dwrite")]
    @[Link("D2d1")]
    @[Link("Windowscodecs.lib")]
    @[Link("#{__DIR__}/../../libui")]
  {% elsif flag?(:linux) %}
    @[Link(ldflags: "`pkg-config gtk+-3.0 --libs`")]
    @[Link(ldflags: "#{__DIR__}/../../libui.a")]
  {% elsif flag?(:darwin) %}
    @[Link(framework: "CoreGraphics")]
    @[Link(framework: "AppKit")]
    @[Link(ldflags: "#{__DIR__}/../../libui.a")]
  {% end %}

Without AI’s assistance I would not have found this option. This is because static libraries can only guess the libraries they depend on from the function names in the error messages, and few people are equally familiar with Windows, Mac, or Linux. I have to thank AI for the advances it has made in recent years.

1 Like

This should be equivalent to @[Link("gtk+-3.0")]

1 Like

Thanks! It worked.

Crystal now supports the MinGW platform, so I’m trying to get libui working.
But, Windows is such a pain in the ass…
I respect Microsoft’s commitment to maintaining backward compatibility, but Windows is never something a hobbyist programmer can enjoy :weary:

This linker flag doesn’t always work as expected, but I’m putting it out here—someone might find it useful.

module UIng
  {% if flag?(:msvc) %}
    @[Link("User32")]
    @[Link("Gdi32")]
    @[Link("Comctl32")]
    @[Link("UxTheme")]
    @[Link("Dwrite")]
    @[Link("D2d1")]
    @[Link("Windowscodecs")]
    @[Link("msvcrt")]
    @[Link("#{__DIR__}/../../../libui")]
    @[Link(ldflags: "/SUBSYSTEM:WINDOWS /MANIFEST /MANIFEST:EMBED /MANIFESTDEPENDENCY:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' language='*'\"")]
  {% elsif flag?(:win32) && flag?(:gnu) %}
    @[Link("stdc++")]
    @[Link("supc++")]
    @[Link("user32")]
    @[Link("Gdi32")]
    @[Link("Comctl32")]
    @[Link("D2d1")]
    @[Link("Dwrite")]
    @[Link("WindowsCodecs")]
    @[Link("Uuid")]
    @[Link("Winmm")]
    @[Link("Uxtheme")]
    @[Link("ucrt")]
    @[Link(ldflags: "-mwindows")]
    @[Link(ldflags: "#{__DIR__}/../../../libui.a")]
    @[Link(ldflags: "#{__DIR__}/../../../comctl32.res")]
  {% elsif flag?(:linux) %}
    @[Link("gtk+-3.0")]
    @[Link("m")]
    @[Link(ldflags: "#{__DIR__}/../../../libui.a")]
  {% elsif flag?(:darwin) %}
    @[Link(framework: "CoreGraphics")]
    @[Link(framework: "AppKit")]
    @[Link(ldflags: "#{__DIR__}/../../../libui.a")]
  {% end %}
3 Likes