Skip to content

Commit 37a1758

Browse files
authored
[Xamarin.Android.Build.Tasks] Improve aapt2+file not found handling (#7644)
Context: #7639 If a project has a long path name, this can cause `aapt2` to fail: error APT2000: The system cannot find the file specified. (2). This is not very helpful since there is no obvious reason to the user as to *why* the build is failing. We should do better. We *can* do better. Catch this specific error message and report a helpful, actionable message instead. error APT2264: This is probably caused by the project exceeding the Windows maximum path length limitation. See https://learn.microsoft.com/xamarin/android/errors-and-warnings/apt2264 for details. In this case we will advise the user that the path is probably too long and they should consult the documentation on how to resolve it. The documentation includes a number of options for resolutions, so it should cover all use cases. Generally these are: 1. Move the project closer to the root of the drive. 2. Enable long path support in windows. 3. Make changes to the `$(BaseIntermediateOutputPath)` MSBuild property to move only the `obj` folder closer to the drive root. Most users can get away with (1), though with Maui and Blazor based apps this might not solve the problem as the project itself might have a deep folder structure. Options (2) and (3) are available to cover those scenarios.
1 parent fc34ead commit 37a1758

File tree

5 files changed

+91
-3
lines changed

5 files changed

+91
-3
lines changed

Documentation/guides/messages/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ ms.date: 01/24/2020
3030
+ APT0002: Invalid file name: It must contain only \[^a-zA-Z0-9_.-\]+.
3131
+ APT0003: Invalid file name: It must contain only \[^a-zA-Z0-9_.\]+.
3232
+ APT0004: Invalid file name: It must start with either A-Z or a-z or an underscore.
33+
+ [APT2264](apt2264.md): The system cannot find the file specified. (2).
3334

3435
## JAVAxxxx: Java Tool
3536

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
---
2+
title: Xamarin.Android error APT2264
3+
description: APT2264 error code
4+
ms.date: 12/16/2022
5+
---
6+
# Xamarin.Android error APT2264
7+
8+
## Issue
9+
10+
The tool `aapt2` is unable to resolve one of the files it was passed.
11+
This is generally caused by the path being longer than the Maximum Path
12+
length allowed on windows.
13+
14+
## Solution
15+
16+
The best way to avoid this is to ensure that your project is not located
17+
deep in the folder structure. For example if you create all of your
18+
projects in folders such as
19+
20+
`C:\Users\shelly\Visual Studio\Android\MyProjects\Com.SomeReallyLongCompanyName.MyBrillantApplication\MyBrilliantApplicaiton.Android\`
21+
22+
you may well encounter problems with not only `aapt2` but also Ahead of Time
23+
compilation. Keeping your project names and folder structures short and
24+
concise will help work around these issues. For example instead of the above
25+
you could use
26+
27+
`C:\Work\Android\MyBrilliantApp`
28+
29+
Which is much shorter and much less likely to encounter path issues.
30+
31+
However this is no always possible. Sometimes a project or a environment requires
32+
deep folder structures. In this case enabling long path support in Windows *might*
33+
be enough to get your project working. Details on how to do this can be found
34+
[here](https://learn.microsoft.com/windows/win32/fileio/maximum-file-path-limitation?tabs=registry#enable-long-paths-in-windows-10-version-1607-and-later).
35+
36+
37+
If long path support does not work changing the location of the
38+
`$(BaseIntermediateOutputPath)` can help solve these problems. In order for this
39+
to work the setting MUST be changed before ANY build or restore occurs. To do this
40+
you can make use of the MSBuild `Directory.Build.props` support.
41+
42+
Creating a `Directory.Build.props` file in your solution or project directory which
43+
redefines the `$(BaseIntermediateOutputPath)` to somewhere nearer the root of the drive
44+
with solve these issues. Adding a file with the following contents will create the `obj`
45+
directory in a different location of your choosing.
46+
47+
```
48+
<Project>
49+
<PropertyGroup>
50+
<BaseIntermediateOutputPath Condition=" '$(OS)' == 'Windows_NT' ">C:\Intermediate\$(ProjectName)</BaseIntermediateOutputPath>
51+
<BaseIntermediateOutputPath Condition=" '$(OS)' != 'Windows_NT' ">/tmp/Intermediate/$(ProjectName)</BaseIntermediateOutputPath>
52+
</PropertyGroup>
53+
</Project
54+
```
55+
56+
Using this technique will reduce the lengths of the paths sent to the various tools like `aapt2`.
57+
Note this is generally only a Windows issue. So there is no need to override the `$(BaseIntermediateOutputPath)`
58+
on Mac or Linux based environments. However you might want to override everywhere to be consistent.

src/Xamarin.Android.Build.Tasks/Properties/Resources.Designer.cs

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Xamarin.Android.Build.Tasks/Properties/Resources.resx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,10 @@ Please change the value to an assembly-qualifed type name which inherits from '{
530530
<comment>The following are literal names and should not be translated: Java.Interop.DoNotPackageAttribute
531531
{0} - The assembly name</comment>
532532
</data>
533+
<data name="APT2264" xml:space="preserve">
534+
<value>This is probably caused by the project exceeding the Windows maximum path length limitation. See https://learn.microsoft.com/xamarin/android/errors-and-warnings/apt2264 for details.</value>
535+
<comment>The following are literal names and should not be translated:</comment>
536+
</data>
533537
<data name="XA3001" xml:space="preserve">
534538
<value>Could not AOT the assembly: {0}</value>
535539
<comment>The abbreviation "AOT" should not be translated.</comment>

src/Xamarin.Android.Build.Tasks/Tasks/Aapt2.cs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -188,23 +188,38 @@ protected bool LogAapt2EventsFromOutput (string singleLine, MessageImportance me
188188
message = message.Substring ("error: ".Length);
189189

190190
if (level.Contains ("error") || (line != 0 && !string.IsNullOrEmpty (file))) {
191+
var errorCode = GetErrorCode (message);
191192
if (manifestError)
192-
LogCodedError (GetErrorCode (message), string.Format (Xamarin.Android.Tasks.Properties.Resources.AAPTManifestError, message.TrimEnd('.')), AndroidManifestFile.ItemSpec, 0);
193+
LogCodedError (errorCode, string.Format (Xamarin.Android.Tasks.Properties.Resources.AAPTManifestError, message.TrimEnd('.')), AndroidManifestFile.ItemSpec, 0);
193194
else
194-
LogCodedError (GetErrorCode (message), message, file, line);
195+
LogCodedError (errorCode, AddAdditionalErrorText (errorCode, message), file, line);
195196
return true;
196197
}
197198
}
198199

199200
if (!apptResult) {
200201
var message = string.Format ("{0} \"{1}\".", singleLine.Trim (), singleLine.Substring (singleLine.LastIndexOfAny (new char [] { '\\', '/' }) + 1));
201-
LogCodedError (GetErrorCode (message), message, ToolName);
202+
var errorCode = GetErrorCode (message);
203+
LogCodedError (errorCode, AddAdditionalErrorText (errorCode, message), ToolName);
202204
} else {
203205
LogCodedWarning (GetErrorCode (singleLine), singleLine);
204206
}
205207
return true;
206208
}
207209

210+
static string AddAdditionalErrorText (string errorCode, string message)
211+
{
212+
var sb = new StringBuilder ();
213+
sb.AppendLine (message);
214+
switch (errorCode)
215+
{
216+
case "APT2264":
217+
sb.AppendLine (Xamarin.Android.Tasks.Properties.Resources.APT2264);
218+
break;
219+
}
220+
return sb.ToString ();
221+
}
222+
208223
static string GetErrorCode (string message)
209224
{
210225
foreach (var tuple in error_codes)
@@ -478,6 +493,7 @@ static string GetErrorCode (string message)
478493
Tuple.Create ("APT2261", "file failed to compile"),
479494
Tuple.Create ("APT2262", "unexpected element <activity> found in <manifest>"),
480495
Tuple.Create ("APT2263", "found in <manifest>"), // unexpected element <xxxxx> found in <manifest>
496+
Tuple.Create ("APT2264", "The system cannot find the file specified. (2).") // Windows Long Path error from aapt2
481497
};
482498
}
483499
}

0 commit comments

Comments
 (0)