You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Thanks Lennox808 for sharing this information on Discord (#1966)
Here is the faq/environment/index.md file that now describes the workflow to make the ScottPlot5 solution compilable (except ScottPlot.Tests)
---title: Development Environment Setup - ScottPlot FAQdescription: How to Build ScottPlot from Source Code using Visual Studio---## Build ScottPlot from Source_Building from source lets developers modify the ScottPlot code to customize behavior, fix bugs, and add new features. These steps are the easiest way for new contributors to get up and running with ScottPlot._**Step 1:** Install the latest version of [Visual Studio Community](https://visualstudio.microsoft.com/vs/community/) (free). During installation indicate you wish to install the ".NET desktop development" workload.
**Step 2:** Download ScottPlot code from https://github.com/scottplot/scottplot**Step 3:** Open the `.sln` file in the `src` folder in Visual Studio
**Step 4:** Right-click one of the demo projects and "Set as Startup Project"
**Step 5:** Press F5 to Build and Run 🚀
> 💡 If the build fails with an error message, read it carefully. It may indicate you need a particular version of the [.NET SDK SDK](https://dotnet.microsoft.com/en-us/download/visual-studio-sdks) or [.NET Framework Developer Pack](https://dotnet.microsoft.com/en-us/download/dotnet-framework/net48) installed on your system. You may need to restart Visual Studio after installing these tools.## Building with Older Tools**ScottPlot uses modern C# language features** like [file-scoped namespaces](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-10.0/file-scoped-namespaces), [lambda expressions](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/lambda-expressions), [global using directives](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-directive) and some more, which simplify the code but are not supported by older versions of Visual Studio. ScottPlot developers typically work with the latest major version of [Visual Studio Community](https://visualstudio.microsoft.com/vs/community/), but it is possible to build ScottPlot using older tools with some modifications.
### Visual Studio 2019> ⚠️ **WARNING: These steps are not required** for users who can use the latest free version of Visual Studio Community. Visual Studio 2019 is no longer the latest major version, but is officially supported until 2029 (see [Visual Studio 2019 Product Lifecycle](https://docs.microsoft.com/en-us/visualstudio/releases/2019/servicing-vs2019) for details).> 🚀 **Special thanks to Lennox808** from the [ScottPlot Discord](/discord) for sharing these notes after successfully building ScottPlot 4 and ScottPlot 5 in Visual Studio 2019 (version 16.7.5) in September, 2022.#### ScottPlot 4
Try to build the solution one project at a time, starting with `ScottPlot`. The following lists the build errors you will encounter and how to solve them. After fixing a build error, rebuild and repeat, until no errors remain.
* Edit the .csproj file to update target framework(s) to a single version known to be on your system (e.g., `net462`) as well as the language version (e.g., `9.0`).
* Revert file-scoped namespaces. Lines starting with `namespace` should be modified such that the `;` is replaced with a `{` and a `}` must be added to the bottom of the file. Repeatedly attempting to build the solution will identify files requiring this modification by the errors it produces.
* Remove the `$` sign or comment-out `Obsolete` lines that produce build errors.
* Resolve the lambda errors (in `Crosshair` and `Heatmap`) by replacing the expression with explicit logic.
Some of the projects of the ScottPlot solution require specific changes to make them compile with an older version of Visual Studio. The following lists the majority of these changes, nevertheless it may occure that this list may be incomplete.
*`Demos/Eto.Forms Demo`: Add *PresentationFramework* to Assemblys.
*`Demos/WinForms Demo`: Add *System.Windows.Forms* to Assemblys.
*`Demos/WPF Demo`: Replace the standard namespace from *WPF Demo* to *ScottPlot.Demo.WPF* in the project settings.
*`Sandbox/ConsoleApp`: Add `<LangVersion>9.0</LangVersion>` to the .csproj file.
*`Sandbox/WinFormsApp`: Add *System.Windows.Forms* to Assemblys.
*`Sandbox/WpfApp`: Open the .csproj file and change the first line from `<Project Sdk="Microsoft.NET.Sdk">` to `<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">`.
*`ScottPlot.Tests`: Add `<LangVersion>9.0</LangVersion>` to the .csproj file. Comment out the `using` statements that causes an error. Resolve the remaining errors.
#### ScottPlot 5
Even though *ScottPlot 5* is intended for people using .NET 7 and newer, it is still possible to build the solutions projects with older Visual Studio versions. Nevertheless this is only recommended for **debug** purposes as it requires quite some changes to the source files to make the projects compilable. For **contribution** purposes it is recommended to use Visual Studio 2022.
Besides file-scoped namespaces, the `ScottPlot` project makes use of `global using` statements, which means that in every source file of this project the said statements have to be added, either manually or with an automated script. Furthermore the following steps are necessary.
* Replace the `readonly` properties in `Color.cs` with functions returning the color.
* Replace struct declarations with class declaration where needed. Don't use class declaration for `RenderDetails` and `PixelPadding`.
* Initialize properties with `null!` for non nullable properties with argument validation (error *CS8618*).
* Replace the error in `Heatmap` caused by a nullable property with an explicit check for null.
Some projects require specific changes in order to make them compilable with older versions of Visual Studio. The following list contains the typical changes required, but it may happen that this list is incomplete.
*`Controls/ScottPlot.WinForms`: Add *System.Windows.Forms* to Assemblys.
*`Controls/ScottPlot.WPF`: Open the .csproj file and change the first line from `<Project Sdk="Microsoft.NET.Sdk">` to `<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">`.
*`Demo/DemoLauncher`: Add `<LangVersion>9.0</LangVersion>` to the .csproj file. Revert file-scoped namespaces in `HtmlMenu.cs`.
*`Demo/WinForms Demo`: Add `<LangVersion>9.0</LangVersion>` to the .csproj file. Revert file-scoped namespaces in `CookbookViewer.cs`, `CookbookViewer.Designer.cs` and `DemoWindows.cs`. Add *System.Windows.Forms* to Assemblys. Add `using System.Windows.Forms`, `using System.Linq` and `using System` where necessary. Replace `ApplicationConfiguration.Initialize()`in `Program.cs` with `Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false);`. Open the project properties, go to "Build" and select "x64" as target platform.
*`Sandbox/Sandbox.Avalonia`: Add `<LangVersion>9.0</LangVersion>` to the .csproj file.
*`Sandbox/Sandbox.Eto`: Add `using System` where necessary.
*`Sandbox/WPF`: Add `<LangVersion>9.0</LangVersion>` to the .csproj file and change the first line from `<Project Sdk="Microsoft.NET.Sdk">` to `<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">`.
*`ScottPlot Cookbook`: Add `<LangVersion>9.0</LangVersion>` to the .csproj file.
### Automated Conversion with Python
The processes above may be automated using [this python script](convert-vs2017.py) contributed by Lennox808 from the [ScottPlot Discord](/discord). It is not officially supported, but still seems quite useful.
### Troubleshooting* On error code `NU1105` open the cmd, navigate to the respective folder containing the .csproj file and run the command `dotnet restore <project file>`.
* On error code `CS7036` "*There is no argument given that corresponds to the required formal parameter*" replace the class declaration with a struct declaration of the type of the object that causes the error.
* On runtime exception "*Unable to load DLL 'WebView2Loader.dll'*" make sure that the target-platform is x64. If you change the target-platform, do a rebuild.
* On error message "*SourceRoot items must include at least one top-level (not nested) item when DeterministicSourcePaths is true*", add `<DeterministicSourcePaths>false</DeterministicSourcePaths>` to the .csproj file inside a `<PropertyGroup>`.
And here is the Python converter script, it now takes the -ReplaceGlobalUsing, which enables the attachment of the using ... if a file was found that makes use of global using ... for that respective csproj project. I did some clean up and optimizations too to make the code more readable
"""This script automates code changes required to build ScottPlot in VS2019.Run this script without arguments for usage information.Using the script:The python script does the steps which else have to be done manually automatically. The script takes the following arguments: -Repository "PATH_TO_REPOSITORY": Folder from which for .csproj and .cs files are searched for and adapted-TargetFramework "net472": Changes the <TargetFramework> content of each found .csproj file to net472 (net462 for example selects .NET Framework 4.6.2)-LangVersion "9.0": Changes the <LangVersion> content of each found .csproj file to 9.0-ReplaceNamespace: Enables the replacement of the namespace ScottPlot.x; with namespace ScottPlot.x {...}in all found .cs files-ReplaceGlobalUsing: If a file is found that makes use of `global using ...;`, all .cs files of this project get the respective statement appended."""importosimportsysimportre## Class to hold and determine all arguments of this scriptclassArguments:
## Creates an empty Arguments object.def__init__(self):
self.PathRepository="";
self.TargetFramework="";
self.LangVersion="";
self.ReplaceNamespace=False;
self.ReplaceGlobalUsing=False;
## Parses the given \p args which is a string list# and sets the internal properties for further processing.defParse(self, args):
argc=len(args);
foriinrange(argc):
currentArgument=args[i];
nextArgument="";
if ((i+1) <argc):
nextArgument=args[i+1];
if (sys.argv[i] =="-Repository"):
self.PathRepository=nextArgument;
i+=1;
elif (sys.argv[i] =="-TargetFramework"):
self.TargetFramework=nextArgument;
i+=1;
elif (sys.argv[i] =="-LangVersion"):
self.LangVersion=nextArgument;
i+=1;
elif (sys.argv[i] =="-ReplaceNamespace"):
self.ReplaceNamespace=True;
elif (sys.argv[i] =="-ReplaceGlobalUsing"):
self.ReplaceGlobalUsing=True;
## Searches for files with the given \p extension in the given# \p path and all its subdirectories and returns a list of# the absolute paths of these files.defGetAllFiles(path, extension):
foundFiles= [];
if (os.path.isdir(path) ==True):
forpath, subdirs, filesinos.walk(path):
forfileinfiles:
if (file.endswith("."+extension)):
foundFiles.append(os.path.join(path, file));
returnfoundFiles;
## Same as GetAllFiles(), but searches for ".csproj" filesdefGetAllProjectFiles(path):
returnGetAllFiles(path, "csproj");
## Same as GetAllFiles(), but searches for ".cs" filesdefGetAllSourceFiles(path):
returnGetAllFiles(path, "cs");
## If the given \p content contains the XML Tag# "TargetFrameworks" or "TargetFramework", the content/value of this# tag is replaced with the new \p target. This function the returns# a string with the replaced \p content.defReplaceTargetFramework(content, target):
content=re.sub('<TargetFrameworks>(.*)<\/TargetFrameworks>',
"<TargetFrameworks>"+target+"</TargetFrameworks>", content);
content=re.sub('<TargetFramework>(.*)<\/TargetFramework>',
"<TargetFramework>"+target+"</TargetFramework>", content);
returncontent;
## If the given \p content contains the XML Tag# "LangVersion" the content/value of this tag is replaced with the new \p version.# This function the returns a string with the replaced \p content.defReplaceLangVersion(content, version):
content=re.sub('<LangVersion>(.*)<\/LangVersion>',
"<LangVersion>"+version+"</LangVersion>", content);
returncontent;
## Reads the given \p file and returns its content as a single string.defReadFileContent(file):
withopen(file, 'r') asfileHandle:
returnfileHandle.read();
## (Over-)Write the given \p file with the given \p content.defWriteFileContent(file, content):
withopen(file, 'w') asfileHandle:
fileHandle.write(content);
## Returns True if the given \p content makes use of "global using ..." statements.defContainsGlobalUsing(content):
returnbool(re.search('global using (.*);[\r]{0,1}\n', content));
## Returns a list/array of all the "global using ..." statements used in the# given \p content.defGetGlobalUsingStatements(content):
pattern="global using (.*);[\r]{0,1}\n";
returnre.findall(pattern, content);
## Returns the path to the .csproj file of the given \p sourceFile. To do so it is# assumed that the source files of a .csproj file are in the directory of the said# project file or in its containing (sub-)folders. That means, as soon as a folder# is reached, which contains a ".gitignore" file, which indicates the root of the# repository, this function stops.defGetSourceFilesProjectFile(sourceFile):
projectFile="";
if (os.path.exists(sourceFile)):
currentDirectory=os.path.dirname(sourceFile);
# Go down the directories until we reach the repositories root directory# A check for ".gitignore" is better than to check for ".git" as the latter# is not always there when the repository is downloaded instead of cloned.while ((".gitignore"inos.listdir(currentDirectory)) ==False):
# Get all files in the current directory only ...forfilenameinos.listdir(currentDirectory):
filepath=os.path.join(currentDirectory, filename);
# ... and check if current path is a csproj fileif (os.path.isfile(filepath) andfilepath.endswith(".csproj")):
projectFile=filepath;
break;
# No csproj file found, go down one directorycurrentDirectory=os.path.join(currentDirectory, "..");
returnprojectFile;
defmain(args):
arguments=Arguments();
arguments.Parse(args);
if (arguments.PathRepository==""):
print("Please set a -Repository")
return1;
if (os.path.isdir(arguments.PathRepository) ==False):
print ("The given -Repository \""+arguments.PathRepository+"\" does not exist");
return1;
print("Input:");
print("- Repository: \""+arguments.PathRepository+"\"")
print("- TargetFramework: \""+arguments.TargetFramework+"\"")
print("- LangVersion: \""+arguments.LangVersion+"\"")
print("- ReplaceNamespace: "+str(arguments.ReplaceNamespace));
print("- ReplaceGlobalUsing: "+str(arguments.ReplaceGlobalUsing));
projectFiles=GetAllProjectFiles(arguments.PathRepository)
# Replacing the .csproj files "TargetFramework" and "LangVersion"# if necessaryeditCsprojFile= (arguments.TargetFramework!="") or (arguments.LangVersion!="");
if (editCsprojFile):
forprojectFileinprojectFiles:
# Read in the filefilecontent=ReadFileContent(projectFile);
# Change the TargetFramework if wantedif (arguments.TargetFramework!=""):
filecontent=ReplaceTargetFramework(filecontent, arguments.TargetFramework)
# Change the LangVersion if wantedif (arguments.LangVersion!=""):
filecontent=ReplaceLangVersion(filecontent, arguments.LangVersion)
# Write the file out againWriteFileContent(projectFile, filecontent);
# Replace "namespace ScottPlot.x;" with "namespace ScottPlot.x {...}"# if necessaryif (arguments.ReplaceNamespace==True):
# Yes, so search for all source filessourceFiles=GetAllSourceFiles(arguments.PathRepository)
# Todo: Maybe not just "namespace ScottPlot.xxx;" ?regExpression=re.compile(r'namespace ScottPlot(.*);\n')
# Go through all found source filesforsourceFileinsourceFiles:
# Expect the current file not to be changedwriteFile=Falsefilecontent=ReadFileContent(sourceFile);
# Does this file contain the said "namespace ScottPlot.x;" pattern?ifregExpression.search(filecontent):
# Yes it does, replace the temporary data with "namespace ScottPlot.x {...}"...filecontent=re.sub(
r'namespace ScottPlot(.*);\n', r"namespace ScottPlot\g<1>\n{\n", filecontent)
filecontent=filecontent+"\n}"# ... and mark the file to be written againwriteFile=True# Only write the file if there was a changeif (writeFile==True):
WriteFileContent(sourceFile, filecontent);
# Search for "global using ..." statements and replace all source files with the found statements?if (arguments.ReplaceGlobalUsing==True):
# Yes, get all source files ...sourceFiles=GetAllSourceFiles(arguments.PathRepository);
# ... and prepare a list that stores the paths to the files# that makes use of "global using ..."globalUsingSourceFiles= [];
# Go through all source files and check if any makes use of "global using ..." statementsforsourceFileinsourceFiles:
filecontent=ReadFileContent(sourceFile);
if (ContainsGlobalUsing(filecontent) ==True):
# Source file makes use of "global using ..."globalUsingSourceFiles.append(sourceFile);
# Now find out to which project the files belong which makes use of "global using ..."forglobalUsingSourceFileinglobalUsingSourceFiles:
# To do so it is assumed, that the csproj file is the root folder of all the# source files of the project, in which the "using ..." statements have to be# appendedsourceFilesProjectFile=GetSourceFilesProjectFile(globalUsingSourceFile);
if (sourceFilesProjectFile!=""):
# Find out which "global using ..." statements are used in this project ...projectsGlobalUsingStatements=GetGlobalUsingStatements(ReadFileContent(globalUsingSourceFile));
# ... then go through all source files of this project ...projectSourceFiles=GetAllSourceFiles(os.path.dirname(sourceFilesProjectFile));
forprojectSourceFileinprojectSourceFiles:
filecontent=ReadFileContent(projectSourceFile);
writeFile=False;
# ... check if the any source file already# contains the "global using ..." statement(s)forprojectsGlobalUsingStatementinprojectsGlobalUsingStatements:
currentUsingStatement="using "+projectsGlobalUsingStatement+";";
# ... and if not, add only the missing statements# at the beginning of the source fileifcurrentUsingStatementnotinfilecontent:
filecontent=currentUsingStatement+"\n"+filecontent;
writeFile=True;
# Only write the current source file if a using statement was addedif (writeFile==True):
WriteFileContent(projectSourceFile, filecontent);
if__name__=="__main__":
noArgumentsGiven=len(sys.argv) ==1;
if (noArgumentsGiven):
print("""Usage: -Repository \"PATH\" (mandatory) Path to the ScottPlot repository. Absolute recommended. -TargetFramework \"TARGET\" (mandatory) Replaces the \"TargetFramework\" and \"TargetFrameworks\" tags with the given TARGET. For example \"net472\". -LangVersion \"VERSION\" (optional, but recommended) Replaces the \"LangVersion\" tags with the given VERSION. For example \"9.0\", in order to use \"Target-typed New Expressions\" -ReplaceNamespace (optional) Replaces the ScottPlot file scoped namespaces with curly bracets. For example\"namespace ScottPlot.Plottable;\" becomes \"namespace ScottPlot.Plottable {...}\" -ReplaceGlobalUsing: If a file is found that makes use of `global using ...;`, all .cs files of this project get the respective statement appended. """)
else:
main(sys.argv)
The text was updated successfully, but these errors were encountered:
Thanks Lennox808 for sharing this information on Discord (#1966)
The text was updated successfully, but these errors were encountered: