Browse Source

Use the system linker for linking symbols libraries outside Windows.

Builtin lld is giving some weird linking errors when linking with the
new LLVM version. We probably need to set some custom options. Using the
system linker should be a better idea anyway, more robust and future
proof.
pull/1724/head
Joao Matos 3 years ago
parent
commit
a886484ca0
  1. 3
      src/CppParser/Parser.cpp
  2. 1
      src/Generator/Driver.cs
  3. 68
      src/Generator/Passes/GenerateSymbolsPass.cs
  4. 158
      src/Parser/LinkerOptions.cs

3
src/CppParser/Parser.cpp

@ -4851,8 +4851,7 @@ ParserResult* Parser::Compile(const std::string& File) @@ -4851,8 +4851,7 @@ ParserResult* Parser::Compile(const std::string& File)
const llvm::Triple Triple = c->getTarget().getTriple();
llvm::StringRef Dir(llvm::sys::path::parent_path(File));
llvm::SmallString<1024> Object(Dir);
llvm::sys::path::append(Object,
(Triple.isOSWindows() ? "" : "lib") + Stem + ".o");
llvm::sys::path::append(Object, Stem + ".o");
c->getFrontendOpts().OutputFile = std::string(Object);
llvm::LLVMContext context;

1
src/Generator/Driver.cs

@ -87,7 +87,6 @@ namespace CppSharp @@ -87,7 +87,6 @@ namespace CppSharp
ValidateOptions();
ParserOptions.Setup(Platform.Host);
Context = new BindingContext(Options, ParserOptions);
Context.LinkerOptions.Setup(ParserOptions.TargetTriple, ParserOptions.LanguageVersion);
Generator = CreateGeneratorFromKind(Options.GeneratorKind);
}

68
src/Generator/Passes/GenerateSymbolsPass.cs

@ -63,24 +63,72 @@ namespace CppSharp.Passes @@ -63,24 +63,72 @@ namespace CppSharp.Passes
new[] { module }).SelectMany(d => d.Libraries))
linkerOptions.AddLibraries(library);
using (var result = Parser.ClangParser.Build(
Context.ParserOptions, linkerOptions, path,
Last: remainingCompilationTasks == 1))
compiledLibraries[module] = Build(linkerOptions, path, module);
}
}
RemainingCompilationTasks--;
}
}
private CompiledLibrary Build(LinkerOptions linkerOptions, string path, Module module)
{
if (PrintDiagnostics(result))
var useBuiltinToolchain = Platform.IsWindows;
if (useBuiltinToolchain)
{
compiledLibraries[module] = new CompiledLibrary
linkerOptions.Setup(Context.ParserOptions.TargetTriple, Context.ParserOptions.LanguageVersion);
using var result = Parser.ClangParser.Build(
Context.ParserOptions, linkerOptions, path,
Last: remainingCompilationTasks == 1);
if (!PrintDiagnostics(result))
return null;
}
else
{
OutputDir = Options.OutputDir,
Library = module.SymbolsLibraryName
};
using var result = Parser.ClangParser.Compile(Context.ParserOptions, path);
if (result != null)
{
if (!PrintDiagnostics(result))
return null;
}
linkerOptions.Setup(Context.ParserOptions.TargetTriple, Context.ParserOptions.LanguageVersion);
linkerOptions.AddArguments("-L" + Path.GetDirectoryName(path));
var objectFile = Path.ChangeExtension(path, "o");
linkerOptions.AddArguments(objectFile);
var targetPlatform = Options.Compilation.Platform.GetValueOrDefault(Platform.Host);
var sharedObjectFile = LinkerOptions.GetSharedObjectName(path, targetPlatform);
linkerOptions.AddArguments("-o " + sharedObjectFile);
linkerOptions.SetupLibraryArguments();
var linker = LinkerOptions.GetLinkerExecutableName(targetPlatform);
var invocation = linkerOptions.GetLinkerInvocation();
Diagnostics.Message($"Linking library {Path.GetFileName(sharedObjectFile)}...");
if (Options.Verbose)
Diagnostics.Message($"Invoking the linker with: {linker} {invocation}");
var outMessage = ProcessHelper.Run(
linker, invocation, out var errorCode, out var errorMessage);
if (errorCode != 0)
{
Diagnostics.Error($"Linking failed with: {outMessage} {errorMessage}");
}
else
{
Diagnostics.Message($"Linking success.");
}
}
RemainingCompilationTasks--;
}
return new CompiledLibrary
{
OutputDir = Options.OutputDir,
Library = module.SymbolsLibraryName
};
}
public override bool VisitClassTemplateSpecializationDecl(ClassTemplateSpecialization specialization)

158
src/Parser/LinkerOptions.cs

@ -1,4 +1,8 @@ @@ -1,4 +1,8 @@
using System.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
namespace CppSharp.Parser
{
@ -8,6 +12,8 @@ namespace CppSharp.Parser @@ -8,6 +12,8 @@ namespace CppSharp.Parser
{
}
public static bool UseCompilerDriverAsLinker = true;
public LinkerOptions(LinkerOptions other)
{
for (uint i = 0; i < other.ArgumentsCount; i++)
@ -45,7 +51,7 @@ namespace CppSharp.Parser @@ -45,7 +51,7 @@ namespace CppSharp.Parser
AddArguments("-L" + (SystemLibraryPath ?? "/usr/lib/x86_64-linux-gnu"));
AddArguments("-lc");
AddArguments("--shared");
AddArguments("-rpath");
AddArguments(UseCompilerDriverAsLinker ? "-Wl,-rpath" : "-rpath");
AddArguments(".");
break;
case TargetPlatform.MacOS:
@ -70,5 +76,153 @@ namespace CppSharp.Parser @@ -70,5 +76,153 @@ namespace CppSharp.Parser
break;
}
}
public void SetupLibraryArguments()
{
for (uint i = 0; i < LibraryDirsCount; i++)
{
var dir = GetLibraryDirs(i);
AddArguments("-L" + dir);
}
for (uint i = 0; i < LibrariesCount; i++)
{
var lib = GetLibraries(i);
AddArguments("-l" + lib);
}
}
public string GetLinkerInvocation()
{
var args = new List<string>();
for (uint i = 0; i < ArgumentsCount; i++)
{
var arg = GetArguments(i);
args.Add(arg);
}
return string.Join(" ", args);
}
public static string GetSharedObjectName(string path, TargetPlatform targetPlatform)
{
var prefix = GetPlatformSharedObjectPrefix(targetPlatform);
var extension = GetPlatformSharedObjectExtension(targetPlatform);
var name = $"{prefix}{Path.GetFileNameWithoutExtension(path)}.{extension}";
return Path.Join(Path.GetDirectoryName(path), name);
}
public static string GetLinkerExecutableName(TargetPlatform targetPlatform)
{
// If LLD exists on the PATH, then prefer it. If not, use the host linker.
var lldLinkerExe = GetLLDLinkerExecutableName(targetPlatform);
return (ExistsOnPath(lldLinkerExe) && !UseCompilerDriverAsLinker) ?
lldLinkerExe : GetPlatformLinkerExecutableName(targetPlatform);
}
public static string GetPlatformSharedObjectPrefix(TargetPlatform targetPlatform)
{
switch (targetPlatform)
{
case TargetPlatform.Windows:
return "";
case TargetPlatform.Linux:
case TargetPlatform.Android:
case TargetPlatform.MacOS:
case TargetPlatform.iOS:
case TargetPlatform.WatchOS:
case TargetPlatform.TVOS:
case TargetPlatform.Emscripten:
return "lib";
default:
throw new ArgumentOutOfRangeException(nameof(targetPlatform), targetPlatform, null);
}
}
public static string GetPlatformSharedObjectExtension(TargetPlatform targetPlatform)
{
switch (targetPlatform)
{
case TargetPlatform.Windows:
return "dll";
case TargetPlatform.Linux:
case TargetPlatform.Android:
case TargetPlatform.Emscripten:
return "so";
case TargetPlatform.MacOS:
case TargetPlatform.iOS:
case TargetPlatform.WatchOS:
case TargetPlatform.TVOS:
return "dylib";
default:
throw new ArgumentOutOfRangeException(nameof(targetPlatform), targetPlatform, null);
}
}
public static string GetPlatformLinkerExecutableName(TargetPlatform targetPlatform)
{
switch (targetPlatform)
{
case TargetPlatform.Windows:
return "link.exe";
case TargetPlatform.Linux:
return UseCompilerDriverAsLinker ? "gcc" : "ld";
case TargetPlatform.Android:
case TargetPlatform.MacOS:
case TargetPlatform.iOS:
case TargetPlatform.WatchOS:
case TargetPlatform.TVOS:
return "ld";
case TargetPlatform.Emscripten:
return GetLLDLinkerExecutableName(targetPlatform);
default:
throw new ArgumentOutOfRangeException(nameof(targetPlatform), targetPlatform, null);
}
}
public static string GetLLDLinkerExecutableName(TargetPlatform targetPlatform)
{
switch (targetPlatform)
{
case TargetPlatform.Windows:
return "lld-link";
case TargetPlatform.Linux:
case TargetPlatform.Android:
return "ld.lld";
case TargetPlatform.MacOS:
case TargetPlatform.iOS:
case TargetPlatform.WatchOS:
case TargetPlatform.TVOS:
return "ld64.lld";
case TargetPlatform.Emscripten:
return "wasm-ld";
default:
throw new ArgumentOutOfRangeException(nameof(targetPlatform), targetPlatform, null);
}
}
private static bool ExistsOnPath(string fileName)
{
return GetFullPath(fileName) != null;
}
private static string GetFullPath(string fileName)
{
if (fileName == null) throw new ArgumentNullException(nameof(fileName));
if (File.Exists(fileName))
return Path.GetFullPath(fileName);
var environmentVariablePath = Environment.GetEnvironmentVariable("PATH");
if (environmentVariablePath == null)
throw new NullReferenceException(nameof(environmentVariablePath));
foreach (var path in environmentVariablePath.Split(Path.PathSeparator))
{
var fullPath = Path.Combine(path, fileName);
if (File.Exists(fullPath))
return fullPath;
}
return null;
}
}
}

Loading…
Cancel
Save