From 8eb66763ac700820e22e26248c679fb2ccb641ea Mon Sep 17 00:00:00 2001 From: Dean Ellis Date: Fri, 16 Feb 2024 09:33:56 +0000 Subject: [PATCH 1/6] 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 ~//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. --- .vscode/launch.json | 12 +++++ Documentation/guides/MSBuildBestPractices.md | 46 +++++++++++++++++++ .../Xamarin.Android.Build.Tasks.targets | 2 + 3 files changed, 60 insertions(+) diff --git a/.vscode/launch.json b/.vscode/launch.json index 777abde3cf6..4a6ce142d66 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -44,6 +44,12 @@ "port": 10000, "preLaunchTask": "run-sample-under-dotnet", }, + { + "name": "Debug MSBuild Task", + "type": "coreclr", + "request": "attach", + "processId": "${input:processid}" + } ], "inputs": [ { @@ -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", } ] } diff --git a/Documentation/guides/MSBuildBestPractices.md b/Documentation/guides/MSBuildBestPractices.md index bca45d30b5e..64e5a89b9ff 100644 --- a/Documentation/guides/MSBuildBestPractices.md +++ b/Documentation/guides/MSBuildBestPractices.md @@ -5,6 +5,52 @@ 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. + +```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 ~//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. + ## Naming MSBuild targets, properties, and item groups are prefixed with an diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.targets index 081fbb15896..91a88bedf80 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Build.Tasks.targets @@ -28,6 +28,7 @@ <_MultiDexAarInAndroidSdk>extras\android\m2repository\com\android\support\multidex\1.0.1\multidex-1.0.1.aar <_SupportLicense Condition="Exists('$(_AndroidSdkLocation)\extras\android\m2repository\NOTICE.txt')">$(_AndroidSdkLocation)\extras\android\m2repository\NOTICE.txt <_SupportLicense Condition="Exists('$(_AndroidSdkLocation)\extras\android\m2repository\m2repository\NOTICE.txt')">$(_AndroidSdkLocation)\extras\android\m2repository\m2repository\NOTICE.txt + <_ILRepackEnabled Condition=" '$(_ILRepackEnabled)' == '' ">true From ce859e636c1eb76055ffff9f262af8f765888702 Mon Sep 17 00:00:00 2001 From: Dean Ellis Date: Fri, 16 Feb 2024 09:39:08 +0000 Subject: [PATCH 2/6] Update docs --- Documentation/guides/MSBuildBestPractices.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/guides/MSBuildBestPractices.md b/Documentation/guides/MSBuildBestPractices.md index 64e5a89b9ff..c1c1a934184 100644 --- a/Documentation/guides/MSBuildBestPractices.md +++ b/Documentation/guides/MSBuildBestPractices.md @@ -39,6 +39,8 @@ You can then start your test app with the `dotnet-local` script (so it uses your MSBUILDDEBUGONSTART=2 ~//dotnet-local.sh 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 From 5ef39fbd25cad990e39f9fe093dfdc153625532c Mon Sep 17 00:00:00 2001 From: Dean Ellis Date: Fri, 16 Feb 2024 09:52:21 +0000 Subject: [PATCH 3/6] more docs --- Documentation/guides/MSBuildBestPractices.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/guides/MSBuildBestPractices.md b/Documentation/guides/MSBuildBestPractices.md index c1c1a934184..55dd95bd8c1 100644 --- a/Documentation/guides/MSBuildBestPractices.md +++ b/Documentation/guides/MSBuildBestPractices.md @@ -25,9 +25,10 @@ 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. +MSBuild will pickup. You will also need to build the `Debug` Configuration. ```dotnetcli +export CONFIGURATION=Debug make prepare && _ILRepackEnabled=false make jenkins ``` From 6f180c025b7b77d9411410bde96f74c6bb70444e Mon Sep 17 00:00:00 2001 From: Dean Ellis Date: Fri, 16 Feb 2024 13:19:48 +0000 Subject: [PATCH 4/6] Fix docs --- Documentation/guides/MSBuildBestPractices.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/guides/MSBuildBestPractices.md b/Documentation/guides/MSBuildBestPractices.md index 55dd95bd8c1..6c26e383170 100644 --- a/Documentation/guides/MSBuildBestPractices.md +++ b/Documentation/guides/MSBuildBestPractices.md @@ -50,7 +50,7 @@ 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. +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. From 88c356743948286846de1772ac18b86cd4ebeea0 Mon Sep 17 00:00:00 2001 From: Dean Ellis Date: Fri, 16 Feb 2024 15:12:28 +0000 Subject: [PATCH 5/6] Update docs and launch task names --- .vscode/launch.json | 4 ++-- .vscode/tasks.json | 18 +++++++++++++---- Documentation/guides/MSBuildBestPractices.md | 21 +++++++++++++++++++- 3 files changed, 36 insertions(+), 7 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 4a6ce142d66..8917bb93a8a 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -45,7 +45,7 @@ "preLaunchTask": "run-sample-under-dotnet", }, { - "name": "Debug MSBuild Task", + "name": "Attach to Process", "type": "coreclr", "request": "attach", "processId": "${input:processid}" @@ -64,6 +64,6 @@ "type": "promptString", "default": "0", "description": "Enter dotnet build process id reported when setting the env var MSBUILDDEBUGONSTART=2", - } + }, ] } diff --git a/.vscode/tasks.json b/.vscode/tasks.json index e79dfcacc8d..4b652be3076 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -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 @@ -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 @@ -220,5 +220,15 @@ "Everything", ] }, + { + "id": "debugbuildtasks", + "type": "pickString", + "default": "", + "description": "Debug Build Tasks?", + "options": [ + "", + "MSBUILDDEBUGONSTART=2" + ] + }, ] } \ No newline at end of file diff --git a/Documentation/guides/MSBuildBestPractices.md b/Documentation/guides/MSBuildBestPractices.md index 6c26e383170..24fdd647792 100644 --- a/Documentation/guides/MSBuildBestPractices.md +++ b/Documentation/guides/MSBuildBestPractices.md @@ -36,10 +36,27 @@ 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 ~//dotnet-local.sh build -m:1 +``` + +### [MacOS](#tab/linux) + ```dotnetcli MSBUILDDEBUGONSTART=2 ~//dotnet-local.sh build -m:1 ``` +### [Windows](#tab/windows) + +```dotnetcli +set MSBUILDDEBUGONSTART=2 +~//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 @@ -48,12 +65,14 @@ Once MSBuild starts it will print the following 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. +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 From 26e3ff920f8026e8facd9b8ad4f298a255e1a76b Mon Sep 17 00:00:00 2001 From: Dean Ellis Date: Fri, 16 Feb 2024 15:19:32 +0000 Subject: [PATCH 6/6] rename MacOS->Linux --- Documentation/guides/MSBuildBestPractices.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/guides/MSBuildBestPractices.md b/Documentation/guides/MSBuildBestPractices.md index 24fdd647792..69c1b49d057 100644 --- a/Documentation/guides/MSBuildBestPractices.md +++ b/Documentation/guides/MSBuildBestPractices.md @@ -42,7 +42,7 @@ You can then start your test app with the `dotnet-local` script (so it uses your MSBUILDDEBUGONSTART=2 ~//dotnet-local.sh build -m:1 ``` -### [MacOS](#tab/linux) +### [Linux](#tab/linux) ```dotnetcli MSBUILDDEBUGONSTART=2 ~//dotnet-local.sh build -m:1