-
Notifications
You must be signed in to change notification settings - Fork 564
[Xamarin.Android.Build.Tasks] Path is too long #700
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
Just wondering if we should come up with even shorter names for the projects to buy us as many extra characters as possible? so "__library_project_imports" -> "lp" (rather than my proposed "lp") |
| // lets "upgrade" the old directory. | ||
| string oldPath = Path.GetFullPath (Path.Combine (OutputImportDirectory, "..", "__library_projects__")); | ||
| if (!OutputImportDirectory.Contains ("__library_projects__") && Directory.Exists (oldPath)) { | ||
| MonoAndroidHelper.SetDirectoryWriteable (oldPath); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we're going to delete oldPath, don't we need to make the parent directory of oldPath writable as well, so that we can delete oldPath?
|
Comment-wise, it would be nice if the commit also described the new directory structure. :-) What it looks like -- at a quick glance -- is that Possibly "even further!", should we "hash" the assembly name so that we have a consistent 8-character "assembly name" directory instead of the variable length setup it currently uses? (This might be significantly more complicated, but it's a thought!) |
f27d52f to
b13639a
Compare
|
That moment when i find the the length of ROFLMAO. |
| } | ||
|
|
||
| if (Directory.Exists (outDirForDll)) | ||
| Directory.Delete (outDirForDll, true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This presents a theoretical problem -- which presumably won't be all that theoretical? -- in which two assemblies have an md2 which is the same value. (This should plausibly be more common, since we're only taking the first 5 values in the md2 value! See MonoAndroidHelper.GetLibraryImportDirectoryNameForAssembly(). That said, I don't see any issues in my $HOME/.local/share/Xamarin, so maybe conflict isn't that likely?)
If we have two directories which hash to the same value, what should be done, and how can it be supported?
(Can it be supported?)
For example, assume that assemblies A1 and A2 have names which hash to the same value. The Directory.Delete() here will nuke the extraction of one, which will presumably result in a later build break, as e.g. some resource is used which doesn't exist.
Alternatively, instead of the Directory.Delete(), we could instead extract both files into the same directory. The problem with this approach is deleting entries which no longer exist (bleh). Alternatively, there would be a problem if both assemblies provide a resource of the same name, e.g. classes.jar (which iirc is a fairly common name).
Offhand, I'm not immediately sure if this is solvable. At the same time, I'm also not sure if its "fixable", or that it even should be fixed.
What might be a good idea, though, is to check for it: we have all of the Assemblies of interest, and therefore we can compute the abbreviated md2 for all of those assemblies, and check to see if there are any conflicts at all:
var haveConflicts = new Dictionary<string, int>();
foreach (var a in Assemblies) {
var n = Xamarin.Android.Tasks.MonoAndroidHelper.GetLibraryImportDirectoryNameForAssembly (Path.GetFileNameWithoutExtension (a));
int c;
if (!haveConflicts.TryGetValue (n, out c)) {
haveConflicts.Add (n, 1);
}
else haveConflicts [n] = c+1;
}
if (haveConflicts.Values.Any (v => v > 1))
Log.LogError ("We have a hash conflict! Please rebuild with `$(UseShortFileNames)`=False.");That's clearly not a great error message, but the idea is there.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Hash has been replaced by a lookup cache file which will map the assembly to a integer index directory. So you get something like
MyProject=1
Xamarin.Android.Support.v7.AppCompat.21.0.3.0=2
So on the path we only take up "1" or "2" (up to the number of dependencies). Rather than a ton of redundant characters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As elaborated on in an earlier comment/down below, I believe that the lookup cache file needs to instead have:
1=MyProject
2=Xamarin.Android.Support.v7.AppCompat.21.0.3.0
|
|
||
| Assert.AreEqual (so.TextContent ().Length, new FileInfo (Path.Combine (Root, libbuilder.ProjectDirectory, lib.IntermediateOutputPath, | ||
| "native_library_imports", "armeabi-v7a", "libfoo.so")).Length, | ||
| "nl", "armeabi-v7a", "libfoo.so")).Length, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Smells like we should parameterize this test so that both native_library_imports ($(UseShortFileNames)=False)andnl ($(UseShortFileNames)`=True) are checked.
| entry.FullName.EndsWith ("/__MACOSX", StringComparison.OrdinalIgnoreCase) || | ||
| entry.FullName.EndsWith ("/.DS_Store", StringComparison.OrdinalIgnoreCase)) | ||
| continue; | ||
| var fullName = modifyCallback != null ? modifyCallback (entry.FullName) : entry.FullName; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we could go all C# 6 on this and do:
var fullName = modifyCallback?.Invoke (entry.FullName) ?? entry.FullName;:-D
| <RemoveDirFixed Directories="$(IntermediateOutputPath)library_project_annotations" Condition="Exists ('$(IntermediateOutputPath)library_project_annotations')" /> | ||
| <RemoveDirFixed Directories="$(IntermediateOutputPath)$(_LibraryProjectImportsDirectoryName)" Condition="Exists ('$(IntermediateOutputPath)$(_LibraryProjectImportsDirectoryName)')" /> | ||
| <RemoveDirFixed Directories="$(IntermediateOutputPath)__library_projects__" Condition="Exists ('$(IntermediateOutputPath)__library_projects__')"/> | ||
| <RemoveDirFixed Directories="$(_AndroidLibrayProjectIntermediatePath)" Condition="Exists ('$(_AndroidLibrayProjectIntermediatePath)')" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indentation here doesn't match surrounding text.
(The perils of a single file that uses both tabs and spaces...)
| <_AndroidResourcePathsCache>$(IntermediateOutputPath)resourcepaths.cache</_AndroidResourcePathsCache> | ||
| <_AndroidLibraryImportsCache>$(IntermediateOutputPath)libraryimports.cache</_AndroidLibraryImportsCache> | ||
| <_AndroidLibraryProjectImportsCache>$(IntermediateOutputPath)libraryprojectimports.cache</_AndroidLibraryProjectImportsCache> | ||
| <_AndroidLibrayProjectIntermediatePath Condition=" '$(_AndroidLibrayProjectIntermediatePath)' == '' And '$(UseShortFileNames)' == 'True' ">$(IntermediateOutputPath)lp</_AndroidLibrayProjectIntermediatePath> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if this is important/matters, but e.g. in the previous <ResolveLibraryProjectImports/> invocation, we had:
<ResolveLibraryProjectImports
OutputImportDirectory="$(IntermediateOutputPath)__library_projects__\"That would now be:
<ResolveLibraryProjectImports
OutputImportDirectory="$(IntermediateOutputPath)__library_projects__"Note the removal of the trailing \.
Is this a problem? Possibly; I know we've encountered previous bugs where the presence/lack of a trailing / would alter behavior, causing the "wrong" directory to be deleted. For example, monodroid/a22d699b / Bug #27442, which references the "same" property!
For sanity, this property should also include a trailing \, both on this line and the following line.
| <RemoveDirFixed Directories="$(MonoAndroidIntermediate)aidl" Condition="Exists ('$(MonoAndroidIntermediate)aidl')" /> | ||
| <RemoveDirFixed Directories="$(MonoAndroidIntermediate)bundles" Condition="Exists ('$(MonoAndroidIntermediate)bundles')" /> | ||
| <RemoveDirFixed Directories="$(MonoAndroidIntermediate)__library_projects__" Condition="Exists ('$(MonoAndroidIntermediate)__library_projects__')" /> | ||
| <RemoveDirFixed Directories="$(_AndroidLibrayProjectIntermediatePath)" Condition="Exists ('$(_AndroidLibrayProjectIntermediatePath)')" /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might be a variation on monodroid/a22d699b?
7ba050e to
318e562
Compare
| return id; | ||
| } | ||
|
|
||
| static Dictionary<string, string> assemblyIdentityMap; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this actually be static? This gives me the heeby-jeebies. Are we sure this won't be "mis-used"? What happens when multiple projects are built within the IDE, could things get out-of-sync/inconsistent?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In retrospect, it "needs" to be static in order to allow GetLibraryImportDirectoryNameForAssembly() to work at all.
I'm still not sure that's a good idea, though. Perhaps we should introduce a new type, and make assemblyIdentityMap and GetLibraryImportDirectoryNameForAssembly() instance members on that new type? The problem with such an approach is that all tasks that require the map would need to create an instance of this type instead of sharing a static instance, but that approach would certainly alleviate my concerns about building multiple projects -- possibly concurrently! -- in the same process over time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm gonna rework to use a wrapper class and no statics..
There will be a small overhead since we need to load that data from disk each time
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm willing to accept that overhead because I have no idea what the ramifications of "too much static data" is in the larger ecosystem. That scares me.
| { | ||
| return string.Concat (new MD2Managed ().ComputeHash (Encoding.UTF8.GetBytes (assemblyIdentName)).Take (5).Select (b => b.ToString ("X02"))); | ||
| if (assemblyIdentityMap == null) { | ||
| throw new Exception ("Mapping was not loaded!"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should throw InvalidOperationException, not Exception.
| if (!File.Exists (mapPath)) | ||
| return; | ||
| foreach (var s in File.ReadLines (mapPath)) { | ||
| var items = s.Split ('='); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question: What should happen if the assembly contains =? = isn't a restricted character; an assembly named foo=bar=baz.dll is perfectly kosher.
What will happen is that things will break two lines down, because the assumption is that there is only one = on a line. If there are more than one, the first item is the assembly, the second is the value, but we'd actually have a line containing:
foo=bar=baz=1
but then do assemblyIdentityMap.Add("foo", "bar"), which is wrong.
What we can instead do is reorder the values: instead of ASSEMBLY=DIRECTORY, do DIRECTOR=ASSEMBLY, then use the string.Split(char[], int) overload.
For example, if we instead had a line of:
1=foo=bar=baz.dll
Then line.Split(new[]{'='}, 2) will return new[]{ "1", "foo=bar=baz.dll" }, which is fine.
This implies that the file format needs "reversing".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if we really think about it we don't need a dictionary since we are just using the index of the item. So we just add the item names to a list in order and save that to disk. Then we can just using IndexOf to get the id.
I don't think there is any need to have a key=value.. apart from ease of reading.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yup.
|
|
||
| var assembly = res.GetAssembly (assemblyPath); | ||
|
|
||
| foreach (var mod in assembly.Modules) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I half wonder if the diff would be smaller if, before this line, we did:
if (true) {so that the indentation matched what we had before.
Even if this did result in a smaller diff, I'm not sure that would actually be a good idea. :-/
e8c89b0 to
ffbae07
Compare
|
|
||
| namespace Xamarin.Android.Tasks | ||
| { | ||
| public class AssemblyIdentityMap |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This type should be internal, if possible.
Fixes https://bugzilla.xamarin.com/show_bug.cgi?id=30147 Windows (still) has a max path limit of 260 characters.. This can cause us a problem if the user creates a project in a directory which already takes up most of that limit.. Like on their Desktop! This is because of the intermediate structure that was introduced to handle embedding resources into the assemblies. The current intermediate structure is as follows `$(IntermediateOutputPath)\__library_project_imports__\$(AssemblyName)\library_project_imports\` `$(IntermediateOutputPath)\__library_project_imports__\$(AssemblyName)\native_library_imports\` Now consider that `$(AssemblyName)` can sometimes end up with something lile "Xamarin.Android.Support.v7.AppCompat.21.0.3.0" you can easily see how we start getting into trouble. There was an attempt to fix this up a while ago (722dcc05) by introducing the `$(UseShortFileNames)` property. However while this did introduce a directory structure which was shorter is broke backwards compatability with older versions of xamarin-android. This is because of the structore of the zip files we that are embedded into the assemblies. The current system just extracts the zip into the `$(IntermediateOutputPath)\__library_project_imports__\$(AssemblyName)\` directory and assumes that it contains a `library_project_imports` directory. All the build tasks also assumed that as well. So the fix needs to be done on a number of fronts. Firstly we need to update the `$(_LibraryProjectImportsDirectoryName)` and `$(_NativeLibraryImportsDirectoryName)` to be something shorter. Next up we need to shorten "__library_project_imports__" to something else verbose as well. This should cut down on the amount of the MAX_PATH we chew up. The real key to this is to NOT change the structure of the zip files in the assemblies! So when we generate a zip from "jlibs" we make sure that the folder in the zip is called "library_project_imports". And when we extract the zip file we makle sure that "library_project_imports" is replaced by the shorter name. This will ensure that we are backward compatbile with older versions BUT more importantly we get to use the shorter directory structure. The files for native librarys are not extracted to disk but are extracted from memory so as long as the structure remains the same i.e "native_library_imports" that code does not need to change. The other thing we need to do is to update ResolveLibraryProjectImports Task to upgrade the system when it runs. So if we already have a "libraryprojectimports.cache" in place we just use that as is. But if we re-run the ResolveLibraryProjectImports task (due to a change or a clean build) we detect if we have the older structure in place and just remove it.. Since we are going to regenerate the entire cache again anyway we might as well start from scratch. With this in place it becomes possible we can now enable `$(UseShortFileNames)` by default! So the new structure that is created is as follows `$(IntermediateOutputPath)\lp\<id>\jl` `$(IntermediateOutputPath)\lp\<id>\nl` The <id> will be a single integer value which can be mapped to the source assembly via a new map.cache file. This .cache file will contain a list of assemblys. We use the `Index` of the assembly in the list to figure out which cache directory to use. UnnamedProject Library1 In this case `Library1` would have an index of `1` and `UnnamedProject` will be `0`. The old behaviour can be enabled by setting `$(UseShortFileNames)` to `False`. Note in order to keep existing bindings generator behaviour consistent, the BindingsGenerator task will not use the `$(UseShortFileNames)` property to control how it generates its .cs files. Instead a new property `$(UseShortGeneratorFileNames)` which can be used to control if the generator produces short names (e.g 1.cs, 2.cs). This will be `False` by default.
|
build |
Fixes: https://bugzilla.xamarin.com/show_bug.cgi?id=30147 Windows (still) has a max path limit of 260 characters.. This can cause us a problem if the user creates a project in a directory which already takes up most of that limit.. Like on their Desktop! This is because of the intermediate structure that was introduced to handle embedding resources into the assemblies. The current intermediate structure is as follows $(IntermediateOutputPath)\__library_project_imports__\$(AssemblyName)\library_project_imports\ $(IntermediateOutputPath)\__library_project_imports__\$(AssemblyName)\native_library_imports\ Now consider that `$(AssemblyName)` can sometimes end up with something lile "Xamarin.Android.Support.v7.AppCompat.21.0.3.0" you can easily see how we start getting into trouble. There was an attempt to fix this up a while ago (722dcc05) by introducing the `$(UseShortFileNames)` property. However while this did introduce a directory structure which was shorter is broke backwards compatability with older versions of xamarin-android. This is because of the structore of the zip files we that are embedded into the assemblies. The current system just extracts the zip into the `$(IntermediateOutputPath)\__library_project_imports__\$(AssemblyName)\` directory and assumes that it contains a `library_project_imports` directory. All the build tasks also assumed that as well. So the fix needs to be done on a number of fronts. Firstly we need to update the `$(_LibraryProjectImportsDirectoryName)` and `$(_NativeLibraryImportsDirectoryName)` to be something shorter. Next up we need to shorten "__library_project_imports__" to something else verbose as well. This should cut down on the amount of the MAX_PATH we chew up. The real key to this is to NOT change the structure of the zip files in the assemblies! So when we generate a zip from "jlibs" we make sure that the folder in the zip is called "library_project_imports". And when we extract the zip file we makle sure that "library_project_imports" is replaced by the shorter name. This will ensure that we are backward compatbile with older versions BUT more importantly we get to use the shorter directory structure. The files for native librarys are not extracted to disk but are extracted from memory so as long as the structure remains the same i.e "native_library_imports" that code does not need to change. The other thing we need to do is to update ResolveLibraryProjectImports Task to upgrade the system when it runs. So if we already have a "libraryprojectimports.cache" in place we just use that as is. But if we re-run the ResolveLibraryProjectImports task (due to a change or a clean build) we detect if we have the older structure in place and just remove it.. Since we are going to regenerate the entire cache again anyway we might as well start from scratch. With this in place it becomes possible we can now enable `$(UseShortFileNames)` by default! So the new structure that is created is as follows $(IntermediateOutputPath)\lp\<id>\jl $(IntermediateOutputPath)\lp\<id>\nl The <id> will be a single integer value which can be mapped to the source assembly via a new map.cache file. This .cache file will contain a list of assemblys. We use the `Index` of the assembly in the list to figure out which cache directory to use. UnnamedProject Library1 In this case `Library1` would have an index of `1` and `UnnamedProject` will be `0`. The old behaviour can be enabled by setting `$(UseShortFileNames)` to `False`. Note in order to keep existing bindings generator behaviour consistent, the BindingsGenerator task will not use the `$(UseShortFileNames)` property to control how it generates its .cs files. Instead a new property $(UseShortGeneratorFileNames) which can be used to control if the generator produces short names (e.g 1.cs, 2.cs). This will be `False` by default.
Fixes: dotnet/java-interop#694 Fixes: #3776 Fixes: #4989 Changes: dotnet/java-interop@a92fd18...b4c2a67 * dotnet/java-interop@b4c2a67c: [Xamarin.Android.Tools.Bytecode] Hide Kotlin synthetic constructors (#700) * dotnet/java-interop@4141d848: [Java.Interop] Avoid double-disposing PeerReferences (#690)
Fixes: https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1139590 Context: dotnet/java-interop@afbc5b3 Changes: dotnet/java-interop@dcaf794...afbc5b3 * dotnet/java-interop@afbc5b32: [C++] Get rid of compiler warnings (#703) * dotnet/java-interop@e295b498: [generator] Fix localization error. (#702) * dotnet/java-interop@5a0e37e0: [generator] Support 'managedOverride' metadata (#701) * dotnet/java-interop@f6c12ba3: [Xamarin.Android.Tools.Bytecode] Hide Kotlin synthetic constructors (#700) * dotnet/java-interop@0334f424: [generator] Hide Java.Lang.Object infrastructure (#698) * dotnet/java-interop@c0fcc435: [jcw-gen] Make MSBuild warning/error strings localizable. (#695) Fixes a handful of warnings reported by GCC and clang when building for different platforms. `-Wshadow` warnings: monodroid-glue.cc:1609:8: warning: declaration shadows a static data member of 'xamarin::android::internal::MonodroidRuntime' [-Wshadow] void *api_dso_handle = nullptr; ^ monodroid-glue.cc:102:25: note: previous declaration is here void *MonodroidRuntime::api_dso_handle = nullptr; Fix by renaming the local variable. No functionality changes result from this fix. MinGW builds report: xa-internal-api.cc: In member function ‘virtual mono_bool xamarin::android::internal::MonoAndroidInternalCalls_Impl::monodroid_get_network_interface_up_state(const char*, mono_bool*)’: xa-internal-api.cc:24:86: warning: unused parameter ‘ifname’ [-Wunused-parameter] 24 | MonoAndroidInternalCalls_Impl::monodroid_get_network_interface_up_state (const char *ifname, mono_bool *is_up) | ~~~~~~~~~~~~^~~~~~ xa-internal-api.cc:24:105: warning: unused parameter ‘is_up’ [-Wunused-parameter] 24 | MonoAndroidInternalCalls_Impl::monodroid_get_network_interface_up_state (const char *ifname, mono_bool *is_up) | ~~~~~~~~~~~^~~~~ xa-internal-api.cc: In member function ‘virtual mono_bool xamarin::android::internal::MonoAndroidInternalCalls_Impl::monodroid_get_network_interface_supports_multicast(const char*, mono_bool*)’: xa-internal-api.cc:34:96: warning: unused parameter ‘ifname’ [-Wunused-parameter] 34 | MonoAndroidInternalCalls_Impl::monodroid_get_network_interface_supports_multicast (const char *ifname, mono_bool *supports_multicast) | ~~~~~~~~~~~~^~~~~~ xa-internal-api.cc:34:115: warning: unused parameter ‘supports_multicast’ [-Wunused-parameter] 34 | MonoAndroidInternalCalls_Impl::monodroid_get_network_interface_supports_multicast (const char *ifname, mono_bool *supports_multicast) | ~~~~~~~~~~~^~~~~~~~~~~~~~~~~~ xa-internal-api.cc: In member function ‘virtual int xamarin::android::internal::MonoAndroidInternalCalls_Impl::monodroid_get_dns_servers(void**)’: xa-internal-api.cc:44:66: warning: unused parameter ‘dns_servers_array’ [-Wunused-parameter] 44 | MonoAndroidInternalCalls_Impl::monodroid_get_dns_servers (void **dns_servers_array) | ~~~~~~~^~~~~~~~~~~~~~~~~ xa-internal-api.cc: In member function ‘virtual int xamarin::android::internal::MonoAndroidInternalCalls_Impl::monodroid_getifaddrs(_monodroid_ifaddrs**)’: xa-internal-api.cc:54:82: warning: unused parameter ‘ifap’ [-Wunused-parameter] 54 | MonoAndroidInternalCalls_Impl::monodroid_getifaddrs (struct _monodroid_ifaddrs **ifap) | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~ xa-internal-api.cc: In member function ‘virtual void xamarin::android::internal::MonoAndroidInternalCalls_Impl::monodroid_freeifaddrs(_monodroid_ifaddrs*)’: xa-internal-api.cc:64:82: warning: unused parameter ‘ifa’ [-Wunused-parameter] 64 | MonoAndroidInternalCalls_Impl::monodroid_freeifaddrs (struct _monodroid_ifaddrs *ifa) | ~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~ Fix by ignoring the unused parameters only during Windows builds by using the C++17 attribute `[[maybe_unused]]` MinGW also reports: embedded-assemblies.cc: In static member function ‘static ssize_t xamarin::android::internal::EmbeddedAssemblies::do_read(int, void*, size_t)’: embedded-assemblies.cc:663:26: warning: conversion from ‘size_t’ {aka ‘long long unsigned int’} to ‘unsigned int’ may change value [-Wconversion] 663 | ret = ::read (fd, buf, count); | It is caused by **read**(2) declared in MinGW headers with the third parameter using an `unsigned int` type instead of the standard `size_t`. Fixed by casting properly on Windows builds.
Fixes https://bugzilla.xamarin.com/show_bug.cgi?id=30147
Windows (still) has a max path limit of 260 characters..
This can cause us a problem if the user creates a project in
a directory which already takes up most of that limit.. Like on
their Desktop!
This is because of the intermediate structure that was introduced
to handle embedding resources into the assemblies. The current
intermediate structure is as follows
Now consider that
$(AssemblyName)can sometimes end up with something lile"Xamarin.Android.Support.v7.AppCompat.21.0.3.0" you can easily see how we
start getting into trouble.
There was an attempt to fix this up a while ago (722dcc05) by introducing the
$(UseShortFileNames)property. However while this did introduce adirectory structure which was shorter is broke backwards compatability
with older versions of xamarin-android.
This is because of the structore of the zip files we that are embedded
into the assemblies. The current system just extracts the zip into
the
$(IntermediateOutputPath)\__library_project_imports__\$(AssemblyName)\directory and assumes that it contains a
library_project_importsdirectory.All the build tasks also assumed that as well.
So the fix needs to be done on a number of fronts. Firstly we need to
update the
$(_LibraryProjectImportsDirectoryName)and$(_NativeLibraryImportsDirectoryName)to be something shorter.Next up we need to shorten "library_project_imports" to something
else verbose as well. This should cut down on the amount of the MAX_PATH
we chew up.
The real key to this is to NOT change the structure of the zip files in the
assemblies! So when we generate a zip from "jlibs" we make sure that the
folder in the zip is called "library_project_imports". And when we extract
the zip file we makle sure that "library_project_imports" is replaced by
the shorter name.
This will ensure that we are backward compatbile with older versions BUT
more importantly we get to use the shorter directory structure.
The files for native librarys are not extracted to disk but are extracted
from memory so as long as the structure remains the same i.e "native_library_imports"
that code does not need to change.
The other thing we need to do is to update ResolveLibraryProjectImports Task to
upgrade the system when it runs. So if we already have a "libraryprojectimports.cache"
in place we just use that as is. But if we re-run the ResolveLibraryProjectImports
task (due to a change or a clean build) we detect if we have the older structure in place
and just remove it.. Since we are going to regenerate the entire cache again anyway
we might as well start from scratch.
With this in place it becomes possible we can now enable
$(UseShortFileNames)by default!
So the new structure that is created is as follows
The will be a single integer value which can be mapped to the source
assembly via a new map.cache file. This .cache file will contain a list of
assemblys. We use the
Indexof the assembly in the list to figure outwhich cache directory to use.
In this case
Library1would have an index of1andUnnamedProjectwillbe
0. The old behaviour can be enabled by setting$(UseShortFileNames)toFalse.Note in order to keep existing bindings generator behaviour consistent,
the BindingsGenerator task will not use the
$(UseShortFileNames)property to control how it generates its .cs files. Instead a new
property
which can be used to control if the generator produces short names
(e.g 1.cs, 2.cs). This will be
Falseby default.