If CTRL-C terminates the alias but the child ignores CTRL-C, the parent
of the alias (shell, make, etc.) will be led to beleive the real command
terminated despite continuing to run. Because a null CTRL-C handler is
inherited, the alias sets a real handler that ignores all CTRL events,
relying on the child to make a decision. To minimize the window between
starting to ignore CTRL-C and spawning the child, SetConsoleCtrlHandler
is called as late as possible.
The busybox-w32 alias binaries need not be unique. The command line
string contains all the necessary information, and busybox-w32 already
interprets that information properly. So just forward the command line
string to busybox.exe.
I also gave alias.c another tidying pass following my personal Windows
systems programming style. I'm sufficiently confident in this approach
that I feel it no longer requires apologetics. It speaks for itself. It
also now releases its "heap" before waiting on the target process.
While I'm at it, I also added a c89 command which is as "standard" as
the already-existing c99 command.
ConEmu injects a thread (ConEmuCD.dll) and injects a DLL that starts
threads (ConEmuHk.dll). These threads may linger after the main thread
has returned, delaying the process exit and even interfering with the
exit status. As a work around, call ExitProcess instead of returning
from the main thread. This terminates extra threads so that the process
will no longer wait for their voluntarily exit.
I've gotten a lot better at CRT-free since I first wrote this. I'm more
confident about this version, it produces better error messages, and it
compiles around 10x faster. The last point matters because w64devkit
currently compiles this program 181 times.
In the future I plan to call these "CRT-free" rather than "freestanding"
since it is more accurate. This approach has been trial-and-error due to
its unusual nature, the lack of convention, non-existing documentation,
and poor implicit defaults in the GNU toolchain. After spending time
navigating the problem space and discovering its pitfalls, I understand
much better how to construct these binaries. The changes at a high level
and their reasoning:
Avoid -ffreestanding since this is not really its purpose. It may still
be necessary to use -fno-builtin to prevent certain CRT calls.
Replace -fno-ident with -Wl,--gc-sections. It accomplishes the same and
much more. Even better, it is only needed at link time.
Do not qualify mainCRTStartup with WINAPI. By default, the GNU linker
looks for this symbol as the entry point. Not finding one, it silently
chooses the beginning of the .text section as the entry point. Marked
WINAPI, it gets __stdcall-decorated on i686 and is no longer recognized
by the linker. In the past I have been lucky that "main" happened to be
the first function in .text, so this worked out. This is incompatible
with the MSVC toolchain (an oversight in MinGW / Mingw-w64) since it is
explicitly documented that the entry point uses __stdcall. Since there
are no arguments, __stdcall and __cdecl happen to be identical, which is
why nobody notices.
Alternatively I could use -Wl,--entry= to choose an entry point, which
at least produces a warning when the symbol is not found. However, this
accepts the decorated symbol name, and so the exact invocation depends
on the target: i686 or x86-64. Rather inconvenient. The implicit search
for mainCRTStartup resolves this automatically, except when __stdcall is
involved, per above.
If using more than two pages of local variables in any function, you
must disable the stack probe with -mno-stack-arg-probe because the probe
is provided by the CRT. Normally the stack grows with use, and the probe
handles large stack frames that may jump the guard page. Instead commit
a larger stack at startup: "-Xlinker --stack=Z,Z" where Z is the desired
size, e.g. use 0x100000 to commit a 1MiB stack.
This program is compiled many times, and 99% of the build time is GCC
parsing windows.h repeatedly. This macro trims the header and cuts the
build time almost in half, which will improve the overall w64devkit
build time.
Neither are needed and they each add kB of weight to executables due to
alignment requirements. Most of it compresses away, but excluding them
still shrinks the overall w64devkit .zip by a few kB.