Allow using LinkWith attribute without a native library. (#997)
This makes it possible to set linker flags per assembly: [assembly: LinkWith (LinkerFlags = "-lsqlite3")] Which is required when incremental builds is enabled and a particular assembly needs special linker flags (because we don't propagate the global -gcc_flags to each dylib we build when doing incremental builds). Also add an option to set the dlsym mode for an assembly (using the LinkWith attribute).
This commit is contained in:
Родитель
b6a0d06143
Коммит
dde242c32a
|
@ -2122,6 +2122,7 @@ public enum LinkTarget {
|
|||
|
||||
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple=true)]
|
||||
public class LinkWithAttribute : Attribute {
|
||||
public LinkWithAttribute ();
|
||||
public LinkWithAttribute (string libraryName);
|
||||
public LinkWithAttribute (string libraryName, LinkTarget target);
|
||||
public LinkWithAttribute (string libraryName, LinkTarget target, string linkerFlags);
|
||||
|
@ -2149,6 +2150,13 @@ into the resulting assembly, allowing users to ship a single DLL that contains
|
|||
both the unmanaged dependencies as well as the command line flags necessary to
|
||||
properly consume the library from Xamarin.iOS.
|
||||
|
||||
It' s also possible to not provide a `libraryName`, in which case the
|
||||
`LinkWith` attribute can be used to only specify additional linker flags:
|
||||
|
||||
``` csharp
|
||||
[assembly: LinkWith (LinkerFlags = "-lsqlite3")]
|
||||
```
|
||||
|
||||
<a name="LinkWithAttribute_Constructors" class="injected"></a>
|
||||
|
||||
|
||||
|
@ -2163,6 +2171,9 @@ Note that the LinkTarget argument is inferred by Xamarin.iOS and does not need t
|
|||
Examples:
|
||||
|
||||
```
|
||||
// Specify additional linker:
|
||||
[assembly: LinkWith (LinkerFlags = "-sqlite3")]
|
||||
|
||||
// Specify library name for the constructor:
|
||||
[assembly: LinkWith ("libDemo.a");
|
||||
|
||||
|
|
|
@ -40,6 +40,13 @@ namespace XamCore.ObjCRuntime {
|
|||
x86_64 = Simulator64
|
||||
}
|
||||
|
||||
public enum DlsymOption
|
||||
{
|
||||
Default,
|
||||
Required,
|
||||
Disabled,
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple=true)]
|
||||
#if XAMCORE_2_0
|
||||
sealed
|
||||
|
@ -62,6 +69,10 @@ namespace XamCore.ObjCRuntime {
|
|||
{
|
||||
LibraryName = libraryName;
|
||||
}
|
||||
|
||||
public LinkWithAttribute ()
|
||||
{
|
||||
}
|
||||
|
||||
public bool ForceLoad {
|
||||
get; set;
|
||||
|
@ -98,5 +109,9 @@ namespace XamCore.ObjCRuntime {
|
|||
public bool SmartLink {
|
||||
get; set;
|
||||
}
|
||||
|
||||
public DlsymOption Dlsym {
|
||||
get; set;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -134,6 +134,7 @@ namespace Introspection
|
|||
"dlerror",
|
||||
"Dlfcn",
|
||||
"dlopen",
|
||||
"Dlsym",
|
||||
"dlsym",
|
||||
"Dng",
|
||||
"Dns",
|
||||
|
|
|
@ -1961,6 +1961,31 @@ class Test {
|
|||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void LinkWithNoLibrary ()
|
||||
{
|
||||
using (var tool = new MTouchTool ()) {
|
||||
tool.Profile = Profile.Unified;
|
||||
tool.CreateTemporaryApp (@"
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using ObjCRuntime;
|
||||
[assembly: LinkWith (Dlsym = DlsymOption.Required)]
|
||||
class C {
|
||||
[DllImport (""libsqlite3"")]
|
||||
static extern void sqlite3_column_database_name16 ();
|
||||
static void Main ()
|
||||
{
|
||||
}
|
||||
}
|
||||
");
|
||||
tool.NoFastSim = true;
|
||||
tool.Dlsym = false;
|
||||
tool.Linker = MTouchLinker.LinkSdk;
|
||||
Assert.AreEqual (0, tool.Execute (MTouchAction.BuildDev), "build");
|
||||
}
|
||||
}
|
||||
|
||||
#region Helper functions
|
||||
static string CompileUnifiedTestAppExecutable (string targetDirectory, string code = null, string extraArg = "")
|
||||
{
|
||||
|
|
|
@ -164,7 +164,8 @@ namespace Xamarin.Bundler {
|
|||
string libraryName = linkWith.LibraryName;
|
||||
|
||||
// Remove the resource from the assembly at a later stage.
|
||||
AddResourceToBeRemoved (libraryName);
|
||||
if (!string.IsNullOrEmpty (libraryName))
|
||||
AddResourceToBeRemoved (libraryName);
|
||||
|
||||
// We can't add -dead_strip if there are any LinkWith attributes where smart linking is disabled.
|
||||
if (!linkWith.SmartLink)
|
||||
|
@ -202,59 +203,65 @@ namespace Xamarin.Bundler {
|
|||
if (linkWith.IsCxx)
|
||||
EnableCxx = true;
|
||||
|
||||
path = Path.Combine (Cache.Location, libraryName);
|
||||
if (path.EndsWith (".framework", StringComparison.Ordinal)) {
|
||||
#if MONOTOUCH
|
||||
if (App.DeploymentTarget.Major < 8) {
|
||||
throw ErrorHelper.CreateError (1305, "The binding library '{0}' contains a user framework ({0}), but embedded user frameworks require iOS 8.0 (the deployment target is {1}). Please set the deployment target in the Info.plist file to at least 8.0.",
|
||||
FileName, Path.GetFileName (path), App.DeploymentTarget);
|
||||
}
|
||||
if (linkWith.Dlsym != DlsymOption.Default)
|
||||
App.SetDlsymOption (FullPath, linkWith.Dlsym == DlsymOption.Required);
|
||||
#endif
|
||||
var zipPath = path + ".zip";
|
||||
if (!Application.IsUptodate (FullPath, zipPath)) {
|
||||
Application.ExtractResource (assembly.MainModule, libraryName, zipPath, false);
|
||||
Driver.Log (3, "Extracted third-party framework '{0}' from '{1}' to '{2}'", libraryName, FullPath, zipPath);
|
||||
LogLinkWithAttribute (linkWith);
|
||||
|
||||
if (!string.IsNullOrEmpty (libraryName)) {
|
||||
path = Path.Combine (Cache.Location, libraryName);
|
||||
if (path.EndsWith (".framework", StringComparison.Ordinal)) {
|
||||
#if MONOTOUCH
|
||||
if (App.DeploymentTarget.Major < 8) {
|
||||
throw ErrorHelper.CreateError (1305, "The binding library '{0}' contains a user framework ({0}), but embedded user frameworks require iOS 8.0 (the deployment target is {1}). Please set the deployment target in the Info.plist file to at least 8.0.",
|
||||
FileName, Path.GetFileName (path), App.DeploymentTarget);
|
||||
}
|
||||
#endif
|
||||
var zipPath = path + ".zip";
|
||||
if (!Application.IsUptodate (FullPath, zipPath)) {
|
||||
Application.ExtractResource (assembly.MainModule, libraryName, zipPath, false);
|
||||
Driver.Log (3, "Extracted third-party framework '{0}' from '{1}' to '{2}'", libraryName, FullPath, zipPath);
|
||||
LogLinkWithAttribute (linkWith);
|
||||
} else {
|
||||
Driver.Log (3, "Target '{0}' is up-to-date.", path);
|
||||
}
|
||||
|
||||
if (!File.Exists (zipPath)) {
|
||||
ErrorHelper.Warning (1302, "Could not extract the native framework '{0}' from '{1}'. " +
|
||||
"Please ensure the native framework was properly embedded in the managed assembly " +
|
||||
"(if the assembly was built using a binding project, the native framework must be included in the project, and its Build Action must be 'ObjcBindingNativeFramework').",
|
||||
libraryName, zipPath);
|
||||
} else {
|
||||
if (!Directory.Exists (path))
|
||||
Directory.CreateDirectory (path);
|
||||
|
||||
if (Driver.RunCommand ("/usr/bin/unzip", string.Format ("-u -o -d {0} {1}", Driver.Quote (path), Driver.Quote (zipPath))) != 0)
|
||||
throw ErrorHelper.CreateError (1303, "Could not decompress the native framework '{0}' from '{1}'. Please review the build log for more information from the native 'unzip' command.", libraryName, zipPath);
|
||||
}
|
||||
|
||||
if (Frameworks == null)
|
||||
Frameworks = new HashSet<string> ();
|
||||
Frameworks.Add (path);
|
||||
} else {
|
||||
Driver.Log (3, "Target '{0}' is up-to-date.", path);
|
||||
if (!Application.IsUptodate (FullPath, path)) {
|
||||
Application.ExtractResource (assembly.MainModule, libraryName, path, false);
|
||||
Driver.Log (3, "Extracted third-party binding '{0}' from '{1}' to '{2}'", libraryName, FullPath, path);
|
||||
LogLinkWithAttribute (linkWith);
|
||||
} else {
|
||||
Driver.Log (3, "Target '{0}' is up-to-date.", path);
|
||||
}
|
||||
|
||||
if (!File.Exists (path))
|
||||
ErrorHelper.Warning (1302, "Could not extract the native library '{0}' from '{1}'. " +
|
||||
"Please ensure the native library was properly embedded in the managed assembly " +
|
||||
"(if the assembly was built using a binding project, the native library must be included in the project, and its Build Action must be 'ObjcBindingNativeLibrary').",
|
||||
libraryName, path);
|
||||
|
||||
if (LinkWith == null)
|
||||
LinkWith = new List<string> ();
|
||||
LinkWith.Add (path);
|
||||
}
|
||||
|
||||
if (!File.Exists (zipPath)) {
|
||||
ErrorHelper.Warning (1302, "Could not extract the native framework '{0}' from '{1}'. " +
|
||||
"Please ensure the native framework was properly embedded in the managed assembly " +
|
||||
"(if the assembly was built using a binding project, the native framework must be included in the project, and its Build Action must be 'ObjcBindingNativeFramework').",
|
||||
libraryName, zipPath);
|
||||
} else {
|
||||
if (!Directory.Exists (path))
|
||||
Directory.CreateDirectory (path);
|
||||
|
||||
if (Driver.RunCommand ("/usr/bin/unzip", string.Format ("-u -o -d {0} {1}", Driver.Quote (path), Driver.Quote (zipPath))) != 0)
|
||||
throw ErrorHelper.CreateError (1303, "Could not decompress the native framework '{0}' from '{1}'. Please review the build log for more information from the native 'unzip' command.", libraryName, zipPath);
|
||||
}
|
||||
|
||||
if (Frameworks == null)
|
||||
Frameworks = new HashSet<string> ();
|
||||
Frameworks.Add (path);
|
||||
} else {
|
||||
if (!Application.IsUptodate (FullPath, path)) {
|
||||
Application.ExtractResource (assembly.MainModule, libraryName, path, false);
|
||||
Driver.Log (3, "Extracted third-party binding '{0}' from '{1}' to '{2}'", libraryName, FullPath, path);
|
||||
LogLinkWithAttribute (linkWith);
|
||||
} else {
|
||||
Driver.Log (3, "Target '{0}' is up-to-date.", path);
|
||||
}
|
||||
|
||||
if (!File.Exists (path))
|
||||
ErrorHelper.Warning (1302, "Could not extract the native library '{0}' from '{1}'. " +
|
||||
"Please ensure the native library was properly embedded in the managed assembly " +
|
||||
"(if the assembly was built using a binding project, the native library must be included in the project, and its Build Action must be 'ObjcBindingNativeLibrary').",
|
||||
libraryName, path);
|
||||
|
||||
if (LinkWith == null)
|
||||
LinkWith = new List<string> ();
|
||||
LinkWith.Add (path);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (exceptions != null && exceptions.Count > 0)
|
||||
|
@ -297,6 +304,9 @@ namespace Xamarin.Bundler {
|
|||
case 2:
|
||||
linkWith = new LinkWithAttribute ((string) cargs [0].Value, (LinkTarget) cargs [1].Value);
|
||||
break;
|
||||
case 0:
|
||||
linkWith = new LinkWithAttribute ();
|
||||
break;
|
||||
default:
|
||||
case 1:
|
||||
linkWith = new LinkWithAttribute ((string) cargs [0].Value);
|
||||
|
@ -329,6 +339,9 @@ namespace Xamarin.Bundler {
|
|||
case "SmartLink":
|
||||
linkWith.SmartLink = (bool) property.Argument.Value;
|
||||
break;
|
||||
case "Dlsym":
|
||||
linkWith.Dlsym = (DlsymOption) property.Argument.Value;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -155,6 +155,16 @@ namespace Xamarin.Bundler {
|
|||
List<Abi> abis;
|
||||
HashSet<Abi> all_architectures; // all Abis used in the app, including extensions.
|
||||
|
||||
public void SetDlsymOption (string asm, bool dlsym)
|
||||
{
|
||||
if (DlsymAssemblies == null)
|
||||
DlsymAssemblies = new List<Tuple<string, bool>> ();
|
||||
|
||||
DlsymAssemblies.Add (new Tuple<string, bool> (Path.GetFileNameWithoutExtension (asm), dlsym));
|
||||
|
||||
DlsymOptions = DlsymOptions.Custom;
|
||||
}
|
||||
|
||||
public void ParseDlsymOptions (string options)
|
||||
{
|
||||
bool dlsym;
|
||||
|
@ -186,13 +196,6 @@ namespace Xamarin.Bundler {
|
|||
{
|
||||
string asm;
|
||||
|
||||
switch (DlsymOptions) {
|
||||
case DlsymOptions.All:
|
||||
return true;
|
||||
case DlsymOptions.None:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (DlsymAssemblies != null) {
|
||||
asm = Path.GetFileNameWithoutExtension (assembly);
|
||||
foreach (var tuple in DlsymAssemblies) {
|
||||
|
@ -201,6 +204,13 @@ namespace Xamarin.Bundler {
|
|||
}
|
||||
}
|
||||
|
||||
switch (DlsymOptions) {
|
||||
case DlsymOptions.All:
|
||||
return true;
|
||||
case DlsymOptions.None:
|
||||
return false;
|
||||
}
|
||||
|
||||
if (EnableLLVMOnlyBitCode)
|
||||
return false;
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче