Added F# Support to BepInEx.PluginInfoProps#18
Added F# Support to BepInEx.PluginInfoProps#18wwwDayDream wants to merge 2 commits intoBepInEx:masterfrom
Conversation
|
@wwwDayDream Holy crap, this nerd-sniped me. Have you tested any plugins with il2cpp backend games? any caveats or issues you've encountered since? |
There was a problem hiding this comment.
Pull request overview
Adds F# support to the BepInEx.PluginInfoProps MSBuild-based MyPluginInfo auto-generation, including updated documentation.
Changes:
- Detect project language via
$(MSBuildProjectExtension)and generate eitherMyPluginInfo.csorMyPluginInfo.fs. - Adjust F# compilation item ordering so the generated file is compiled before existing
Compileitems. - Update
BepInEx.PluginInfoPropsREADME with F# usage/output examples.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| BepInEx.PluginInfoProps/README.md | Documents new F# support and shows example generated output. |
| BepInEx.PluginInfoProps/BepInEx.PluginInfoProps.props | Adds language detection, F# codegen output, and compile ordering adjustments. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| <FileExtension Condition="$(MSBuildProjectExtension) == '.fsproj'">fs</FileExtension> | ||
| <FileExtension Condition="$(MSBuildProjectExtension) == '.csproj'">cs</FileExtension> | ||
| </PropertyGroup> | ||
| <Target Name="AddGeneratedFile" BeforeTargets="BeforeCompile;CoreCompile" Inputs="$(MSBuildAllProjects)" Outputs="$(IntermediateOutputPath)GeneratedFile.$(FileExtension)"> |
There was a problem hiding this comment.
The target Outputs path ($(IntermediateOutputPath)GeneratedFile.$(FileExtension)) doesn’t match the file actually written/included ($(IntermediateOutputPath)MyPluginInfo.$(FileExtension)). This prevents incremental build from correctly skipping the target and can cause it to run every build. Align Outputs with the real generated file path (or update GeneratedFilePath to match).
| <Target Name="AddGeneratedFile" BeforeTargets="BeforeCompile;CoreCompile" Inputs="$(MSBuildAllProjects)" Outputs="$(IntermediateOutputPath)GeneratedFile.$(FileExtension)"> | |
| <Target Name="AddGeneratedFile" BeforeTargets="BeforeCompile;CoreCompile" Inputs="$(MSBuildAllProjects)" Outputs="$(IntermediateOutputPath)MyPluginInfo.$(FileExtension)"> |
| Generates a `MyPluginInfo.cs`, or `.fs`, based on project tags. | ||
|
|
||
| Supports C# & F# projects, and will read the `.csproj` or `.fsproj` to determine values. |
There was a problem hiding this comment.
README says it generates MyPluginInfo.cs, or .fs, but the build writes MyPluginInfo.$(FileExtension) (i.e., MyPluginInfo.fs). Also, the generated file includes a namespace $(RootNamespace) wrapper (see props), which isn’t reflected in either the C# or F# examples. Update the wording and samples so they match the actual generated output.
| @@ -14,13 +16,23 @@ Define the following properties in your `csproj`: | |||
|
|
|||
| this will generate the following class: | |||
There was a problem hiding this comment.
The text "this will generate the following class:" is no longer accurate for F# output (it generates a module). Consider rephrasing to something language-neutral (e.g., "this will generate the following code") or splitting wording per language section.
| this will generate the following class: | |
| this will generate the following code: |
| <FileExtension Condition="$(MSBuildProjectExtension) == '.fsproj'">fs</FileExtension> | ||
| <FileExtension Condition="$(MSBuildProjectExtension) == '.csproj'">cs</FileExtension> | ||
| </PropertyGroup> | ||
| <Target Name="AddGeneratedFile" BeforeTargets="BeforeCompile;CoreCompile" Inputs="$(MSBuildAllProjects)" Outputs="$(IntermediateOutputPath)GeneratedFile.$(FileExtension)"> |
There was a problem hiding this comment.
FileExtension is only set for .csproj/.fsproj, but the target still runs and unconditionally adds $(GeneratedFilePath) to @(Compile). If this .props is imported by another project type (e.g., .vbproj), $(FileExtension) will be empty and this can generate/include MyPluginInfo. (no extension), breaking the build. Add a target-level Condition (e.g., only run when $(FileExtension) is cs or fs) and/or set a safe default / emit a clear error for unsupported project types.
| <Target Name="AddGeneratedFile" BeforeTargets="BeforeCompile;CoreCompile" Inputs="$(MSBuildAllProjects)" Outputs="$(IntermediateOutputPath)GeneratedFile.$(FileExtension)"> | |
| <Target Name="AddGeneratedFile" BeforeTargets="BeforeCompile;CoreCompile" Condition=" '$(FileExtension)' == 'cs' Or '$(FileExtension)' == 'fs' " Inputs="$(MSBuildAllProjects)" Outputs="$(IntermediateOutputPath)GeneratedFile.$(FileExtension)"> |
Expands functionality of BepInEx.PluginInfoProps' auto-generation.
I won't get into the debate of using F# to mod, but adding support is somewhat trivial, with the exception of F#'s dependency-based compilation order throwing a wrench in the plans. Thankfully, or maybe regrettably, detecting the language via project file extension is easy enough to then determine file contents, extension, and how we handle compilation insertion.
Traditionally, the <Compile> is all that's necessary, but FSharp's compiler will take that as the final file and so it won't be visible by any <Compile> files declared before it (which is all the .fsproj files). In order to avoid this, we store the compile into an interim item and reinsert it after we add MyPluginInfo's compile tag. Woohoo, just like that we supprt MyPluginInfo goodness in a few more mods in all of the ecosystem; but hey! "Functionality" (ᵖˡᵘˢ ⁱ'ᵈ ˡᵒᵛᵉ ⁱᵗ ˡᵒˡ)