Skip to content

Commit

Permalink
Debugging MSBuild Tasks (#8730)
Browse files Browse the repository at this point in the history
* 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.
  • Loading branch information
dellis1972 authored Feb 19, 2024
1 parent e987ac4 commit 0418e7b
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 5 deletions.
14 changes: 13 additions & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@
"port": 10000,
"preLaunchTask": "run-sample-under-dotnet",
},
{
"name": "Attach to Process",
"type": "coreclr",
"request": "attach",
"processId": "${input:processid}"
}
],
"inputs": [
{
Expand All @@ -52,6 +58,12 @@
"default": "Debug",
"description": "The Build Configuration",
"options": [ "Debug", "Release"]
}
},
{
"id": "processid",
"type": "promptString",
"default": "0",
"description": "Enter dotnet build process id reported when setting the env var MSBUILDDEBUGONSTART=2",
},
]
}
18 changes: 14 additions & 4 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,8 @@
"label": "build-sample-under-dotnet",
"type": "shell",
"windows": { "command": "dotnet-local.cmd build ${input:project} -p:Configuration=${input:configuration} -t:${input:target} -bl:${input:target}.binlog", },
"linux": { "command": "./dotnet-local.sh build ${input:project} -p:Configuration=${input:configuration} -t:${input:target} -bl:${input:target}.binlog",},
"osx": { "command": "./dotnet-local.sh build ${input:project} -p:Configuration=${input:configuration} -t:${input:target} -bl:${input:target}.binlog",},
"linux": { "command": "${input:debugbuildtasks} ./dotnet-local.sh build ${input:project} -p:Configuration=${input:configuration} -t:${input:target} -bl:${input:target}.binlog",},
"osx": { "command": "${input:debugbuildtasks} ./dotnet-local.sh build ${input:project} -p:Configuration=${input:configuration} -t:${input:target} -bl:${input:target}.binlog",},
"group": {
"kind": "build",
"isDefault": true
Expand All @@ -141,8 +141,8 @@
"label": "run-sample-under-dotnet",
"type": "shell",
"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", },
"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",},
"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",},
"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",},
"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",},
"group": {
"kind": "build",
"isDefault": true
Expand Down Expand Up @@ -220,5 +220,15 @@
"Everything",
]
},
{
"id": "debugbuildtasks",
"type": "pickString",
"default": "",
"description": "Debug Build Tasks?",
"options": [
"",
"MSBUILDDEBUGONSTART=2"
]
},
]
}
68 changes: 68 additions & 0 deletions Documentation/guides/MSBuildBestPractices.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,74 @@ This guide is a work-in-progress, but really has two main goals:
- What are good MSBuild practice in relation to what we already have
going on in Xamarin.Android MSBuild targets?

## 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. You will also need to build the `Debug` Configuration.

```dotnetcli
export CONFIGURATION=Debug
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)

### [MacOS](#tab/macos)

```dotnetcli
MSBUILDDEBUGONSTART=2 ~/<some xamarin.android checkout>/dotnet-local.sh build -m:1
```

### [Linux](#tab/linux)

```dotnetcli
MSBUILDDEBUGONSTART=2 ~/<some xamarin.android checkout>/dotnet-local.sh build -m:1
```

### [Windows](#tab/windows)

```dotnetcli
set MSBUILDDEBUGONSTART=2
~/<some xamarin.android checkout>/dotnet-local.cmd build -m:1
```

---

Note: the `-m:1` is important as it restricts MSBuild to 1 node.

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 `Attach to Process` Run and Debug option. You will be prompted for the PID and it will then connect.

Once connected 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.

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.

## Naming

MSBuild targets, properties, and item groups are prefixed with an
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
<_MultiDexAarInAndroidSdk>extras\android\m2repository\com\android\support\multidex\1.0.1\multidex-1.0.1.aar</_MultiDexAarInAndroidSdk>
<_SupportLicense Condition="Exists('$(_AndroidSdkLocation)\extras\android\m2repository\NOTICE.txt')">$(_AndroidSdkLocation)\extras\android\m2repository\NOTICE.txt</_SupportLicense>
<_SupportLicense Condition="Exists('$(_AndroidSdkLocation)\extras\android\m2repository\m2repository\NOTICE.txt')">$(_AndroidSdkLocation)\extras\android\m2repository\m2repository\NOTICE.txt</_SupportLicense>
<_ILRepackEnabled Condition=" '$(_ILRepackEnabled)' == '' ">true</_ILRepackEnabled>
</PropertyGroup>
<ItemGroup>
<None
Expand Down Expand Up @@ -271,6 +272,7 @@
</ItemGroup>

<Target Name="ILRepacker"
Condition=" '$(_ILRepackEnabled)' == 'true' "
BeforeTargets="CopyFilesToOutputDirectory"
Inputs="$(MSBuildAllProjects);@(IntermediateAssembly);@(InputAssemblies)"
Outputs="$(IntermediateOutputPath)ILRepacker.stamp" >
Expand Down

0 comments on commit 0418e7b

Please sign in to comment.