From 146fe8de5988c61ccf5c84f668049f19e7216f72 Mon Sep 17 00:00:00 2001 From: Jonathan Pryor Date: Fri, 2 Dec 2016 20:39:18 -0500 Subject: [PATCH] Support building with `msbuild` MSBuild is open source -- has been for ages -- and we'd *really* like to migrate all things Mono to MSBuild and deprecate/remove `xbuild`. Which means we need to ensure that all of our products build with `msbuild`. [Which unfortunately isn't the case in `Java.Interop`][0]: MSB3375: The file "../../bin/Release/Xamarin.Android.Cecil.dll" does not exist. ... Java.Interop/MarshalMemberBuilder.cs(9,20): error CS0234: The type or namespace name `Expressions' does not exist in the namespace `Java.Interop'. Are you missing an assembly reference? ... 36 Warning(s) 69 Error(s) For starters, bring Java.Interop into aligntment/convention with the [`xamarin-android` repo][1], so that `$(MSBUILD)` is the Make variable to specify the MSBuild engine to use, not `$(XBUILD)`, and allow `$(V)` to set `$MONO_OPTIONS` so that line numbers are included in stack traces from mono. Which brings us to the build errors. The MSB3375 error happens when building e.g. `Xamarin.Android.Cecil.csproj` from another directory: $ msbuild src/Xamarin.Android.Cecil/Xamarin.Android.Cecil.csproj ... .../src/Xamarin.Android.Cecil/Xamarin.Android.Cecil.targets(33,5): error MSB3375: The file "../../bin/Debug/Xamarin.Android.Cecil.dll" does not exist. ... The cause, in turn, is because the nested `` invocation overrides `$(OutputPath)` when building `external/Cecil/Mono.Cecil.csproj` to be *`Xamarin.Android.Cecil.csproj`'s* `$(OutputPath)`: $([System.IO.Path]::GetFullPath ('$(OutputPath)')) Or rather, it *tries* to. It uses `Path.GetFullPath()` on `$(OutputPath)` so that `Mono.Cecil.csproj` writes the assembly into the expected `Xamarin.Android.Cecil.csproj`-specified directory. The problem is that the `Path.GetFullPath()` call is relative to the *current working directory*, so when: 1. The current working directory isn't the same directory as the directory containing `Xamarin.Android.Cecil.csproj`, and 2. We're building `Xamarin.Android.Cecil.csproj`, which defines `$(OutputPath)` as e.g. `..\..\Debug` (1) and (2) interplay so that `$(CecilOutputPath)` becomes e.g. `$CWD/../../bin/Debug`, which is *not* the correct directory, and may (will!) be outside of the repo checkout directory. Modify the `$(CecilOutputPath)` definition so that it instead assumes that `$(OutputPath)` is a directory *relative to* `$(MSBuildThisFileDirectory)`, equivalent to C#: var OutputPath = ... var MSBuildThisFileDirectory = ... var CecilOutputPath = Path.Combine (MSBuildThisFileDirectory, OutputPath); CecilOutputPath = Path.GetFullPath (CecilOutputPath); This fixes the above interplay by "inserting" use of `$(MSBuildThisFileDirectory)` into the "normal" `msbuild Xamarin.Android.Cecil.csproj` invocation path, ensuring that output paths behave as expected. This in turn allows `Xamarin.Android.Cecil.dll` to be placed into the correct directory, which in turn fixes all of the other C# errors (present apparently because `Xamarin.Android.Cecil.dll` couldn't be resolved). [0]: https://jenkins.mono-project.com/view/Xamarin.Android/job/Java.Interop-msbuild/5/consoleText [1]: https://github.com/xamarin/xamarin-android --- Makefile | 15 +++++----- README.md | 6 ++-- build-tools/scripts/mono.mk | 9 ++++++ build-tools/scripts/msbuild.mk | 29 +++++++++++++++++++ .../Xamarin.Android.Cecil.targets | 5 ++-- src/java-interop/java-interop.mdproj | 2 +- tests/invocation-overhead/Makefile | 3 +- 7 files changed, 55 insertions(+), 14 deletions(-) create mode 100644 build-tools/scripts/msbuild.mk diff --git a/Makefile b/Makefile index c964ecd68..779525772 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,6 @@ OS ?= $(shell uname) +V ?= 0 CONFIGURATION = Debug ifeq ($(OS),Darwin) @@ -39,7 +40,6 @@ PTESTS = \ ATESTS = \ bin/Test$(CONFIGURATION)/Android.Interop-Tests.dll -XBUILD = xbuild $(if $(V),/v:diag,) NUNIT_CONSOLE = packages/NUnit.Runners.2.6.3/tools/nunit-console.exe BUILD_PROPS = bin/Build$(CONFIGURATION)/JdkInfo.props bin/Build$(CONFIGURATION)/MonoInfo.props @@ -57,12 +57,13 @@ prepare-external: $(PACKAGES) $(NUNIT_CONSOLE) git submodule update --init --recursive clean: - -$(XBUILD) /t:Clean + -$(MSBUILD) $(MSBUILD_FLAGS) /t:Clean -rm -Rf bin/$(CONFIGURATION) bin/Build$(CONFIGURATION) bin/Test$(CONFIGURATION) bin/XAIntegration$(CONFIGURATION) -rm src/Java.Runtime.Environment/Java.Runtime.Environment.dll.config include build-tools/scripts/mono.mk include build-tools/scripts/jdk.mk +include build-tools/scripts/msbuild.mk $(PACKAGES) $(NUNIT_CONSOLE): nuget restore @@ -97,7 +98,7 @@ endif # Usage: $(call TestAssemblyTemplate,assembly-basename) define TestAssemblyTemplate bin/Test$$(CONFIGURATION)/$(1)-Tests.dll: $(wildcard src/$(1)/*/*.cs src/$(1)/Test*/*/*.cs) - $$(XBUILD) + $$(MSBUILD) $$(MSBUILD_FLAGS) touch $$@ endef # TestAssemblyTemplate @@ -107,15 +108,15 @@ $(eval $(call TestAssemblyTemplate,Java.Interop.Export)) $(eval $(call TestAssemblyTemplate,Java.Interop.Tools.JavaCallableWrappers)) bin/Test$(CONFIGURATION)/Java.Interop-PerformanceTests.dll: $(wildcard tests/Java.Interop-PerformanceTests/*.cs) bin/Test$(CONFIGURATION)/$(NATIVE_TIMING_LIB) - $(XBUILD) + $(MSBUILD) $(MSBUILD_FLAGS) touch $@ bin/Test$(CONFIGURATION)/Android.Interop-Tests.dll: $(wildcard src/Android.Interop/*/*.cs src/Android.Interop/Tests/*/*.cs) - $(XBUILD) + $(MSBUILD) $(MSBUILD_FLAGS) touch $@ bin/$(XA_CONFIGURATION)/Java.Interop.dll: $(wildcard src/Java.Interop/*/*.cs) src/Java.Interop/Java.Interop.csproj - $(XBUILD) /p:Configuration=$(XA_CONFIGURATION) $(if $(SNK),"/p:AssemblyOriginatorKeyFile=$(SNK)",) + $(MSBUILD) $(if $(V),/v:diag,) /p:Configuration=$(XA_CONFIGURATION) $(if $(SNK),"/p:AssemblyOriginatorKeyFile=$(SNK)",) CSHARP_REFS = \ bin/$(CONFIGURATION)/Java.Interop.dll \ @@ -150,7 +151,7 @@ bin/Test$(CONFIGURATION)/$(JAVA_INTEROP_LIB): bin/$(CONFIGURATION)/$(JAVA_INTERO cp $< $@ run-android: $(ATESTS) - (cd src/Android.Interop/Tests; $(XBUILD) '/t:Install;RunTests' $(if $(FIXTURE),/p:TestFixture=$(FIXTURE))) + (cd src/Android.Interop/Tests; $(MSBUILD) $(MSBUILD_FLAGS) '/t:Install;RunTests' $(if $(FIXTURE),/p:TestFixture=$(FIXTURE))) run-test-jnimarshal: bin/Test$(CONFIGURATION)/Java.Interop.Export-Tests.dll bin/Test$(CONFIGURATION)/$(JAVA_INTEROP_LIB) MONO_TRACE_LISTENER=Console.Out \ diff --git a/README.md b/README.md index f2f464ca5..581f33e5e 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ on the command line or by specifying MSBuild properties to control behavior. The following **make**(1) variables may be specified: * `$(CONFIGURATION)`: The product configuration to build, and corresponds - to the `$(Configuration)` MSBuild property when running `$(XBUILD)`. + to the `$(Configuration)` MSBuild property when running `$(MSBUILD)`. Valid values are `Debug` and `Release`. Default value is `Debug`. * `$(RUNTIME)`: The managed runtime to use to execute utilities, tests. Default value is `mono64` if present in `$PATH`, otherwise `mono`. @@ -85,9 +85,9 @@ The following **make**(1) variables may be specified: make run-tests TESTS=bin/Debug/Java.Interop.Dynamic-Tests.dll -* `$(V)`: If set to a non-empty string, adds `/v:diag` to `$(XBUILD)` +* `$(V)`: If set to a non-empty string, adds `/v:diag` to `$(MSBUILD_FLAGS)` invocations. -* `$(XBUILD)`: The MSBuild build tool to execute for builds. +* `$(MSBUILD)`: The MSBuild build tool to execute for builds. Default value is `xbuild`. diff --git a/build-tools/scripts/mono.mk b/build-tools/scripts/mono.mk index c491f48d5..38bd1bf48 100644 --- a/build-tools/scripts/mono.mk +++ b/build-tools/scripts/mono.mk @@ -5,6 +5,7 @@ # # $(OS): Optional; **uname**(1) value of the host operating system # $(CONFIGURATION): Build configuration name, e.g. Debug or Release +# $(V): Output verbosity. If != 0, then `MONO_OPTIONS` is exported with --debug. # # Outputs: # @@ -27,6 +28,14 @@ OS ?= $(shell uname) RUNTIME := $(shell if [ -f "`which mono64`" ] ; then echo mono64 ; else echo mono; fi) --debug=casts +ifneq ($(V),0) +MONO_OPTIONS += --debug +endif # $(V) != 0 + +ifneq ($(MONO_OPTIONS),) +export MONO_OPTIONS +endif # $(MONO_OPTIONS) != '' + ifeq ($(OS),Darwin) JI_MONO_FRAMEWORK_PATH = /Library/Frameworks/Mono.framework/Libraries/libmonosgen-2.0.1.dylib JI_MONO_INCLUDE_PATHS = /Library/Frameworks/Mono.framework/Headers/mono-2.0 diff --git a/build-tools/scripts/msbuild.mk b/build-tools/scripts/msbuild.mk new file mode 100644 index 000000000..0c36207f0 --- /dev/null +++ b/build-tools/scripts/msbuild.mk @@ -0,0 +1,29 @@ +# +# MSBuild Abstraction. +# +# Makefile targets which need to invoke MSBuild should use `$(MSBUILD)`, +# not some specific MSBuild program such as `xbuild` or `msbuild`. +# +# Typical use will also include `$(MSBUILD_FLAGS)`, which provides the +# Configuration and logging verbosity, as per $(CONFIGURATION) and $(V): +# +# $(MSBUILD) $(MSBUILD_FLAGS) path/to/Project.csproj +# +# Inputs: +# +# $(CONFIGURATION): Build configuration name, e.g. Debug or Release +# $(MSBUILD): The MSBuild program to use. +# $(MSBUILD_ARGS): Extra arguments to pass to $(MSBUILD); embedded into $(MSBUILD_FLAGS) +# $(V): Build verbosity +# +# Outputs: +# +# $(MSBUILD): The MSBuild program to use. Defaults to `xbuild` unless overridden. +# $(MSBUILD_FLAGS): Additional MSBuild flags; contains $(CONFIGURATION), $(V), $(MSBUILD_ARGS). + +MSBUILD = xbuild +MSBUILD_FLAGS = /p:Configuration=$(CONFIGURATION) $(MSBUILD_ARGS) + +ifneq ($(V),0) +MSBUILD_FLAGS += /v:d +endif # $(V) != 0 diff --git a/src/Xamarin.Android.Cecil/Xamarin.Android.Cecil.targets b/src/Xamarin.Android.Cecil/Xamarin.Android.Cecil.targets index 2c228fea2..06839ae2d 100644 --- a/src/Xamarin.Android.Cecil/Xamarin.Android.Cecil.targets +++ b/src/Xamarin.Android.Cecil/Xamarin.Android.Cecil.targets @@ -3,8 +3,9 @@ $(MSBuildThisFileDirectory)\..\..\external\cecil prepared.flag - $(MSBuildThisFileDirectory)\..\..\bin\$(Configuration) - $([System.IO.Path]::GetFullPath ('$(OutputPath)')) + ..\..\bin\$(Configuration) + $([System.IO.Path]::Combine ($(MSBuildThisFileDirectory), $(OutputPath))) + $([System.IO.Path]::GetFullPath ($(CecilOutputPath))) $(OutputPath)\Xamarin.Android.Cecil.dll;$(OutputPath)\Xamarin.Android.Cecil.Mdb.dll - <_FixedDefines>$(DefineSymbols.Replace(' ', ';')) + <_FixedDefines>$(DefineSymbols.Split(' ')) <_Defines Include="$(_FixedDefines)" /> diff --git a/tests/invocation-overhead/Makefile b/tests/invocation-overhead/Makefile index d56491650..66f61d798 100644 --- a/tests/invocation-overhead/Makefile +++ b/tests/invocation-overhead/Makefile @@ -9,9 +9,10 @@ clean: include ../../build-tools/scripts/mono.mk include ../../build-tools/scripts/jdk.mk +include ../../build-tools/scripts/msbuild.mk $(JNIENV_GEN): - (cd ../../build-tools/jnienv-gen ; xbuild /p:Configuration=$(CONFIGURATION)) + (cd ../../build-tools/jnienv-gen ; $(MSBUILD) $(MSBUILD_FLAGS) ) HANDLE_FEATURES = \ -d:FEATURE_JNIENVIRONMENT_JI_INTPTRS \