Skip to content

Commit

Permalink
Merge branch 'main' into dev/grendel/xxhash3
Browse files Browse the repository at this point in the history
* main:
  Bump to xamarin/xamarin-android-tools/main@37d79c9 (#8752)
  Bump to dotnet/installer@d070660282 9.0.100-preview.3.24126.2 (#8763)
  Bump to xamarin/java.interop/main@14a9470 (#8766)
  $(AndroidPackVersionSuffix)=preview.3; net9 is 34.99.0.preview.3 (#8765)
  [Mono.Android] Do not dispose request content stream in AndroidMessageHandler (#8764)
  Bump com.android.tools:r8 from 8.2.42 to 8.2.47 (#8761)
  [Mono.Android] fix a set of the "easiest" trimmer warnings (#8731)
  Bump to dotnet/installer@0a73f814e1 9.0.100-preview.2.24122.3 (#8716)
  [ci] Always run the MAUI test job (#8750)
  Add a property required by #8478 (#8749)
  [xamarin-android-tools] import $(LibZipSharpVersion) value (#8738)
  Bump to xamarin/Java.Interop/main@c825dcad (#8701)
  Bump to xamarin/monodroid@cb01503327 (#8742)
  Bump to xamarin/Java.Interop/main@ae65609 (#8744)
  Bring in changes from PR #8478 (#8727)
  [xaprepare] Make 7zip work with "dangerous" symlinks in ZIPs (#8737)
  Bump NDK to r26c (#8732)
  Debugging MSBuild Tasks (#8730)
  • Loading branch information
grendello committed Feb 28, 2024
2 parents b86a1c5 + 4a2179c commit ab8db9b
Show file tree
Hide file tree
Showing 46 changed files with 1,070 additions and 345 deletions.
2 changes: 1 addition & 1 deletion .external
Original file line number Diff line number Diff line change
@@ -1 +1 @@
xamarin/monodroid:main@848d1277b76a599d8a280d58ec06e95477b4a7e5
xamarin/monodroid:main@cb01503327f7723ec138ec4cc051610fecee1bf7
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"
]
},
]
}
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
* Bump first digit of the patch version for feature releases (and reset the first two digits to 0)
-->
<AndroidPackVersion>34.99.0</AndroidPackVersion>
<AndroidPackVersionSuffix>preview.2</AndroidPackVersionSuffix>
<AndroidPackVersionSuffix>preview.3</AndroidPackVersionSuffix>
</PropertyGroup>

<!-- Common <PackageReference/> versions -->
Expand Down
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
2 changes: 1 addition & 1 deletion build-tools/automation/azure-pipelines.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ stages:
- stage: maui_tests
displayName: MAUI Tests
dependsOn: mac_build
condition: and(eq(dependencies.mac_build.result, 'Succeeded'), eq(variables['System.PullRequest.TargetBranch'], 'main'))
condition: and(eq(dependencies.mac_build.result, 'Succeeded'), eq(variables['RunMAUITestJob'], 'true'))
jobs:
# Check - "Xamarin.Android (MAUI Tests MAUI Integration)"
- job: maui_tests_integration
Expand Down
2 changes: 2 additions & 0 deletions build-tools/automation/yaml-templates/variables.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,5 @@ variables:
value: 34
- name: ExcludedNightlyNUnitCategories
value: 'cat != SystemApplication & cat != TimeZoneInfo & cat != Localization'
- name: RunMAUITestJob
value: true
Original file line number Diff line number Diff line change
Expand Up @@ -12,78 +12,78 @@ namespace Xamarin.Android.Prepare
/// <see cref="VersionOutputLine"/> is set to any other value only that line is taken into consideration. This is
/// done to make processing less ambiguous and faster.
/// </summary>
class RegexProgramVersionParser : ProgramVersionParser
{
const string VersionGroupName = "Version";
static readonly char[] LineSeparator = new [] { '\n' };
class RegexProgramVersionParser : ProgramVersionParser
{
public const string VersionGroupName = "Version";
public static readonly char[] LineSeparator = new [] { '\n' };

Regex rx;
Regex rx;

public RegexProgramVersionParser (string programName, string versionArguments, Regex regex, uint versionOutputLine = 0, Log? log = null)
: base (programName, versionArguments, versionOutputLine, log)
{
if (regex == null)
throw new ArgumentNullException (nameof (regex));
rx = regex;
}
public RegexProgramVersionParser (string programName, string versionArguments, Regex regex, uint versionOutputLine = 0, Log? log = null)
: base (programName, versionArguments, versionOutputLine, log)
{
if (regex == null)
throw new ArgumentNullException (nameof (regex));
rx = regex;
}

public RegexProgramVersionParser (string programName, string versionArguments, string regex, uint versionOutputLine = 0, Log? log = null)
: base (programName, versionArguments, versionOutputLine, log)
{
if (String.IsNullOrEmpty (regex))
throw new ArgumentException ("must not be null or empty", nameof (regex));
public RegexProgramVersionParser (string programName, string versionArguments, string regex, uint versionOutputLine = 0, Log? log = null)
: base (programName, versionArguments, versionOutputLine, log)
{
if (String.IsNullOrEmpty (regex))
throw new ArgumentException ("must not be null or empty", nameof (regex));

rx = new Regex (regex, RegexOptions.Compiled);
}
rx = new Regex (regex, RegexOptions.Compiled);
}

protected override string ParseVersion (string programOutput)
{
string output = programOutput.Trim ();
if (String.IsNullOrEmpty (output)) {
Log.WarningLine ($"Unable to parse version of {ProgramName} because version output was empty");
return DefaultVersionString;
}
protected override string ParseVersion (string programOutput)
{
string output = programOutput.Trim ();
if (String.IsNullOrEmpty (output)) {
Log.WarningLine ($"Unable to parse version of {ProgramName} because version output was empty");
return DefaultVersionString;
}

string ret = String.Empty;
string[] lines = programOutput.Split (LineSeparator);
if (VersionOutputLine > 0) {
if (lines.Length < VersionOutputLine) {
Log.WarningLine ($"Not enough lines in version output of {ProgramName}: version number was supposed to be found on line {VersionOutputLine} but there are only {lines.Length} lines");
return DefaultVersionString;
}
string ret = String.Empty;
string[] lines = programOutput.Split (LineSeparator);
if (VersionOutputLine > 0) {
if (lines.Length < VersionOutputLine) {
Log.WarningLine ($"Not enough lines in version output of {ProgramName}: version number was supposed to be found on line {VersionOutputLine} but there are only {lines.Length} lines");
return DefaultVersionString;
}

if (TryMatch (lines [VersionOutputLine - 1], out ret) && !String.IsNullOrEmpty (ret)) {
return ret;
}
if (TryMatch (rx, lines [VersionOutputLine - 1], out ret) && !String.IsNullOrEmpty (ret)) {
return ret;
}

return DefaultVersionString;
}
return DefaultVersionString;
}

foreach (string line in lines) {
if (TryMatch (line, out ret))
break;
}
foreach (string line in lines) {
if (TryMatch (rx, line, out ret))
break;
}

return ret ?? DefaultVersionString;
}
return ret ?? DefaultVersionString;
}

bool TryMatch (string line, out string version)
{
version = String.Empty;
public static bool TryMatch (Regex regex, string line, out string version)
{
version = String.Empty;

Match match = rx.Match (line);
if (!match.Success || match.Groups.Count <= 0) {
return false;
}
Match match = regex.Match (line);
if (!match.Success || match.Groups.Count <= 0) {
return false;
}

foreach (Group group in match.Groups) {
if (String.Compare (group.Name, VersionGroupName, StringComparison.OrdinalIgnoreCase) == 0) {
version = group.Value;
return true;
}
}
foreach (Group group in match.Groups) {
if (String.Compare (group.Name, VersionGroupName, StringComparison.OrdinalIgnoreCase) == 0) {
version = group.Value;
return true;
}
}

return false;
}
}
return false;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
using System;
using System.Text.RegularExpressions;

namespace Xamarin.Android.Prepare;

class SevenZipVersionParser : ProgramVersionParser
{
const string VersionArgument = "--help";
readonly Regex fallbackRegex;
readonly Regex modernRegex;

public SevenZipVersionParser (string programName, Regex fallbackRegex, Log? log = null)
: base (programName, VersionArgument, 0, log)
{
this.fallbackRegex = fallbackRegex;
modernRegex = VersionFetchers.MakeRegex (@"^7-Zip (\(a\) ){0,1}(?<Version>[\d]+\.[\d]+)");
}

protected override string ParseVersion (string programOutput)
{
string output = programOutput.Trim ();
if (String.IsNullOrEmpty (output)) {
Log.WarningLine ($"Unable to parse version of {ProgramName} because version output was empty");
return DefaultVersionString;
}

string ret = String.Empty;
string[] lines = programOutput.Split (RegexProgramVersionParser.LineSeparator);

// First try to find the official 7zip release version
foreach (string l in lines) {
string line = l.Trim ();

if (line.Length == 0) {
continue;
}

if (line.StartsWith ("7-Zip", StringComparison.OrdinalIgnoreCase)) {
// Strings of the form:
// 7-Zip 23.01 (x64) : Copyright (c) 1999-2023 Igor Pavlov : 2023-06-20
// 7-Zip (a) 23.01 (x64) : Copyright (c) 1999-2023 Igor Pavlov : 2023-06-20
// 7-Zip (a) 18.01 (x64) : Copyright (c) 1999-2018 Igor Pavlov : 2018-01-28
// 7-Zip (a) 18.01 (x86) : Copyright (c) 1999-2018 Igor Pavlov : 2018-01-28
if (RegexProgramVersionParser.TryMatch (modernRegex, line, out ret)) {
return ret;
}
}

// Since we know we're dealing with `--help` option output, we can short-circuit things
if (line.StartsWith ("Usage:", StringComparison.OrdinalIgnoreCase)) {
break;
}
}

// Modern version wasn't found, try again with the fallback one
foreach (string l in lines) {
string line = l.Trim ();

if (line.Length == 0) {
continue;
}

if (RegexProgramVersionParser.TryMatch (fallbackRegex, line, out ret)) {
return ret;
}
}

return DefaultVersionString;
}
}
Loading

0 comments on commit ab8db9b

Please sign in to comment.