Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/sdks/ios
diff options
context:
space:
mode:
authorZoltan Varga <vargaz@gmail.com>2017-12-19 17:04:44 +0300
committerGitHub <noreply@github.com>2017-12-19 17:04:44 +0300
commita2407ac76a50cc1b5fdfbea83adb135d9be40356 (patch)
treedfa460cbae693e9f9e286d6eefc0b0a159995edd /sdks/ios
parente9e17e069e6949600a382341e8888d7486553f21 (diff)
IOS SDKs (#6257)
* [ios-sdk] Rename test-runner directory to 'runtime' to be consistent with xamarin.ios. * [ios-sdk] Add missing xamarin_log () icall used by Console.Write (). * [ios-sdk] Change the run-ios-sim target so it works on ios11 as well, the --console option to simctl appears to be broken. * [ios-sdk] Add a test harness. The test harness is resposible for starting the emulator, installing the app on the emulator, running it, and collecting application output using the osx logging facilities. * [ios-sdk] Fix detection of the app exiting with an unhandled exception. * [ios-sdk] Add CI support for running some test suites on the simulator. * [ios-sdk] Kill the log reader process on shutdown. * [ios-sdk] Disable android on CI because the make targets error out if the android sdk is not installed. * [ios-sdk] Fix error checking in make targets. * [ios-sdk] Remove accidently commited binary. * [ios-sdk] Switch to using os_log instead of NSLog (), the latter doesn't seem to show up in the logs anymore. Switch to using the default ios sdk instead of hardcoding 11.1. * [ios-sdk] Don't hardcode the ios version when creating a simulator. * [ios-sdk] Parse the output of simctl list runtimes as json. * [ios-sdk] Use 'syslog' style logging, its supported by older osx versions. * [ios-sdk] Fix logfile parsing. * [ios-sdk] Fix log filtering. * [ios-sdk] Add test exclusions file for System. * [ios-sdk] Redirect runtime logging to os_log (). * [ios-sdk] Link libMonoPosixHelper and zlib into the test runner. * [ios-sdk] Fix the target64 and cross64 builds. * [ios-sdk] Build target64/cross64 on CI. * [ios-sdk] Add device support to the runtime lib. Mark strings in os_log () calls as public. * [ios-sdk] Log stdout messages using a separate subsystem for easier filtering. * [ios-sdk] Add an 'appbuilder' tool which can generate simulator and device apps. * [ios-sdk] Build device tests on CI. * [ios-sdk] Add a test-runner instead of using nunit-lite-console.exe. The two are identical right now, but they might diverge in the future. * [ios-sdk] Add a script to download prebuild llvm binaries. * [ios-sdk] Run the runtime initialization on a separate thread, not the UI thread. * [ios-sdks] Fix the build. * [ios-sdk] Build the cross compiler against llvm. * [ios-sdk] Add missing file. * [ios-sdk] Add llvm support, enabled by passing LLVM=1 to make build-ios-dev-<app>. * [bcl] Enable System.Security tests on the MOBILE profile. * [ios-sdk] Enable more test suites. * [ios-sdk] Fix device builds. * [ios-sdk] Make some test steps non-fatal. * [ios-dev] Use ad-hoc signing to sign device apps. * [ios-sdk] Decrease the timeout on run-sim to 20m. * [ios-sdk] Send back the test results using a tcp connection, parsing the ios logs is too fragile. * [ios-sdk] Mark System.Net.Http tests as notworking, they seem to fail on CI. * [ios-sdk] Compile the 32 bit cross compiler against llvm as well. * [ios-sdk] Package up the binaries which can be uploaded to storage. * [ios-sdk] Fix the download-llvm.sh script. * [ios-sdk] Compile cross32 on CI. * [ios-sdk] Use Options.cs from the mcs sources instead of making a copy. * [ios-sdk] Avoid hardcoding the xcode sysroot, obtain it using 'xcode-select -p'. * [ios-sdk] Fix the previous change. * [ios-sdk] Add an option to appbuilder to cache aot compilation results between building different apps. * [ios-sdk] Build device apps with llvm as well on CI. * [ios-skd] Use XCODE_ROOT in a few more places, update README.md.
Diffstat (limited to 'sdks/ios')
-rw-r--r--sdks/ios/Makefile202
-rw-r--r--sdks/ios/README.md36
-rw-r--r--sdks/ios/appbuilder/appbuilder.cs247
-rw-r--r--sdks/ios/harness/harness.cs196
-rw-r--r--sdks/ios/runtime/AppDelegate.h (renamed from sdks/ios/test-runner/AppDelegate.h)0
-rw-r--r--sdks/ios/runtime/AppDelegate.m (renamed from sdks/ios/test-runner/AppDelegate.m)0
-rw-r--r--sdks/ios/runtime/Base.lproj/LaunchScreen.storyboardc/01J-lp-oVM-view-Ze5-6b-2t3.nib (renamed from sdks/ios/test-runner/Base.lproj/LaunchScreen.storyboardc/01J-lp-oVM-view-Ze5-6b-2t3.nib)bin1136 -> 1136 bytes
-rw-r--r--sdks/ios/runtime/Base.lproj/LaunchScreen.storyboardc/Info.plist (renamed from sdks/ios/test-runner/Base.lproj/LaunchScreen.storyboardc/Info.plist)bin258 -> 258 bytes
-rw-r--r--sdks/ios/runtime/Base.lproj/LaunchScreen.storyboardc/UIViewController-01J-lp-oVM.nib (renamed from sdks/ios/test-runner/Base.lproj/LaunchScreen.storyboardc/UIViewController-01J-lp-oVM.nib)bin832 -> 832 bytes
-rw-r--r--sdks/ios/runtime/Base.lproj/Main.storyboardc/BYZ-38-t0r-view-8bC-Xf-vdC.nib (renamed from sdks/ios/test-runner/Base.lproj/Main.storyboardc/BYZ-38-t0r-view-8bC-Xf-vdC.nib)bin1136 -> 1136 bytes
-rw-r--r--sdks/ios/runtime/Base.lproj/Main.storyboardc/Info.plist (renamed from sdks/ios/test-runner/Base.lproj/Main.storyboardc/Info.plist)bin258 -> 258 bytes
-rw-r--r--sdks/ios/runtime/Base.lproj/Main.storyboardc/UIViewController-BYZ-38-t0r.nib (renamed from sdks/ios/test-runner/Base.lproj/Main.storyboardc/UIViewController-BYZ-38-t0r.nib)bin916 -> 916 bytes
-rw-r--r--sdks/ios/runtime/Entitlements.xcent12
-rw-r--r--sdks/ios/runtime/Info.plist.in (renamed from sdks/ios/test-runner/Info.plist.in)0
-rw-r--r--sdks/ios/runtime/Makefile74
-rw-r--r--sdks/ios/runtime/ViewController.h (renamed from sdks/ios/test-runner/ViewController.h)0
-rw-r--r--sdks/ios/runtime/ViewController.m (renamed from sdks/ios/test-runner/ViewController.m)8
-rw-r--r--sdks/ios/runtime/main.m (renamed from sdks/ios/test-runner/main.m)0
-rw-r--r--sdks/ios/runtime/runtime.h (renamed from sdks/ios/test-runner/runtime.h)0
-rw-r--r--sdks/ios/runtime/runtime.m (renamed from sdks/ios/test-runner/runtime.m)171
-rw-r--r--sdks/ios/test-runner/Makefile29
-rw-r--r--sdks/ios/test-runner/runner.cs72
22 files changed, 970 insertions, 77 deletions
diff --git a/sdks/ios/Makefile b/sdks/ios/Makefile
index fe168f9ade8..f6cc556691f 100644
--- a/sdks/ios/Makefile
+++ b/sdks/ios/Makefile
@@ -1,53 +1,153 @@
-all:
+all: harness.exe appbuilder.exe test-runner.exe
BCL_DIR = ../../mcs/class/lib/monotouch
+XCODE_ROOT=$(shell xcode-select -p)
+SYSROOT=$(XCODE_ROOT)/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk
+
+TEST_SUITES = \
+ Mono.Runtime.Tests \
+ corlib \
+ System.Core \
+ System.Data \
+ System.Numerics \
+ System.Runtime.Serialization \
+ System.Transactions \
+ System.IO.Compression \
+ System.IO.Compression.FileSystem \
+ System.Json \
+ System.ComponentModel.DataAnnotations \
+ System.Security \
+ System.Xml.Linq \
+ System.ServiceModel.Web \
+ Mono.Data.Tds \
+ Mono.Security
+
+TEST_SUITES_NOTWORKING = \
+ System \
+ System.Net.Http \
+ System.Web.Services \
+ System.Xml \
+ Mono.Data.Sqlite \
+ Mono.CSharp \
+
+SIM_NAME = xamarin.ios-sdk.sim
+
+OPTIONS_CS = ../../mcs/class/Mono.Options//Mono.Options/Options.cs
+
+harness.exe: harness/harness.cs $(OPTIONS_CS)
+ csc /out:$@ -r:System.Json.dll $^
+
+appbuilder.exe: appbuilder/appbuilder.cs $(OPTIONS_CS)
+ csc /out:$@ $^
+
+test-runner.exe: test-runner/runner.cs
+ csc /out:$@ -r:$(BCL_DIR)/nunitlite.dll test-runner/runner.cs
+
+runtime/runtime:
+ make -C runtime
+
+runtime/libmonoios.a:
+ make -C runtime
# Build % from assemblies %_ASSEMBLIES
# The end result is in bin/ios-sim/test-%.app
-build-ios-sim-%:
- make -C test-runner/
- rm -rf tmp.app
- mkdir -p tmp.app
- cp test-runner/test-runner tmp.app/test-$*
- cp test-runner/Info.plist.in tmp.app/1
- sed -e "s/BUNDLE_IDENTIFIER/com.xamarin.mono.ios.test-$*/g" < tmp.app/1 > tmp.app/2
- sed -e "s/BUNDLE_EXECUTABLE/test-$*/g" < tmp.app/2 > tmp.app/3
- sed -e "s/BUNDLE_NAME/test-$*/g" < tmp.app/3 > tmp.app/Info.plist
- rm -f tmp.app/{1,2,3}
- plutil -convert binary1 tmp.app/Info.plist
- cp -r test-runner/Base.lproj tmp.app
- cp -r $(BCL_DIR)/{mscorlib.dll,System.dll,System.Xml.dll,System.Core.dll,I18N.dll,I18N.West.dll,Mono.Simd.dll,System.Numerics.dll,System.Numerics.Vectors.dll,nunitlite.dll,nunit-lite-console.exe} $($*_ASSEMBLIES) $($*_EXTRA_FILES) tmp.app
- /usr/bin/codesign --force --sign - --timestamp=none tmp.app
- mkdir -p bin/ios-sim
- rm -rf bin/ios-sim/test-$*.app
- mv tmp.app bin/ios-sim/test-$*.app
-# Install % on the simulator
-install-ios-sim-%:
- xcrun simctl install booted bin/ios-sim/test-$*.app
+TEST_ASSEMBLIES = $(BCL_DIR)/mscorlib.dll \
+ $(BCL_DIR)/System.dll \
+ $(BCL_DIR)/System.Xml.dll \
+ $(BCL_DIR)/System.Core.dll \
+ $(BCL_DIR)/I18N.dll \
+ $(BCL_DIR)/I18N.West.dll \
+ $(BCL_DIR)/Mono.Simd.dll \
+ $(BCL_DIR)/Mono.Security.dll \
+ $(BCL_DIR)/System.Numerics.dll \
+ $(BCL_DIR)/System.Numerics.Vectors.dll \
+ $(BCL_DIR)/nunitlite.dll \
+ test-runner.exe
+
+build-ios-sim-%: appbuilder.exe test-runner.exe runtime/runtime $($*_ASSEMBLIES)
+ mono appbuilder.exe --target ios-sim64 --mono-sdkdir $(PWD)/../out --appdir $(PWD)/bin/ios-sim/test-$*.app --runtimedir $(PWD)/runtime --builddir obj/ios-sim/test-$*.app --sysroot $(SYSROOT) --bundle-executable test-$* --bundle-identifier com.xamarin.mono.ios.test-$* --bundle-name test-$* $(patsubst %,-r %,$(TEST_ASSEMBLIES) $($*_ASSEMBLIES))
+ mkdir -p $(PWD)/bin/ios-sim/test-$*.app
+ if test "x$($*_EXTRA_FILES)" != "x"; then cp -r $($*_EXTRA_FILES) $(PWD)/bin/ios-sim/test-$*.app/; fi
+ ninja -C obj/ios-sim/test-$*.app -v
+
+ifdef LLVM
+APPBUILDER_ARGS += --llvm
+endif
+
+#
+# This enables caching of aot outputs between different apps.
+# Changes to the assemblies/runtimes etc. are not detected, so this should only
+# be used when compiling multiple apps with the same assemblies, i.e. the -all
+# targets.
+#
+ifdef ENABLE_AOT_CACHE
+APPBUILDER_ARGS += --aot-cachedir $(PWD)/aot-cache
+endif
+
+build-ios-dev-%: appbuilder.exe test-runner.exe runtime/libmonoios.a $($*_ASSEMBLIES)
+ mkdir -p $(PWD)/aot-cache
+ mono appbuilder.exe $(APPBUILDER_ARGS) --target ios-dev64 --mono-sdkdir $(PWD)/../out --appdir $(PWD)/bin/ios-dev/test-$*.app --runtimedir $(PWD)/runtime --builddir obj/ios-dev/test-$*.app --sysroot $(SYSROOT) --bundle-executable test-$* --bundle-identifier com.xamarin.mono.ios.test-$* --bundle-name test-$* --exe test-runner.exe $(patsubst %,-r %,$(TEST_ASSEMBLIES) $($*_ASSEMBLIES))
+ mkdir -p $(PWD)/bin/ios-dev/test-$*.app
+ if test "x$($_EXTRA_FILES)" != "x"; then cp -r $($*_EXTRA_FILES) $(PWD)/bin/ios-dev/test-$*.app/; fi
+ ninja -C obj/ios-dev/test-$*.app -v
# Clean %
clean-ios-sim-%:
- $(RM) -rf bin/ios-sim/test-$*.app
+ $(RM) -rf obj/ios-sim/test-$*.app bin/ios-sim/test-$*.app
-# Run % on the simulator with args $(ARGS) %_ARGS
-# 'launch' doesn't propagate the error code
-run-ios-sim-%:
- xcrun simctl terminate booted com.xamarin.mono.ios.test-$*
- xcrun simctl launch --console booted com.xamarin.mono.ios.test-$* $(ARGS) $($*_ARGS)
+clean-ios-dev-%:
+ $(RM) -rf obj/ios-dev/test-$*.app bin/ios-dev/test-$*.app
+
+# Install and run % on the simulator with args $(ARGS) %_ARGS
+run-ios-sim-%: harness.exe
+ mono harness.exe --start-sim
+ xcrun simctl install $(SIM_NAME) bin/ios-sim/test-$*.app
+ mono harness.exe --run-sim --logfile ios-sim-$*.log --bundle-id com.xamarin.mono.ios.test-$* --bundle-dir bin/ios-sim/test-$*.app $(ARGS) $($*_ARGS)
clean:
- $(MAKE) -C test-runner clean
- $(RM) -rf bin
+ $(MAKE) -C runtime clean
+ $(RM) -rf bin obj *.exe *.log aot-cache
+
+# Compile all the test assemblies
+compile-tests:
+ for suite in $(TEST_SUITES); do make -C ../../mcs/class/$$suite PROFILE=monotouch test || exit 1; done
+
+run-ios-sim-all:
+ for suite in $(TEST_SUITES); do make build-ios-sim-$$suite || exit 1; make run-ios-sim-$$suite || exit 1; done
+
+build-ios-dev-all:
+ rm -rf aot-cache
+ for suite in $(TEST_SUITES); do make clean-ios-dev-$$suite; make build-ios-dev-$$suite ENABLE_AOT_CACHE=1 || exit 1; done
+
+build-ios-dev-llvm-all:
+ rm -rf aot-cache
+ for suite in $(TEST_SUITES); do echo "*** $$suite ***"; make clean-ios-dev-$$suite; make build-ios-dev-$$suite LLVM=1 ENABLE_AOT_CACHE=1 || exit 1; done
+
+# Developer targets, ignore
+# 'launch' doesn't propagate the error code
+# With ios11, --console doesn't work any more, it makes the app deadlock
+# Install % on the simulator
+install-ios-sim-%:
+ xcrun simctl install $(SIM_NAME) bin/ios-sim/test-$*.app
+
+run-ios-sim-direct-%:
+ xcrun simctl terminate $(SIM_NAME) com.xamarin.mono.ios.test-$*
+ xcrun simctl launch $(SIM_NAME) com.xamarin.mono.ios.test-$* $(ARGS) $($*_ARGS)
+ log stream --level debug --predicate 'senderImagePath contains "$*"' --style compact
+
+create-sim:
+ xcrun simctl create $(SIM_NAME) 'iPhone 7' com.apple.CoreSimulator.SimRuntime.iOS-11-1
start-sim:
- xcrun simctl boot 94619BF8-ED9C-4A14-BA8C-6A22140ABA2C
+ xcrun simctl boot $(SIM_NAME)
stop-sim:
- xcrun simctl shutdown booted
+ xcrun simctl shutdown $(SIM_NAME)
-NUNIT = nunit-lite-console.exe -exclude:MobileNotWorking,NotOnMac,NotWorking,ValueAdd,CAS,InetAccess,NotWorkingLinqInterpreter -labels
+# CONNSTR will be replace by the harness with the real connection string
+NUNIT = test-runner.exe CONNSTR -exclude:MobileNotWorking,NotOnMac,NotWorking,ValueAdd,CAS,InetAccess,NotWorkingLinqInterpreter -labels
TESTDIR = $(BCL_DIR)/tests
# Options for each test
@@ -58,8 +158,44 @@ corlib_EXTRA_FILES = ../../mcs/class/corlib/{es-ES,nn-NO}
corlib_ARGS = $(NUNIT) monotouch_corlib_test.dll
System.Core_ASSEMBLIES = $(TESTDIR)/monotouch_System.Core_test.dll
System.Core_ARGS = $(NUNIT) monotouch_System.Core_test.dll
-System_ASSEMBLIES = $(TESTDIR)/monotouch_System_test.dll
+System_ASSEMBLIES = $(TESTDIR)/monotouch_System_test.dll $(BCL_DIR)/Mono.Security.dll
System_ARGS = $(NUNIT) monotouch_System_test.dll
System.Data_ASSEMBLIES = $(BCL_DIR)/System.Data.dll $(BCL_DIR)/System.Transactions.dll $(TESTDIR)/monotouch_System.Data_test.dll
System.Data_EXTRA_FILES = ../../mcs/class/System.Data/Test
System.Data_ARGS = $(NUNIT) monotouch_System.Data_test.dll
+System.Net.Http_ASSEMBLIES = $(BCL_DIR)/System.Net.Http.dll $(TESTDIR)/monotouch_System.Net.Http_test.dll
+System.Net.Http_ARGS = $(NUNIT) monotouch_System.Net.Http_test.dll
+System.Numerics_ASSEMBLIES = $(TESTDIR)/monotouch_System.Numerics_test.dll
+System.Numerics_ARGS = $(NUNIT) monotouch_System.Numerics_test.dll
+System.Runtime.Serialization_ASSEMBLIES = $(BCL_DIR)/System.Runtime.Serialization.dll $(BCL_DIR)/System.ServiceModel.dll $(BCL_DIR)/System.ServiceModel.Internals.dll $(TESTDIR)/monotouch_System.Runtime.Serialization_test.dll
+System.Runtime.Serialization_ARGS = $(NUNIT) monotouch_System.Runtime.Serialization_test.dll
+System.Transactions_ASSEMBLIES = $(BCL_DIR)/System.Transactions.dll $(TESTDIR)/monotouch_System.Transactions_test.dll
+System.Transactions_ARGS = $(NUNIT) monotouch_System.Transactions_test.dll
+System.IO.Compression_ASSEMBLIES = $(BCL_DIR)/System.IO.Compression.dll $(TESTDIR)/monotouch_System.IO.Compression_test.dll
+System.IO.Compression_ARGS = $(NUNIT) monotouch_System.IO.Compression_test.dll
+System.IO.Compression_EXTRA_FILES = ../../mcs/class/System.IO.Compression/{archive.zip,test.nupkg}
+System.IO.Compression.FileSystem_ASSEMBLIES = $(BCL_DIR)/System.IO.Compression.FileSystem.dll $(BCL_DIR)/System.IO.Compression.dll $(TESTDIR)/monotouch_System.IO.Compression.FileSystem_test.dll
+System.IO.Compression.FileSystem_ARGS = $(NUNIT) monotouch_System.IO.Compression.FileSystem_test.dll
+System.IO.Compression.FileSystem_EXTRA_FILES = ../../mcs/class/System.IO.Compression.FileSystem/foo
+Mono.CSharp_ASSEMBLIES = $(BCL_DIR)/Mono.CSharp.dll $(TESTDIR)/monotouch_Mono.CSharp_test.dll
+Mono.CSharp_ARGS = $(NUNIT) monotouch_Mono.CSharp_test.dll
+System.Json_ASSEMBLIES = $(BCL_DIR)/System.Json.dll $(TESTDIR)/monotouch_System.Json_test.dll
+System.Json_ARGS = $(NUNIT) monotouch_System.Json_test.dll
+System.ComponentModel.DataAnnotations_ASSEMBLIES = $(BCL_DIR)/System.ComponentModel.DataAnnotations.dll $(TESTDIR)/monotouch_System.ComponentModel.DataAnnotations_test.dll
+System.ComponentModel.DataAnnotations_ARGS = $(NUNIT) monotouch_System.ComponentModel.DataAnnotations_test.dll
+Mono.Data.Sqlite_ASSEMBLIES = $(BCL_DIR)/Mono.Data.Sqlite.dll $(TESTDIR)/monotouch_Mono.Data.Sqlite_test.dll
+Mono.Data.Sqlite_ARGS = $(NUNIT) monotouch_Mono.Data.Sqlite_test.dll
+Mono.Data.Tds_ASSEMBLIES = $(BCL_DIR)/Mono.Data.Tds.dll $(TESTDIR)/monotouch_Mono.Data.Tds_test.dll
+Mono.Data.Tds_ARGS = $(NUNIT) monotouch_Mono.Data.Tds_test.dll
+System.Security_ASSEMBLIES = $(BCL_DIR)/System.Security.dll $(TESTDIR)/monotouch_System.Security_test.dll
+System.Security_ARGS = $(NUNIT) monotouch_System.Security_test.dll
+System.Xml_ASSEMBLIES = $(BCL_DIR)/System.Xml.dll $(TESTDIR)/monotouch_System.Xml_test.dll
+System.Xml_ARGS = $(NUNIT) monotouch_System.Xml_test.dll
+System.Xml.Linq_ASSEMBLIES = $(BCL_DIR)/System.Xml.Linq.dll $(TESTDIR)/monotouch_System.Xml.Linq_test.dll
+System.Xml.Linq_ARGS = $(NUNIT) monotouch_System.Xml.Linq_test.dll
+Mono.Security_ASSEMBLIES = $(TESTDIR)/monotouch_Mono.Security_test.dll
+Mono.Security_ARGS = $(NUNIT) monotouch_Mono.Security_test.dll
+System.ServiceModel.Web_ASSEMBLIES = $(BCL_DIR)/System.ServiceModel.Web.dll $(BCL_DIR)/System.ServiceModel.dll $(BCL_DIR)/System.ServiceModel.Internals.dll $(BCL_DIR)/System.IdentityModel.dll $(BCL_DIR)/System.Runtime.Serialization.dll $(TESTDIR)/monotouch_System.ServiceModel.Web_test.dll
+System.ServiceModel.Web_ARGS = $(NUNIT) monotouch_System.ServiceModel.Web_test.dll
+System.Web.Services_ASSEMBLIES = $(BCL_DIR)/System.Web.Services.dll $(TESTDIR)/monotouch_System.Web.Services_test.dll
+System.Web.Services_ARGS = $(NUNIT) monotouch_System.Web.Services_test.dll
diff --git a/sdks/ios/README.md b/sdks/ios/README.md
index 2490d0dc1b2..bcd89f2a8e4 100644
--- a/sdks/ios/README.md
+++ b/sdks/ios/README.md
@@ -3,6 +3,16 @@
The test runner is an objective-c app which embeds the runtime. It has a command line interface similar to the mono runtime, i.e.
<exe> <arguments>.
+# The test harness
+
+The test harness is a C# app which automates running a test suite. It
+install the app on the simulator, runs it, and collects output into
+a log file.
+
+# The app builder
+
+This is a C# app which is used to create an ios .app bundle.
+
# Make targets
Similar to the ones in xamarin-macios/tests
@@ -22,7 +32,33 @@ Similar to the ones in xamarin-macios/tests
* Where
* -sim-
+ * -dev-
* Project
* corlib etc.
+
+The test apps require the corresponding test assembly to be already
+built, i.e. by running make PROFILE=monotouch test in mcs/class/corlib
+etc.
+
+# Running tests on device
+
+This is currently not implemented.
+
+The app can be started on the device by using ios-deploy (https://github.com/phonegap/ios-deploy):
+`ios-deploy -d -b bin/ios-dev/test-Mono.Runtime.Tests.app/ -d -a 'nunit-lite-console.exe bin/ios-dev/test-Mono.Runtime.Tests.app/monotouch_Mono.Runtime.Tests_test.dll -labels'`
+
+Getting test results from the app is more complicated. Some possible approaches:
+* Using the ios os_log facility. Unfortunately, the command line 'log' tool cannot
+seem to read the device logs, only the graphical Console app can.
+* Using `idevicesyslog` from `libimobiledevice`.
+* Have the app send back results using a tcp connection. This requires starting a
+server from the test harness, and passing the address to the app using a command line
+option. It also requires the device and the host to be on the same network.
+* Have the app listen on a port, and have the test harness connect to it using
+`libimobiledevice`, i.e. https://github.com/rsms/peertalk.
+* Use a publish-subscribe pattern by uploading test results to some cloud service like
+Azure EventHub. This only requires client side internet access on the device and
+the test harness.
+
diff --git a/sdks/ios/appbuilder/appbuilder.cs b/sdks/ios/appbuilder/appbuilder.cs
new file mode 100644
index 00000000000..bd8f6bf5247
--- /dev/null
+++ b/sdks/ios/appbuilder/appbuilder.cs
@@ -0,0 +1,247 @@
+using System;
+using System.IO;
+using System.Reflection;
+using System.Collections.Generic;
+using Mono.Options;
+
+public class AppBuilder
+{
+ public static void Main (String[] args) {
+ new AppBuilder ().Run (args);
+ }
+
+ void GenMain (string builddir, List<string> assembly_names) {
+ var symbols = new List<string> ();
+ foreach (var img in assembly_names) {
+ symbols.Add (String.Format ("mono_aot_module_{0}_info", img.Replace ('.', '_').Replace ('-', '_')));
+ }
+
+ var w = File.CreateText (Path.Combine (builddir, "main.m"));
+
+ w.WriteLine ($"extern void mono_aot_register_module (char *name);");
+
+ foreach (var symbol in symbols) {
+ w.WriteLine ($"extern void *{symbol};");
+ }
+
+ w.WriteLine ();
+ w.WriteLine ("void mono_ios_register_modules (void)");
+ w.WriteLine ("{");
+ foreach (var symbol in symbols) {
+ w.WriteLine ($"\tmono_aot_register_module ({symbol});");
+ }
+ w.WriteLine ("}");
+ w.Close ();
+ }
+
+ void check_mandatory (string val, string name) {
+ if (val == null) {
+ Console.Error.WriteLine ($"The {name} argument is mandatory.");
+ Environment.Exit (1);
+ }
+ }
+
+ void Run (String[] args) {
+ string target = null;
+ string appdir = null;
+ string builddir = null;
+ string runtimedir = null;
+ string mono_sdkdir = null;
+ string bundle_identifier = null;
+ string bundle_name = null;
+ string bundle_executable = null;
+ string sysroot = null;
+ string aotdir = null;
+ string exe = null;
+ bool isdev = false;
+ bool isrelease = false;
+ bool isllvm = false;
+ var assemblies = new List<string> ();
+ var p = new OptionSet () {
+ { "target=", s => target = s },
+ { "appdir=", s => appdir = s },
+ { "builddir=", s => builddir = s },
+ { "runtimedir=", s => runtimedir = s },
+ { "mono-sdkdir=", s => mono_sdkdir = s },
+ { "sysroot=", s => sysroot = s },
+ { "aot-cachedir=", s => aotdir = s },
+ { "bundle-identifier=", s => bundle_identifier = s },
+ { "bundle-name=", s => bundle_name = s },
+ { "bundle-executable=", s => bundle_executable = s },
+ { "llvm", s => isllvm = true },
+ { "exe=", s => exe = s },
+ { "r=", s => assemblies.Add (s) },
+ };
+
+ var new_args = p.Parse (args).ToArray ();
+
+ check_mandatory (target, "--target");
+ check_mandatory (runtimedir, "--runtimedir");
+ check_mandatory (appdir, "--appdir");
+ check_mandatory (mono_sdkdir, "--mono-sdkdir");
+ check_mandatory (sysroot, "--sysroot");
+
+ switch (target) {
+ case "ios-dev64":
+ isdev = true;
+ break;
+ case "ios-sim64":
+ break;
+ default:
+ Console.WriteLine ($"Possible values for the '--target=' argument are 'ios-dev64', 'ios-sim64', got {target}.");
+ Environment.Exit (1);
+ break;
+ }
+
+ if (isllvm)
+ isrelease = true;
+
+ string aot_args = "";
+ string cross_runtime_args = "";
+ if (!isrelease)
+ aot_args = "soft-debug";
+ if (isllvm) {
+ cross_runtime_args = "--llvm";
+ aot_args = ",llvm-path=$mono_sdkdir/llvm64/bin,llvm-outfile=$llvm_outfile";
+ }
+
+ Directory.CreateDirectory (builddir);
+
+ // Create Info.plist file
+ var lines = File.ReadAllLines (Path.Combine (runtimedir, "Info.plist.in"));
+ for (int i = 0; i < lines.Length; ++i) {
+ string line = lines [i];
+ line = line.Replace ("BUNDLE_IDENTIFIER", bundle_identifier);
+ line = line.Replace ("BUNDLE_EXECUTABLE", bundle_executable);
+ line = line.Replace ("BUNDLE_NAME", bundle_name);
+ line = line.Replace ("PLATFORM", isdev ? "iPhoneOS" : "iPhoneSimulator");
+ lines [i] = line;
+ }
+ File.WriteAllLines (Path.Combine (builddir, "Info.plist"), lines);
+
+ // Create config.json file
+ string config = "{ \"exe\" : \"" + exe + "\" }";
+ File.WriteAllLines (Path.Combine (builddir, "config.json"), new string [] { config });
+
+ var ninja = File.CreateText (Path.Combine (builddir, "build.ninja"));
+
+ // Defines
+ ninja.WriteLine ($"mono_sdkdir = {mono_sdkdir}");
+ ninja.WriteLine ($"monoios_dir = {runtimedir}");
+ ninja.WriteLine ($"appdir = {appdir}");
+ ninja.WriteLine ($"sysroot = {sysroot}");
+ ninja.WriteLine ("cross = $mono_sdkdir/ios-cross64/bin/aarch64-darwin-mono-sgen");
+ ninja.WriteLine ($"builddir = .");
+ if (aotdir != null)
+ ninja.WriteLine ($"aotdir = {aotdir}");
+ // Rules
+ ninja.WriteLine ("rule aot");
+ ninja.WriteLine ($" command = MONO_PATH=$mono_path $cross -O=gsharedvt,float32 --debug {cross_runtime_args} --aot=mtriple=arm64-ios,full,static,asmonly,direct-icalls,no-direct-calls,dwarfdebug,{aot_args},outfile=$outfile,data-outfile=$data_outfile $src_file");
+ ninja.WriteLine (" description = [AOT] $src_file -> $outfile");
+ // ninja remakes files it hadn't seen before even if the timestamp is newer, so have to add a test ourselves
+ ninja.WriteLine ("rule aot-cached");
+ ninja.WriteLine ($" command = if ! test -f $outfile; then MONO_PATH=$mono_path $cross -O=gsharedvt,float32 --debug {cross_runtime_args} --aot=mtriple=arm64-ios,full,static,asmonly,direct-icalls,no-direct-calls,dwarfdebug,{aot_args},outfile=$outfile,data-outfile=$data_outfile $src_file; fi");
+ ninja.WriteLine (" description = [AOT] $src_file -> $outfile");
+ ninja.WriteLine ("rule assemble");
+ ninja.WriteLine (" command = clang -isysroot $sysroot -miphoneos-version-min=10.1 -arch arm64 -c -o $out $in");
+ ninja.WriteLine (" description = [ASM] $in -> $out");
+ ninja.WriteLine ("rule assemble-cached");
+ ninja.WriteLine (" command = if ! test -f $out; then clang -isysroot $sysroot -miphoneos-version-min=10.1 -arch arm64 -c -o $out $in; fi");
+ ninja.WriteLine (" description = [ASM] $in -> $out");
+ ninja.WriteLine ("rule cp");
+ ninja.WriteLine (" command = cp $in $out");
+ ninja.WriteLine (" description = [CP] $in -> $out");
+ ninja.WriteLine ("rule cp-recursive");
+ ninja.WriteLine (" command = cp -r $in $out");
+ ninja.WriteLine ("rule cpifdiff");
+ ninja.WriteLine (" command = if cmp -s $in $out ; then : ; else cp $in $out ; fi");
+ ninja.WriteLine (" restat = true");
+ ninja.WriteLine ("rule plutil");
+ ninja.WriteLine (" command = cp $in $out; plutil -convert binary1 $out");
+ ninja.WriteLine ("rule codesign");
+ ninja.WriteLine (" command = codesign -v --force --sign - --entitlements $entitlements --timestamp=none $in");
+ ninja.WriteLine ("rule codesign-sim");
+ ninja.WriteLine (" command = codesign --force --sign - --timestamp=none $in");
+ ninja.WriteLine ("rule mkdir");
+ ninja.WriteLine (" command = mkdir -p $out");
+ ninja.WriteLine ("rule compile-objc");
+ ninja.WriteLine (" command = clang -isysroot $sysroot -miphoneos-version-min=10.1 -arch arm64 -c -o $out $in");
+ ninja.WriteLine ("rule gen-exe");
+ ninja.WriteLine (" command = mkdir $appdir");
+ ninja.WriteLine ($" command = clang -ObjC -isysroot $sysroot -miphoneos-version-min=10.1 -arch arm64 -framework Foundation -framework UIKit -o $appdir/{bundle_executable} $in -liconv");
+
+ var ofiles = "";
+ var assembly_names = new List<string> ();
+ foreach (var assembly in assemblies) {
+ string filename = Path.GetFileName (assembly);
+ var filename_noext = Path.GetFileNameWithoutExtension (filename);
+
+ File.Copy (assembly, Path.Combine (builddir, filename), true);
+ if (aotdir != null && !File.Exists (Path.Combine (aotdir, filename)))
+ /* Don't overwrite to avoid changing the timestamp */
+ File.Copy (assembly, Path.Combine (aotdir, filename), false);
+
+ ninja.WriteLine ($"build $appdir/{filename}: cpifdiff $builddir/{filename}");
+ if (isdev) {
+ string destdir = null;
+ string srcfile = null;
+ string assemble_rule = null;
+ if (aotdir != null) {
+ destdir = "$aotdir";
+ srcfile = Path.Combine (aotdir, filename);
+ assemble_rule = "assemble-cached";
+ } else {
+ destdir = "$builddir";
+ srcfile = $"{filename}";
+ assemble_rule = "assemble";
+ }
+ string outputs = $"{destdir}/{filename}.s {destdir}/{filename_noext}.aotdata";
+ if (isllvm)
+ outputs += $" {destdir}/{filename}.llvm.s";
+ if (aotdir != null)
+ ninja.WriteLine ($"build {outputs}: aot-cached {srcfile}");
+ else
+ ninja.WriteLine ($"build {outputs}: aot {srcfile}");
+ ninja.WriteLine ($" src_file={srcfile}");
+ ninja.WriteLine ($" outfile={destdir}/{filename}.s");
+ ninja.WriteLine ($" data_outfile={destdir}/{filename_noext}.aotdata");
+ ninja.WriteLine ($" mono_path={destdir}");
+ if (isllvm)
+ ninja.WriteLine ($" llvm_outfile={destdir}/{filename}.llvm.s");
+ ninja.WriteLine ($"build {destdir}/{filename}.o: {assemble_rule} {destdir}/{filename}.s");
+ if (isllvm)
+ ninja.WriteLine ($"build {destdir}/{filename}.llvm.o: {assemble_rule} {destdir}/{filename}.llvm.s");
+ ninja.WriteLine ($"build $appdir/{filename_noext}.aotdata: cp {destdir}/{filename_noext}.aotdata");
+
+ ofiles += " " + ($"{destdir}/{filename}.o");
+ if (isllvm)
+ ofiles += " " + ($"{destdir}/{filename}.llvm.o");
+ }
+ var aname = AssemblyName.GetAssemblyName (assembly);
+ assembly_names.Add (aname.Name);
+ }
+
+ ninja.WriteLine ("build $appdir: mkdir");
+
+ if (isdev) {
+ ninja.WriteLine ($"build $appdir/{bundle_executable}: gen-exe {ofiles} $builddir/main.o $mono_sdkdir/ios-target64/lib/libmonosgen-2.0.a $monoios_dir/libmonoios.a");
+ ninja.WriteLine ("build $builddir/main.o: compile-objc $builddir/main.m");
+ } else {
+ ninja.WriteLine ($"build $appdir/{bundle_executable}: cp $monoios_dir/runtime");
+ }
+ ninja.WriteLine ("build $builddir/Info.plist.binary: plutil $builddir/Info.plist");
+ ninja.WriteLine ("build $appdir/Info.plist: cpifdiff $builddir/Info.plist.binary");
+ ninja.WriteLine ("build $appdir/config.json: cpifdiff $builddir/config.json");
+ ninja.WriteLine ("build $builddir/Entitlements.xcent: cpifdiff $monoios_dir/Entitlements.xcent");
+ if (isdev)
+ ninja.WriteLine ($"build $appdir/_CodeSignature: codesign $appdir/{bundle_executable} | $builddir/Entitlements.xcent");
+ else
+ ninja.WriteLine ($"build $appdir/_CodeSignature: codesign-sim $appdir/{bundle_executable} | $builddir/Entitlements.xcent");
+ ninja.WriteLine (" entitlements=$builddir/Entitlements.xcent");
+ ninja.WriteLine ("build $appdir/Base.lproj: cp-recursive $monoios_dir/Base.lproj");
+
+ ninja.Close ();
+
+ GenMain (builddir, assembly_names);
+ }
+}
diff --git a/sdks/ios/harness/harness.cs b/sdks/ios/harness/harness.cs
new file mode 100644
index 00000000000..cd838be4ed2
--- /dev/null
+++ b/sdks/ios/harness/harness.cs
@@ -0,0 +1,196 @@
+using System;
+using System.IO;
+using System.Json;
+using System.Threading;
+using System.Diagnostics;
+using System.Net;
+using System.Net.Sockets;
+using Mono.Options;
+
+public class Harness
+{
+ public const string SIM_NAME = "xamarin.ios-sdk.sim";
+
+ static void Usage () {
+ Console.WriteLine ("Usage: mono harness.exe <options> <app dir>");
+ Console.WriteLine ("Where options are:");
+ Console.WriteLine ("\t--run-sim");
+ Console.WriteLine ("\t--app=<app bundle id>");
+ Console.WriteLine ("\t--logfile=<log file name>");
+ }
+
+ public static int Main (string[] args) {
+ new Harness ().Run (args);
+ return 0;
+ }
+
+ string bundle_id;
+ string bundle_dir;
+ string logfile_name;
+ string[] new_args;
+
+ public void Run (string[] args) {
+ string action = "";
+ bundle_id = "";
+ bundle_dir = "";
+ logfile_name = "";
+
+ var p = new OptionSet () {
+ { "start-sim", s => action = "start-sim" },
+ { "run-sim", s => action = "run-sim" },
+ { "bundle-id=", s => bundle_id = s },
+ { "bundle-dir=", s => bundle_dir = s },
+ { "logfile=", s => logfile_name = s },
+ };
+ new_args = p.Parse (args).ToArray ();
+
+ if (action == "start-sim") {
+ StartSim ();
+ } else if (action == "run-sim") {
+ if (bundle_id == "" || bundle_dir == "") {
+ Console.WriteLine ("The --bundle-id and --bundle-dir arguments are mandatory.");
+ Environment.Exit (1);
+ }
+ RunSim ();
+ } else {
+ Usage ();
+ Environment.Exit (1);
+ }
+ }
+
+ void StartSim () {
+ // Check whenever our simulator instance exists
+ string state_line = "";
+ {
+ var args = "simctl list devices";
+ Console.WriteLine ("Running: " + "xcrun " + args);
+ var start_info = new ProcessStartInfo ("xcrun", args);
+ start_info.RedirectStandardOutput = true;
+ start_info.UseShellExecute = false;
+ var process = Process.Start (start_info);
+ var stream = process.StandardOutput;
+ string line = "";
+ while (true) {
+ line = stream.ReadLine ();
+ if (line == null)
+ break;
+ if (line.Contains (SIM_NAME)) {
+ state_line = line;
+ break;
+ }
+ }
+ process.WaitForExit ();
+ if (process.ExitCode != 0)
+ Environment.Exit (1);
+ }
+
+ bool need_start = false;
+ if (state_line == "") {
+ // Get the runtime type
+ var args = "simctl list -j runtimes";
+ Console.WriteLine ("Running: " + "xcrun " + args);
+ var start_info = new ProcessStartInfo ("xcrun", args);
+ start_info.RedirectStandardOutput = true;
+ start_info.UseShellExecute = false;
+ var process = Process.Start (start_info);
+ var stream = process.StandardOutput;
+ JsonObject value = JsonValue.Parse (stream.ReadToEnd ()) as JsonObject;
+ string runtime = value ["runtimes"][0]["identifier"];
+
+ // Create the simulator
+ args = "simctl create " + SIM_NAME + " 'iPhone 7' " + runtime;
+ Console.WriteLine ("Running: " + "xcrun " + args);
+ process = Process.Start ("xcrun", args);
+ process.WaitForExit ();
+ if (process.ExitCode != 0)
+ Environment.Exit (1);
+ need_start = true;
+ } else if (state_line.Contains ("(Shutdown)")) {
+ need_start = true;
+ }
+
+ if (need_start) {
+ var args = "simctl boot " + SIM_NAME;
+ Console.WriteLine ("Running: " + "xcrun " + args);
+ var process = Process.Start ("xcrun", args);
+ process.WaitForExit ();
+ if (process.ExitCode != 0)
+ Environment.Exit (1);
+ }
+ }
+
+ void RunSim () {
+ Console.WriteLine ("App: " + bundle_id);
+
+ StartSim ();
+
+ // Install the app
+ // We do this all the time since its cheap
+ string exe = "xcrun";
+ string args = "simctl install " + SIM_NAME + " " + bundle_dir;
+ Console.WriteLine ("Running: " + exe + " " + args);
+ var process = Process.Start (exe, args);
+ process.WaitForExit ();
+ if (process.ExitCode != 0)
+ Environment.Exit (1);
+
+ //
+ // Test results are returned using an socket connection.
+ //
+ var host = Dns.GetHostEntry (Dns.GetHostName ());
+ var server = new TcpListener (System.Net.IPAddress.Loopback, 0);
+ server.Start ();
+ int port = ((IPEndPoint)server.LocalEndpoint).Port;
+
+ string app_args = "";
+ foreach (var a in new_args)
+ app_args += a + " ";
+ if (!app_args.Contains ("CONNSTR"))
+ throw new Exception ();
+ app_args = app_args.Replace ("CONNSTR", $"tcp:localhost:{port}");
+
+ // Terminate previous app
+ exe = "xcrun";
+ args = "simctl terminate " + SIM_NAME + " " + bundle_id;
+ Console.WriteLine ("Running: " + exe + " " + args);
+ process = Process.Start (exe, args);
+ process.WaitForExit ();
+ if (process.ExitCode != 0)
+ Environment.Exit (1);
+
+ // Launch new app
+ exe = "xcrun";
+ args = "simctl launch " + SIM_NAME + " " + bundle_id + " " + app_args;
+ Console.WriteLine ("Running: " + exe + " " + args);
+ process = Process.Start (exe, args);
+ process.WaitForExit ();
+ if (process.ExitCode != 0)
+ Environment.Exit (1);
+
+ //
+ // Read test results from the tcp connection
+ //
+ TextWriter w = new StreamWriter (logfile_name);
+ string result_line = null;
+ var client = server.AcceptTcpClient ();
+ var stream = client.GetStream ();
+ var reader = new StreamReader (stream);
+ while (true) {
+ var line = reader.ReadLine ();
+ if (line == null)
+ break;
+ Console.WriteLine (line);
+ w.WriteLine (line);
+ if (line.Contains ("Tests run:"))
+ result_line = line;
+ // Printed by the runtime
+ if (line.Contains ("Exit code:"))
+ break;
+ }
+
+ if (result_line != null && result_line.Contains ("Errors: 0"))
+ Environment.Exit (0);
+ else
+ Environment.Exit (1);
+ }
+}
diff --git a/sdks/ios/test-runner/AppDelegate.h b/sdks/ios/runtime/AppDelegate.h
index fd49c47b337..fd49c47b337 100644
--- a/sdks/ios/test-runner/AppDelegate.h
+++ b/sdks/ios/runtime/AppDelegate.h
diff --git a/sdks/ios/test-runner/AppDelegate.m b/sdks/ios/runtime/AppDelegate.m
index 1578910d7b2..1578910d7b2 100644
--- a/sdks/ios/test-runner/AppDelegate.m
+++ b/sdks/ios/runtime/AppDelegate.m
diff --git a/sdks/ios/test-runner/Base.lproj/LaunchScreen.storyboardc/01J-lp-oVM-view-Ze5-6b-2t3.nib b/sdks/ios/runtime/Base.lproj/LaunchScreen.storyboardc/01J-lp-oVM-view-Ze5-6b-2t3.nib
index 9aa00f51419..9aa00f51419 100644
--- a/sdks/ios/test-runner/Base.lproj/LaunchScreen.storyboardc/01J-lp-oVM-view-Ze5-6b-2t3.nib
+++ b/sdks/ios/runtime/Base.lproj/LaunchScreen.storyboardc/01J-lp-oVM-view-Ze5-6b-2t3.nib
Binary files differ
diff --git a/sdks/ios/test-runner/Base.lproj/LaunchScreen.storyboardc/Info.plist b/sdks/ios/runtime/Base.lproj/LaunchScreen.storyboardc/Info.plist
index 32288e88f6e..32288e88f6e 100644
--- a/sdks/ios/test-runner/Base.lproj/LaunchScreen.storyboardc/Info.plist
+++ b/sdks/ios/runtime/Base.lproj/LaunchScreen.storyboardc/Info.plist
Binary files differ
diff --git a/sdks/ios/test-runner/Base.lproj/LaunchScreen.storyboardc/UIViewController-01J-lp-oVM.nib b/sdks/ios/runtime/Base.lproj/LaunchScreen.storyboardc/UIViewController-01J-lp-oVM.nib
index 6b39fef6975..6b39fef6975 100644
--- a/sdks/ios/test-runner/Base.lproj/LaunchScreen.storyboardc/UIViewController-01J-lp-oVM.nib
+++ b/sdks/ios/runtime/Base.lproj/LaunchScreen.storyboardc/UIViewController-01J-lp-oVM.nib
Binary files differ
diff --git a/sdks/ios/test-runner/Base.lproj/Main.storyboardc/BYZ-38-t0r-view-8bC-Xf-vdC.nib b/sdks/ios/runtime/Base.lproj/Main.storyboardc/BYZ-38-t0r-view-8bC-Xf-vdC.nib
index de467bf1fc8..de467bf1fc8 100644
--- a/sdks/ios/test-runner/Base.lproj/Main.storyboardc/BYZ-38-t0r-view-8bC-Xf-vdC.nib
+++ b/sdks/ios/runtime/Base.lproj/Main.storyboardc/BYZ-38-t0r-view-8bC-Xf-vdC.nib
Binary files differ
diff --git a/sdks/ios/test-runner/Base.lproj/Main.storyboardc/Info.plist b/sdks/ios/runtime/Base.lproj/Main.storyboardc/Info.plist
index 9a41f2cb91b..9a41f2cb91b 100644
--- a/sdks/ios/test-runner/Base.lproj/Main.storyboardc/Info.plist
+++ b/sdks/ios/runtime/Base.lproj/Main.storyboardc/Info.plist
Binary files differ
diff --git a/sdks/ios/test-runner/Base.lproj/Main.storyboardc/UIViewController-BYZ-38-t0r.nib b/sdks/ios/runtime/Base.lproj/Main.storyboardc/UIViewController-BYZ-38-t0r.nib
index e22d2126647..e22d2126647 100644
--- a/sdks/ios/test-runner/Base.lproj/Main.storyboardc/UIViewController-BYZ-38-t0r.nib
+++ b/sdks/ios/runtime/Base.lproj/Main.storyboardc/UIViewController-BYZ-38-t0r.nib
Binary files differ
diff --git a/sdks/ios/runtime/Entitlements.xcent b/sdks/ios/runtime/Entitlements.xcent
new file mode 100644
index 00000000000..ff24d120cea
--- /dev/null
+++ b/sdks/ios/runtime/Entitlements.xcent
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>get-task-allow</key>
+ <true/>
+ <key>application-identifier</key>
+ <string>C9D4426WFH.com.xamarin.test2</string>
+ <key>com.apple.developer.team-identifier</key>
+ <string>C9D4426WFH</string>
+</dict>
+</plist>
diff --git a/sdks/ios/test-runner/Info.plist.in b/sdks/ios/runtime/Info.plist.in
index 9c4c239cb34..9c4c239cb34 100644
--- a/sdks/ios/test-runner/Info.plist.in
+++ b/sdks/ios/runtime/Info.plist.in
diff --git a/sdks/ios/runtime/Makefile b/sdks/ios/runtime/Makefile
new file mode 100644
index 00000000000..6fcfe7b36c9
--- /dev/null
+++ b/sdks/ios/runtime/Makefile
@@ -0,0 +1,74 @@
+all: runtime libmonoios.a
+
+XCODE_ROOT=$(shell xcode-select -p)
+
+UNREFERENCED_SYMBOLS = \
+ _xamarin_log \
+ _xamarin_timezone_get_data \
+ _xamarin_timezone_get_names \
+ _CloseZStream \
+ _CreateZStream \
+ _Flush \
+ _ReadZStream \
+ _WriteZStream
+
+CC = $(XCODE_ROOT)/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang
+SIM_SYSROOT = $(XCODE_ROOT)/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk
+SIM_ARCH = x86_64
+SIM_SDK_DIR = ../../out/ios-sim64
+SIM_CFLAGS = \
+ -std=gnu11 \
+ -fobjc-arc \
+ -isysroot $(SIM_SYSROOT) \
+ -mios-simulator-version-min=10.1 \
+ -g \
+ -I$(SIM_SDK_DIR)/include/mono-2.0
+
+SIM_LDFLAGS = \
+ -isysroot $(SIM_SYSROOT) \
+ -mios-simulator-version-min=10.1 \
+ -framework Foundation \
+ -framework UIKit \
+ $(foreach u,$(UNREFERENCED_SYMBOLS),-u $u) \
+ $(SIM_SDK_DIR)/lib/libmonosgen-2.0.a \
+ $(SIM_SDK_DIR)/lib/libMonoPosixHelper.a \
+ -liconv -lz
+
+sim-%.o: %.m
+ $(ENV) $(CC) -arch $(SIM_ARCH) $(SIM_CFLAGS) -c -o $@ $^
+
+runtime: sim-main.o sim-runtime.o sim-AppDelegate.o sim-ViewController.o
+ $(ENV) $(CC) -arch $(SIM_ARCH) $(SIM_LDFLAGS) -o $@ $^
+
+DEV_ARCH = arm64
+DEV_SDK_DIR = ../../out/ios-target64
+DEV_SYSROOT = $(XCODE_ROOT)/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/
+DEV_CFLAGS = \
+ -isysroot $(DEV_SYSROOT) \
+ -std=gnu11 \
+ -fobjc-arc \
+ -mios-simulator-version-min=10.1 \
+ -g \
+ -fPIC \
+ -DDEVICE=1 \
+ -I$(DEV_SDK_DIR)/include/mono-2.0
+
+DEV_LDFLAGS = \
+ -isysroot $(DEV_SYSROOT) \
+ -mios-simulator-version-min=10.1 \
+ -framework Foundation \
+ -framework UIKit \
+ -Wl,-pie \
+ $(foreach u,$(UNREFERENCED_SYMBOLS),-u $u) \
+ $(DEV_SDK_DIR)/lib/libmonosgen-2.0.a \
+ $(DEV_SDK_DIR)/lib/libMonoPosixHelper.a \
+ -liconv -lz
+
+dev-%.o: %.m
+ $(ENV) $(CC) -arch $(DEV_ARCH) $(DEV_CFLAGS) -c -o $@ $^
+
+libmonoios.a: dev-main.o dev-runtime.o dev-AppDelegate.o dev-ViewController.o
+ libtool -static -o $@ $^
+
+clean:
+ $(RM) -rf runtime *.o *.a
diff --git a/sdks/ios/test-runner/ViewController.h b/sdks/ios/runtime/ViewController.h
index 2904d029aad..2904d029aad 100644
--- a/sdks/ios/test-runner/ViewController.h
+++ b/sdks/ios/runtime/ViewController.h
diff --git a/sdks/ios/test-runner/ViewController.m b/sdks/ios/runtime/ViewController.m
index a7e9b4c16a4..d7d0b8b49bc 100644
--- a/sdks/ios/test-runner/ViewController.m
+++ b/sdks/ios/runtime/ViewController.m
@@ -18,11 +18,15 @@
- (void)viewDidLoad {
[super viewDidLoad];
- NSLog (@"HELLO!\n");
- mono_ios_runtime_init ();
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
+ [self startRuntime];
+ });
// Do any additional setup after loading the view, typically from a nib.
}
+- (void)startRuntime {
+ mono_ios_runtime_init ();
+}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
diff --git a/sdks/ios/test-runner/main.m b/sdks/ios/runtime/main.m
index ff82643884a..ff82643884a 100644
--- a/sdks/ios/test-runner/main.m
+++ b/sdks/ios/runtime/main.m
diff --git a/sdks/ios/test-runner/runtime.h b/sdks/ios/runtime/runtime.h
index 7f6450f8204..7f6450f8204 100644
--- a/sdks/ios/test-runner/runtime.h
+++ b/sdks/ios/runtime/runtime.h
diff --git a/sdks/ios/test-runner/runtime.m b/sdks/ios/runtime/runtime.m
index d88b66891ef..39a2a2867d7 100644
--- a/sdks/ios/test-runner/runtime.m
+++ b/sdks/ios/runtime/runtime.m
@@ -4,13 +4,17 @@
//
#import <Foundation/Foundation.h>
+#import <os/log.h>
#include <mono/utils/mono-publib.h>
+#include <mono/utils/mono-logger.h>
#include <mono/metadata/assembly.h>
#include <mono/metadata/mono-debug.h>
#include <mono/metadata/exception.h>
#include <mono/jit/jit.h>
+#include <mono/jit/jit.h>
#include <sys/stat.h>
+#include <sys/mman.h>
//
// Based on runtime/ in xamarin-macios
@@ -18,6 +22,13 @@
#define PRINT(...) do { printf (__VA_ARGS__); } while (0);
+static os_log_t stdout_log;
+
+/* These are not in public headers */
+typedef unsigned char* (*MonoLoadAotDataFunc) (MonoAssembly *assembly, int size, void *user_data, void **out_handle);
+typedef void (*MonoFreeAotDataFunc) (MonoAssembly *assembly, int size, void *user_data, void *handle);
+void mono_install_load_aot_data_hook (MonoLoadAotDataFunc load_func, MonoFreeAotDataFunc free_func, void *user_data);
+
bool
file_exists (const char *path)
{
@@ -43,6 +54,50 @@ get_bundle_path (void)
return bundle_path;
}
+static unsigned char *
+load_aot_data (MonoAssembly *assembly, int size, void *user_data, void **out_handle)
+{
+ *out_handle = NULL;
+
+ char path [1024];
+ int res;
+
+ MonoAssemblyName *assembly_name = mono_assembly_get_name (assembly);
+ const char *aname = mono_assembly_name_get_name (assembly_name);
+ const char *bundle = get_bundle_path ();
+
+ // LOG (PRODUCT ": Looking for aot data for assembly '%s'.", name);
+ res = snprintf (path, sizeof (path) - 1, "%s/%s.aotdata", bundle, aname);
+ assert (res > 0);
+
+ int fd = open (path, O_RDONLY);
+ if (fd < 0) {
+ //LOG (PRODUCT ": Could not load the aot data for %s from %s: %s\n", aname, path, strerror (errno));
+ return NULL;
+ }
+
+ void *ptr = mmap (NULL, size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
+ if (ptr == MAP_FAILED) {
+ //LOG (PRODUCT ": Could not map the aot file for %s: %s\n", aname, strerror (errno));
+ close (fd);
+ return NULL;
+ }
+
+ close (fd);
+
+ //LOG (PRODUCT ": Loaded aot data for %s.\n", name);
+
+ *out_handle = ptr;
+
+ return (unsigned char *) ptr;
+}
+
+static void
+free_aot_data (MonoAssembly *assembly, int size, void *user_data, void *handle)
+{
+ munmap (handle, size);
+}
+
static MonoAssembly*
load_assembly (const char *name, const char *culture)
{
@@ -50,7 +105,7 @@ load_assembly (const char *name, const char *culture)
char path [1024];
int res;
- NSLog (@"assembly_preload_hook: %s %s %s\n", name, culture, bundle);
+ os_log_info (OS_LOG_DEFAULT, "assembly_preload_hook: %{public}s %{public}s %{public}s\n", name, culture, bundle);
if (culture && strcmp (culture, ""))
res = snprintf (path, sizeof (path) - 1, "%s/%s/%s", bundle, culture, name);
else
@@ -134,22 +189,73 @@ unhandled_exception_handler (MonoObject *exc, void *user_data)
free (message);
free (type_name);
- NSLog (@"%@", msg);
+ os_log_info (OS_LOG_DEFAULT, "%@", msg);
+ os_log_info (OS_LOG_DEFAULT, "Exit code: %d.", 1);
exit (1);
}
void
+log_callback (const char *log_domain, const char *log_level, const char *message, mono_bool fatal, void *user_data)
+{
+ os_log_info (OS_LOG_DEFAULT, "(%s %s) %s", log_domain, log_level, message);
+ NSLog (@"(%s %s) %s", log_domain, log_level, message);
+ if (fatal) {
+ os_log_info (OS_LOG_DEFAULT, "Exit code: %d.", 1);
+ exit (1);
+ }
+}
+
+/* Implemented by generated code */
+void mono_ios_register_modules (void);
+
+void
mono_ios_runtime_init (void)
{
- int res;
+ NSBundle *main_bundle = [NSBundle mainBundle];
+ NSString *path;
+ char *result;
+ int res, nargs, config_nargs;
+ char *executable;
+ char **args, **config_args = NULL;
+
+ stdout_log = os_log_create ("com.xamarin", "stdout");
id args_array = [[NSProcessInfo processInfo] arguments];
- int nargs = [args_array count];
- char **args;
+ nargs = [args_array count];
+
+ //
+ // Read executable name etc. from an embedded config file if its exists
+ //
+ path = [[NSString alloc] initWithFormat: @"%@/config.json", [main_bundle bundlePath]];
+ NSData *data = [NSData dataWithContentsOfFile: path];
+ if (data) {
+ NSError *error = nil;
+ id json = [NSJSONSerialization
+ JSONObjectWithData:data
+ options:0
+ error:&error];
+ assert (!error);
+ assert ([json isKindOfClass:[NSDictionary class]]);
+ NSDictionary *dict = (NSDictionary*)json;
+ id val = dict [@"exe"];
+ assert (val);
+ executable = strdup ([((NSString*)val) UTF8String]);
+ config_nargs = 2;
+ config_args = malloc (nargs * sizeof (char*));
+ config_args [0] = strdup ([((NSString*)[args_array objectAtIndex: 0]) UTF8String]);
+ config_args [1] = executable;
+ }
- args = malloc (nargs * sizeof (char*));
- for (int i = 0; i < nargs; ++i)
- args [i] = strdup ([((NSString*)[args_array objectAtIndex: i]) UTF8String]);
+ if (nargs == 1) {
+ /* Use the args from the config file */
+ nargs = config_nargs;
+ args = config_args;
+ } else {
+ /* Use the real command line args */
+ args = malloc (nargs * sizeof (char*));
+ for (int i = 0; i < nargs; ++i)
+ args [i] = strdup ([((NSString*)[args_array objectAtIndex: i]) UTF8String]);
+ }
int aindex = 1;
while (aindex < nargs) {
@@ -163,30 +269,42 @@ mono_ios_runtime_init (void)
*eq = '\0';
char *name = strdup (p);
char *val = strdup (eq + 1);
- NSLog (@"%s=%s.", name, val);
+ os_log_info (OS_LOG_DEFAULT, "%s=%s.", name, val);
setenv (name, val, TRUE);
}
aindex ++;
}
- assert (aindex < nargs);
- char *executable = args [aindex];
+ if (aindex == nargs) {
+ os_log_info (OS_LOG_DEFAULT, "Executable argument missing.");
+ exit (1);
+ }
+ executable = args [aindex];
aindex ++;
const char *bundle = get_bundle_path ();
chdir (bundle);
+#ifdef DEVICE
+ mono_ios_register_modules ();
+ mono_jit_set_aot_mode (MONO_AOT_MODE_FULL);
+#endif
+
mono_debug_init (MONO_DEBUG_FORMAT_MONO);
mono_install_assembly_preload_hook (assembly_preload_hook, NULL);
+ mono_install_load_aot_data_hook (load_aot_data, free_aot_data, NULL);
mono_install_unhandled_exception_hook (unhandled_exception_handler, NULL);
+ mono_trace_set_log_handler (log_callback, NULL);
mono_set_signal_chaining (TRUE);
mono_set_crash_chaining (TRUE);
+ //setenv ("MONO_LOG_LEVEL", "debug", TRUE);
+
mono_jit_init_version ("Mono.ios", "mobile");
MonoAssembly *assembly = load_assembly (executable, NULL);
assert (assembly);
- NSLog (@"Executable: %s", executable);
+ os_log_info (OS_LOG_DEFAULT, "Executable: %{public}s", executable);
int managed_argc = nargs - aindex;
char *managed_argv [128];
assert (managed_argc < 128 - 2);
@@ -194,7 +312,7 @@ mono_ios_runtime_init (void)
managed_argv [managed_aindex ++] = "test-runner";
for (int i = 0; i < managed_argc; ++i) {
managed_argv [managed_aindex] = args [aindex];
- NSLog (@"Arg: %s", managed_argv [managed_aindex]);
+ os_log_info (OS_LOG_DEFAULT, "Arg: %s", managed_argv [managed_aindex]);
managed_aindex ++;
aindex ++;
}
@@ -202,6 +320,8 @@ mono_ios_runtime_init (void)
managed_argc = managed_aindex;
res = mono_jit_exec (mono_domain_get (), assembly, managed_argc, managed_argv);
+ // Print this so apps parsing logs can detect when we exited
+ os_log_info (OS_LOG_DEFAULT, "Exit code: %d.", res);
exit (res);
}
@@ -251,3 +371,28 @@ xamarin_GetFolderPath (int folder)
NSString *path = [url path];
return strdup ([path UTF8String]);
}
+
+
+// mcs/class/corlib/System/Console.iOS.cs
+void
+xamarin_log (const unsigned short *unicodeMessage)
+{
+ // COOP: no managed memory access: any mode.
+ int length = 0;
+ const unsigned short *ptr = unicodeMessage;
+ while (*ptr++)
+ length += sizeof (unsigned short);
+ NSString *msg = [[NSString alloc] initWithBytes: unicodeMessage length: length encoding: NSUTF16LittleEndianStringEncoding];
+
+#if TARGET_OS_WATCH && defined (__arm__) // maybe make this configurable somehow?
+ const char *utf8 = [msg UTF8String];
+ int len = strlen (utf8);
+ fwrite (utf8, 1, len, stdout);
+ if (len == 0 || utf8 [len - 1] != '\n')
+ fwrite ("\n", 1, 1, stdout);
+ fflush (stdout);
+#else
+ os_log (stdout_log, "%{public}@", msg);
+ //NSLog (@"%@", msg);
+#endif
+}
diff --git a/sdks/ios/test-runner/Makefile b/sdks/ios/test-runner/Makefile
deleted file mode 100644
index 404334f81dd..00000000000
--- a/sdks/ios/test-runner/Makefile
+++ /dev/null
@@ -1,29 +0,0 @@
-all: test-runner
-
-CC = /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang
-ARCH = x86_64
-SDK_DIR = ../../out/ios-sim64
-CFLAGS = \
- -std=gnu11 \
- -fobjc-arc \
- -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator11.1.sdk \
- -mios-simulator-version-min=11.1 \
- -g \
- -I$(SDK_DIR)/include/mono-2.0
-
-LDFLAGS = \
- -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator11.1.sdk \
- -mios-simulator-version-min=11.1 \
- -framework Foundation \
- -framework UIKit \
- $(SDK_DIR)/lib/libmonosgen-2.0.a \
- -liconv
-
-%.o: %.m
- $(ENV) $(CC) -arch $(ARCH) $(CFLAGS) -c -o $@ $^
-
-test-runner: main.o runtime.o AppDelegate.o ViewController.o
- $(ENV) $(CC) -arch $(ARCH) $(LDFLAGS) -o $@ $^
-
-clean:
- $(RM) -rf test-runner *.o
diff --git a/sdks/ios/test-runner/runner.cs b/sdks/ios/test-runner/runner.cs
new file mode 100644
index 00000000000..dc8d87cb147
--- /dev/null
+++ b/sdks/ios/test-runner/runner.cs
@@ -0,0 +1,72 @@
+using System;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Net.Sockets;
+using NUnitLite.Runner;
+using NUnit.Framework.Internal;
+
+ class TcpWriter : TextWriter
+ {
+ private string hostName;
+ private int port;
+
+ private TcpClient client;
+ private NetworkStream stream;
+ private StreamWriter writer;
+
+ public TcpWriter(string hostName, int port)
+ {
+ this.hostName = hostName;
+ this.port = port;
+ this.client = new TcpClient(hostName, port);
+ this.stream = client.GetStream();
+ this.writer = new StreamWriter(stream);
+ }
+
+ public override void Write(char value)
+ {
+ writer.Write(value);
+ }
+
+ public override void Write(string value)
+ {
+ writer.Write(value);
+ }
+
+ public override void WriteLine(string value)
+ {
+ writer.WriteLine(value);
+ writer.Flush();
+ }
+
+ public override System.Text.Encoding Encoding
+ {
+ get { return System.Text.Encoding.Default; }
+ }
+ }
+
+public class TestRunner
+{
+ public static int Main(string[] args) {
+ TextUI runner;
+
+ // First argument is the connection string
+ if (args [0].StartsWith ("tcp:")) {
+ var parts = args [0].Split (':');
+ if (parts.Length != 3)
+ throw new Exception ();
+ string host = parts [1];
+ string port = parts [2];
+ args = args.Skip (1).ToArray ();
+
+ Console.WriteLine ($"Connecting to harness at {host}:{port}.");
+ runner = new TextUI (new TcpWriter (host, Int32.Parse (port)));
+ } else {
+ runner = new TextUI ();
+ }
+ runner.Execute (args);
+
+ return (runner.Failure ? 1 : 0);
+ }
+}