[objc] Add support fat and static libraries for all platforms. (#97)

[objc] Add support fat and static libraries for all platforms.
This commit is contained in:
Rolf Bjarne Kvinge 2017-04-11 15:25:40 +02:00 коммит произвёл GitHub
Родитель 2633f39627
Коммит 7de0e3f0cc
4 изменённых файлов: 246 добавлений и 27 удалений

Просмотреть файл

@ -228,59 +228,263 @@ namespace Embeddinator {
return 0;
}
class BuildInfo
{
public string Sdk;
public string [] Architectures;
public string SdkName; // used in -m{SdkName}-version-min
public string MinVersion;
public string XamariniOSSDK;
public string CompilerFlags;
public string LinkerFlags;
}
static int Compile ()
{
Console.WriteLine ("Compiling binding code...");
BuildInfo [] build_infos;
switch (Platform) {
case Platform.macOS:
build_infos = new BuildInfo [] {
new BuildInfo { Sdk = "MacOSX", Architectures = new string [] { "i386", "x86_64" }, SdkName = "macosx", MinVersion = "10.7" },
};
break;
case Platform.iOS:
case Platform.watchOS:
build_infos = new BuildInfo [] {
new BuildInfo { Sdk = "iPhoneOS", Architectures = new string [] { "armv7", "armv7s", "arm64" }, SdkName = "iphoneos", MinVersion = "8.0", XamariniOSSDK = "MonoTouch.iphoneos.sdk" },
new BuildInfo { Sdk = "iPhoneSimulator", Architectures = new string [] { "i386", "x86_64" }, SdkName = "ios-simulator", MinVersion = "8.0", XamariniOSSDK = "MonoTouch.iphonesimulator.sdk" },
};
break;
case Platform.tvOS:
throw new NotImplementedException ($"platform={Platform}");
build_infos = new BuildInfo [] {
new BuildInfo { Sdk = "AppleTVOS", Architectures = new string [] { "arm64" }, SdkName = "tvos", MinVersion = "9.0", XamariniOSSDK = "Xamarin.AppleTVOS.sdk", CompilerFlags = "-fembed-bitcode", LinkerFlags = "-fembed-bitcode" },
new BuildInfo { Sdk = "AppleTVSimulator", Architectures = new string [] { "x86_64" }, SdkName = "tvos-simulator", MinVersion = "9.0", XamariniOSSDK = "Xamarin.AppleTVSimulator.sdk" },
};
break;
case Platform.watchOS:
build_infos = new BuildInfo [] {
new BuildInfo { Sdk = "WatchOS", Architectures = new string [] { "armv7k" }, SdkName = "watchos", MinVersion = "2.0", XamariniOSSDK = "Xamarin.WatchOS.sdk", CompilerFlags = "-fembed-bitcode", LinkerFlags = "-fembed-bitcode" },
new BuildInfo { Sdk = "WatchSimulator", Architectures = new string [] { "i386" }, SdkName = "watchos-simulator", MinVersion = "2.0", XamariniOSSDK = "Xamarin.WatchSimulator.sdk" },
};
break;
default:
throw ErrorHelper.CreateError (99, "Internal error: invalid platform {0}. Please file a bug report with a test case (https://github.com/mono/Embeddinator-4000/issues).", Platform);
}
switch (CompilationTarget) {
case CompilationTarget.SharedLibrary:
case CompilationTarget.StaticLibrary:
break;
case CompilationTarget.Framework:
case CompilationTarget.StaticLibrary:
throw new NotImplementedException ($"Compilation target: {CompilationTarget}");
default:
throw ErrorHelper.CreateError (99, "Internal error: invalid compilation target {0}. Please file a bug report with a test case (https://github.com/mono/Embeddinator-4000/issues).", CompilationTarget);
}
StringBuilder options = new StringBuilder ("clang ");
if (Debug)
options.Append ("-g -O0 ");
options.Append ("-fobjc-arc ");
options.Append ("-DMONO_EMBEDDINATOR_DLL_EXPORT ");
options.Append ("-framework CoreFoundation ");
options.Append ("-framework Foundation ");
options.Append ("-I\"/Library/Frameworks/Mono.framework/Versions/Current/include/mono-2.0\" -L\"/Library/Frameworks/Mono.framework/Versions/Current/lib/\" -lmonosgen-2.0 ");
options.Append ("glib.c mono_embeddinator.c objc-support.m bindings.m ");
options.Append ("-ObjC -lobjc ");
var lipo_files = new List<string> ();
var output_file = string.Empty;
var files = new string [] {
Path.Combine (OutputDirectory, "glib.c"),
Path.Combine (OutputDirectory, "mono_embeddinator.c"),
Path.Combine (OutputDirectory, "objc-support.m"),
Path.Combine (OutputDirectory, "bindings.m"),
};
switch (CompilationTarget) {
case CompilationTarget.SharedLibrary:
options.Append ($"-dynamiclib ");
options.Append ($"-install_name @rpath/lib{LibraryName}.dylib ");
options.Append ($"-o lib{LibraryName}.dylib ");
output_file = $"lib{LibraryName}.dylib";
break;
case CompilationTarget.StaticLibrary:
throw new NotImplementedException ("compile to static library");
case CompilationTarget.Framework:
throw new NotImplementedException ("compile to framework");
output_file = $"{LibraryName}.a";
break;
default:
throw ErrorHelper.CreateError (99, "Internal error: invalid compilation target {0}. Please file a bug report with a test case (https://github.com/mono/Embeddinator-4000/issues).", CompilationTarget);
}
Console.WriteLine ($"\tInvoking: xcrun {options}");
var p = Process.Start ("xcrun", options.ToString ());
p.WaitForExit ();
return p.ExitCode;
int exitCode;
foreach (var build_info in build_infos) {
foreach (var arch in build_info.Architectures) {
var archOutputDirectory = Path.Combine (OutputDirectory, arch);
Directory.CreateDirectory (archOutputDirectory);
var common_options = new StringBuilder ("clang ");
if (Debug)
common_options.Append ("-g -O0 ");
common_options.Append ("-fobjc-arc ");
common_options.Append ("-ObjC ");
common_options.Append ($"-arch {arch} ");
common_options.Append ($"-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/{build_info.Sdk}.platform/Developer/SDKs/{build_info.Sdk}.sdk ");
common_options.Append ($"-m{build_info.SdkName}-version-min={build_info.MinVersion} ");
common_options.Append ("-I/Library/Frameworks/Mono.framework/Versions/Current/include/mono-2.0 ");
// Build each file to a .o
var object_files = new List<string> ();
foreach (var file in files) {
var compiler_options = new StringBuilder (common_options.ToString ());
compiler_options.Append ("-DMONO_EMBEDDINATOR_DLL_EXPORT ");
compiler_options.Append (build_info.CompilerFlags).Append (" ");
compiler_options.Append ("-c ");
compiler_options.Append (Quote (file)).Append (" ");
var objfile = Path.Combine (archOutputDirectory, Path.ChangeExtension (Path.GetFileName (file), "o"));
compiler_options.Append ($"-o {Quote (objfile)} ");
object_files.Add (objfile);
if (!Xcrun (compiler_options, out exitCode))
return exitCode;
}
switch (CompilationTarget) {
case CompilationTarget.SharedLibrary:
// Link all the .o files into a .dylib
var options = new StringBuilder (common_options.ToString ());
options.Append ($"-dynamiclib ");
options.Append (build_info.LinkerFlags).Append (" ");
options.Append ("-lobjc ");
options.Append ("-framework CoreFoundation ");
options.Append ("-framework Foundation ");
options.Append ($"-install_name {Quote ("@rpath/" + output_file)} ");
foreach (var objfile in object_files)
options.Append (Quote (objfile)).Append (" ");
var dynamic_ofile = Path.Combine (archOutputDirectory, output_file);
options.Append ($"-o ").Append (Quote (dynamic_ofile)).Append (" ");
lipo_files.Add (dynamic_ofile);
if (!string.IsNullOrEmpty (build_info.XamariniOSSDK)) {
options.Append ($"-L/Library/Frameworks/Xamarin.iOS.framework/Versions/Current/SDKs/{build_info.XamariniOSSDK}/usr/lib ");
} else {
options.Append ("-L/Library/Frameworks/Mono.framework/Versions/Current/lib/ ");
}
options.Append ("-lmonosgen-2.0 ");
if (!Xcrun (options, out exitCode))
return exitCode;
break;
case CompilationTarget.StaticLibrary:
// Archive all the .o files into a .a
var archive_options = new StringBuilder ("ar cru ");
var static_ofile = Path.Combine (archOutputDirectory, output_file);
archive_options.Append (static_ofile).Append (" ");
lipo_files.Add (static_ofile);
foreach (var objfile in object_files)
archive_options.Append (objfile).Append (" ");
if (!Xcrun (archive_options, out exitCode))
return exitCode;
break;
case CompilationTarget.Framework:
throw new NotImplementedException ("compile to framework");
default:
throw ErrorHelper.CreateError (99, "Internal error: invalid compilation target {0}. Please file a bug report with a test case (https://github.com/mono/Embeddinator-4000/issues).", CompilationTarget);
}
}
}
var output_path = Path.Combine (OutputDirectory, output_file);
if (!Lipo (lipo_files, output_path, out exitCode))
return exitCode;
if (!DSymUtil (output_path, out exitCode))
return exitCode;
return 0;
}
static string GetTargetFramework ()
{
switch (Platform) {
case Platform.macOS:
throw new NotImplementedException ("target framework for macOS");
case Platform.iOS:
return "Xamarin.iOS,v1.0";
case Platform.tvOS:
return "Xamarin.TVOS,v1.0";
case Platform.watchOS:
return "Xamarin.WatchOS,v1.0";
default:
throw ErrorHelper.CreateError (99, "Internal error: invalid platform {0}. Please file a bug report with a test case (https://github.com/mono/Embeddinator-4000/issues).", Platform);
}
}
static int RunProcess (string filename, string arguments)
{
Console.WriteLine ($"\t{filename} {arguments}");
using (var p = Process.Start (filename, arguments)) {
p.WaitForExit ();
return p.ExitCode;
}
}
static bool RunProcess (string filename, string arguments, out int exitCode)
{
exitCode = RunProcess (filename, arguments);
return exitCode == 0;
}
static bool Xcrun (StringBuilder options, out int exitCode)
{
return RunProcess ("xcrun", options.ToString (), out exitCode);
}
static bool DSymUtil (string input, out int exitCode)
{
exitCode = 0;
if (!Debug)
return true;
string output;
switch (CompilationTarget) {
case CompilationTarget.StaticLibrary:
return true;
case CompilationTarget.SharedLibrary:
output = input + ".dSYM";
break;
default:
throw ErrorHelper.CreateError (99, "Internal error: invalid compilation target {0}. Please file a bug report with a test case (https://github.com/mono/Embeddinator-4000/issues).", CompilationTarget);
}
var dsymutil_options = new StringBuilder ("dsymutil ");
dsymutil_options.Append (Quote (input)).Append (" ");
dsymutil_options.Append ($"-o {Quote (output)} ");
return Xcrun (dsymutil_options, out exitCode);
}
static bool Lipo (List<string> inputs, string output, out int exitCode)
{
Directory.CreateDirectory (Path.GetDirectoryName (output));
if (inputs.Count == 1) {
File.Copy (inputs [0], output, true);
exitCode = 0;
return true;
} else {
var lipo_options = new StringBuilder ("lipo ");
foreach (var file in inputs)
lipo_options.Append (file).Append (" ");
lipo_options.Append ("-create -output ");
lipo_options.Append (Quote (output));
return Xcrun (lipo_options, out exitCode);
}
}
public static string Quote (string f)
{
if (f.IndexOf (' ') == -1 && f.IndexOf ('\'') == -1 && f.IndexOf (',') == -1 && f.IndexOf ('$') == -1)
return f;
var s = new StringBuilder ();
s.Append ('"');
foreach (var c in f) {
if (c == '"' || c == '\\')
s.Append ('\\');
s.Append (c);
}
s.Append ('"');
return s.ToString ();
}
}
}

Просмотреть файл

@ -151,15 +151,17 @@ namespace ObjC {
var native_name = GetTypeName (t);
headers.WriteLine ();
headers.WriteLine ($"// {t.AssemblyQualifiedName}");
headers.WriteLine ($"@interface {native_name} : {GetTypeName (t.BaseType)}");
headers.WriteLine ($"@interface {native_name} : {GetTypeName (t.BaseType)} {{");
if (!static_type && !has_bound_base_class) {
headers.WriteLine ("\tMonoEmbedObject* _object;");
}
headers.WriteLine ("}");
headers.WriteLine ();
implementation.WriteLine ();
implementation.WriteLine ($"// {t.AssemblyQualifiedName}");
implementation.WriteLine ($"@implementation {native_name} {{");
// our internal field is only needed once in the type hierarchy
if (!static_type && !has_bound_base_class)
implementation.WriteLine ("\t@public MonoEmbedObject* _object;");
implementation.WriteLine ("}");
implementation.WriteLine ();

3
tests/objc-cli/.gitignore поставляемый
Просмотреть файл

@ -24,3 +24,6 @@ profile
*.moved-aside
DerivedData
.idea/
i386
x86_64

Просмотреть файл

@ -1,4 +1,4 @@
all: run-test perf xctest test-leaks
all: run-test perf xctest test-leaks test-static test-dynamic
OBJC_GEN_DIR=../../objcgen
OBJC_GEN=$(OBJC_GEN_DIR)/bin/Debug/objcgen.exe
@ -52,3 +52,13 @@ test-xctest-leaks: ../leaktest/bin/Debug/leaktest.exe $(MANAGED_DLL) libmanaged.
libLeakCheckAtExit.dylib: leak-at-exit.c
clang -arch i386 -arch x86_64 -shared $< -o $@
test-static: test-static-macos test-static-ios test-static-tvos test-static-watchos
test-static-%: managed.dll $(OBJC_GEN)
/Library/Frameworks/Mono.framework/Versions/Current/Commands/mono --debug $(OBJC_GEN) --debug managed.dll -c --outdir=build/$@-temp-dir --target=staticlibrary --platform=$*
test-dynamic: test-dynamic-macos test-dynamic-ios test-dynamic-tvos test-dynamic-watchos
test-dynamic-%: managed.dll $(OBJC_GEN)
/Library/Frameworks/Mono.framework/Versions/Current/Commands/mono --debug $(OBJC_GEN) --debug managed.dll -c --outdir=build/$@-temp-dir --target=dylib --platform=$*