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:
Rolf Bjarne Kvinge 2016-10-28 16:50:42 +02:00 коммит произвёл Sebastien Pouliot
Родитель b6a0d06143
Коммит dde242c32a
6 изменённых файлов: 131 добавлений и 56 удалений

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

@ -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;