Skip to content

Conversation

@dellis1972
Copy link
Contributor

The native libraries are output into an specific folder in

lib/xbuild/Xamarin/Android/libs

As a result we really do not need to have an suffix as part
of the native library name. In additon the libmonosgen library was
having -unstripped appended to the end of the library so it was

libmonosgen-2.0.so-unstripped

this looks a bit weird since it replaces the normal .so extension.
This has been removed.

@dellis1972 dellis1972 force-pushed the runtimenamechange branch 2 times, most recently from 5025acd to 917211d Compare May 25, 2016 10:42
<ConfigureFlags>--host=armv5-linux-androideabi $(_TargetConfigureFlags)</ConfigureFlags>
<OutputRuntime>libmonosgen-2.0.so</OutputRuntime>
<OutputRuntime>libmonosgen-2.0</OutputRuntime>
<OutputRuntimeExtension>so</OutputRuntimeExtension>
Copy link
Contributor

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 split out the extension like this, we should alter %(OutputProfiler) and %(OutputMonoPosixHelper) to follow suit.

I'd also be inclined to change the naming convention, but I'm not aware of a short name for "name without extension", and %(OutputRuntimeWithoutExtension) looks ugly. %(OutputRuntimeBasename) also doesn't quite fit the bill, as normally "basename" includes the file extension.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looking at the well known msbuild properties [1]

%(Filename) = Filename without the extension
%(Extension) = extension :)

so following that

%(OutputRuntimeFilename)
%(OutputRuntimeExtension)

seems to be reasonable.

[1] https://msdn.microsoft.com/en-us/library/ms164313.aspx

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, I like that. However, we don't need %(OutputRuntimeExtension); the extension will be the same for all those %(Output*) properties. Thus, %(OutputRuntimeFilename) and %(NativeLibraryExtension)?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yup already on it :)

@dellis1972 dellis1972 force-pushed the runtimenamechange branch from 917211d to 5c8217f Compare May 26, 2016 09:56
@dellis1972
Copy link
Contributor Author

@jonpryor this has been updated as per our discussion

/>
</Target>
<ItemGroup>
<_InstallRuntimesInputs Include="@(_MonoRuntime->'$(IntermediateOutputPath)\%(Identity)\mono\mini\.libs\%(OutputRuntimeFilename).%(NativeLibraryExtension)')" />
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't @(_InstallRuntimeInputs) be identical to @(_BuildRuntimeOutputs)? Meaning you could just use @(_BuildRuntimeOutputs)?

@dellis1972 dellis1972 force-pushed the runtimenamechange branch from 5c8217f to 8fe53f6 Compare May 27, 2016 09:25
SourceFiles="@(_MonoRuntime->'$(IntermediateOutputPath)\%(Identity)\support\.libs\%(OutputMonoPosixHelper)')"
DestinationFiles="@(_MonoRuntime->'$(OutputPath)\lib\xbuild\Xamarin\Android\lib\%(Identity)\%(OutputMonoPosixHelper)')"
Conditional=" '$(Configuration)' != 'Debug' "
Command="%(_MonoRuntime.Strip) &quot;$(OutputPath)\lib\xbuild\Xamarin\Android\lib\%(Identity)\%(OutputRuntimeFilename).%(NativeLibraryExtension)&quot;"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

%(_MonoRuntime.Strip) should be quoted, in case the path contains spaces:

"&quot;%(_MonoRuntime.Strip)&quot; ..."

@dellis1972 dellis1972 force-pushed the runtimenamechange branch 2 times, most recently from c20043d to abf645b Compare May 27, 2016 12:41
The native libraries are output into an <abi> specific folder in

	lib/xbuild/Xamarin/Android/libs

As a result we really do not need to have an <abi> suffix as part
of the native library name. In additon the libmonosgen library was
having -unstripped appended to the end of the library so it was

	libmonosgen-2.0.so-unstripped

this looks a bit weird since it replaces the normal .so extension.
This has been removed.
@jonpryor jonpryor merged commit 05aebd7 into dotnet:master May 27, 2016
radical pushed a commit that referenced this pull request May 8, 2018
Commit b6431ac broke the build of `src/java-interop`:

	Using task Exec from Microsoft.Build.Tasks.Exec, Microsoft.Build.Tasks.v4.0, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
	Executing: gcc -g -shared -std=c99 -o "obj/libjava-interop-m32.dylib" -m32 -DDEBUG -DJI_DLL_EXPORT -DMONODEVELOP -DMONO_DLL_EXPORT -fvisibility=hidden -Wl,-undefined -Wl,suppress -Wl,-flat_namespace -L /Library/Frameworks/Mono.framework/Libraries -lmonosgen-2.0   jni.c java-interop.c java-interop-mono.c java-interop-gc-bridge-mono.c
	Environment variables being passed to the tool:
	jni.c:7:10: fatal error: 'jni.h' file not found
	#include <jni.h>
	         ^
	1 error generated.
	In file included from java-interop-mono.c:1:
	./java-interop-mono.h:30:11: fatal error: 'mono/metadata/assembly.h' file not found
	        #include <mono/metadata/assembly.h>
	                 ^
	1 error generated.

The problem? There's no `gcc -Ipath` option, so the compiler doesn't
know where to find `<jni.h>` or `<mono/metadata/assembly.h>`.

The `-I` values are derived from the `@(JdkIncludePath) and
`@(MonoIncludePath)` MSBuild item groups:

	<!-- via bin/BuildDebug/JdkInfo.props -->
	<PropertyGroup>
	  <JdkJvmPath Condition=" '$(JdkJvmPath)' == '' ">/Library/Java/JavaVirtualMachines/jdk1.8.0_77.jdk/Contents/Home/jre/lib/server/libjvm.dylib</JdkJvmPath>
	</PropertyGroup>
	<ItemGroup>
	  <JdkIncludePath Condition=" '$(JdkJvmPath)' == '' " Include="/Library/Java/JavaVirtualMachines/jdk1.8.0_77.jdk/Contents/Home/include" />
	  <JdkIncludePath Condition=" '$(JdkJvmPath)' == '' " Include="/Library/Java/JavaVirtualMachines/jdk1.8.0_77.jdk/Contents/Home/include/darwin" />
	</ItemGroup>

	<!-- via bin/BuildDebug/MonoInfo.props -->
	<PropertyGroup>
	  <MonoFrameworkPath Condition=" '$(MonoFrameworkPath)' == '' ">/Library/Frameworks/Mono.framework/Libraries/libmonosgen-2.0.1.dylib</MonoFrameworkPath>
	</PropertyGroup>
	<ItemGroup>
	  <MonoIncludePath Condition=" '$(MonoFrameworkPath)' == '' " Include="/Library/Frameworks/Mono.framework/Headers/mono-2.0" />
	</ItemGroup>

The *intent* to commit b6431ac is that if e.g. `$(JdkJvmPath)` is
overridden, then we shouldn't automatically generate the
`@(JdkIncludePath)` items, because they'll be for the "wrong" JDK.
If `$(JdkJvmPath)` is overridden, then `@(JdkIncludePath)` should be
as well. (Ditto `$(MonoFrameworkPath)` and `@(MonoIncludePath)`.)

The problem is [evaluation time][0]:

> During the evaluation phase of a build, imported files are
> incorporated into the build in the order in which they appear.
> Properties and items are defined in three passes in the following
> order:
>
> * Properties are defined and modified in the order in which they appear.
> * Item definitions are defined and modified in the order in which they appear.
> * Items are defined and modified in the order in which they appear.

Properties are *always* evaluated before items, meaning when it came
time to evaluate `//JdkIncludePath/@Condition`, `$(JdkJvmPath)` was
*always* defined, and thus `@(JdkIncludePath)` was *always* empty.

Which is why there are no instances of `gcc -I` in the `gcc` compile
line, and why those headers can't be found.

The fix is to instead use the `<Choose/>` element to ensure that the
default items are specified when the "controlling" property isn't
overridden:

	<!-- via bin/BuildDebug/JdkInfo.props -->
	<Choose>
	  <When Condition=" '$(JdkJvmPath)' == '' ">
	    <PropertyGroup>
	      <JdkJvmPath>/Library/Java/JavaVirtualMachines/jdk1.8.0_77.jdk/Contents/Home/jre/lib/server/libjvm.dylib</JdkJvmPath>
	    </PropertyGroup>
	    <ItemGroup>
	      <JdkIncludePath Include="/Library/Java/JavaVirtualMachines/jdk1.8.0_77.jdk/Contents/Home/include" />
	      <JdkIncludePath Include="/Library/Java/JavaVirtualMachines/jdk1.8.0_77.jdk/Contents/Home/include/darwin" />
	    </ItemGroup>
	  </When>
	</Choose>

	<!-- via bin/BuildDebug/MonoInfo.props -->
	<Choose>
	  <When Condition=" '$(MonoFrameworkPath)' == '' ">
	    <PropertyGroup>
	      <MonoFrameworkPath>/Library/Frameworks/Mono.framework/Libraries/libmonosgen-2.0.1.dylib</MonoFrameworkPath>
	      <MonoLibs         >-L /Library/Frameworks/Mono.framework/Libraries -lmonosgen-2.0</MonoLibs>
	    </PropertyGroup>
	    <ItemGroup>
	      <MonoIncludePath Include="/Library/Frameworks/Mono.framework/Headers/mono-2.0" />
	    </ItemGroup>
	  </When>
	</Choose>

This allows `@(JdkIncludePath)` and `@(MonoIncludePath)` to have
values when `$(JdkJvmPath)` and `$(MonoFrameworkPath)` aren't
overridden, which in turn allows `gcc -I` to be used, and allows
`src/java-interop` to build.

[0]: https://msdn.microsoft.com/en-us/library/dd997067.aspx#Anchor_2
dellis1972 referenced this pull request in dellis1972/xamarin-android Mar 26, 2019
In commit 75023bd we noticed an issue the
value of `MonoPackageManager_Resouces.ApiPackageName` was
`""` even after it was replaced at built time with a new
`.class` file which contained an actual value.

The fix in that PR was to make the temp file in java-runtime
have a value of `null` rather than `""`. This made thing work
but we didn't know WHY.

After some more investigation it turns out that the value
was being inlined by the java compiler.

	public static java.lang.String getApiPackageName();
	    descriptor: ()Ljava/lang/String;
	    Code:
	       0: ldc           #48                 // String
	       2: areturn

The code above is pointing to a string in the Constants table.
What we were expecting was that the statick method would be
called in the file generated by the build system. Making
the temp file have a `null` rather than `""` resulted in the
following code

	public static java.lang.String getApiPackageName();
	    descriptor: ()Ljava/lang/String;
	    Code:
	       0: getstatic     #47                 // Field mono/MonoPackageManager_Resources.ApiPackageName:Ljava/lang/String;
	       3: areturn

This is why changing to `null` worked. It prevented the compiler
from inlining the value.

This commit removes the `final` keyword from the `MonoPackageManager_Resources`
class fields to make sure that they never get inlined.
jonpryor pushed a commit that referenced this pull request Mar 26, 2019
In commit 75023bd we noticed that the value of
`MonoPackageManager_Resouces.ApiPackageName` was `""` even after it
was replaced at build time with a new `.class` file which contained
an actual value:

> We don't yet fully understand this failure scenario, but setting
> `ApiPackageName` to null allows things to work.

The fix in 75023bd was to make the default value within
`MonoPackageManager_Resources.java` have a value of `null` rather
than `""`.  This allowed things to work but we didn't know WHY.

After some more investigation it turns out that when
`MonoPackageManager_Resouces.ApiPackageName` was `""`, the empty
string value was being *inlined* by `javac` when generating
`MonoPackageManager.getApiPackageName()`:

	public static java.lang.String getApiPackageName();
	    descriptor: ()Ljava/lang/String;
	    Code:
	       0: ldc           #48                 // String
	       2: areturn

`ldc` loads a constant from the Constants table, in this case `""`.

When `null` was used, `javac` instead emitted a field access:

	public static java.lang.String getApiPackageName();
	    descriptor: ()Ljava/lang/String;
	    Code:
	       0: getstatic     #47                 // Field mono/MonoPackageManager_Resources.ApiPackageName:Ljava/lang/String;
	       3: areturn

(Why `javac` didn't inline `null` is beyond @jonpryor.)

This is why changing to `null` worked: it prevented the compiler from
inlining the value.

However, while that "worked," it is not at all obvious, and short of
reading the Java Language Spec to determine if `null` is even a value
which *can* be inlined, the current approach of using a `final` value
seems potentially *dangerous*, as behavior may be subject to the
compiler used and subject to change.

To fix this, remove the `final` keyword from the
`MonoPackageManager_Resources` fields prevent inlining.
@github-actions github-actions bot locked and limited conversation to collaborators Feb 2, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants