1.5 - Pen support on Windows build query

44 views
Skip to first unread message

imacarthur

unread,
Jun 17, 2026, 6:58:43 AMJun 17
to fltk.coredev
Matt,

Can I ask what checks cmake is doing to determine whether pen support is available under Windows?
(This is mainly just laziness, I didn't try and look...)

I was just rebuilding things, and _some_ of my build setups work just fine, pen support is detected and built (and works) but a few of my older mingw setups don't - basically cmake says it's not supported.

At first glance, this appears to be because, although the compiler involved is fairly recent, it uses the mingw headers and they are woefully outdated, so I suspect they are missing a few symbols that we now need.

Gonzalo Garramuño

unread,
Jun 17, 2026, 7:12:11 AMJun 17
to fltkc...@googlegroups.com

On 6/17/26 07:58, imacarthur wrote:
> Matt,
>
> Can I ask what checks cmake is doing to determine whether pen support
> is available under Windows?
> (This is mainly just laziness, I didn't try and look...)
>
> I was just rebuilding things, and _some_ of my build setups work just
> fine, pen support is detected and built (and works) but a few of my
> older mingw setups don't - basically cmake says it's not supported.
>
On Windows there's only a single check done:


/* We require Windows 8 or later features for Pen/Tablet support */

# if !defined(WINVER) || (WINVER < 0x0602)
#  ifdef WINVER
#   undef WINVER
#  endif
#  define WINVER 0x0602
# endif
# if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0602)
#  ifdef _WIN32_WINNT
#   undef _WIN32_WINNT
#  endif
#  define _WIN32_WINNT 0x0602
# endif

#include <windows.h>

int main() {
    return POINTER_CHANGE_FIRSTBUTTON_DOWN; /* required symbol */
}

imacarthur

unread,
Jun 17, 2026, 8:13:44 AMJun 17
to fltk.coredev
On Wednesday, 17 June 2026 at 12:12:11 UTC+1 Gonzalo wrote:

On Windows there's only a single check done:


/* We require Windows 8 or later features for Pen/Tablet support */

# if !defined(WINVER) || (WINVER < 0x0602)
#  ifdef WINVER
#   undef WINVER
#  endif
#  define WINVER 0x0602
# endif
# if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0602)
#  ifdef _WIN32_WINNT
#   undef _WIN32_WINNT
#  endif
#  define _WIN32_WINNT 0x0602
# endif

#include <windows.h>

int main() {
    return POINTER_CHANGE_FIRSTBUTTON_DOWN; /* required symbol */
}


Thanks Gonzalo,

Yeah, I guess that would do it.
The WINVER/_WIN32_WINNT check looks pretty normal (the mingw toolchain is notoriously bad at setting anything useful for WINVER, so that seems sensible. I use basically that stanza all over the code for those builds...)
However, there's no trace of the POINTER_CHANGE_* enum in the (really old) mingw32 headers, whereas later mingw variants (mingw64 et al) do have it.

That said, we don't actually use the  POINTER_CHANGE_* values - I assume they are being used in the check as a surrogate for checking the POINTER_INFO struct etc...

Anyway, I don't think we can realistically fill in all the missing pieces, so I guess that toolchain is a lost cause!

Cheers....

Albrecht Schlosser

unread,
Jun 18, 2026, 3:02:56 AMJun 18
to fltkc...@googlegroups.com
On 6/17/26 14:13 imacarthur wrote:
> we don't actually use the POINTER_CHANGE_* values - I assume they are
> being used in the check as a surrogate for checking the POINTER_INFO
> struct etc...
>
> Anyway, I don't think we can realistically fill in all the missing
> pieces, so I guess that toolchain is a lost cause!

You can disable pen support entirely by using CMake option
"FLTK_OPTION_PEN_SUPPORT - default ON". This *should* disable
compilation of all pen support code. If this doesn't help, then this is
supposedly a bug in our source code.

imacarthur

unread,
Jun 18, 2026, 4:16:41 AMJun 18
to fltk.coredev
On Thursday, 18 June 2026 at 08:02:56 UTC+1 Albrecht wrote:
>
> Anyway, I don't think we can realistically fill in all the missing
> pieces, so I guess that toolchain is a lost cause!

You can disable pen support entirely by using CMake option
"FLTK_OPTION_PEN_SUPPORT - default ON". This *should* disable
compilation of all pen support code. If this doesn't help, then this is
supposedly a bug in our source code.

There's no problem with the FLTK build as such (other than pen support not working.)
It actually builds fine with FLTK_OPTION_PEN_SUPPORT either set or unset - so there's no "bug" as such (other than with the migw32 headers being Too Old, which is not our fault!)

I was poking at this yesterday specifically because I have a number of devices with pen or stylus support, and was planning on doing some tests for a wee project I had in mind.

FWIW, looking back at my notes, it appears I already _knew_ this was broken in the old mingw headers; but it rather seems I had forgotten and "discovered" it all over again!

Albrecht Schlosser

unread,
Jun 20, 2026, 7:51:32 AMJun 20
to fltkc...@googlegroups.com
On 6/18/26 10:16 imacarthur wrote:
On Thursday, 18 June 2026 at 08:02:56 UTC+1 Albrecht wrote:
[Ian wrote]

> Anyway, I don't think we can realistically fill in all the missing
> pieces, so I guess that toolchain is a lost cause!

You can disable pen support entirely by using CMake option
"FLTK_OPTION_PEN_SUPPORT - default ON". This *should* disable
compilation of all pen support code. If this doesn't help, then this is
supposedly a bug in our source code.

There's no problem with the FLTK build as such (other than pen support not working.)
It actually builds fine with FLTK_OPTION_PEN_SUPPORT either set or unset - so there's no "bug" as such (other than with the migw32 headers being Too Old, which is not our fault!)

FWIW, looking back at my notes, it appears I already _knew_ this was broken in the old mingw headers; ...

Yes, I remember that it was your report that made me add the compilation test *and* the CMake option. The former should work OOTB to discover missing pieces, the latter should be a last resort if it doesn't build for any (other)reason on any platform.

None of these mechanisms would help to enable pen/table t support on such old systems as yours though.

It's a pity that the old ("classic") MinGW system is no longer maintained. It looks like you have to use MSYS2/MinGW-w64 to build under Windows with GNU tools nowadays.

While we're at it, do you have any information about the maintenance of the old MinGW toolchain? The last time I checked I could still download the "latest" version (i.e. my old status) with `mingw-get`, but it's probably no longer possible to install the toolchain from scratch. Their website is (was) gone. What do you think, should we remove instructions on building with "classic" MinGW from our docs?

melcher....@googlemail.com

unread,
Jun 20, 2026, 9:11:39 AMJun 20
to fltk.coredev
Sorry for the late reply. I was busy IRL. Yes, I think the previous explanations are right. This is just to add that I fixed a lot of stuff in the Windows driver as of an hour ago.

External testing with a small app would be really helpful, Ian. Feel free to post your findings as an Issue on GitHub, bugs, unexpected behavior, missing features, etc. . I am not a regular tablet/pen user, and my old Wacom PTH-450 does not get any driver support port by Wacom anymore, so I can't test it on my ARM64 machine. 

 - Matthias

imacarthur

unread,
Jun 22, 2026, 6:08:55 AMJun 22
to fltk.coredev
On Saturday, 20 June 2026 at 12:51:32 UTC+1 Albrecht-S wrote:

It's a pity that the old ("classic") MinGW system is no longer maintained. It looks like you have to use MSYS2/MinGW-w64 to build under Windows with GNU tools nowadays.

Yes, it appears so.
And that, it transpires, brings its own issues (more on that in a reply to Matt later...)
 

While we're at it, do you have any information about the maintenance of the old MinGW toolchain? The last time I checked I could still download the "latest" version (i.e. my old status) with `mingw-get`, but it's probably no longer possible to install the toolchain from scratch. Their website is (was) gone. What do you think, should we remove instructions on building with "classic" MinGW from our docs?

It's a shame, because I quite liked the old Mingw32 stuff, but yes, it seems to be "dead" for all practical purposes. We probably should remove it from the docs, or at the very least mark it as being deprecated in some way.

My situation is "odd" in that we have a lot of "old" PCs (many of them 32-bit, hence the ongoing use of 32-bit builds) that are running test sets on isolated, standalone networks. Since these machines cannot be (have never been) connected to the internet, the mingw installation they have is "cloned" from a reference build, rather than downloaded online, so that's quite unlike what most users would do.
 

imacarthur

unread,
Jun 22, 2026, 6:26:23 AMJun 22
to fltk.coredev
On Saturday, 20 June 2026 at 14:11:39 UTC+1 Matt wrote:

External testing with a small app would be really helpful, Ian. Feel free to post your findings as an Issue on GitHub, bugs, unexpected behavior, missing features, etc. . I am not a regular tablet/pen user, and my old Wacom PTH-450 does not get any driver support port by Wacom anymore, so I can't test it on my ARM64 machine. 

I'll give it a whirl, time permitting, but it might not be promptly... (Sorry)

Like you, the tablets I have are older, so somewhat unsupported on my "new" machines.
They tend to be attached to older machines (many of them 32-bit OS versions of Windows, hence the ongoing use of mingw32).

FWIW, I had a poke at the DLLs on one of these, and it looks as if the requisite API are present; the issue is really just that the mingw32 headers do not expose them, rather than any issue with the target PCs per se.

But... here's the tricky bit: I can use the mingw64 tools to build 32-bit Windows code, but it turns out that the version of the mingw64 tools I have implements C++ threads as pthreads, and does this on Windows by wrapping winpthreads.
Now, I'm not using C++ threading at all in my code, but the compiled exe seems to be dragging it in at link time anyway.
My older "standalone" machines don't have any winpthread DLL of course, so then the code won't run. Agh!

There's ostensibly some compile / link time flag (e.g. "-no-pthread" or something, forget the details) that's supposed to help dodge that issue, but it didn't seem to work for me. The other option seems to be to download and static-link a winpthread stub, but I've not tried that yet.

Anyway, the upshot is that I can build a 32-bit Windows version to test, using the mingw64 tooling, but I can't currently run the resulting binary on the machines where I can test it...

(And, FWIW, 64-bit binaries built with that mingw64 tooling are similarly afflicted when subsequently run on Win64 machines that do not have winpthreads - which is most of them,,,)

Albrecht Schlosser

unread,
Jun 22, 2026, 8:45:06 AMJun 22
to fltkc...@googlegroups.com
On 6/22/26 12:26 imacarthur wrote:
[...] here's the tricky bit: I can use the mingw64 tools to build 32-bit Windows code, but it turns out that the version of the mingw64 tools I have implements C++ threads as pthreads, and does this on Windows by wrapping winpthreads.

Same here.


Now, I'm not using C++ threading at all in my code, but the compiled exe seems to be dragging it in at link time anyway.
My older "standalone" machines don't have any winpthread DLL of course, so then the code won't run. Agh!

Workaround #1:
you can find the MinW-w64 winpthread DLL and install it side by side with your executable. This *should* work, but it's only a workaround.


There's ostensibly some compile / link time flag (e.g. "-no-pthread" or something, forget the details) that's supposed to help dodge that issue, but it didn't seem to work for me. The other option seems to be to download and static-link a winpthread stub, but I've not tried that yet.

Neither did I.


Anyway, the upshot is that I can build a 32-bit Windows version to test, using the mingw64 tooling, but I can't currently run the resulting binary on the machines where I can test it...

(And, FWIW, 64-bit binaries built with that mingw64 tooling are similarly afflicted when subsequently run on Win64 machines that do not have winpthreads - which is most of them,,,)

Workaround #2: once I tried to remove (rename) the conflicting DLL linker stubs (winpthread*.dll.a file(s)) - maybe more than one - before linking. Since the DLL stubs can't be found, the code was statically linked in, et voilà, it worked. This is error-prone though, and re-installing the MSYS2/MinGW-w64 stuff restores the *.dll.a files, and you have to repeat what you did before.

Finally, my SOLUTION (off the top of my head, and IIRC): I assume you are using linker flags "-static-libgcc -static-libstdc++" anyway. You can add "-static" after these flags, and it "magically" works to link everything statically, as far as possible. I believe I'm doing it like this in the first CMake execution:

  $ cmake -G "..." -D CMAKE_EXE_LINKER_FLAGS_INIT="-static-libgcc -static-libstdc++ -static" ...

and this seems to do it. Note that I didn't try if "-static" alone works, and I don't know if any of this has any notable side effects (except executable size, of course).

I don't have my Win10 VM running right now, but I think this is mostly correct. I could even execute the binaries on WinXP !

BTW: my plausibility check (except running `ldd` on the binaries) is to open the Windows explorer and double-click on the respective binaries. It's important to ensure that no MinGW directories are in the PATH though, which I avoid like the plague (setting the PATH only in the respective MSYS2/MinGW environment).


I hope this helps, and I'd appreciate all feedback or better proposals. My intention is to add something like this to our docs.


Disclaimer: I can't tell if this would also work for tablet/pen support. You'd likely need to provide one of the Windows DLL's to the target system as well. Maybe.

Albrecht Schlosser

unread,
Jun 22, 2026, 8:53:10 AMJun 22
to fltkc...@googlegroups.com
On 6/22/26 14:45 schrieb 'Albrecht Schlosser' wrote:
Finally, my SOLUTION (off the top of my head, and IIRC): I assume you are using linker flags "-static-libgcc -static-libstdc++" anyway. You can add "-static" after these flags, and it "magically" works to link everything statically, as far as possible. I believe I'm doing it like this in the first CMake execution:

  $ cmake -G "..." -D CMAKE_EXE_LINKER_FLAGS_INIT="-static-libgcc -static-libstdc++ -static" ...

and this seems to do it. Note that I didn't try if "-static" alone works, and I don't know if any of this has any notable side effects (except executable size, of course).

I should add that I didn't find a way to build FLTK DLL's with similar flags. If I set "CMAKE_SHARED_LINKER_FLAGS_INIT=..." I get lots of linker errors (multiply defined symbols or whatever). I gave up, but if anybody can help, that would be appreciated.

And, FWIW, this is not an issue if you use the Visual Studio to build.

imacarthur

unread,
Jun 23, 2026, 11:07:31 AMJun 23
to fltk.coredev
On Monday, 22 June 2026 at 13:53:10 UTC+1 Albrecht-S wrote:
On 6/22/26 14:45 schrieb 'Albrecht Schlosser' wrote:
Finally, my SOLUTION (off the top of my head, and IIRC): I assume you are using linker flags "-static-libgcc -static-libstdc++" anyway. You can add "-static" after these flags, and it "magically" works to link everything statically, as far as possible. I believe I'm doing it like this in the first CMake execution:

  $ cmake -G "..." -D CMAKE_EXE_LINKER_FLAGS_INIT="-static-libgcc -static-libstdc++ -static" ...

and this seems to do it. Note that I didn't try if "-static" alone works, and I don't know if any of this has any notable side effects (except executable size, of course).


Thanks Albrecht - I'll give these various ways a try, see what might work "best" for me right now...

 
I should add that I didn't find a way to build FLTK DLL's with similar flags. If I set "CMAKE_SHARED_LINKER_FLAGS_INIT=..." I get lots of linker errors (multiply defined symbols or whatever). I gave up, but if anybody can help, that would be appreciated.

Yup - fortunately I don't use the DLL all that often, so that's  OK in the short term.
But I will need the DLL for a thing I have coming up, so this maybe get tricky...


And, FWIW, this is not an issue if you use the Visual Studio to build.

Which is fine until I need the DLL build, as I will probably have to a load a few DLL's  that weren't built with VS, and the C++ ABI is "broken".

It's annoying though, since this is all to make the C++ threads work - which I will not be using. 
It'd be handy if there were some way to tell gcc not to incorporate that C++ threads capability - though I tried asking for an "older" C++ level and that did not seem to help.

Albrecht Schlosser

unread,
Jun 23, 2026, 2:29:35 PMJun 23
to fltkc...@googlegroups.com
On 6/23/26 17:07 imacarthur wrote:
On Monday, 22 June 2026 at 13:53:10 UTC+1 Albrecht-S wrote:
On 6/22/26 14:45 schrieb 'Albrecht Schlosser' wrote:
Finally, my SOLUTION (off the top of my head, and IIRC): I assume you are using linker flags "-static-libgcc -static-libstdc++" anyway. You can add "-static" after these flags, and it "magically" works to link everything statically, as far as possible. I believe I'm doing it like this in the first CMake execution:

  $ cmake -G "..." -D CMAKE_EXE_LINKER_FLAGS_INIT="-static-libgcc -static-libstdc++ -static" ...

and this seems to do it. Note that I didn't try if "-static" alone works, and I don't know if any of this has any notable side effects (except executable size, of course).


Thanks Albrecht - I'll give these various ways a try, see what might work "best" for me right now...

Good luck. I'd be glad to read about your results.


I should add that I didn't find a way to build FLTK DLL's with similar flags. If I set "CMAKE_SHARED_LINKER_FLAGS_INIT=..." I get lots of linker errors (multiply defined symbols or whatever). I gave up, but if anybody can help, that would be appreciated.

Yup - fortunately I don't use the DLL all that often, so that's  OK in the short term.

To add a tiny bit: "-static" advises the linker (AFAICT) to link everything that follows statically. Obviously there's a conflict to link a shared library with all static components. If we could link only the winpthread stuff statically then we might perhaps succeed to link the shared lib w/o a reference to the winpthread DLL. Although I believe that this may be possible, I didn't try it because it looked like a frustrating experience. Today we could likely ask a good (?) AI and get it ready in seconds. (?)


But I will need the DLL for a thing I have coming up, so this maybe get tricky...

ISTR that there were different builds of MinGW or even MinGW-w64 that used different versions of threading and exception handling. If there was a build that didn't use MSYS2's winpthread DLL, then this would obviously be the way to go. I tried to use every flavor of MSYS2 I could find and install to build FLTK (these "types" or whatever are IIRC called UCRT64, MSYS2-32-bit, and MSYS2-64-bit) - names are not exact -, but none of them gave me a "native Windows" build that could be ported to other systems w/o MinGW etc.. Unfortunately.


And, FWIW, this is not an issue if you use the Visual Studio to build.

Which is fine until I need the DLL build, as I will probably have to a load a few DLL's  that weren't built with VS, and the C++ ABI is "broken".

That sounds bad.


It's annoying though, since this is all to make the C++ threads work - which I will not be using.
It'd be handy if there were some way to tell gcc not to incorporate that C++ threads capability

Indeed, I agree.


 - though I tried asking for an "older" C++ level and that did not seem to help.

You need C++11 for FLTK 1.5 anyway, and I wouldn't have expected this to help. It's more a linker thing that's buried in the MSYS2 build (and maybe compiler and linker as well).

Hmm, here are a few results from using the "built-in" AI of the `brave` browser (https://search.brave.com).

"1. Use the Win32 Threading Model The most effective method is to switch from the POSIX threading model (which requires libwinpthread) to the native Windows threading model. This is achieved by using the win32 variant of the MinGW-w64 toolchain.
  • Set the C++ compiler to the win32 variant: CXX=/usr/bin/i686-w64-mingw32-g++-win32 (for 32-bit) or the corresponding 64-bit path.

  • Alternatively, in newer MSYS2 environments, ensure you are using the UCRT64 or MINGW64 shell which may default to different threading models, but explicitly using the win32 variant guarantees no POSIX pthread dependency."

I can't confirm the latter because I tried it (see emphasis on "may default", set by me), but I didn't know the former. This looks very similar to cross-compiling, but maybe it's *just that*. I'll give it a try, but not right now. Feel free to do it yourself and to report back what you find.

Method 2 mentions "-static-libgcc -static-libstdc++", but we knew that.

The 3rd method is (similar to) what I also suggested above:

"3. Manual Removal of Import Libraries (Advanced) If the above methods fail (particularly with newer GCC versions in MSYS2 where -static forces all libraries to be static):

  • Locate the MSYS2 installation directory (typically C:\msys64\mingw64\lib).

  • Delete or rename libwinpthread.dll.a and libpthread.dll.a (the import libraries).

  • This forces the linker to fail if it tries to dynamically link libwinpthread, but allows static linking if the static archive libwinpthread.a is available and linked manually via -Bstatic -lwinpthread -Bdynamic. However, using the win32 toolchain variant is the recommended and cleaner approach."


I'm not sure if I posted this earlier somewhere, maybe they found my own advice?  ;-)

Anyway, method 1 is certainly something we could try. It should be easily doable with CMake and looks clean and well supported (obviously used together with "-static-libgcc -static-libstdc++").

I also don't remember if I ever tried "-Bstatic -lwinpthread -Bdynamic"  instead of "-static" in my previous suggestion. Would this help to link the shared FLTK libs (DLL's) ?

If this worked w/o renaming the winpthread import libs this would really be "nice". Let's try!

Albrecht Schlosser

unread,
Jun 24, 2026, 9:20:24 AMJun 24
to fltkc...@googlegroups.com
On 6/23/26 20:29 Albrecht Schlosser wrote:
here are a few results from using the "built-in" AI of the `brave` browser (https://search.brave.com).

"1. Use the Win32 Threading Model The most effective method is to switch from the POSIX threading model (which requires libwinpthread) to the native Windows threading model. This is achieved by using the win32 variant of the MinGW-w64 toolchain.
  • Set the C++ compiler to the win32 variant: CXX=/usr/bin/i686-w64-mingw32-g++-win32 (for 32-bit) or the corresponding 64-bit path.

  • Alternatively, in newer MSYS2 environments, ensure you are using the UCRT64 or MINGW64 shell which may default to different threading models, but explicitly using the win32 variant guarantees no POSIX pthread dependency."

I can't confirm the latter because I tried it (see emphasis on "may default", set by me), but I didn't know the former. This looks very similar to cross-compiling, but maybe it's *just that*. I'll give it a try, but not right now. Feel free to do it yourself and to report back what you find.

Method 2 mentions "-static-libgcc -static-libstdc++", but we knew that.

The 3rd method is (similar to) what I also suggested above:

"3. Manual Removal of Import Libraries (Advanced) If the above methods fail (particularly with newer GCC versions in MSYS2 where -static forces all libraries to be static):

  • Locate the MSYS2 installation directory (typically C:\msys64\mingw64\lib).

  • Delete or rename libwinpthread.dll.a and libpthread.dll.a (the import libraries).

  • This forces the linker to fail if it tries to dynamically link libwinpthread, but allows static linking if the static archive libwinpthread.a is available and linked manually via -Bstatic -lwinpthread -Bdynamic. However, using the win32 toolchain variant is the recommended and cleaner approach."

[...]

I also don't remember if I ever tried "-Bstatic -lwinpthread -Bdynamic"  instead of "-static" in my previous suggestion. Would this help to link the shared FLTK libs (DLL's) ?

If this worked w/o renaming the winpthread import libs this would really be "nice". Let's try!


OK, I tried. Here's my progress report: I had to rename the above mentioned import DLL's, but then I still had some issues, particularly with building FLTK executables linked to the shared FLTK libs. After some more questions to `Brave AI` I found a solution that works for me. Details may be platform specific, but I'm posting it here anyway. YMMV.

Note also that I didn't use method 1 (CXX=/usr/bin/i686-w64-mingw32-g++-win32) because I didn't find that specific compiler version and I didn't know which package I'd have to install. Therefore I tried with my existing system first. I'll try to investigate that option as well (unless you, Ian, or anybody else tries and reports their solution).


Step 0 (optional): Update your MSYS2 installation. Close all but one MSYS2 shell windows, then run `pacman -Syu` multiple times, until it says that there's nothing to do. Keep in mind that you must stop all instances of MSYS2 when instructions say so.

I updated my MSYS2 installation today, hence I'm now working with the latest version. Things may be different if you're using an older version.


Step 1: open an MSYS2 shell if you don't have one open. Note that I used the "MINGW64" flavor, but the "more modern" one would be "UCRT64". I'll try that too. Later, if time permits.
See MSYS2 "Environments": https://www.msys2.org/docs/environments/

Take care that the PATH is clean, i.e. that it doesn't include any unwanted software folders. I strongly recommend not to add any MSYS2 or MinGW installation folders to the system PATH when installing MSYS2.


Step 2: rename lib[win]winpthread import libraries (might not be required with the latest iteration of my attempts). Anyway, on my system it looks like this:
$ find /mingw64 -name '*pthread*.dll.a'
/mingw64/lib/libpthread__RENAMED__.dll.a
/mingw64/lib/libwinpthread__RENAMED__.dll.a

This needs to be done only once, unless you update your MSYS2 installation.
I'm not sure if we need to rename both import libraries.


Step 3: configure CMake with the following linker flags (among others, as usual). The CMake recommendation is to use the _INIT suffix on these variables in the very first CMake run, but I'm omitting this here:

-D CMAKE_EXE_LINKER_FLAGS:STRING=-static-libgcc -static-libstdc++ -l:libwinpthread.a -Wl,--exclude-libs,libgcc_eh.a

-D CMAKE_SHARED_LINKER_FLAGS:STRING=-static-libgcc -static-libstdc++ -l:libwinpthread.a -Wl,--exclude-libs,libwinpthread.a -Wl,--exclude-libs,libgcc_eh.a


The (AI's) recommendation is to use '-l:libwinpthread.a' explicitly to link libwinpthread statically, but ISTR that this worked only after I renamed the DLL import stubs (step 2).

The other flags "-Wl,--exclude-libs,libgcc_eh.a" are necessary to avoid the linker error ".../libgcc_eh.a(unwind-seh.o):...multiple definition of `_Unwind_Resume'". Again, YMMV (you may need to adjust library names or paths).

Note that parts of this are the results of trial and error, educated guessing, and the help of the AI. Cleaning up unneeded parts, i.e. optimizing these instructions, is subject to later investigation.


Step 4: build as usual.

Step 5: verify using `ldd`. This is an excerpt of the output on my system. Note that "no output" on a particular executable means that it uses ONLY existing Windows system libs.
$ ldd bin/*.exe bin/test/*.exe | grep -iv /c/WINDOWS/
bin/fltk-options-cmd.exe:
bin/fltk-options-shared.exe:
        libfltk.dll => /c/git/fltk/master/build/msys2-mingw64/bin/libfltk.dll (0x7ffefc530000)
bin/fltk-options.exe:
bin/fluid-cmd.exe:
bin/fluid-shared.exe:
        libfltk_z.dll => /c/git/fltk/master/build/msys2-mingw64/bin/libfltk_z.dll (0x7fff1cce0000)
        libfltk_images.dll => /c/git/fltk/master/build/msys2-mingw64/bin/libfltk_images.dll (0x7fff0a630000)
        libfltk.dll => /c/git/fltk/master/build/msys2-mingw64/bin/libfltk.dll (0x7ffefc530000)
        libfltk_png.dll => /c/git/fltk/master/build/msys2-mingw64/bin/libfltk_png.dll (0x7fff0c880000)
        libfltk_jpeg.dll => /c/git/fltk/master/build/msys2-mingw64/bin/libfltk_jpeg.dll (0x7ffefe280000)
bin/fluid.exe:
bin/test/CubeView.exe:
...
bin/test/handle_keys.exe:
bin/test/hello-shared.exe:
        libfltk.dll => /c/git/fltk/master/build/msys2-mingw64/bin/test/libfltk.dll (0x7ffefc530000)
bin/test/hello.exe:
bin/test/help_dialog.exe:
...
bin/test/pixmap.exe:
bin/test/pixmap_browser-shared.exe:
        libfltk_images.dll => /c/git/fltk/master/build/msys2-mingw64/bin/test/libfltk_images.dll (0x7fff0a630000)
        libfltk.dll => /c/git/fltk/master/build/msys2-mingw64/bin/test/libfltk.dll (0x7ffefc530000)
        libfltk_png.dll => /c/git/fltk/master/build/msys2-mingw64/bin/test/libfltk_png.dll (0x7fff0c880000)
        libfltk_z.dll => /c/git/fltk/master/build/msys2-mingw64/bin/test/libfltk_z.dll (0x7fff1cce0000)
        libfltk_jpeg.dll => /c/git/fltk/master/build/msys2-mingw64/bin/test/libfltk_jpeg.dll (0x7ffefe280000)
bin/test/pixmap_browser.exe:
bin/test/preferences.exe:
...

Note that there are NO MSYS2 DLL's involved, which is what we wanted to achieve.


Step 6: verify using Windows Explorer:

Start the Windows Explorer, cd to the build/bin or build/bin/test folder(s), and double-click on any executables. All the statically linked executables should work, but the executables linked to the shared FLTK libs (DLL's) may need the FLTK DLL's in the same folder. This is "normal" -- unless you add the build/lib path to the Windows system PATH which is strongly discouraged.

    Step 7: deploy your executables and - optionally - the FLTK
    DLL's to your target machine(s) and test.

Step 8: please report your results, all feedback from all users (not only from Ian) would be appreciated. Thanks in advance.

Enjoy!


Further investigation may show that there are easier solutions (maybe remove some superfluous flags), but this is at least one way to make it work.

imacarthur

unread,
Jun 24, 2026, 9:41:12 AMJun 24
to fltk.coredev
On Wednesday, 24 June 2026 at 14:20:24 UTC+1 Albrecht-S wrote:
 
Step 8: please report your results, all feedback from all users (not only from Ian) would be appreciated. Thanks in advance.

Thanks Albrecht - that all looks great!
I haven't had a chance to do any testing, and might not for a bit - been tied up in "meetings" the last two days, and probably tomorrow (at least) as well... Sorry. 

Albrecht Schlosser

unread,
Jun 24, 2026, 10:07:58 AMJun 24
to fltkc...@googlegroups.com
On 6/24/26 15:41 imacarthur wrote:
On Wednesday, 24 June 2026 at 14:20:24 UTC+1 Albrecht-S wrote:
 
Step 8: please report your results, all feedback from all users (not only from Ian) would be appreciated. Thanks in advance.

Thanks Albrecht - that all looks great!

Welcome.


I haven't had a chance to do any testing, and might not for a bit - been tied up in "meetings" the last two days, and probably tomorrow (at least) as well... Sorry. 

No problem. I'll try to test some more options, and my "working time" for FLTK is also limited, so this may also take some time on my side.

Albrecht Schlosser

unread,
Jun 26, 2026, 8:36:11 AMJun 26
to fltkc...@googlegroups.com
On 6/24/26 16:07 Albrecht Schlosser  wrote:
I'll try to test some more options, and ...

OK, here we go:

1) In my previous attempts I was using the "MINGW64" environment, and I reported that I renamed the import libs for (win)pthread DLL's. Meanwhile I tried if it worked w/o renaming these files, but this didn't work, hence I confirm that it is indeed necessary to get rid of these import libs during build (link) time to make it work:
$ find /mingw64 -name '*pthread*.dll.a'
/mingw64/lib/libpthread__RENAMED__.dll.a
/mingw64/lib/libwinpthread__RENAMED__.dll.a

Take care to restore the files if you ever need them for other projects.

FWIW, in my previous post I missed to add required quotes. Here is the modified (and hopefully correct) version:
cmake .. -G "Ninja" \
 -D CMAKE_EXE_LINKER_FLAGS:STRING='-static-libgcc -static-libstdc++ -l:libwinpthread.a -Wl,--exclude-libs,libgcc_eh.a' \
 -D CMAKE_SHARED_LINKER_FLAGS:STRING='-static-libgcc -static-libstdc++ -l:libwinpthread.a -Wl,--exclude-libs,libwinpthread.a -Wl,--exclude-libs,libgcc_eh.a' \
 [...]

Replace Ninja with the generator of your choice, and add other switches as needed.


2) Now I also tried the "CLANG64" environment, and it turned out that this is much more comfortable. I works OOTB to build "native" Windows executables if you add the well-known switches as noted below:
cmake .. -G "Ninja" \
 -D CMAKE_EXE_LINKER_FLAGS:STRING='-static-libgcc -static-libstdc++' \
 -D CMAKE_SHARED_LINKER_FLAGS:STRING='-static-libgcc -static-libstdc++' \
 [...]

As above, replace Ninja with the generator of your choice, and add other switches as needed.

Note 1: you need to install the clang/clang++ compilers, but this is out of scope here.

Note 2: although these switches are known from GNU compilers/linkers, they are valid for clang as well. Particularly -static-libstdc++ is applied to link the clang specific libc++ statically.


This concludes my investigation. There are other MSYS2 "environments" available (see the link I posted recently), and I tried (some of) them earlier with more or less success. The above mentioned builds produce 64-bit executables which may or may not work on earlier Windows versions. They will definitely not work on 32-bit Windows XP etc., but I'm pretty sure I built 32-bit versions previously as well as a proof of concept (but this may also have been by using the old/classic 32-bit MinGW).


FWIW: I setup my Win10 system with desktop links to start the respective MSYS2 environment, for instance with this commandline:

    C:\msys64\msys2_shell.cmd -clang64

Replace `-clang64` with the environment of your choice.

Enjoy! (Feedback still appreciated)

imm

unread,
Jun 26, 2026, 9:14:26 AMJun 26
to fltkc...@googlegroups.com
Thanks Albrecht.

Some other things that I think "may be true" that I have found whilst
poking at this. I'm posting here in case others stumble across this
and it may prove useful.

If you use the TDM-GCC distro of gcc, it pretty much "just works",
because TDM-GCC is configured to static-link various "internal libs"
that are needed, by default, including libgcc, libstdc++ and
libwinpthreads. Which is convenient.
The downside of this approach is that TDM-GCC seems to be somewhat
unmaintained and hasn't seen much action in the past 5 years or so (as
of mid 2026) so the latest is something like gcc-10.1 or thereabouts.

If the tools offer you a choice of UCRT vs MINGW, the key difference
seems to be the choice of MS C-runtime that is invoked. Recent MS
Windows systems (Win10 onwards, basically) have a "new and improved"
C-runtime called UCRT that is "better", whereas the other options use
the "legacy" MSVCRT.
The downside is that programs built against UCRT probably will not run
on older Windows targets, whereas MSVCRT is (at least in principle)
compatible all the way back to Win98 or so...
So if you are only targeting Win10 or later, choose UCRT, otherwise
you may need to stick with the legacy option.

If the tools offer a choice of exception handling schemes (typically
either SJLJ or SEH) then :
For 32-bit Windows builds, the SJLJ option _seems_ to be the preferred
scheme, though it may not play nice with other code that was built
with MS tooling for 32-bit.
For 64-bit Windows builds, SEH _seems_ to be the preferred scheme,
since it ought to work (more or less) OK with Microsoft's Structured
Exception Handling scheme.
> --
> You received this message because you are subscribed to the Google Groups "fltk.coredev" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to fltkcoredev...@googlegroups.com.
> To view this discussion visit https://groups.google.com/d/msgid/fltkcoredev/d0e7ca99-9333-47ad-ad4f-b9db2d96d5fa%40aljus.de.

Albrecht Schlosser

unread,
Jun 26, 2026, 4:19:25 PMJun 26
to fltkc...@googlegroups.com
Thanks Ian.

I knew of TDM-GCC, but I never tried it. There was even a post in fltk.general in 2017, IIRC.
I also tried the UCRT64 environment of MSYS2 today, which is very similar to what I had found so far.
Having to care about different ways of exception handling is ... annoying. As a user I don't care, and I shouldn't have to. IMHO.

<rant>This reminds me of near and far pointers at times of 16-bit Windows. Or memory "overlays" we had to build on our PDP-11 (RSX-11M) in the 1980's.
</rant>

Today I built (among others) my old ("classic") MinGW 32-bit setup successfully, including shared libs. I copied the EXE's and DLL's to my WinXP VM, and guess what? They all worked, including all shared libs. q.e.d. BTW, the glpuzzle executable, 32-bit, linked against the FLTK DLL's, had a (stripped) size of 78 KB. That's nice!

I'll post more tomorrow if time permits.
Reply all
Reply to author
Forward
0 new messages