@@ -224,6 +224,80 @@ export class JustLspInstaller {
224224 }
225225 }
226226
227+ /**
228+ * Check if the correct linker is first in PATH on Windows
229+ * Returns information about potential PATH issues
230+ */
231+ private async checkWindowsLinker ( ) : Promise < { isCorrect : boolean , message : string , linkPath ?: string } > {
232+ if ( process . platform !== 'win32' ) {
233+ return { isCorrect : true , message : 'Not Windows' } ;
234+ }
235+
236+ try {
237+ // Use where.exe to find all link.exe in PATH
238+ const { stdout } = await asyncExec ( 'where.exe link.exe' ) ;
239+ const linkPaths = stdout . trim ( ) . split ( '\n' ) . map ( p => p . trim ( ) ) . filter ( p => p ) ;
240+
241+ if ( linkPaths . length === 0 ) {
242+ return {
243+ isCorrect : false ,
244+ message : 'No link.exe found in PATH. Visual Studio Build Tools may not be installed.'
245+ } ;
246+ }
247+
248+ const firstLink = linkPaths [ 0 ] . toLowerCase ( ) ;
249+ logger . info ( `First link.exe in PATH: ${ firstLink } ` , 'JustLspInstaller' ) ;
250+
251+ // Check if the first link.exe is from a Unix-like environment
252+ const unixToolPaths = [
253+ '\\git\\' ,
254+ '\\msys' ,
255+ '\\cygwin' ,
256+ '\\mingw' ,
257+ '\\usr\\bin' ,
258+ ] ;
259+
260+ const isUnixLink = unixToolPaths . some ( unixPath => firstLink . includes ( unixPath . toLowerCase ( ) ) ) ;
261+
262+ if ( isUnixLink ) {
263+ return {
264+ isCorrect : false ,
265+ message : `Found Unix 'link' command before MSVC linker in PATH: ${ firstLink } ` ,
266+ linkPath : firstLink
267+ } ;
268+ }
269+
270+ // Check if it's the MSVC linker
271+ const isMsvcLink = firstLink . includes ( 'microsoft visual studio' ) ||
272+ firstLink . includes ( '\\vc\\tools\\' ) ||
273+ firstLink . includes ( '\\msvc\\' ) ;
274+
275+ if ( isMsvcLink ) {
276+ logger . info ( 'Correct MSVC linker found first in PATH' , 'JustLspInstaller' ) ;
277+ return {
278+ isCorrect : true ,
279+ message : 'MSVC linker correctly positioned in PATH' ,
280+ linkPath : firstLink
281+ } ;
282+ }
283+
284+ // Unknown link.exe - could be problematic
285+ return {
286+ isCorrect : false ,
287+ message : `Unknown link.exe found first in PATH: ${ firstLink } . Expected MSVC linker.` ,
288+ linkPath : firstLink
289+ } ;
290+
291+ } catch ( error ) {
292+ // where.exe failed - likely no link.exe in PATH
293+ logger . warning ( 'Failed to check for link.exe in PATH' , 'JustLspInstaller' ) ;
294+ return {
295+ isCorrect : false ,
296+ message : 'Could not find link.exe in PATH. Visual Studio Build Tools may not be installed or not in PATH.'
297+ } ;
298+ }
299+ }
300+
227301 private async installFromLocalBuild ( progress : vscode . Progress < { message ?: string } > ) : Promise < InstallationResult > {
228302 progress . report ( { message : 'Building from local source...' } ) ;
229303
@@ -345,6 +419,35 @@ export class JustLspInstaller {
345419 const { stdout : cargoVersion } = await asyncExec ( cargoCheckCmd ) ;
346420 logger . info ( `Found cargo: ${ cargoVersion . trim ( ) } ` , 'JustLspInstaller' ) ;
347421
422+ // On Windows, proactively check for the wrong linker issue
423+ if ( process . platform === 'win32' ) {
424+ const linkerCheck = await this . checkWindowsLinker ( ) ;
425+ if ( ! linkerCheck . isCorrect ) {
426+ logger . warning ( 'Wrong linker detected in PATH' , 'JustLspInstaller' ) ;
427+
428+ const choice = await vscode . window . showWarningMessage (
429+ `Potential PATH issue detected: ${ linkerCheck . message } \n\nThis will likely cause cargo install to fail. Would you like to see instructions to fix this first?` ,
430+ 'Show Fix Instructions' ,
431+ 'Try Anyway' ,
432+ 'Cancel'
433+ ) ;
434+
435+ if ( choice === 'Show Fix Instructions' ) {
436+ this . showWrongLinkerInstructions ( ) ;
437+ return {
438+ success : false ,
439+ error : 'Installation cancelled - user chose to fix PATH issue first'
440+ } ;
441+ } else if ( choice === 'Cancel' ) {
442+ return {
443+ success : false ,
444+ error : 'Installation cancelled by user'
445+ } ;
446+ }
447+ // If "Try Anyway", continue with installation
448+ }
449+ }
450+
348451 // Install just-lsp (this will install the original just-lsp from crates.io)
349452 progress . report ( { message : 'Running cargo install just-lsp (this may take several minutes)...' } ) ;
350453 logger . info ( 'Running cargo install just-lsp...' , 'JustLspInstaller' ) ;
@@ -386,7 +489,71 @@ export class JustLspInstaller {
386489 const errorMsg = error instanceof Error ? error . message : String ( error ) ;
387490 logger . errorFromException ( error , 'Cargo installation failed' , 'JustLspInstaller' ) ;
388491
389- // Check if this is a linker error indicating missing Visual Studio Build Tools
492+ // Check if this is the "wrong link.exe" problem (GNU coreutils link instead of MSVC linker)
493+ if ( errorMsg . includes ( 'link.exe' ) && errorMsg . includes ( 'extra operand' ) ) {
494+ if ( process . platform === 'win32' ) {
495+ const message = `Rust compilation failed: The wrong 'link.exe' is being used.
496+
497+ This happens when Unix tools (Git for Windows, MSYS2, etc.) are in your PATH before the MSVC linker.
498+
499+ To fix this:
500+ 1. Install Visual Studio Build Tools with C++ support
501+ 2. Ensure the MSVC linker is found before Unix tools in your PATH
502+
503+ Would you like to see detailed instructions?` ;
504+
505+ const choice = await vscode . window . showErrorMessage (
506+ message ,
507+ 'Show Instructions' ,
508+ 'Try Installing Build Tools' ,
509+ 'Cancel'
510+ ) ;
511+
512+ if ( choice === 'Show Instructions' ) {
513+ this . showWrongLinkerInstructions ( ) ;
514+ } else if ( choice === 'Try Installing Build Tools' ) {
515+ try {
516+ progress . report ( { message : 'Installing Visual Studio Build Tools...' } ) ;
517+ await asyncExec ( 'winget install --id Microsoft.VisualStudio.2022.BuildTools --override "--quiet --wait --add Microsoft.VisualStudio.Workload.VCTools;includeRecommended" --accept-source-agreements --accept-package-agreements' , {
518+ timeout : 900000 // 15 minutes
519+ } ) ;
520+
521+ vscode . window . showInformationMessage (
522+ 'Visual Studio Build Tools installed. You may need to restart your computer, then reload VS Code.' ,
523+ 'Reload Window' ,
524+ 'Show PATH Fix Instructions'
525+ ) . then ( choice => {
526+ if ( choice === 'Reload Window' ) {
527+ vscode . commands . executeCommand ( 'workbench.action.reloadWindow' ) ;
528+ } else if ( choice === 'Show PATH Fix Instructions' ) {
529+ this . showWrongLinkerInstructions ( ) ;
530+ }
531+ } ) ;
532+
533+ return {
534+ success : false ,
535+ error : 'Visual Studio Build Tools installed. Please restart your computer and reload VS Code, then check PATH ordering.'
536+ } ;
537+ } catch ( installError ) {
538+ vscode . window . showErrorMessage (
539+ 'Failed to install Build Tools automatically. Please install manually.' ,
540+ 'Show Instructions'
541+ ) . then ( choice => {
542+ if ( choice === 'Show Instructions' ) {
543+ this . showWrongLinkerInstructions ( ) ;
544+ }
545+ } ) ;
546+ }
547+ }
548+
549+ return {
550+ success : false ,
551+ error : 'Wrong link.exe detected (GNU coreutils instead of MSVC linker). Visual Studio Build Tools required and PATH must be configured correctly.'
552+ } ;
553+ }
554+ }
555+
556+ // Check if this is a generic linker error indicating missing Visual Studio Build Tools
390557 if ( errorMsg . includes ( 'link.exe' ) && errorMsg . includes ( 'Visual Studio build tools' ) ) {
391558 if ( process . platform === 'win32' ) {
392559 const choice = await vscode . window . showErrorMessage (
@@ -398,9 +565,10 @@ export class JustLspInstaller {
398565
399566 if ( choice === 'Install Build Tools' ) {
400567 try {
401- // Try using winget to install Visual Studio Build Tools
402- await asyncExec ( 'winget install --id Microsoft.VisualStudio.2022.BuildTools --accept-source-agreements --accept-package-agreements' , {
403- timeout : 600000 // 10 minutes
568+ progress . report ( { message : 'Installing Visual Studio Build Tools...' } ) ;
569+ // Install with C++ workload explicitly
570+ await asyncExec ( 'winget install --id Microsoft.VisualStudio.2022.BuildTools --override "--quiet --wait --add Microsoft.VisualStudio.Workload.VCTools;includeRecommended" --accept-source-agreements --accept-package-agreements' , {
571+ timeout : 900000 // 15 minutes
404572 } ) ;
405573
406574 vscode . window . showInformationMessage (
@@ -456,6 +624,90 @@ export class JustLspInstaller {
456624 }
457625
458626
627+ private showWrongLinkerInstructions ( ) : void {
628+ const instructions = `# Fixing the "Wrong link.exe" Error on Windows
629+
630+ ## Problem
631+ Rust is trying to use the GNU coreutils \`link\` command (from Git for Windows, MSYS2, etc.) instead of the Microsoft Visual C++ linker (\`link.exe\`) that it needs.
632+
633+ This error looks like:
634+ \`\`\`
635+ link: extra operand 'C:\\Users\\...\\something.o'
636+ Try 'link --help' for more information.
637+ \`\`\`
638+
639+ ## Solution
640+
641+ ### Step 1: Install Visual Studio Build Tools
642+ 1. Open PowerShell as Administrator
643+ 2. Run:
644+ \`\`\`powershell
645+ winget install --id Microsoft.VisualStudio.2022.BuildTools --override "--quiet --wait --add Microsoft.VisualStudio.Workload.VCTools;includeRecommended"
646+ \`\`\`
647+ 3. **Restart your computer** after installation completes
648+
649+ ### Step 2: Fix Your PATH (Choose One Method)
650+
651+ #### Method A: Use the Visual Studio Developer Command Prompt
652+ - Launch "Developer Command Prompt for VS 2022" or "Developer PowerShell for VS 2022"
653+ - This automatically sets up the correct PATH
654+ - Install just-lsp from there:
655+ \`\`\`powershell
656+ cargo install just-lsp
657+ \`\`\`
658+
659+ #### Method B: Reorder Your System PATH
660+ 1. Open System Environment Variables:
661+ - Press Win+R, type \`sysdm.cpl\`, press Enter
662+ - Click "Advanced" tab → "Environment Variables"
663+ 2. In "System variables", find and edit "Path"
664+ 3. Move these entries to the **top** (before Git, MSYS2, etc.):
665+ \`\`\`
666+ C:\\Program Files\\Microsoft Visual Studio\\2022\\BuildTools\\VC\\Tools\\MSVC\\<version>\\bin\\Hostx64\\x64
667+ C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\BuildTools\\VC\\Tools\\MSVC\\<version>\\bin\\Hostx64\\x64
668+ \`\`\`
669+ (The exact path depends on your Visual Studio version)
670+ 4. **Restart your computer** for PATH changes to take effect
671+
672+ #### Method C: Use rustup's MSVC toolchain explicitly
673+ \`\`\`powershell
674+ rustup default stable-x86_64-pc-windows-msvc
675+ cargo install just-lsp
676+ \`\`\`
677+
678+ ### Step 3: Verify the Fix
679+ Open a new PowerShell window and run:
680+ \`\`\`powershell
681+ where.exe link
682+ \`\`\`
683+
684+ The **first** result should be the MSVC linker, something like:
685+ \`\`\`
686+ C:\\Program Files\\Microsoft Visual Studio\\2022\\BuildTools\\VC\\Tools\\MSVC\\...\\link.exe
687+ \`\`\`
688+
689+ NOT:
690+ \`\`\`
691+ C:\\Program Files\\Git\\usr\\bin\\link.exe
692+ \`\`\`
693+
694+ ### Step 4: Retry Installation
695+ Once the PATH is fixed, try installing just-lsp again:
696+ \`\`\`powershell
697+ cargo install just-lsp
698+ \`\`\`
699+
700+ ## Additional Resources
701+ - [Visual Studio Build Tools Download](https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2022)
702+ - [Rust Windows Prerequisites](https://rust-lang.github.io/rustup/installation/windows.html)
703+ ` ;
704+
705+ vscode . workspace . openTextDocument ( {
706+ content : instructions ,
707+ language : 'markdown'
708+ } ) . then ( doc => vscode . window . showTextDocument ( doc ) ) ;
709+ }
710+
459711 private showManualInstallationInstructions ( ) : void {
460712 const isWindows = process . platform === 'win32' ;
461713 const isMac = process . platform === 'darwin' ;
0 commit comments