Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Nov 13, 2025

Description

When building VisualFSharpDebug.vsix for local F# compiler development, the VSIX installs language service and editor components but MSBuild continues using the system-installed compiler from Common7/IDE/CommonExtensions/Microsoft/FSharp/Tools/. This PR automatically sets the FSharpCompilerPath environment variable when pressing F5 on VisualFSharpDebug, so the locally built compiler is used.

How It Works

The existing F# shim mechanism in vsintegration/shims/Microsoft.FSharp.ShimHelpers.props (line 10) checks if FSharpCompilerPath is set:

  • If set via environment variable → uses that path
  • If not set → defaults to $(VsInstallRoot)/Common7/IDE/CommonExtensions/Microsoft/FSharp/Tools/

This PR follows the same pattern as VSSDKTargetPlatformRegRootSuffix:

  1. Property is defined in vsintegration/Vsix/Directory.Build.props
  2. Referenced via $(FSharpCompilerPath) in launchSettings.json
  3. Visual Studio expands the property when starting the debug session

Changes

  • vsintegration/Vsix/Directory.Build.props: Added FSharpCompilerPath property pointing to $(ArtifactsDir)bin/fsc/$(Configuration)/net472/

  • launchSettings.json: Added environmentVariables section that sets FSharpCompilerPath to $(FSharpCompilerPath) - Visual Studio expands this when launching the debug session

Verification

  1. Build the solution in Debug configuration
  2. Press F5 on VisualFSharpDebug project
  3. In the experimental VS instance, build any F# project
  4. Use MSBuild /v:d and search for FSharpCompilerPath to verify it points to the artifacts folder

Notes

  • Automatic: No manual environment variable setup required - just press F5
  • Debug VSIX only — production VSIX (VisualFSharpFull.csproj) unchanged

Checklist

  • Test cases added

  • Performance benchmarks added in case of performance changes

  • Release notes entry updated:

    Please make sure to add an entry with short succinct description of the change as well as link to this pull request to the respective release notes file, if applicable.

    Release notes files:

    • If anything under src/Compiler has been changed, please make sure to make an entry in docs/release-notes/.FSharp.Compiler.Service/<version>.md, where <version> is usually "highest" one, e.g. 42.8.200
    • If language feature was added (i.e. LanguageFeatures.fsi was changed), please add it to docs/release-notes/.Language/preview.md
    • If a change to FSharp.Core was made, please make sure to edit docs/release-notes/.FSharp.Core/<version>.md where version is "highest" one, e.g. 8.0.200.

    Information about the release notes entries format can be found in the documentation.
    Example:

    If you believe that release notes are not necessary for this PR, please add NO_RELEASE_NOTES label to the pull request.

Original prompt

Enable VisualFSharpDebug VSIX to Override F# Compiler Path

Problem

When developers build and install VisualFSharpDebug.vsix for local F# development, the VSIX installs the language service and editor components but does NOT update the F# compiler (fscAnyCpu.exe) used by MSBuild when building F# projects.

Currently:

  • VSIX installs to: %LOCALAPPDATA%\Microsoft\VisualStudio\<version>\Extensions\...
  • MSBuild uses compiler from: C:\Program Files\Microsoft Visual Studio\<version>\Common7\IDE\CommonExtensions\Microsoft\FSharp\Tools\

This means locally built compiler changes are not used when building F# projects, which is a major pain point for F# compiler development.

Solution

Deploy an MSBuild .props file via the VSIX that automatically overrides the FSharpCompilerPath property to point to the VSIX's Tools directory where the custom-built compiler is located.

The F# build system uses a shim mechanism (in vsintegration/shims/Microsoft.FSharp.ShimHelpers.props) that checks for FSharpCompilerPath and uses it to load the compiler. By setting this property before the shims evaluate, we can redirect all F# builds to use the VSIX compiler.

Implementation Details

File 1: Create New Props File

Path: vsintegration/Vsix/VisualFSharpFull/Microsoft.FSharp.VSIX.Debug.Overrides.props

Content:

<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) Microsoft Corporation.  All Rights Reserved.  See License.txt in the project root for license information. -->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  
  <PropertyGroup>
    <!-- Override FSharpCompilerPath to point to VSIX Tools directory -->
    <!-- This props file is deployed alongside the Tools directory in the VSIX -->
    <!-- Calculate path from this file's location to Tools -->
    <_FSharpDebugVsixPropsDir>$(MSBuildThisFileDirectory)</_FSharpDebugVsixPropsDir>
    <_FSharpDebugVsixToolsPath>$(_FSharpDebugVsixPropsDir)Tools\</_FSharpDebugVsixToolsPath>
    
    <!-- Override only if not already set and compiler exists -->
    <FSharpCompilerPath Condition="'$(FSharpCompilerPath)' == '' and Exists('$(_FSharpDebugVsixToolsPath)fscAnyCpu.exe')">$(_FSharpDebugVsixToolsPath)</FSharpCompilerPath>
  </PropertyGroup>
  
  <Target Name="WarnAboutDebugVsixCompiler" BeforeTargets="BeforeBuild" Condition="'$(FSharpCompilerPath)' == '$(_FSharpDebugVsixToolsPath)'">
    <Warning Text="🔧 [F# Debug VSIX] Using custom F# compiler from: $(FSharpCompilerPath)" />
  </Target>

</Project>

File 2: Modify VisualFSharpDebug.csproj

Path: vsintegration/Vsix/VisualFSharpFull/VisualFSharpDebug.csproj

Change: Add the following ItemGroup after line 86 (before the closing </Project> tag):

  <ItemGroup>
    <!-- Deploy the override props file as an MSBuild asset -->
    <Content Include="Microsoft.FSharp.VSIX.Debug.Overrides.props">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <IncludeInVSIX>true</IncludeInVSIX>
      <VSixSubPath>.</VSixSubPath>
    </Content>
  </ItemGroup>

File 3: Modify VSIX Manifest

Path: vsintegration/Vsix/VisualFSharpFull/Source.extension.vsixmanifest

Change: Add the following Asset element in the <Assets> section (after the existing Asset elements, around line 43):

    <Asset Type="Microsoft.VisualStudio.MsBuildProps" 
           d:Source="File" 
           Path="Microsoft.FSharp.VSIX.Debug.Overrides.props" />

How It Works

  1. The new props file is deployed in the VSIX root directory (same level as Tools/)
  2. The VSIX manifest declares it as a Microsoft.VisualStudio.MsBuildProps asset
  3. Visual Studio automatically imports MSBuild props files registered this way
  4. The props file calculates the path to the VSIX Tools directory using $(MSBuildThisFileDirectory)
  5. It sets FSharpCompilerPath to point to the VSIX Tools directory (only if not already set)
  6. The F# shim mechanism (in vsintegration/shims/Microsoft.FSharp.ShimHelpers.props) uses FSharpCompilerPath to load the compiler
  7. All F# project builds now use the custom compiler from the VSIX
  8. A warning message appears in build output to indicate the override is active

Testing

After these changes:

  1. Build the solution in Debug configuration
  2. Press F5 on VisualFSharpDebug project (or install manually via VSIXInstaller)
  3. Build any F# project
  4. You should see: 🔧 [F# Debug VSIX] Using custom F# compiler from: <path to VSIX>\Tools\
  5. Verify the custom compiler is being used (check timestamps, add debug output, etc.)

Safety

  • ✅ Debug-only: Only affects VisualFSharpDebug.csproj, not VisualFSharpFull.csproj
  • ✅ Conditional: Only overrides if FSharpCompilerPath is not already set
  • ✅ Safe fallback: Checks if compiler exists before setting the property
  • ✅ Pure: No registry modifications, no environment variables
  • ✅ Self-cleaning: Uninstalling the VSIX removes all files automatically
  • ✅ Visible: Shows clear warning when acti...

This pull request was created as a result of the following prompt from Copilot chat.

Enable VisualFSharpDebug VSIX to Override F# Compiler Path

Problem

When developers build and install VisualFSharpDebug.vsix for local F# development, the VSIX installs the language service and editor components but does NOT update the F# compiler (fscAnyCpu.exe) used by MSBuild when building F# projects.

Currently:

  • VSIX installs to: %LOCALAPPDATA%\Microsoft\VisualStudio\<version>\Extensions\...
  • MSBuild uses compiler from: C:\Program Files\Microsoft Visual Studio\<version>\Common7\IDE\CommonExtensions\Microsoft\FSharp\Tools\

This means locally built compiler changes are not used when building F# projects, which is a major pain point for F# compiler development.

Solution

Deploy an MSBuild .props file via the VSIX that automatically overrides the FSharpCompilerPath property to point to the VSIX's Tools directory where the custom-built compiler is located.

The F# build system uses a shim mechanism (in vsintegration/shims/Microsoft.FSharp.ShimHelpers.props) that checks for FSharpCompilerPath and uses it to load the compiler. By setting this property before the shims evaluate, we can redirect all F# builds to use the VSIX compiler.

Implementation Details

File 1: Create New Props File

Path: vsintegration/Vsix/VisualFSharpFull/Microsoft.FSharp.VSIX.Debug.Overrides.props

Content:

<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) Microsoft Corporation.  All Rights Reserved.  See License.txt in the project root for license information. -->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  
  <PropertyGroup>
    <!-- Override FSharpCompilerPath to point to VSIX Tools directory -->
    <!-- This props file is deployed alongside the Tools directory in the VSIX -->
    <!-- Calculate path from this file's location to Tools -->
    <_FSharpDebugVsixPropsDir>$(MSBuildThisFileDirectory)</_FSharpDebugVsixPropsDir>
    <_FSharpDebugVsixToolsPath>$(_FSharpDebugVsixPropsDir)Tools\</_FSharpDebugVsixToolsPath>
    
    <!-- Override only if not already set and compiler exists -->
    <FSharpCompilerPath Condition="'$(FSharpCompilerPath)' == '' and Exists('$(_FSharpDebugVsixToolsPath)fscAnyCpu.exe')">$(_FSharpDebugVsixToolsPath)</FSharpCompilerPath>
  </PropertyGroup>
  
  <Target Name="WarnAboutDebugVsixCompiler" BeforeTargets="BeforeBuild" Condition="'$(FSharpCompilerPath)' == '$(_FSharpDebugVsixToolsPath)'">
    <Warning Text="🔧 [F# Debug VSIX] Using custom F# compiler from: $(FSharpCompilerPath)" />
  </Target>

</Project>

File 2: Modify VisualFSharpDebug.csproj

Path: vsintegration/Vsix/VisualFSharpFull/VisualFSharpDebug.csproj

Change: Add the following ItemGroup after line 86 (before the closing </Project> tag):

  <ItemGroup>
    <!-- Deploy the override props file as an MSBuild asset -->
    <Content Include="Microsoft.FSharp.VSIX.Debug.Overrides.props">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <IncludeInVSIX>true</IncludeInVSIX>
      <VSixSubPath>.</VSixSubPath>
    </Content>
  </ItemGroup>

File 3: Modify VSIX Manifest

Path: vsintegration/Vsix/VisualFSharpFull/Source.extension.vsixmanifest

Change: Add the following Asset element in the <Assets> section (after the existing Asset elements, around line 43):

    <Asset Type="Microsoft.VisualStudio.MsBuildProps" 
           d:Source="File" 
           Path="Microsoft.FSharp.VSIX.Debug.Overrides.props" />

How It Works

  1. The new props file is deployed in the VSIX root directory (same level as Tools/)
  2. The VSIX manifest declares it as a Microsoft.VisualStudio.MsBuildProps asset
  3. Visual Studio automatically imports MSBuild props files registered this way
  4. The props file calculates the path to the VSIX Tools directory using $(MSBuildThisFileDirectory)
  5. It sets FSharpCompilerPath to point to the VSIX Tools directory (only if not already set)
  6. The F# shim mechanism (in vsintegration/shims/Microsoft.FSharp.ShimHelpers.props) uses FSharpCompilerPath to load the compiler
  7. All F# project builds now use the custom compiler from the VSIX
  8. A warning message appears in build output to indicate the override is active

Testing

After these changes:

  1. Build the solution in Debug configuration
  2. Press F5 on VisualFSharpDebug project (or install manually via VSIXInstaller)
  3. Build any F# project
  4. You should see: 🔧 [F# Debug VSIX] Using custom F# compiler from: <path to VSIX>\Tools\
  5. Verify the custom compiler is being used (check timestamps, add debug output, etc.)

Safety

  • ✅ Debug-only: Only affects VisualFSharpDebug.csproj, not VisualFSharpFull.csproj
  • ✅ Conditional: Only overrides if FSharpCompilerPath is not already set
  • ✅ Safe fallback: Checks if compiler exists before setting the property
  • ✅ Pure: No registry modifications, no environment variables
  • ✅ Self-cleaning: Uninstalling the VSIX removes all files automatically
  • ✅ Visible: Shows clear warning when active so developers know what's happening

Important Notes

  • This ONLY applies to VisualFSharpDebug.vsix (the debug variant used for F5 development)
  • VisualFSharpFull.csproj (the production VSIX) should NOT include these changes
  • The override uses the standard Microsoft-documented VSIX MSBuild integration mechanism
  • The Microsoft.VisualStudio.MsBuildProps asset type ensures automatic import by MSBuild

💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com>
Copilot AI changed the title [WIP] Add support for overriding F# compiler path in VSIX Enable VisualFSharpDebug VSIX to override F# compiler path via MSBuild props Nov 13, 2025
Copilot AI requested a review from T-Gro November 13, 2025 13:46
Copilot finished work on behalf of T-Gro November 13, 2025 13:46
@github-actions
Copy link
Contributor

✅ No release notes required

Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com>
Copilot AI changed the title Enable VisualFSharpDebug VSIX to override F# compiler path via MSBuild props Deploy F# compiler override props file via VisualFSharpDebug VSIX (manual import required) Nov 26, 2025
Copilot AI requested a review from T-Gro November 26, 2025 12:19
Copilot finished work on behalf of T-Gro November 26, 2025 12:19
Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com>
Copilot AI changed the title Deploy F# compiler override props file via VisualFSharpDebug VSIX (manual import required) Deploy F# compiler override props file via VisualFSharpDebug VSIX with usage documentation Nov 27, 2025
Copilot finished work on behalf of T-Gro November 27, 2025 12:23
Copy link
Member

@T-Gro T-Gro left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot
Wait what is actually the added value of this?

It does not accomplish anything at all.

I wanted the F5 behavior of the VisualFSharpDebug project to set the variable automatically, not that people have to set it on their own - they know they can do it already.

Just drop these changes, all of them, and focus on the launch settings.json file - in there, you shall be able to set the env var for the user.

Add it to Directory.Build.Props just how VSSDKTargetPlatformRegRootSuffix (search!!!) is added.
This should form the path to the FSharpCompilerPath that you must figure out from the context.

And the launch settings.json can set it as an env var for the started project.

Co-authored-by: T-Gro <46543583+T-Gro@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Nov 27, 2025

@copilot
Wait what is actually the added value of this?...

Refactored the approach in commit 59d23ba:

  1. Added FSharpCompilerPath to vsintegration/Vsix/Directory.Build.props pointing to $(ArtifactsDir)bin/fsc/$(Configuration)/net472/
  2. Updated launchSettings.json to pass $(FSharpCompilerPath) as environment variable
  3. Removed the props file and all related VSIX changes

This follows the same pattern as VSSDKTargetPlatformRegRootSuffix. When pressing F5, VS expands the property and sets the environment variable for the debug session.

Copilot AI changed the title Deploy F# compiler override props file via VisualFSharpDebug VSIX with usage documentation Auto-set FSharpCompilerPath when debugging VisualFSharpDebug VSIX Nov 27, 2025
Copilot finished work on behalf of T-Gro November 27, 2025 14:14
Copilot AI requested a review from T-Gro November 27, 2025 14:14
@T-Gro T-Gro marked this pull request as ready for review November 28, 2025 11:58
@T-Gro T-Gro requested a review from a team as a code owner November 28, 2025 11:59
@T-Gro T-Gro merged commit ce8cf73 into main Dec 1, 2025
38 checks passed
@github-project-automation github-project-automation bot moved this from In Progress to Done in F# Compiler and Tooling Dec 1, 2025
@T-Gro T-Gro deleted the copilot/enable-vsix-override-fsharp-compiler branch December 1, 2025 10:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

3 participants