Skip to content

Commit

Permalink
[native_toolchain_c] Support ld.ldd as linker on Linux (#1468)
Browse files Browse the repository at this point in the history
  • Loading branch information
dcharkes authored Aug 28, 2024
1 parent 62b9ac2 commit eec08d8
Show file tree
Hide file tree
Showing 3 changed files with 54 additions and 30 deletions.
6 changes: 5 additions & 1 deletion pkgs/native_toolchain_c/lib/src/cbuilder/linker_options.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import 'dart:io';

import '../native_toolchain/apple_clang.dart';
import '../native_toolchain/clang.dart';
import '../native_toolchain/gcc.dart';
import '../tool/tool.dart';
Expand Down Expand Up @@ -61,13 +62,16 @@ class LinkerOptions {
Iterable<String> _toLinkerSyntax(Tool linker, List<String> flagList) {
if (linker == clang) {
return flagList.map((e) => '-Wl,$e');
} else if (linker == gnuLinker) {
} else if (isClangLikeLinker(linker)) {
return flagList;
} else {
throw UnsupportedError('Linker flags for $linker are not supported');
}
}

static bool isClangLikeLinker(Tool tool) =>
tool == appleLd || tool == gnuLinker || tool == lld;

static Uri? _createLinkerScript(Iterable<String>? symbols) {
if (symbols == null) return null;
final tempDir = Directory.systemTemp.createTempSync();
Expand Down
68 changes: 40 additions & 28 deletions pkgs/native_toolchain_c/lib/src/cbuilder/run_cbuilder.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import '../native_toolchain/clang.dart';
import '../native_toolchain/gcc.dart';
import '../native_toolchain/msvc.dart';
import '../native_toolchain/xcode.dart';
import '../tool/tool.dart';
import '../tool/tool_instance.dart';
import '../utils/env_from_bat.dart';
import '../utils/run_process.dart';
Expand Down Expand Up @@ -113,10 +114,7 @@ class RunCBuilder {
final toolInstance_ =
linkerOptions != null ? await linker() : await compiler();
final tool = toolInstance_.tool;
if (tool == appleClang ||
tool == clang ||
tool == gcc ||
tool == gnuLinker) {
if (isClangLikeCompiler(tool) || LinkerOptions.isClangLikeLinker(tool)) {
await runClangLike(tool: toolInstance_);
return;
} else if (tool == cl) {
Expand All @@ -126,6 +124,9 @@ class RunCBuilder {
}
}

static bool isClangLikeCompiler(Tool tool) =>
tool == appleClang || tool == clang || tool == gcc;

Future<void> runClangLike({required ToolInstance tool}) async {
final isStaticLib = staticLibrary != null;
Uri? archiver_;
Expand Down Expand Up @@ -200,8 +201,9 @@ class RunCBuilder {
}
}

/// [toolInstance] is either a compiler or a linker.
Future<void> _compile(
ToolInstance compiler,
ToolInstance toolInstance,
Architecture? architecture,
int? targetAndroidNdkApi,
IOSSdk? targetIosSdk,
Expand All @@ -211,13 +213,13 @@ class RunCBuilder {
Uri? outFile,
) async {
await runProcess(
executable: compiler.uri,
executable: toolInstance.uri,
arguments: [
if (config.targetOS == OS.android) ...[
'--target='
'${androidNdkClangTargetFlags[architecture]!}'
'${targetAndroidNdkApi!}',
'--sysroot=${androidSysroot(compiler).toFilePath()}',
'--sysroot=${androidSysroot(toolInstance).toFilePath()}',
],
if (config.targetOS == OS.macOS)
'--target=${appleClangMacosTargetFlags[architecture]!}',
Expand All @@ -239,26 +241,35 @@ class RunCBuilder {
installName!.toFilePath(),
],
if (pic != null)
if (pic!) ...[
if (dynamicLibrary != null) '-fPIC',
// Using PIC for static libraries allows them to be linked into
// any executable, but it is not necessarily the best option in
// terms of overhead. We would have to know wether the target into
// which the static library is linked is PIC, PIE or neither. Then
// we could use the same option for the static library.
if (staticLibrary != null) '-fPIC',
if (executable != null) ...[
// Generate position-independent code for executables.
'-fPIE',
// Tell the linker to generate a position-independent executable.
'-pie',
if (isClangLikeCompiler(toolInstance.tool)) ...[
if (pic!) ...[
if (dynamicLibrary != null) '-fPIC',
// Using PIC for static libraries allows them to be linked into
// any executable, but it is not necessarily the best option in
// terms of overhead. We would have to know wether the target into
// which the static library is linked is PIC, PIE or neither. Then
// we could use the same option for the static library.
if (staticLibrary != null) '-fPIC',
if (executable != null) ...[
// Generate position-independent code for executables.
'-fPIE',
// Tell the linker to generate a position-independent
// executable.
'-pie',
],
] else ...[
// Disable generation of any kind of position-independent code.
'-fno-PIC',
'-fno-PIE',
// Tell the linker to generate a position-dependent executable.
if (executable != null) '-no-pie',
],
] else if (LinkerOptions.isClangLikeLinker(toolInstance.tool)) ...[
if (pic!) ...[
if (executable != null) '--pie',
] else ...[
if (executable != null) '--no-pie',
],
] else ...[
// Disable generation of any kind of position-independent code.
'-fno-PIC',
'-fno-PIE',
// Tell the linker to generate a position-dependent executable.
if (executable != null) '-no-pie',
],
if (std != null) '-std=$std',
if (language == Language.cpp) ...[
Expand All @@ -267,7 +278,7 @@ class RunCBuilder {
'-l',
cppLinkStdLib ?? defaultCppLinkStdLib[config.targetOS]!
],
...linkerOptions?.preSourcesFlags(compiler.tool, sourceFiles) ?? [],
...linkerOptions?.preSourcesFlags(toolInstance.tool, sourceFiles) ?? [],
...flags,
for (final MapEntry(key: name, :value) in defines.entries)
if (value == null) '-D$name' else '-D$name=$value',
Expand All @@ -292,7 +303,8 @@ class RunCBuilder {
'-o',
outFile!.toFilePath(),
],
...linkerOptions?.postSourcesFlags(compiler.tool, sourceFiles) ?? [],
...linkerOptions?.postSourcesFlags(toolInstance.tool, sourceFiles) ??
[],
],
logger: logger,
captureOutput: false,
Expand Down
10 changes: 9 additions & 1 deletion pkgs/native_toolchain_c/lib/src/native_toolchain/gcc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,15 @@ import '../tool/tool_resolver.dart';
/// The GNU Compiler Collection for [Architecture.current].
///
/// https://gcc.gnu.org/
final gcc = Tool(name: 'GCC');
final gcc = Tool(
name: 'GCC',
defaultResolver: CliVersionResolver(
wrappedResolver: PathToolResolver(
toolName: 'GCC',
executableName: 'gcc',
),
),
);

/// The GNU GCC archiver for [Architecture.current].
final gnuArchiver = Tool(name: 'GNU archiver');
Expand Down

0 comments on commit eec08d8

Please sign in to comment.