Add `.exe` extension to cmdliner tool on Windows
This fixes new build failures reported in #233:
cmdliner.2.0.0:
ocaml build.ml cma
ocaml build.ml cmxa
ocaml build.ml natexe
_build/src/tool/cmdliner generic-completion bash > _build/src/tool/bash-completion.sh
_build/src/tool/cmdliner tool-completion bash cmdliner > _build/src/tool/bash-cmdliner.sh
_build/src/tool/cmdliner generic-completion zsh > _build/src/tool/zsh-completion.sh
_build/src/tool/cmdliner tool-completion zsh cmdliner > _build/src/tool/zsh-cmdliner.sh
_build/src/tool/cmdliner install tool-manpages _build/src/tool/cmdliner _build/src/tool/man
'"_build\src\tool\cmdliner"' is not recognized as an internal or external command,
operable program or batch file.
""_build\src\tool\cmdliner" "--__complete" "--__complete=" > "C:\Users\misterda\AppData\Local\opam\.cygwin\root\tmp\cmd9740adstdout"": exited with 1
make: *** [Makefile:80: build-man] Error 123
cmdliner.2.1.0:
ocaml build.ml cma
ocaml build.ml cmxa
ocaml build.ml natexe
_build/src/tool/cmdliner generic-completion bash > _build/src/tool/bash-completion.sh
_build/src/tool/cmdliner tool-completion bash cmdliner > _build/src/tool/bash-cmdliner.sh
_build/src/tool/cmdliner generic-completion zsh > _build/src/tool/zsh-completion.sh
_build/src/tool/cmdliner tool-completion zsh cmdliner > _build/src/tool/zsh-cmdliner.sh
_build/src/tool/cmdliner generic-completion pwsh > _build/src/tool/pwsh-completion.ps1
_build/src/tool/cmdliner tool-completion pwsh cmdliner > _build/src/tool/pwsh-cmdliner.ps1
_build/src/tool/cmdliner install tool-manpages _build/src/tool/cmdliner _build/src/tool/man
'"_build\src\tool\cmdliner"' is not recognized as an internal or external command,
operable program or batch file.
""_build\src\tool\cmdliner" "--__complete" "--__complete=" > "C:\Users\misterda\AppData\Local\opam\.cygwin\root\tmp\cmd735a8astdout"": exited with 1
make: *** [Makefile:83: build-man] Error 123
I would enjoy a patch release with this fix.
Do you understand why the extension matters?
The cmd uses the registry to associate loaders with file types. See assoc and ftype.
> assoc .exe
.exe=exefile
> ftype exefile
exefile="%1" %*
There's also the PATHEXT environment variable that comes into play.
PATHEXTis used to start a program, batch file or script without explicitly specifying its suffix incmd.exeor itsstartcommand.
.com;.exe;.bat;.cmd;.vbs;.vbe;.js;.jse;.wsf;.wsh;.msc
So if the file ends in .exe and PATHEXT contains .exe then the executable can be started in cmd without specifying the extension, but the real filename still need to have it, otherwise the cmd doesn't know it's an executable.
It's a bit vague…
@MisterDA just to rule out something in your environment, can you try reproducing by calling the command in question directly from cmd.exe ? (ie execute cmd.exe /C ""_build\src\tool\cmdliner ...."" in cmd.exe)
@MisterDA just to rule out something in your environment, can you try reproducing by calling the command in question directly from
cmd.exe? (ie executecmd.exe /C ""_build\src\tool\cmdliner ....""incmd.exe)
Same error. I do have clink 1.9.2 installed on my cmd.
The error seems to be repeatable on any executable, though:
> cat main.c
#include <stdio.h>
int main(void) {
printf("Hello, world!\n");
return 0;
}
> cl -nologo -W4 -O2 main.c
main.c
> .\main.exe
Hello, world!
> mv .\main.exe .\main
> .\main
'.\main' is not recognized as an internal or external command,
operable program or batch file.
Do you get the error with all commands? eg cmd.exe /C ""foo\bar"" where foo/bar.exe exists?
Do you get the error with all commands? eg
cmd.exe /C ""foo\bar""wherefoo/bar.exeexists?
If test\main.exe exists, calling it both with and without .exe succeeds, because .exe is in PATHEXT.
> cmd.exe /C ""test\main.exe""
Hello, world!
> cmd.exe /C ""test\main""
Hello, world!
because
.exeis inPATHEXT.
Sorry, but is it the case that the executable _build\src\tool\cmdliner does not have the .exe extension on disk?
(Sorry for all the questions, but I cannot test locally right now.)
Sorry, but is it the case that the executable
_build\src\tool\cmdlinerdoes not have the .exe extension on disk?
Yes! and my patch adds the .exe.
> git checkout v2.1.0
HEAD is now at dbd9b51 Restore OCaml 4.08 compatibility
> git clean -fdX
Removing _build/
> opam switch system-msvc
> C:\Users\misterda\AppData\Local\opam\.cygwin\root\bin\make.exe all -j1
ocaml build.ml cma
ocaml build.ml cmxa
ocaml build.ml natexe
_build/src/tool/cmdliner generic-completion bash > _build/src/tool/bash-completion.sh
_build/src/tool/cmdliner tool-completion bash cmdliner > _build/src/tool/bash-cmdliner.sh
_build/src/tool/cmdliner generic-completion zsh > _build/src/tool/zsh-completion.sh
_build/src/tool/cmdliner tool-completion zsh cmdliner > _build/src/tool/zsh-cmdliner.sh
_build/src/tool/cmdliner generic-completion pwsh > _build/src/tool/pwsh-completion.ps1
_build/src/tool/cmdliner tool-completion pwsh cmdliner > _build/src/tool/pwsh-cmdliner.ps1
_build/src/tool/cmdliner install tool-manpages _build/src/tool/cmdliner _build/src/tool/man
'"_build\src\tool\cmdliner"' is not recognized as an internal or external command,
operable program or batch file.
""_build\src\tool\cmdliner" "--__complete" "--__complete=" > "C:\Users\misterda\AppData\Local\Temp\cmd344836stdout"": exited with 1
make: *** [Makefile:83: build-man] Error 123
> dir _build\src\tool\
Volume in drive C has no label.
Volume Serial Number is 669D-C810
Directory of C:\Users\misterda\Tarides\cmdliner\_build\src\tool
11/27/2025 09:19 AM <DIR> .
11/27/2025 09:19 AM <DIR> ..
11/27/2025 09:19 AM 133 bash-cmdliner.sh
11/27/2025 09:19 AM 2,774 bash-completion.sh
11/27/2025 09:19 AM 1,924,096 cmdliner
11/27/2025 09:19 AM 835 cmdliner_data.cmi
11/27/2025 09:19 AM 35,077 cmdliner_data.cmt
11/27/2025 09:19 AM 24,564 cmdliner_data.cmx
11/27/2025 09:19 AM 11,227 cmdliner_data.ml
11/27/2025 09:19 AM 28,546 cmdliner_data.obj
11/27/2025 09:19 AM 12,121 cmdliner_main.cmi
11/27/2025 09:19 AM 301,683 cmdliner_main.cmt
11/27/2025 09:19 AM 4,427 cmdliner_main.cmx
11/27/2025 09:19 AM 26,333 cmdliner_main.ml
11/27/2025 09:19 AM 114,333 cmdliner_main.obj
11/27/2025 09:19 AM 96 pwsh-cmdliner.ps1
11/27/2025 09:19 AM 5,547 pwsh-completion.ps1
11/27/2025 09:19 AM 63 zsh-cmdliner.sh
11/27/2025 09:19 AM 2,748 zsh-completion.sh
17 File(s) 2,494,603 bytes
2 Dir(s) 10,358,571,008 bytes free
> mklink _build\src\tool\cmdliner.exe cmdliner
symbolic link created for _build\src\tool\cmdliner.exe <<===>> cmdliner
> C:\Users\misterda\AppData\Local\opam\.cygwin\root\bin\make.exe all -j1
ocaml build.ml cma
ocaml build.ml cmxa
ocaml build.ml natexe
_build/src/tool/cmdliner generic-completion bash > _build/src/tool/bash-completion.sh
_build/src/tool/cmdliner tool-completion bash cmdliner > _build/src/tool/bash-cmdliner.sh
_build/src/tool/cmdliner generic-completion zsh > _build/src/tool/zsh-completion.sh
_build/src/tool/cmdliner tool-completion zsh cmdliner > _build/src/tool/zsh-cmdliner.sh
_build/src/tool/cmdliner generic-completion pwsh > _build/src/tool/pwsh-completion.ps1
_build/src/tool/cmdliner tool-completion pwsh cmdliner > _build/src/tool/pwsh-cmdliner.ps1
_build/src/tool/cmdliner install tool-manpages _build/src/tool/cmdliner _build/src/tool/man
Writing _build/src/tool/man\man1\cmdliner.1
Writing _build/src/tool/man\man1\cmdliner-generic-completion.1
Writing _build/src/tool/man\man1\cmdliner-install.1
Writing _build/src/tool/man\man1\cmdliner-install-generic-completion.1
Writing _build/src/tool/man\man1\cmdliner-install-tool-completion.1
Writing _build/src/tool/man\man1\cmdliner-install-tool-manpages.1
Writing _build/src/tool/man\man1\cmdliner-install-tool-support.1
Writing _build/src/tool/man\man1\cmdliner-tool-commands.1
Writing _build/src/tool/man\man1\cmdliner-tool-completion.1
ocaml build.ml cmxs
but I confirm that this only happens with a system-msvc switch and not with a system-mingw switch. With mingw, _build/src/tool/cmdliner.exe gets the .exe extension!
With mingw,
_build/src/tool/cmdliner.exegets the.exeextension!
Just to make sure I understand: this means that the executable on disk has the .exe extension, or that Sys.command manages to execute the executable despite it not having the .exe extension?
With system-mingw the executable on disk has the .exe extension, with system-msvc the executable on disk doesn't have the extension.
With
system-mingwthe executable on disk has the.exeextension, withsystem-msvcthe executable on disk doesn't have the extension.
I see. This is because gcc (from mingw-w64) automatically adds this extension, but cl does not. The fix is to always add the extension in the build system (when under Windows):
https://github.com/dbuenzli/cmdliner/blob/dbd9b51cb6dd4af6de11229f68a36cf455ae301e/build.ml#L145-L149
This is because
gcc(frommingw-w64) automatically adds this extension, butcldoes not. The fix is to always add the extension in the build system (when under Windows):
I take that as an approval for this patch ;)
This is because
gcc(frommingw-w64) automatically adds this extension, butcldoes not. The fix is to always add the extension in the build system (when under Windows):I take that as an approval for this patch ;)
Indeed! (Sorry, I hadn't looked at the patch :))