Our AOT system has issues when a user uses
non ASCII characters and spaces on Windows.
We use `GetShortPath` to get the old DOS
8.3 short names of paths to get around
paths having spaces and unicode characters.
However on the latest versions of windows
`GetShortPath` seems to be supported only
on the main system drive (C:). Many of our
developers and CI will be building on other
drives. So we really need to support paths
with spaces and unicode.
This commit reworks the way we provide the
`--aot` pargument to the cross compilers so
that it actually works in those senarios.
The first thing was how the arguments were
parsed. `mono` uses the build in system
command line parser `GetCommandLineW` to parse
arguments. Given the following `--aot` argument
--aot=outfile="c:\Sandbox\repo\bin\BuildAotApplicationAndBundle AndÜmläüts_x86_True_True\obj\Release\libaot-Mono.Android.dll.so",asmwriter,mtriple=i686-linux-android,tool-prefix=C:\ProgramData\Microsoft\AndroidNDK\android-ndk-r13b\toolchains\x86-4.9\prebuilt\windows\bin\i686-linux-android-,ld-flags=C:\ProgramData\Microsoft\AndroidNDK\android-ndk-r13b\toolchains\x86-4.9\prebuilt\windows\lib\gcc\i686-linux-android\4.9.x\libgcc.a;C:\ProgramData\Microsoft\AndroidNDK\android-ndk-r13b\platforms\android-16\arch-x86\usr\lib\libc.so;C:\ProgramData\Microsoft\AndroidNDK\android-ndk-r13b\platforms\android-16\arch-x86\usr\lib\libm.so,temp-path="c:\Sandbox\repo\BuildAotApplicationAndBundle AndÜmläüts_x86_True_True\obj\Release\temp"
This ends up as the following arguments
--aot=outfile="c:\Sandbox\repo\bin\BuildAotApplicationAndBundle
AndÜmläüts_x86_True_True\obj\Release\libaot-Mono.Android.dll.so"
,asmwriter,mtriple=i686-linux-android,tool-prefix=C:\ProgramData\Microsoft\AndroidNDK\android-ndk-r13b\toolchains\x86-4.9\prebuilt\windows\bin\i686-linux-android-,ld-flags=C:\ProgramData\Microsoft\AndroidNDK\android-ndk-r13b\toolchains\x86-4.9\prebuilt\windows\lib\gcc\i686-linux-android\4.9.x\libgcc.a;C:\ProgramData\Microsoft\AndroidNDK\android-ndk-r13b\platforms\android-16\arch-x86\usr\lib\libc.so;C:\ProgramData\Microsoft\AndroidNDK\android-ndk-r13b\platforms\android-16\arch-x86\usr\lib\libm.so,temp-path="c:\Sandbox\repo\BuildAotApplicationAndBundle
AndÜmläüts_x86_True_True\obj\Release\temp"
As you can see the parameters have been split
where there is a space. The solution to this is
to double quote the ENTIRE argument and remove
any quotes within the parameter list like so
"--aot=outfile=c:\Sandbox\repo\bin\BuildAotApplicationAndBundle AndÜmläüts_x86_True_True\obj\Release\libaot-Mono.Android.dll.so,asmwriter,mtriple=i686-linux-android,tool-prefix=C:\ProgramData\Microsoft\AndroidNDK\android-ndk-r13b\toolchains\x86-4.9\prebuilt\windows\bin\i686-linux-android-,ld-flags=C:\ProgramData\Microsoft\AndroidNDK\android-ndk-r13b\toolchains\x86-4.9\prebuilt\windows\lib\gcc\i686-linux-android\4.9.x\libgcc.a;C:\ProgramData\Microsoft\AndroidNDK\android-ndk-r13b\platforms\android-16\arch-x86\usr\lib\libc.so;C:\ProgramData\Microsoft\AndroidNDK\android-ndk-r13b\platforms\android-16\arch-x86\usr\lib\libm.so,temp-path=c:\Sandbox\repo\BuildAotApplicationAndBundle AndÜmläüts_x86_True_True\obj\Release\temp"
This allows windows (and mac) to parse the paremters
correctly as one block.
There is another issue however. With the new argument
line above if the `temp=` path has a space in it `mono`
still has issues with that path. The good news is that we
can use some domain knowledge to reduce not only the
paths which need spaces but also the overall length of
the argument.
Because we know the cross compiler will be executed within
`WorkingDirectory` we can shorten any path which is within
that directory structure. `WorkingDirectory` is set to the
directory of the projects csproj file. So the following
E:\Some Project\My Project\obj\Release\aot\System.dll\
will become
obj\Release\aot\System.dll\
This will fix the issue with the `temp=` argument. So we end up
with something like this
"--aot=outfile=obj\Release\libaot-Mono.Android.dll.so,asmwriter,mtriple=i686-linux-android,tool-prefix=C:\ProgramData\Microsoft\AndroidNDK\android-ndk-r13b\toolchains\x86-4.9\prebuilt\windows\bin\i686-linux-android-,ld-flags=C:\ProgramData\Microsoft\AndroidNDK\android-ndk-r13b\toolchains\x86-4.9\prebuilt\windows\lib\gcc\i686-linux-android\4.9.x\libgcc.a;C:\ProgramData\Microsoft\AndroidNDK\android-ndk-r13b\platforms\android-16\arch-x86\usr\lib\libc.so;C:\ProgramData\Microsoft\AndroidNDK\android-ndk-r13b\platforms\android-16\arch-x86\usr\lib\libm.so,temp-path=obj\Release\temp"
However we might still start hitting the command line length limit
on windows. This is currently 246 characters. So depending on where
a user creates the project we might end up with a long command line.
To work around this issue we can make use of the new `--response=`
argument in `mono`. Instead of passing all the arguments to the
cross compiler we can instead write them to a file and pass the
path to that file as the `--response=` argument. This will reduce
our command line length to be within an acceptable range unless
the user creates a project in a very very deep directory structure.
So the final call will be something like
cross-arm --response="c:\Sandbox\repo\bin\BuildAotApplicationAndBundle AndÜmläüts_x86_True_True\obj\Release\Mono.Android.dll\response.txt"
Which works perfectly.
This commit also updates the `BuildAotApplication` and
`BuildAotApplicationAndBundle` unit tests to use paths with
both spaces and non-ascii characters to make sure we support
both of those senarios.