Skip to content

Commit 501fcef

Browse files
jjonesczCopilot
andauthored
Add more details to dotnet run app.cs spec (#49527)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 7ee7342 commit 501fcef

File tree

1 file changed

+49
-15
lines changed

1 file changed

+49
-15
lines changed

documentation/general/dotnet-run-file.md

Lines changed: 49 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,23 @@ The [guiding principle](#guiding-principle) implies that we can think of file-ba
2828
The implicit project file is the default project that would be created by running `dotnet new console`.
2929
This means that the behavior of `dotnet run file.cs` can change between SDK versions if the `dotnet new console` template changes.
3030

31+
Additionally, the implicit project file has the following customizations:
32+
33+
- `PublishAot` is set to `true`, see [`dotnet publish file.cs`](#other-commands) for more details.
34+
35+
- [File-level directives](#directives-for-project-metadata) are applied.
36+
37+
- The following are virtual only, i.e., not preserved after [converting to a project](#grow-up):
38+
39+
- `ArtifactsPath` is set to a [temp directory](#build-outputs).
40+
41+
- `RuntimeHostConfigurationOption`s are set for `EntryPointFilePath` and `EntryPointFileDirectoryPath` which can be accessed in the app via `AppContext`:
42+
43+
```cs
44+
string? filePath = AppContext.GetData("EntryPointFilePath") as string;
45+
string? directoryPath = AppContext.GetData("EntryPointFileDirectoryPath") as string;
46+
```
47+
3148
## Grow up
3249

3350
When file-based programs reach an inflection point where build customizations in a project file are needed,
@@ -60,6 +77,8 @@ The file-based build and run kicks in only when:
6077
- a project file cannot be found (in the current directory or via the `--project` option), and
6178
- if the target file exists, and has the `.cs` file extension or contents that start with `#!`.
6279

80+
Otherwise, project-based `dotnet run` fallback is used and you might get an error like "Couldn't find a project to run."
81+
6382
File-based programs are processed by `dotnet run` equivalently to project-based programs unless specified otherwise in this document.
6483
For example, the remaining command-line arguments after the first argument (the target path) are passed through to the target app
6584
(except for the arguments recognized by `dotnet run` unless they are after the `--` separator)
@@ -179,20 +198,28 @@ Other directives result in an error, reserving them for future use.
179198
#:project ../MyLibrary
180199
```
181200

182-
The value must be separated from the kind (`package`/`sdk`/`property`) of the directive by whitespace
183-
and any leading and trailing white space is not considered part of the value.
184-
Any value can optionally have two parts separated by `@` in case of `package`/`sdk` or `=` in case of `property`
185-
and whitespace is trimmed from the two parts around the separator.
186-
The value of the first `#:sdk` is injected into `<Project Sdk="{0}">` with the separator (if any) replaced with `/`,
187-
and the subsequent `#:sdk` directive values are split by the separator and injected as `<Sdk Name="{0}" Version="{1}" />` elements (or without the `Version` attribute if there is no separator).
188-
It is an error if the first part (name) is empty (the version is allowed to be empty, but that results in empty `Version=""`).
189-
The value of `#:property` is split by the separator and injected as `<{0}>{1}</{0}>` in a `<PropertyGroup>`.
190-
It is an error if no separator appears in the value or if the first part (property name) is empty (the property value is allowed to be empty) or contains invalid characters.
191-
The value of `#:package` is split by the separator and injected as `<PackageReference Include="{0}" Version="{1}">` (or without the `Version` attribute if there is no separator) in an `<ItemGroup>`.
192-
It is an error if the first part (package name) is empty (the package version is allowed to be empty, but that results in empty `Version=""`).
193-
The value of `#:project` is injected as `<ProjectReference Include="{0}" />` in an `<ItemGroup>`.
194-
If the value points to an existing directory, a project file is found inside that directory and its path is used instead
195-
(because `ProjectReference` items don't support directory paths).
201+
Each directive has a kind (e.g., `package`), a name (e.g., `System.CommandLine`), a separator (e.g., `@`), and a value (e.g., the package version).
202+
The value is required for `#:property`, optional for `#:package`/`#:sdk`, and disallowed for `#:project`.
203+
204+
The name must be separated from the kind (`package`/`sdk`/`property`) of the directive by whitespace
205+
and any leading and trailing white space is not considered part of the name and value.
206+
207+
The directives are processed as follows:
208+
209+
- The name and value of the first `#:sdk` is injected into `<Project Sdk="{0}/{1}">` (or just `<Project Sdk="{0}">` if it has no value),
210+
and the subsequent `#:sdk` directive names and values are injected as `<Sdk Name="{0}" Version="{1}" />` elements (or without the `Version` attribute if it has no value).
211+
It is an error if the name is empty (the version is allowed to be empty, but that results in empty `Version=""`).
212+
213+
- A `#:property` is injected as `<{0}>{1}</{0}>` in a `<PropertyGroup>`.
214+
It is an error if property does not have a value or if its name is empty (the value is allowed to be empty) or contains invalid characters.
215+
216+
- A `#:package` is injected as `<PackageReference Include="{0}" Version="{1}">` (or without the `Version` attribute if it has no value) in an `<ItemGroup>`.
217+
It is an error if its name is empty (the value, i.e., package version, is allowed to be empty, but that results in empty `Version=""`).
218+
219+
- A `#:project` is injected as `<ProjectReference Include="{0}" />` in an `<ItemGroup>`.
220+
If the path points to an existing directory, a project file is found inside that directory and its path is used instead
221+
(because `ProjectReference` items don't support directory paths).
222+
An error is reported if zero or more than one projects are found in the directory, just like `dotnet reference add` would do.
196223

197224
Because these directives are limited by the C# language to only appear before the first "C# token" and any `#if`,
198225
dotnet CLI can look for them via a regex or Roslyn lexer without any knowledge of defined conditional symbols
@@ -235,7 +262,13 @@ The build is performed using MSBuild APIs on in-memory project files.
235262

236263
### Optimizations
237264

238-
MSBuild invocation can be skipped in subsequent `dotnet run file.cs` invocations if an up-to-date check detects that inputs didn't change.
265+
If an up-to-date check detects that inputs didn't change in subsequent `dotnet run file.cs` invocations,
266+
building is skipped (as if `--no-build` option has been passed).
267+
The up-to-date check is not 100% precise (e.g., files imported through an implicit build file are not considered).
268+
It is possible to enforce a full build using `--no-cache` flag or `dotnet build file.cs`.
269+
Environment variable [`DOTNET_CLI_CONTEXT_VERBOSE=true`][verbose-env] can be used to get more details about caching decisions made by `dotnet run file.cs`.
270+
271+
There are multiple optimization levels - skipping build altogether, running just the C# compiler, or running full MSBuild.
239272
We always need to re-run MSBuild if implicit build files like `Directory.Build.props` change but
240273
from `.cs` files, the only relevant MSBuild inputs are the `#:` directives,
241274
hence we can first check the `.cs` file timestamps and for those that have changed, compare the sets of `#:` directives.
@@ -351,6 +384,7 @@ Instead of implicitly including files from the target directory, the importing c
351384
-->
352385

353386
[artifacts-output]: https://learn.microsoft.com/dotnet/core/sdk/artifacts-output
387+
[verbose-env]: https://learn.microsoft.com/dotnet/core/tools/dotnet-environment-variables#dotnet_cli_context_
354388
[ignored-directives]: https://github.com/dotnet/csharplang/blob/main/proposals/ignored-directives.md
355389
[shebang]: https://en.wikipedia.org/wiki/Shebang_%28Unix%29
356390
[temp-guidelines]: https://github.com/dotnet/runtime/blob/d0e6ce8332a514d70b635ca4829bf863157256fe/docs/design/security/unix-tmp.md

0 commit comments

Comments
 (0)