Skip to content

Commit ea44685

Browse files
authored
[native_toolchain_c] Add linking for iOS (#2363)
1 parent 574fc52 commit ea44685

16 files changed

+242
-91
lines changed

pkgs/native_toolchain_c/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.16.5
2+
3+
* Support linking for iOS.
4+
15
## 0.16.4
26

37
* Support linking for MacOS.

pkgs/native_toolchain_c/lib/src/cbuilder/clinker.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ class CLinker extends CTool implements Linker {
5353
required LinkOutputBuilder output,
5454
required Logger? logger,
5555
}) async {
56-
const supportedTargetOSs = [OS.linux, OS.android, OS.macOS];
56+
const supportedTargetOSs = [OS.linux, OS.android, OS.macOS, OS.iOS];
5757
if (!supportedTargetOSs.contains(input.config.code.targetOS)) {
5858
throw UnsupportedError(
5959
'This feature is only supported when targeting '

pkgs/native_toolchain_c/lib/src/cbuilder/linker_options.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ extension LinkerOptionsExt on LinkerOptions {
9898
final includeAllSymbols = _symbolsToKeep == null;
9999

100100
switch (targetOS) {
101-
case OS.macOS:
101+
case OS.macOS || OS.iOS:
102102
return [
103103
if (!includeAllSymbols) ...sourceFiles,
104104
..._toLinkerSyntax(tool, [

pkgs/native_toolchain_c/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name: native_toolchain_c
22
description: >-
33
A library to invoke the native C compiler installed on the host machine.
4-
version: 0.16.4
4+
version: 0.16.5
55
repository: https://github.com/dart-lang/native/tree/main/pkgs/native_toolchain_c
66

77
topics:

pkgs/native_toolchain_c/test/cbuilder/cbuilder_cross_ios_test.dart

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,6 @@ import 'package:test/test.dart';
1616

1717
import '../helpers.dart';
1818

19-
const flutteriOSHighestBestEffort = 16;
20-
const flutteriOSHighestSupported = 17;
21-
2219
void main() {
2320
if (!Platform.isMacOS) {
2421
// Avoid needing status files on Dart SDK CI.
@@ -27,12 +24,6 @@ void main() {
2724

2825
const targets = [Architecture.arm64, Architecture.x64];
2926

30-
// Dont include 'mach-o' or 'Mach-O', different spelling is used.
31-
const objdumpFileFormat = {
32-
Architecture.arm64: 'arm64',
33-
Architecture.x64: '64-bit x86-64',
34-
};
35-
3627
const name = 'add';
3728

3829
const optimizationLevels = OptimizationLevel.values;
@@ -124,7 +115,7 @@ void main() {
124115
final machine = objdumpResult.stdout
125116
.split('\n')
126117
.firstWhere((e) => e.contains('file format'));
127-
expect(machine, contains(objdumpFileFormat[target]));
118+
expect(machine, contains(objdumpFileFormatIOS[target]));
128119

129120
final otoolResult = await runProcess(
130121
executable: Uri.file('otool'),

pkgs/native_toolchain_c/test/clinker/build_testfiles.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,19 @@ Future<Uri> buildTestArchive(
1717
Architecture architecture, {
1818
int? androidTargetNdkApi, // Must be specified iff targetOS is OS.android.
1919
int? macOSTargetVersion, // Must be specified iff targetOS is OS.macos.
20+
int? iOSTargetVersion, // Must be specified iff targetOS is OS.iOS.
21+
IOSSdk? iOSTargetSdk, // Must be specified iff targetOS is OS.iOS.
2022
}) async {
2123
if (targetOS == OS.android) {
2224
ArgumentError.checkNotNull(androidTargetNdkApi, 'androidTargetNdkApi');
2325
}
2426
if (targetOS == OS.macOS) {
2527
ArgumentError.checkNotNull(macOSTargetVersion, 'macOSTargetVersion');
2628
}
29+
if (targetOS == OS.iOS) {
30+
ArgumentError.checkNotNull(iOSTargetVersion, 'iOSTargetVersion');
31+
ArgumentError.checkNotNull(iOSTargetSdk, 'iOSTargetSdk');
32+
}
2733

2834
final test1Uri = packageUri.resolve('test/clinker/testfiles/linker/test1.c');
2935
final test2Uri = packageUri.resolve('test/clinker/testfiles/linker/test2.c');
@@ -56,6 +62,12 @@ Future<Uri> buildTestArchive(
5662
macOS: macOSTargetVersion != null
5763
? MacOSCodeConfig(targetVersion: macOSTargetVersion)
5864
: null,
65+
iOS: iOSTargetVersion != null && iOSTargetSdk != null
66+
? IOSCodeConfig(
67+
targetSdk: iOSTargetSdk,
68+
targetVersion: iOSTargetVersion,
69+
)
70+
: null,
5971
),
6072
);
6173

pkgs/native_toolchain_c/test/clinker/objects_cross_android_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ void main() {
1616
flutterAndroidNdkVersionLowestSupported,
1717
flutterAndroidNdkVersionHighestSupported,
1818
]) {
19-
group('Android API$apiLevel', () {
19+
group('Android API$apiLevel:', () {
2020
runObjectsTests(targetOS, architectures, androidTargetNdkApi: apiLevel);
2121
});
2222
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
@TestOn('mac-os')
6+
library;
7+
8+
import 'dart:io';
9+
10+
import 'package:code_assets/code_assets.dart';
11+
import 'package:test/test.dart';
12+
13+
import '../helpers.dart';
14+
import 'objects_helper.dart';
15+
16+
void main() {
17+
if (!Platform.isMacOS) {
18+
// Avoid needing status files on Dart SDK CI.
19+
return;
20+
}
21+
22+
const targetOS = OS.iOS;
23+
24+
for (final iOSVersion in [
25+
flutteriOSHighestBestEffort,
26+
flutteriOSHighestSupported,
27+
]) {
28+
for (final iOSTargetSdk in IOSSdk.values) {
29+
group('$iOSTargetSdk $iOSVersion:', () {
30+
runObjectsTests(
31+
targetOS,
32+
iOSSupportedArchitecturesFor(iOSTargetSdk),
33+
iOSTargetVersion: iOSVersion,
34+
iOSTargetSdk: iOSTargetSdk,
35+
);
36+
});
37+
}
38+
}
39+
}

pkgs/native_toolchain_c/test/clinker/objects_helper.dart

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,19 @@ void runObjectsTests(
1717
List<Architecture> architectures, {
1818
int? androidTargetNdkApi, // Must be specified iff targetOS is OS.android.
1919
int? macOSTargetVersion, // Must be specified iff targetOS is OS.macos.
20+
int? iOSTargetVersion, // Must be specified iff targetOS is OS.iOS.
21+
IOSSdk? iOSTargetSdk, // Must be specified iff targetOS is OS.iOS.
2022
}) {
2123
if (targetOS == OS.android) {
2224
ArgumentError.checkNotNull(androidTargetNdkApi, 'androidTargetNdkApi');
2325
}
2426
if (targetOS == OS.macOS) {
2527
ArgumentError.checkNotNull(macOSTargetVersion, 'macOSTargetVersion');
2628
}
29+
if (targetOS == OS.iOS) {
30+
ArgumentError.checkNotNull(iOSTargetVersion, 'iOSTargetVersion');
31+
ArgumentError.checkNotNull(iOSTargetSdk, 'iOSTargetSdk');
32+
}
2733

2834
const name = 'mylibname';
2935

@@ -39,6 +45,8 @@ void runObjectsTests(
3945
architecture,
4046
androidTargetNdkApi: androidTargetNdkApi,
4147
macOSTargetVersion: macOSTargetVersion,
48+
iOSTargetVersion: iOSTargetVersion,
49+
iOSTargetSdk: iOSTargetSdk,
4250
);
4351

4452
final linkInputBuilder = LinkInputBuilder()
@@ -61,6 +69,12 @@ void runObjectsTests(
6169
macOS: macOSTargetVersion != null
6270
? MacOSCodeConfig(targetVersion: macOSTargetVersion)
6371
: null,
72+
iOS: iOSTargetVersion != null && iOSTargetSdk != null
73+
? IOSCodeConfig(
74+
targetSdk: iOSTargetSdk,
75+
targetVersion: iOSTargetVersion,
76+
)
77+
: null,
6478
),
6579
);
6680

pkgs/native_toolchain_c/test/clinker/throws_test.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ void main() {
1313
for (final targetOS in OS.values) {
1414
if (targetOS == OS.linux ||
1515
targetOS == OS.android ||
16-
targetOS == OS.macOS) {
16+
targetOS == OS.macOS ||
17+
targetOS == OS.iOS) {
1718
// Is implemented.
1819
continue;
1920
}

pkgs/native_toolchain_c/test/clinker/treeshake_cross_android_test.dart

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,19 @@ import 'treeshake_helper.dart';
1010

1111
void main() {
1212
const targetOS = OS.android;
13-
final architectures = supportedArchitecturesFor(targetOS);
1413

1514
for (final apiLevel in [
1615
flutterAndroidNdkVersionLowestSupported,
1716
flutterAndroidNdkVersionHighestSupported,
1817
]) {
19-
group('Android API$apiLevel', () {
20-
runTreeshakeTests(targetOS, architectures, androidTargetNdkApi: apiLevel);
21-
});
18+
for (final architecture in supportedArchitecturesFor(targetOS)) {
19+
group('Android API$apiLevel ($architecture):', () {
20+
runTreeshakeTests(
21+
targetOS,
22+
architecture,
23+
androidTargetNdkApi: apiLevel,
24+
);
25+
});
26+
}
2227
}
2328
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
@TestOn('mac-os')
6+
library;
7+
8+
import 'dart:io';
9+
10+
import 'package:code_assets/code_assets.dart';
11+
import 'package:test/test.dart';
12+
13+
import '../helpers.dart';
14+
import 'treeshake_helper.dart';
15+
16+
void main() {
17+
if (!Platform.isMacOS) {
18+
// Avoid needing status files on Dart SDK CI.
19+
return;
20+
}
21+
22+
const targetOS = OS.iOS;
23+
24+
for (final iOSVersion in [
25+
flutteriOSHighestBestEffort,
26+
flutteriOSHighestSupported,
27+
]) {
28+
for (final iOSTargetSdk in IOSSdk.values) {
29+
for (final architecture in iOSSupportedArchitecturesFor(iOSTargetSdk)) {
30+
group('$iOSTargetSdk $iOSVersion ($architecture):', () {
31+
runTreeshakeTests(
32+
targetOS,
33+
architecture,
34+
iOSTargetVersion: iOSVersion,
35+
iOSTargetSdk: iOSTargetSdk,
36+
);
37+
});
38+
}
39+
}
40+
}
41+
}

pkgs/native_toolchain_c/test/clinker/treeshake_cross_test.dart

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,13 @@ void main() {
2323

2424
final architectures = supportedArchitecturesFor(OS.current)
2525
..remove(Architecture.current); // See treeshake_test.dart for current arch.
26-
27-
runTreeshakeTests(
28-
OS.current,
29-
architectures,
30-
macOSTargetVersion: OS.current == OS.macOS ? defaultMacOSVersion : null,
31-
);
26+
for (final architecture in architectures) {
27+
group('${OS.current} ($architecture):', () {
28+
runTreeshakeTests(
29+
OS.current,
30+
architecture,
31+
macOSTargetVersion: OS.current == OS.macOS ? defaultMacOSVersion : null,
32+
);
33+
});
34+
}
3235
}

0 commit comments

Comments
 (0)