Skip to content

Commit 0418e7b

Browse files
authored
Debugging MSBuild Tasks (#8730)
* Debugging MSBuild Tasks One thing that is very useful is the ability to debug your Tasks while they are being run on a build process. This is possible thanks to the `MSBUILDDEBUGONSTART` environment variable. When set to `2` this will force MSBuild to wait for a debugger connection before continuing. You will see the following prompt. ```dotnetcli Waiting for debugger to attach (dotnet PID 13001). Press enter to continue... ``` You can then use VS or VSCode to attach to this process and debug you tasks. In the case of .NET Android we need to do a couple of thing first though. Firstly we need to disable the use of `ILRepacker` on the `Xamarin.Android.Build.Tasks` assembly. This is because `ILRepacker` does NOT handle debug symbols very well. Assemblies it generates seem to be JIT optimized so the debugger will not load the symbols. A new MSBuild property has been introduced to disable this feature while debugging. `_ILRepackEnabled` can be set as an environment variable which MSBuild will pickup. ```dotnetcli make prepare && _ILRepackEnabled=false make jenkins ``` This will disable the `ILRepacker` for the build. You can then start your test app with the `dotnet-local` script (so it uses your build) ```dotnetcli MSBUILDDEBUGONSTART=2 ~/<some xamarin.android checkout>/dotnet-local.sh build -m:1 ``` Once MSBuild starts it will print the following ```dotnetcli Waiting for debugger to attach (dotnet PID xxxx). Press enter to continue... ``` You need to copy the PID value so we can use this in the IDE. For Visual Studio you can use the `Attach to Process` menu option, while you have the Xamarin.Android.sln solution open. For VSCode open the workspace then use the `Debug MSBuild Task` Run and Debug option. You will be prompted for the PID and it will then connect. Once connection go back to your command prompt and press ENTER so that the MSBuild process can continue. You will be able to set breakpoints in Tasks (but not Targets) and step through code from this point on.
1 parent e987ac4 commit 0418e7b

File tree

4 files changed

+97
-5
lines changed

4 files changed

+97
-5
lines changed

.vscode/launch.json

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@
4444
"port": 10000,
4545
"preLaunchTask": "run-sample-under-dotnet",
4646
},
47+
{
48+
"name": "Attach to Process",
49+
"type": "coreclr",
50+
"request": "attach",
51+
"processId": "${input:processid}"
52+
}
4753
],
4854
"inputs": [
4955
{
@@ -52,6 +58,12 @@
5258
"default": "Debug",
5359
"description": "The Build Configuration",
5460
"options": [ "Debug", "Release"]
55-
}
61+
},
62+
{
63+
"id": "processid",
64+
"type": "promptString",
65+
"default": "0",
66+
"description": "Enter dotnet build process id reported when setting the env var MSBUILDDEBUGONSTART=2",
67+
},
5668
]
5769
}

.vscode/tasks.json

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,8 @@
127127
"label": "build-sample-under-dotnet",
128128
"type": "shell",
129129
"windows": { "command": "dotnet-local.cmd build ${input:project} -p:Configuration=${input:configuration} -t:${input:target} -bl:${input:target}.binlog", },
130-
"linux": { "command": "./dotnet-local.sh build ${input:project} -p:Configuration=${input:configuration} -t:${input:target} -bl:${input:target}.binlog",},
131-
"osx": { "command": "./dotnet-local.sh build ${input:project} -p:Configuration=${input:configuration} -t:${input:target} -bl:${input:target}.binlog",},
130+
"linux": { "command": "${input:debugbuildtasks} ./dotnet-local.sh build ${input:project} -p:Configuration=${input:configuration} -t:${input:target} -bl:${input:target}.binlog",},
131+
"osx": { "command": "${input:debugbuildtasks} ./dotnet-local.sh build ${input:project} -p:Configuration=${input:configuration} -t:${input:target} -bl:${input:target}.binlog",},
132132
"group": {
133133
"kind": "build",
134134
"isDefault": true
@@ -141,8 +141,8 @@
141141
"label": "run-sample-under-dotnet",
142142
"type": "shell",
143143
"windows": { "command": "dotnet-local.cmd build ${input:project} \"-t:Run\" --no-restore -p:TargetFramework=${input:targetframework} -p:Configuration=${input:configuration} -p:AndroidAttachDebugger=${input:attach} -bl:run.binlog", },
144-
"linux": { "command": "./dotnet-local.sh build ${input:project} \"-t:Run\" --no-restore -p:TargetFramework=${input:targetframework} -p:Configuration=${input:configuration} -p:AndroidAttachDebugger=${input:attach} -bl:run.binlog",},
145-
"osx": { "command": "./dotnet-local.sh build ${input:project} \"-t:Run\" --no-restore -p:TargetFramework=${input:targetframework} -p:Configuration=${input:configuration} -p:AndroidAttachDebugger=${input:attach} -bl:run.binlog",},
144+
"linux": { "command": "${input:debugbuildtasks} ./dotnet-local.sh build ${input:project} \"-t:Run\" --no-restore -p:TargetFramework=${input:targetframework} -p:Configuration=${input:configuration} -p:AndroidAttachDebugger=${input:attach} -bl:run.binlog",},
145+
"osx": { "command": "${input:debugbuildtasks} ./dotnet-local.sh build ${input:project} \"-t:Run\" --no-restore -p:TargetFramework=${input:targetframework} -p:Configuration=${input:configuration} -p:AndroidAttachDebugger=${input:attach} -bl:run.binlog",},
146146
"group": {
147147
"kind": "build",
148148
"isDefault": true
@@ -220,5 +220,15 @@
220220
"Everything",
221221
]
222222
},
223+
{
224+
"id": "debugbuildtasks",
225+
"type": "pickString",
226+
"default": "",
227+
"description": "Debug Build Tasks?",
228+
"options": [
229+
"",
230+
"MSBUILDDEBUGONSTART=2"
231+
]
232+
},
223233
]
224234
}

Documentation/guides/MSBuildBestPractices.md

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,74 @@ This guide is a work-in-progress, but really has two main goals:
55
- What are good MSBuild practice in relation to what we already have
66
going on in Xamarin.Android MSBuild targets?
77

8+
## Debugging MSBuild Tasks
9+
10+
One thing that is very useful is the ability to debug your Tasks while
11+
they are being run on a build process. This is possible thanks to the
12+
`MSBUILDDEBUGONSTART` environment variable. When set to `2` this will
13+
force MSBuild to wait for a debugger connection before continuing.
14+
You will see the following prompt.
15+
16+
```dotnetcli
17+
Waiting for debugger to attach (dotnet PID 13001). Press enter to continue...
18+
```
19+
20+
You can then use VS or VSCode to attach to this process and debug you tasks.
21+
22+
In the case of .NET Android we need to do a couple of thing first though. Firstly
23+
we need to disable the use of `ILRepacker` on the `Xamarin.Android.Build.Tasks`
24+
assembly. This is because `ILRepacker` does NOT handle debug symbols very well.
25+
Assemblies it generates seem to be JIT optimized so the debugger will not load
26+
the symbols. A new MSBuild property has been introduced to disable this feature
27+
while debugging. `_ILRepackEnabled` can be set as an environment variable which
28+
MSBuild will pickup. You will also need to build the `Debug` Configuration.
29+
30+
```dotnetcli
31+
export CONFIGURATION=Debug
32+
make prepare && _ILRepackEnabled=false make jenkins
33+
```
34+
35+
This will disable the `ILRepacker` for the build.
36+
37+
You can then start your test app with the `dotnet-local` script (so it uses your build)
38+
39+
### [MacOS](#tab/macos)
40+
41+
```dotnetcli
42+
MSBUILDDEBUGONSTART=2 ~/<some xamarin.android checkout>/dotnet-local.sh build -m:1
43+
```
44+
45+
### [Linux](#tab/linux)
46+
47+
```dotnetcli
48+
MSBUILDDEBUGONSTART=2 ~/<some xamarin.android checkout>/dotnet-local.sh build -m:1
49+
```
50+
51+
### [Windows](#tab/windows)
52+
53+
```dotnetcli
54+
set MSBUILDDEBUGONSTART=2
55+
~/<some xamarin.android checkout>/dotnet-local.cmd build -m:1
56+
```
57+
58+
---
59+
60+
Note: the `-m:1` is important as it restricts MSBuild to 1 node.
61+
62+
Once MSBuild starts it will print the following
63+
64+
```dotnetcli
65+
Waiting for debugger to attach (dotnet PID xxxx). Press enter to continue...
66+
```
67+
68+
You need to copy the PID value so we can use this in the IDE. For Visual Studio you can use the `Attach to Process` menu option, while you have the Xamarin.Android.sln solution open. For VSCode open the workspace then use the `Attach to Process` Run and Debug option. You will be prompted for the PID and it will then connect.
69+
70+
Once connected go back to your command prompt and press ENTER so that the MSBuild process can continue.
71+
72+
You will be able to set breakpoints in Tasks (but not Targets) and step through code from this point on.
73+
74+
If you want to test in-tree using the same the `build-sample-under-dotnet` command will ask you if you want to debug MSBuild tasks and fill in the `MSBUILDDEBUGONSTART` for you. The PID text will appear in the `Terminal` window in VSCode. In addition the `run-sample-under-dotnet` command will ask the same.
75+
876
## Naming
977

1078
MSBuild targets, properties, and item groups are prefixed with an

src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.targets

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
<_MultiDexAarInAndroidSdk>extras\android\m2repository\com\android\support\multidex\1.0.1\multidex-1.0.1.aar</_MultiDexAarInAndroidSdk>
2929
<_SupportLicense Condition="Exists('$(_AndroidSdkLocation)\extras\android\m2repository\NOTICE.txt')">$(_AndroidSdkLocation)\extras\android\m2repository\NOTICE.txt</_SupportLicense>
3030
<_SupportLicense Condition="Exists('$(_AndroidSdkLocation)\extras\android\m2repository\m2repository\NOTICE.txt')">$(_AndroidSdkLocation)\extras\android\m2repository\m2repository\NOTICE.txt</_SupportLicense>
31+
<_ILRepackEnabled Condition=" '$(_ILRepackEnabled)' == '' ">true</_ILRepackEnabled>
3132
</PropertyGroup>
3233
<ItemGroup>
3334
<None
@@ -271,6 +272,7 @@
271272
</ItemGroup>
272273

273274
<Target Name="ILRepacker"
275+
Condition=" '$(_ILRepackEnabled)' == 'true' "
274276
BeforeTargets="CopyFilesToOutputDirectory"
275277
Inputs="$(MSBuildAllProjects);@(IntermediateAssembly);@(InputAssemblies)"
276278
Outputs="$(IntermediateOutputPath)ILRepacker.stamp" >

0 commit comments

Comments
 (0)