MinGW is typically configured to build console applications by default.
So in order to build a normal Windows GUI application, this flag is
needed when linking. Otherwise, a console window will be opened when
the program is run.
Other Windows compilers probably have similar options which can added to
the probe in the future.
--- /dev/null
+dnl Copyright © 2022 Nick Bowler
+dnl
+dnl License WTFPL2: Do What The Fuck You Want To Public License, version 2.
+dnl This is free software: you are free to do what the fuck you want to.
+dnl There is NO WARRANTY, to the extent permitted by law.
+
+dnl DX_W32_GUI
+dnl
+dnl Determine the C linker options needed to build a Windows graphical
+dnl application (i.e., for the "windows" subsystem). The result is saved
+dnl in the cache variable dx_cv_w32_gui_flags.
+dnl
+dnl If no suitable flags could be determined, the cache variable dx_cv_w32_gui
+dnl is set to "unknown" and dx_cv_w32_gui_flags is set to the empty string.
+
+AC_DEFUN([DX_W32_GUI], [AC_REQUIRE([AC_PROG_AWK])dnl
+AC_CACHE_CHECK([for $CC option to target W32 GUI], [dx_cv_w32_gui],
+[_dx_check_pe_subsys () {
+ $AWK -f m4_do([m4_pushdef([m4_include], [$][1])],
+ [m4_include(DX_BASEDIR[/scripts/pe-subsys.awk])],
+ [m4_popdef([m4_include])]) "conftest$EXEEXT"
+}
+dx_cv_w32_gui=unknown _dx_save_LDFLAGS=$LDFLAGS
+for dx_cv_w32_gui_flags in '' -mwindows; do
+LDFLAGS="$_dx_save_LDFLAGS $dx_cv_w32_gui_flags"
+AC_LINK_IFELSE([AC_LANG_PROGRAM],
+[AS_CASE([`_dx_check_pe_subsys`],
+[gui], [dx_cv_w32_gui=${dx_cv_w32_gui_flags:-none needed}; break]
+)])
+done
+test x"$dx_cv_w32_gui" != x"unknown" || dx_cv_w32_gui_flags=
+LDFLAGS=$_dx_save_LDFLAGS])])
--- /dev/null
+#!/bin/awk -f
+#
+# Determine the subsystem of a PE32 executable.
+#
+# Copyright © 2022 Nick Bowler
+#
+# License WTFPL2: Do What The Fuck You Want To Public License, version 2.
+# This is free software: you are free to do what the fuck you want to.
+# There is NO WARRANTY, to the extent permitted by law.
+
+BEGIN {
+ filename = ARGV[1];
+ subsys = "unknown";
+ endian = "unknown";
+
+ if (!filename) {
+ exit(1);
+ }
+ probe_dumper(filename);
+
+ od_read("0");
+ if ($2 == "055115") {
+ endian = "little";
+ } else if ($2 == "046532") {
+ endian = "big";
+ } else {
+ exit(1);
+ }
+
+ od_read("74");
+ val = 65536*od_decode($3) + od_decode($2);
+
+ pe_offset = sprintf("%o", val);
+ pe32_offset = sprintf("%o", val+24);
+ subsys_offset = sprintf("%o", val+24+68);
+
+ od_read(pe_offset);
+ if ($2 != "042520" || $3 != "000000") {
+ # bad PE header
+ exit(1);
+ }
+
+ od_read(pe32_offset);
+ if ($2 != "000413" && $2 != "001013") {
+ # bad PE32(+) header
+ exit(1);
+ }
+
+ od_read(subsys_offset);
+ subsys = od_decode($2);
+ if (subsys == 2)
+ subsys = "gui";
+ else if (subsys == 3)
+ subsys = "console";
+ else
+ subsys = "unknown (" subsys ")";
+
+ exit(0);
+}
+
+END {
+ print subsys
+}
+
+function probe_dumper(filename)
+{
+ (cmd = "od " filename " +10 2>/dev/null") | getline
+ close(cmd)
+
+ sub(/^0*/, "", $1);
+ if ($1 == 10) {
+ dumper_style = "od_traditional";
+ return;
+ }
+
+ (cmd = "od -j010 " filename " 2>/dev/null") | getline
+ close(cmd)
+
+ sub(/^0*/, "", $1);
+ if ($1 == 10) {
+ dumper_style = "od_posix";
+ return;
+ }
+
+ exit(1);
+}
+
+function od_read(offset, cmd)
+{
+ if (dumper_style == "od_traditional") {
+ cmd = "od " filename " +" offset;
+ } else if (dumper_style == "od_posix") {
+ cmd = "od -j0" offset " " filename;
+ }
+
+ cmd | getline
+ close(cmd);
+
+ if (endian == "big") {
+ $2 = od_bswap($2);
+ $3 = od_bswap($3);
+ }
+}
+
+# Byte-swap one of the 2-byte blocks of octal digits emitted by od.
+function od_bswap(word, i, digits, carry)
+{
+ for (i = 0; i < 6; i++) {
+ digits[i] = substr(word, i+1, 1);
+ }
+
+ # suss out the first byte by adjusting the first 4 digits left by 1 bit
+ if (carry = (digits[3] >= 4))
+ digits[3] -= 4;
+
+ for (i = 2; i >= 0; i--) {
+ if (carry = ( (digits[i] = digits[i]*2 + carry) >= 8 ))
+ digits[i] -= 8;
+ }
+
+ # now munge the second byte by adjusting the last 3 digits right 1 bit
+ carry = 0;
+ for (i = 3; i < 6; i++) {
+ carry = (digits[i] += 8*carry) % 2;
+ digits[i] = int(digits[i] / 2);
+ }
+
+ # and put the leftover bit in place
+ digits[0] += 4*carry;
+
+ return digits[3] digits[4] digits[5] digits[0] digits[1] digits[2];
+}
+
+# Parse a string of octal digits into a number.
+function od_decode(word, result)
+{
+ result = 0;
+
+ while (word) {
+ result = 8*result + substr(word, 1, 1);
+ word = substr(word, 2);
+ }
+
+ return result;
+}
--- /dev/null
+#!/bin/sh
+#
+# Copyright © 2022 Nick Bowler
+#
+# Fake C compiler for testing PE subsystem probes.
+#
+# License WTFPL2: Do What The Fuck You Want To Public License, version 2.
+# This is free software: you are free to do what the fuck you want to.
+# There is NO WARRANTY, to the extent permitted by law.
+
+mode=link
+outfile=
+infile=
+
+: "${TEST_SUBSYS=3}"
+: "${TEST_GUI_FLAG=-mwindows}"
+
+for arg; do
+ shift
+
+ case $arg in
+ -o) outfile=$1; ;;
+ -c) mode=compile ;;
+ *.c) infile=$arg ;;
+ $TEST_GUI_FLAG) TEST_SUBSYS=2 ;;
+ esac
+done
+
+test x"$infile" != x || exit
+filebase=`expr "$infile" : '\(.*\).c$'`
+
+case $mode in
+link)
+ : "${outfile:=a.exe}"
+ ;;
+compile)
+ : "${outfile:=$filebase.obj}"
+ ;;
+esac
+
+:; {
+ printf '%-60s' MZ
+ printf '\101\1\0\0%257s' ''
+ printf 'PE\0\0%20s' ''
+ printf '\13\1%66s' ''
+ printf "\\$TEST_SUBSYS\\0"
+} >"$outfile"
AT_CHECK([$SHELL exported.sh nonexistent], [1], [], [ignore])
AT_CLEANUP
+
+AT_SETUP([DX_W32_GUI])
+
+AT_DATA([test.in], [[@dx_cv_w32_gui@
+@dx_cv_w32_gui_flags@
+]])
+
+TEST_CONFIGURE_AC([[DX_W32_GUI
+AC_SUBST([dx_cv_w32_gui])
+AC_SUBST([dx_cv_w32_gui_flags])
+AC_CONFIG_FILES([test])
+]])
+TEST_AUTORECONF
+
+myconf="cross_compiling=yes --host=none CC=$srcdir/t/ccw32.sh"
+
+TEST_CONFIGURE([TEST_SUBSYS=2 TEST_GUI_FLAG=-mwindows $myconf])
+AT_CHECK([cat test], [0], [none needed
+
+])
+
+TEST_CONFIGURE([TEST_SUBSYS=3 TEST_GUI_FLAG=-mwindows $myconf])
+AT_CHECK([cat test], [0], [-mwindows
+-mwindows
+])
+
+TEST_CONFIGURE([TEST_SUBSYS=4 TEST_GUI_FLAG=xxx $myconf])
+AT_CHECK([cat test], [0], [unknown
+
+])
+
+AT_CLEANUP
+
+AT_SETUP([DX_W32_GUI distribution])
+AT_KEYWORDS([DX_W32_GUI macro])
+
+TEST_CONFIGURE_AC([[AM_INIT_AUTOMAKE([foreign])
+DX_W32_GUI
+AC_CONFIG_FILES([Makefile])
+]])
+
+AT_DATA([Makefile.am],
+[[foo: ; printf '%s\n' $(DX_BASEDIR) $(DISTFILES)
+]])
+TEST_AUTORECONF
+
+TEST_CONFIGURE
+AT_CHECK([make -s foo], [0], [stdout])
+AT_CHECK([exec 3<stdout
+read basedir <&3; while read f <&3; do
+ test x"$f" = x"$basedir/scripts/pe-subsys.awk" && exit
+done
+exit 1])
+
+AT_CLEANUP