Skip to content

[native_toolchain_c] Add linking for Android #2347

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jun 12, 2025

Conversation

goderbauer
Copy link
Contributor

@goderbauer goderbauer commented Jun 6, 2025

Towards #1376

This enables linking for Android on Windows, Linux, and MacOS hosts.

With this PR the linker is no longer invoked directly. Instead, it is invoked via the compiler driver (clang, etc.), which has the advantage that we don't have to hand-translate the arguments to the format the linker expects them to be. The compiler driver is doing that for us and we can mostly reuse the compiler driver invocation.


  • I’ve reviewed the contributor guide and applied the relevant portions to this PR.
Contribution guidelines:

Note that many Dart repos have a weekly cadence for reviewing PRs - please allow for some latency before initial review feedback.

Copy link

github-actions bot commented Jun 6, 2025

PR Health

Changelog Entry ✔️
Package Changed Files

Changes to files need to be accounted for in their respective changelogs.

API leaks ✔️

The following packages contain symbols visible in the public API, but not exported by the library. Export these symbols or remove them from your publicly visible API.

Package Leaked API symbols
License Headers ✔️
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
Files
no missing headers

All source files should start with a license header.

Unrelated files missing license headers
Files
pkgs/jni/lib/src/third_party/generated_bindings.dart
pkgs/native_doc_dartifier/example/native_doc_dartifier_example.dart
pkgs/native_doc_dartifier/lib/native_doc_dartifier.dart
pkgs/native_doc_dartifier/lib/src/native_doc_dartifier_base.dart
pkgs/objective_c/lib/src/ns_input_stream.dart

Copy link

github-actions bot commented Jun 6, 2025

Package publishing

Package Version Status Publish tag (post-merge)
package:code_assets 0.19.3 already published at pub.dev
package:data_assets 0.19.1 already published at pub.dev
package:ffi 2.1.4 already published at pub.dev
package:ffigen 19.1.0-wip WIP (no publish necessary)
package:hooks 0.19.3 already published at pub.dev
package:hooks_runner 0.21.0 already published at pub.dev
package:jni 0.14.2 already published at pub.dev
package:jnigen 0.15.0-wip WIP (no publish necessary)
package:native_doc_dartifier 0.0.1-pre already published at pub.dev
package:native_toolchain_c 0.16.3 ready to publish native_toolchain_c-v0.16.3
package:objective_c 8.1.0-wip WIP (no publish necessary)
package:swift2objc 0.0.1-wip WIP (no publish necessary)
package:swiftgen 0.0.1-wip WIP (no publish necessary)

Documentation at https://github.com/dart-lang/ecosystem/wiki/Publishing-automation.

@goderbauer goderbauer force-pushed the android-linker branch 3 times, most recently from 84b1b48 to ca6c274 Compare June 6, 2025 13:22
@goderbauer goderbauer requested review from dcharkes and mosuem June 6, 2025 13:36
@goderbauer
Copy link
Contributor Author

Hm, it's not clear to me why the bot wants the version to be bumped to 0.17.0

@dcharkes
Copy link
Collaborator

dcharkes commented Jun 6, 2025

Hm, it's not clear to me why the bot wants the version to be bumped to 0.17.0

You should be able to repro it with the dart_apitool yourself with https://github.com/dart-lang/ecosystem/blob/64aac3a9c4606950bcf6c8729f01ed8548b9ed87/pkgs/firehose/lib/src/health/health.dart#L152

@goderbauer
Copy link
Contributor Author

goderbauer commented Jun 10, 2025

You should be able to repro it with the dart_apitool yourself

Thank you! I am pretty sure that the tool is wrong here based on what it has identified as a breaking change in a local run:

BREAKING CHANGES
├── Function "environmentFromBatchFile" removed (CE10)
├─┬ Class CBuilder
│ ├─┬ Constructor library
│ │ └── Type of parameter "linkModePreference" changed. InvalidType -> LinkModePreference? (CE08)
│ └─┬ Field linkModePreference
│   └── Type of field changed. InvalidType -> LinkModePreference? (CF04)
└─┬ Class CLinker
  ├─┬ Constructor library
  │ └── Type of parameter "linkModePreference" changed. InvalidType -> LinkModePreference? (CE08)
  └─┬ Field linkModePreference
    └── Type of field changed. InvalidType -> LinkModePreference? (CF04)

The environmentFromBtachFile wasn't touched in this PR, it is still there and properly exported. The tool also seems to be unable to correctly infer the type of the linkModePreference parameter in the old version of this package and now that it can determine the correct type it thinks the type has changed. That's not correct, the type remains unchanged. I am going to overwrite the check for now.

Edit: It looks like the dart_apitool may have trouble with native_toolchain_c being part of a pub workspace. It seems to be checking out the previous version of the package from pub and analyzing that code outside of its workspace, which seems to result in some problems. If I actually check out the whole repository at the old version's revision and have the tool compare that with the current revision, it correctly detects no breaking change: No breaking changes!

@coveralls
Copy link

coveralls commented Jun 10, 2025

Coverage Status

coverage: 82.3%. first build
when pulling 1ec9e5a on goderbauer:android-linker
into fd9415b on dart-lang:main.

@dcharkes
Copy link
Collaborator

Edit: It looks like the dart_apitool may have trouble with native_toolchain_c being part of a pub workspace. It seems to be checking out the previous version of the package from pub and analyzing that code outside of its workspace, which seems to result in some problems. If I actually check out the whole repository at the old version's revision and have the tool compare that with the current revision, it correctly detects no breaking change: No breaking changes!

It does indeed check out the package from pub. See the discussion here: bmw-tech/dart_apitool#216

The packages on pub.dev should work, they are used in the flutter template and flutter integration tests. It's fishy that it fails. (Yeah indeed just apply the label for now.)

@@ -53,10 +53,12 @@ class CLinker extends CTool implements Linker {
required LinkOutputBuilder output,
required Logger? logger,
}) async {
if (OS.current != OS.linux || input.config.code.targetOS != OS.linux) {
const supportedTargetOSs = [OS.linux, OS.android];
if (!supportedTargetOSs.contains(input.config.code.targetOS)) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This no longer checks if the hostOS is Linux if the targetOS is Linux.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was assuming that we only check for combinations that should work, but currently don't because they are still WIP - similarly to how cbuilder.dart is also not checking that you can only target linux from linux.

Copy link
Member

@mosuem mosuem left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean that users need to have clang or similar installed? Linux will have ld preinstalled, but not clang.

@goderbauer
Copy link
Contributor Author

Does this mean that users need to have clang or similar installed? Linux will have ld preinstalled, but not clang.

In theory, it does not require clang on linux and I double checked that in practice everything works if the compiler driver to be used resolves to gcc, which should be installed by default on Linux. However, the native_toolchain_c package currently hard-codes the use of clang on linux systems if host and target OS and architecture match:

// TODO(dacoharkes): Support falling back on other tools.
if (targetArch == hostArchitecture &&
targetOS == hostOS &&
hostOS == OS.linux) {
return clang;
}

Not sure why this is done. When I remove this and let it instead fall through to select the approriate gcc on linux (see below) it just works as expected:

if (hostOS == OS.linux) {
switch (targetArch) {
case Architecture.arm:
return armLinuxGnueabihfGcc;
case Architecture.arm64:
return aarch64LinuxGnuGcc;
case Architecture.ia32:
return i686LinuxGnuGcc;
case Architecture.x64:
return x86_64LinuxGnuGcc;
case Architecture.riscv64:
return riscv64LinuxGnuGcc;
}
}

@dcharkes Since you added this selection code originally, do you have any insights into this? Is it on purpose that we force clang on linux if you don't cross-compile? If yes, do we consider it a requirement that clang is installed on linux if one wants to use the native_toolchain_c package?

@dcharkes
Copy link
Collaborator

Is it on purpose that we force clang on linux if you don't cross-compile?

No. But we haven't implemented fallback tools yet:

// TODO(dacoharkes): Support falling back on other tools.

The tool recognizer works with both clang and gcc if passed in in the CCompilerConfig, but the tool discovery doesn't use fallbacks.

We do have a requirement that we use the compiler/linker/archiver that belong together. We shouldn't be using a linker from a different compiler toolchain. So the fallback logic can't be separate for the compiler/linker. So we might need to introduce something like a ToolGroup and do fallbacks at that level. (And if we make the tool resolver logic more fancy, we should probably also address #19.)

@goderbauer
Copy link
Contributor Author

We shouldn't be using a linker from a different compiler toolchain.

This PR actually simplifies this then since it removes calling the linker directly and instead goes through clang or gcc or whatever compiler driver is available.

I am submitting this as is then since #20 is a separate open issue regarding clang vs. gcc on Linux.

@goderbauer goderbauer merged commit 08c98ed into dart-lang:main Jun 12, 2025
18 checks passed
@goderbauer goderbauer deleted the android-linker branch June 12, 2025 07:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants