Using bash Overrides Microsoft LINK.EXE With /usr/bin/link
Closed this issue · 3 comments
This action appears to work as advertised for CL.EXE and NMAKE.EXE, great!
But I hit a snag when trying to call LINK, and got a message extra operand '/subsystem:console
which I did not get when running the same command in a "Developer Command Prompt"
It seems that path-wise, there's a non-MS /usr/bin/link file that out-prioritizes the MS LINK.EXE that is added to the path. To prove this is the case, I tried just deleting it:
- name: Delete Unwanted Link to Stop It From Interfering
run: rm /usr/bin/link.exe
Once I did this, the correct link was found and worked. Ugly workaround, though. :-/
Is it within the scope of this GitHub Action's mission to try and sort out such an issue? Even if there was just a setting like need-ms-link: true
that renamed the other linker out of the way, it seems it would help document the issue in a central place for when a better answer came along.
Oh hello! Thanks for you the interest, I'm constantly surprised how many people actually use this thing...
Is it within the scope of this GitHub Action's mission to try and sort out such an issue?
It depends.
Removing specific files is probably not in scope of “setting up MSVC development environment”. It's not like there an exhaustive list of binaries that must be available in PATH and must point to MSVC's stuff after this tool is run. So I'd rather not hardcode LINK.EXE specifically.
Say, what if someone sets up their env to have CL.EXE mean "Common Lisp" and they would like to use MSVC but for compiling C# code or whatever, nor caring for the C compiler. They wouldn't be amused if CL.EXE was removed so we probably shouldn't do that. But now, why LINK.EXE should be removed but CL.EXE shouldn't? That's why I'm not a fan of tweaking the env like that. If your environment contains /usr/bin
which conflicts with what MSVC wants to use, then please set up your environment so that it does not happen.
Now, there's another thing about why msvc-dev-cmd
does not override /usr/bin
. I have assumed that this happens because it appends MSVC's directories to PATH. So if /usr/bin
was already there then it will be preferred. If that was the case, it could have been a reasonable feature to have a flag, say, prepend-env: true
which would make msvc-dev-cmd
prepend its stuff into the env, not append it.
However, after running some experiments I see that msvc-dev-cmd
does both.
What new paths are added and where
These paths are prepended to existing Path
value and should be preferred:
C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\\Extensions\Microsoft\IntelliCode\CLI
C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\MSVC\14.28.29333\bin\HostX64\x64
C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\VC\VCPackages
C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\CommonExtensions\Microsoft\TestWindow
C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer
C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\MSBuild\Current\bin\Roslyn
C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Team Tools\Performance Tools\x64
C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Team Tools\Performance Tools
C:\Program Files (x86)\Microsoft Visual Studio\Shared\Common\VSPerfCollectionTools\vs2019\\x64
C:\Program Files (x86)\Microsoft Visual Studio\Shared\Common\VSPerfCollectionTools\vs2019\
C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.8 Tools\x64\
C:\Program Files (x86)\HTML Help Workshop
C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\CommonExtensions\Microsoft\FSharp\
C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\x64
C:\Program Files (x86)\Windows Kits\10\bin\x64
C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\\MSBuild\Current\Bin
C:\windows\Microsoft.NET\Framework64\v4.0.30319
C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\
C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\Tools\
These paths are appended to Path
value and will be used, unless original Path
has an override:
C:\Program Files (x86)\Microsoft Visual Studio\Installer
C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Tools\Llvm\x64\bin
C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin
C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\CommonExtensions\Microsoft\CMake\Ninja
C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\IDE\VC\Linux\bin\ConnectionManagerExe
So I'd guess that if /usr/bin
were in the PATH before msvc-dev-cmd
is run then it should have been shadowed by newly added paths. If it's not, this probably means that /usr/bin
is prepended to the path after msvc-dev-cmd
is run. If that's the case, nothing we can do about it here.
Could you please clarify which /usr/bin
causes path conflicts for you and how exactly it gets into PATH?
P.S. Wow, that's a fancy username and userpic you've got there 😂 Got me scared a bit.
Could you please clarify which /usr/bin causes path conflicts for you and how exactly it gets into PATH?
I figured out that the problem came from the fact that I'm using shell: bash on Windows. (It's a logical choice when trying to maintain a scripts on lots of platforms to have the uniformity.)
/usr/bin/link is actually not a linker at all (like ld
) but a tool for creating a symlink (like ln
).
https://www.gnu.org/software/coreutils/manual/coreutils.html#link-invocation
Removing specific files is probably not in scope of “setting up MSVC development environment”.
Maybe the step could have outputs which tell you where files are as a last resort?
- name: Enable MSVC Dev Commands
id: msvc-dev-cmd
uses: ilammy/msvc-dev-cmd@v1
- name: Set Detected LINK and CL Environment Variables
run: |
echo "LINK=${{ steps.msvc-dev-cmd.outputs.link }}" >> $GITHUB_ENV
echo "CL=${{ steps.msvc-dev-cmd.outputs.cl }}" >> $GITHUB_ENV
If those can be assumed to be accessible from a common directory with more tools in it then maybe giving back that directory is the more general thing...
I'm constantly surprised how many people actually use this thing...
Thanks for the prompt response...and if you keep maintaining small things and become the go-to person for that thing, it can take on a life of its own over time. Maybe there are enough people that I'm not the last person to try and use bash with it!
Perhaps just checking to see what the shell is and printing out a warning if it's not Powershell or CMD would be helpful. Or a section in the README.md on the general topic of path conflicts--this being an example--and what people might do about it.
that's a fancy username and userpic you've got there 😂 Got me scared a bit.
Programming is serious business. 🍴
Uh-huh... So MSVC paths are added to the environment, but then any task that uses shell: bash
will have GNU environment set up for it. As it appears, it prepends /mingw64/bin
, /usr/bin
, and /c/Users/runneradmin/bin
to PATH. This basically ensures that unqualified link
will resolve into /usr/bin/link
. Regardless of if you call MSVC action before or after that. I wonder if there is a nice workaround for that.
Maybe the step could have outputs which tell you where files are as a last resort?
I believe an appropriate action here depends on how this output is meant to be used to work around the issue with GNU link conflicting with MSVC's link. Which only surfaces if you actually use MSVC toolchain from within bash, which is probably the case for people using this action if they are running bash.
One thing that would be "easy" to do is to return all the 'interesting' variables like PATH which the actions sets. Then it it's to users to... uh... prepend that to their PATH again?..
If we do return absolute paths resolved immediately after setting MSVC variables, what are the users supposed to do with them? Somehow persuade their build system to use this absolute path for link
instead of just link
?..
IDK. All of it seems to be awful and as a user I'd prefer everything to "just work" 🤪
I got this problem into my subconscious, maybe a solution will present itself. I'll also go review the docs for action developers, maybe there's some neat hack available there to work around issues like this. GITHUB_PATH
does not look like it, since shell: bash
adds its stuff on top of GITHUB_PATH
still.
Perhaps just checking to see what the shell is and printing out a warning if it's not Powershell or CMD would be helpful.
I guess this could catch the case when bash is set as the default shell for the entire job. (No idea how to access that, but I guess it's possible). But this action definitely wouldn't see the case if you leave the default shell for most actions, but then set shell: bash
only for some – which then may have their link
resolve into something unexpected.
A warning (from the action) in that might be appropriate. But there should be a way to disable it to not be annoying. And it's not really nice to bash people with warnings just because they are using bash by default.
A section in README would be nice, I'll add that regardless of any other thing. Hopefully, it will help people avoid this pitfall. There's at least link
which can have conflicts, maybe there's more.