[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:
Родитель
2633f39627
Коммит
7de0e3f0cc
|
@ -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 ();
|
||||
|
||||
|
|
|
@ -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=$*
|
||||
|
|
Загрузка…
Ссылка в новой задаче