Skip to content

Commit a526e77

Browse files
authored
Move clang-format download into dotnet/runtime and add docs for setting up auto-formatting in the repository (#59374)
1 parent b087228 commit a526e77

10 files changed

+238
-1
lines changed

.clang-format

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
DisableFormat: true

.config/dotnet-tools.json

+6
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@
2525
"commands": [
2626
"slngen"
2727
]
28+
},
29+
"dotnet-format": {
30+
"version": "6.0.240501",
31+
"commands": [
32+
"dotnet-format"
33+
]
2834
}
2935
}
3036
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
# Code Formatting Tools in dotnet/runtime
2+
3+
In this repository, we use various different formatting conventions depending on who owns the code. Additionally, we use different formatting tools depending on if the code is managed C# or VB code or if the code is native C or C++ code.
4+
5+
To help enable an easy workflow and reduce the number of formatting changes requested, this document provides steps to download and enable the various different tools in different development environments to enable a seamless workflow for ensuring that keeping code formatted is a pleasant experience.
6+
7+
## Downloading formatting tools
8+
9+
### C#/VB
10+
11+
C# and VB code in the repository use the built-in Roslyn support for EditorConfig to enable auto-formatting in many IDEs. As a result, no additional tools are required to enable keeping your code formatted. If you want to use `dotnet format` to do formatting or are using the git pre-commit hook mentioned later in this document, you can run `./dotnet.cmd tool restore` or `./dotnet.sh tool restore` from the root of the repository to enable the `dotnet format` command.
12+
13+
### C/C++
14+
15+
To download the formatting tools for C++, run the `download-tools.ps1/sh` script in the `eng/formatting` folder. Specifically, run the `download-tools.ps1` script if you're on Windows, or the `download-tools.sh` script otherwise.
16+
17+
This script will download the `clang-format` and `clang-tidy` tools to the `artifacts/tools` folder in your clone of the repository. Only specific parts of the repository use `clang-tidy`, so this document primarily focuses on setting up `clang-format` for C and C++ scenarios.
18+
19+
#### CoreCLR JIT
20+
21+
The JIT team uses a special `jit-format` tool that runs `clang-format` and `clang-tidy` on their directory with their settings. You can get the `jit-format` tool from the [dotnet/jitutils repository](https://github.com/dotnet/jitutils).
22+
23+
## Setting up automatic formatting
24+
25+
To make the formatting workflow more seamless for contributors, instructions are included below to help enable "format-on-save" or other forms of automatic formatting in various different IDEs or as a Git pre-commit hook for IDEs that do not support "format-on-save" scenarios.
26+
27+
This section is open to contributions for instructions on how to enable "format-on-save"-like semantics in IDEs and editors not mentioned.
28+
29+
### Visual Studio Code
30+
31+
Enabling a "format-on-save" experience in VSCode is quite easy. Add the following setting to your `.vscode/settings.json` file to enable "format-on-save":
32+
33+
```json
34+
"editor.formatOnSave": true,
35+
```
36+
37+
The sections below include any additional instructions to configure the experience for different languages.
38+
39+
#### C#/VB
40+
41+
There are currently some limitations in OmniSharp that causes issues with the auto-formatting. Once a VSCode C# extension releases with both https://github.com/OmniSharp/omnisharp-roslyn/pull/2227 and https://github.com/OmniSharp/omnisharp-vscode/pull/4738, then format-on-save should be possible to enable in VSCode for C# and Visual Basic sources.
42+
43+
#### C/C++
44+
45+
VSCode ships with a different version of clang-format than we use in this repo, so you will need to add a few more settings to get VSCode to run the correct clang-format for "format-on-save".
46+
47+
You can add the following setting on Windows to your `.vscode/settings.json` file to configure clang-format for the repository:
48+
49+
```json
50+
"C_Cpp.clang_format_path": "./artifacts/tools/clang-format.exe"
51+
```
52+
53+
On non-Windows, you can add the following setting instead:
54+
55+
```json
56+
"C_Cpp.clang_format_path": "./artifacts/tools/clang-format"
57+
```
58+
59+
### Visual Studio
60+
61+
Visual Studio does not have a "format-on-save" feature but it does have settings for "format on end of statement" or "format on end of block" that can provide some auto-formatting features.
62+
63+
Using these features in combination with the steps specified in the [Git Hooks](#git-hooks) section will enable a seamless formatting experience.
64+
65+
The settings for C#, VB, C, and C++ are all in a dialog under the `Tools > Options` menu item.
66+
67+
#### C#/VB
68+
69+
In the options view, go to `Text Editor > C# > Code Style > Formatting > General` for C# settings. Make sure to check the various options for whenever you want Visual Studio to auto-format your code.
70+
71+
![C# formatting settings in Visual Studio](./vs-csharp-formatting.png)
72+
73+
#### C/C++
74+
75+
In the options view, go to `Text Editor > C/C++ > Code Style > Formatting > General` for C# settings. Make sure to check the various options for whenever you want Visual Studio to auto-format your code.
76+
77+
![C/C++ formatting settings in Visual Studio](./vs-cpp-formatting.png)
78+
79+
### Git Hooks
80+
81+
Git provides a number of hooks to enable running scripts before commit, push, pull, etc. This section describes adding a pre-commit hook to automatically format code before committing to make formatting seamless even when your development environment doesn't support "format-on-save" or similar functionality with the formatting tools this repository uses.
82+
83+
#### Auto-format before committing
84+
85+
To enable auto-formatting before committing, you can create a `.git/hooks/pre-commit` file in your local `dotnet/runtime` clone and add a call to the script located at `eng/formatting/format.sh` to auto-format your code before committing. Since Git for Windows also installs Git Bash, this script will work for both Windows and non-Windows platforms.
86+
87+
The following code block can be used as the contents of the `pre-commit` file to enable the auto-formatting hook:
88+
89+
```sh
90+
#!/bin/sh
91+
./eng/formatting/format.sh
92+
93+
```

docs/coding-guidelines/coding-style.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
C# Coding Style
22
===============
33

4-
For C++ files (*.cpp and *.h), we use clang-format (version 3.6+) to ensure code styling. After changing any Cpp or H file and before merging, src/Native/format-code.sh must be run. This script will ensure that all native code files adhere to the coding style guidelines.
4+
For C++ files (*.cpp and *.h), we use clang-format (version 3.8) to ensure code styling. After changing any Cpp or H file and before merging, src/Native/format-code.sh must be run. This script will ensure that all native code files adhere to the coding style guidelines.
55

66
For other types of files (xml, bat, sh, etc), our current best guidance is consistency. When editing files, keep new code and changes consistent with the style in the files. For new files, it should conform to the style for that component. If there is a completely new component, anything that is reasonably broadly accepted is fine. For script files, please refer to the scripting blog for [tips](https://devblogs.microsoft.com/scripting/tag/powertip) and [best practices](https://devblogs.microsoft.com/scripting/tag/best-practices).
77

65.8 KB
Loading
48.1 KB
Loading

eng/formatting/download-tools.ps1

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
2+
function DownloadClangTool
3+
{
4+
param (
5+
[string]
6+
$toolName,
7+
[string]
8+
$downloadOutputPath
9+
)
10+
11+
$baseUri = "https://clrjit.blob.core.windows.net/clang-tools/windows"
12+
13+
if (-not $(ls $downloadOutputPath | Where-Object {$_.Name -eq "$toolName.exe"}))
14+
{
15+
$baseBackoffSeconds = 2;
16+
17+
$success = $false
18+
for ($i = 0; $i -lt 5; $i++) {
19+
echo "Attempting download of '$baseUri/$toolName.exe'"
20+
$status = Invoke-WebRequest -Uri "$baseUri/$toolName.exe" -OutFile $(Join-Path $downloadOutputPath -ChildPath "$toolName.exe")
21+
if ($status.StatusCode -lt 400)
22+
{
23+
$success = $true
24+
break
25+
} else {
26+
echo "Download attempt $($i+1) failed. Trying again in $($baseBackoffSeconds + $baseBackoffSeconds * $i) seconds"
27+
Start-Sleep -Seconds $($baseBackoffSeconds + $baseBackoffSeconds * $i)
28+
}
29+
}
30+
if (-not $success)
31+
{
32+
Write-Output "Failed to download clang-format"
33+
return 1
34+
}
35+
}
36+
}
37+
38+
$downloadPathFolder = Split-Path $PSScriptRoot -Parent | Split-Path -Parent | Join-Path -ChildPath "artifacts" | Join-Path -ChildPath "tools"
39+
40+
mkdir $downloadPathFolder -ErrorAction SilentlyContinue
41+
42+
DownloadClangTool "clang-format" "$downloadPathFolder"
43+
DownloadClangTool "clang-tidy" "$downloadPathFolder"
44+
45+
# Add to path to enable scripts to skip additional downloading steps since the tools will already be on the path.
46+
$env:PATH = "$downloadPathFolder;$env:PATH"

eng/formatting/download-tools.sh

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#!/usr/bin/env bash
2+
3+
set -ue
4+
5+
source="${BASH_SOURCE[0]}"
6+
7+
# resolve $source until the file is no longer a symlink
8+
while [[ -h "$source" ]]; do
9+
scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
10+
source="$(readlink "$source")"
11+
# if $source was a relative symlink, we need to resolve it relative to the path where the
12+
# symlink file was located
13+
[[ $source != /* ]] && source="$scriptroot/$source"
14+
done
15+
scriptroot="$( cd -P "$( dirname "$source" )" && pwd )"
16+
17+
function DownloadClangTool {
18+
targetPlatform=$(dotnet --info |grep RID:)
19+
targetPlatform=${targetPlatform##*RID:* }
20+
21+
toolUrl=https://clrjit.blob.core.windows.net/clang-tools/${targetPlatform}/$1
22+
toolOutput=$2/$1
23+
24+
if [[ ! -x "$toolOutput" ]]; then
25+
curl --retry 5 -o "${toolOutput}" "$toolUrl"
26+
chmod 751 $toolOutput
27+
fi
28+
29+
if [[ ! -x "$toolOutput" ]]; then
30+
echo "Failed to download $1"
31+
exit 1
32+
fi
33+
}
34+
35+
36+
engFolder="$(cd -P "$( dirname "$scriptroot" )" && pwd )"
37+
downloadPathFolder="$(cd -P "$( dirname "$engFolder" )" && pwd )/artifacts/tools"
38+
39+
mkdir -p "$downloadPathFolder"
40+
41+
. "$scriptroot/../common/tools.sh"
42+
43+
InitializeDotNetCli true
44+
45+
DownloadClangTool "clang-format" "$downloadPathFolder"
46+
DownloadClangTool "clang-tidy" "$downloadPathFolder"
47+
48+
export PATH=$downloadPathFolder:$PATH

eng/formatting/format.sh

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#!/bin/sh
2+
3+
LC_ALL=C
4+
# Select files to format
5+
NATIVE_FILES=$(git diff --cached --name-only --diff-filter=ACM "*.h" "*.hpp" "*.c" "*.cpp" "*.inl" | sed 's| |\\ |g')
6+
MANAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM "*.cs" "*.vb" | sed 's| |\\ |g')
7+
8+
exec 1>&2
9+
10+
if [[ -n "$NATIVE_FILES" ]]; then
11+
# Format all selected files
12+
echo "$NATIVE_FILES" | cat | xargs | sed -e 's/ /,/g' | xargs "./artifacts/tools/clang-format" -style=file -i
13+
14+
# Add back the modified files to staging
15+
echo "$NATIVE_FILES" | xargs git add
16+
fi
17+
if [[ -n "$MANAGED_FILES" ]]; then
18+
# Format all selected files
19+
echo "$MANAGED_FILES" | cat | xargs | sed -e 's/ /,/g' | dotnet format --include
20+
21+
# Add back the modified files to staging
22+
echo "$MANAGED_FILES" | xargs git add
23+
fi
24+
25+
26+
exit 0

src/tests/Common/scripts/format.py

+17
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,23 @@ def main(argv):
105105

106106
my_env = os.environ
107107

108+
# Download formatting tools
109+
repoRoot = os.path.dirname(os.path.dirname(coreclr))
110+
formattingScriptFolder = os.path.join(repoRoot, "eng", "formatting")
111+
formattingDownloadScriptCommand = []
112+
if platform == 'Linux' or platform == 'OSX':
113+
formattingDownloadScriptCommand = [os.path.join(formattingScriptFolder, "download-tools.sh")]
114+
elif platform == 'windows':
115+
formattingDownloadScriptCommand = ["powershell", os.path.join(formattingScriptFolder, "download-tools.ps1")]
116+
117+
proc = subprocess.Popen(formattingDownloadScriptCommand)
118+
119+
if proc.wait() != 0:
120+
print("Formatting tool download failed")
121+
return -1
122+
123+
my_env["PATH"] = os.path.join(repoRoot, "artifacts", "tools") + os.pathsep + my_env["PATH"]
124+
108125
# Download bootstrap
109126

110127
bootstrapFilename = ""

0 commit comments

Comments
 (0)