Skip to content

Conversation

@liamappelbe
Copy link
Contributor

@liamappelbe liamappelbe commented May 26, 2025

Notes

  • I'm using on @Native annotations to load all the ffi symbols. Previously this worked because I loaded the dylib into the executable first, then relied on the @Native fallback behavior to load the symbols from the exe. Now I'm explicitly setting the asset name to the built dylib, which appears to disable that fallback behavior. But all the core ObjC runtime symbols (eg objc_msgSend) are linked into the exe, not the dylib. So I had to split the C bindings into a set that loads from the dylib, and a set that loads from the exe. There are now 3 sets of ffigen created bindings: the objective C bindings (loads from the dylib), the bindings for my C code (loads from the dylib), and the bindings for the built in ObjC runtime's C code (loads from the exe).
  • Similarly, I had an issue where the global variables exposed by the ObjC bindings were failing to load. So I moved them to the C runtime bindings so they'd be loaded from the exe. This exposed them as a raw Pointer<ObjCObject>, so I had to manually wrap them in NSStrings in globals.dart. I tried splitting the ObjC bindings like I split the C bindings, but this caused all sorts of other problems.
  • ffigen has a dev dep on package:objective_c for testing. All the ObjC tests are disabled on linux and windows, but afaik there's no way of avoiding pulling in the dependency on those platforms. So I had to modify package:objective_c's build script to no-op on those platforms. Seems like a sub-optimal solution.
  • package:objective_c has a util to dispatch calls to the main thread. This works on Flutter but not on Dart, because Dart doesn't drain the main thread dispatch queue. So on Dart we fall back to just running the function on the current thread, and this Flutter/Dart difference was configured with a build flag. In native assets there's no way of passing different flags on flutter vs Dart, so instead we try to detect this at runtime by dispatching a call to the main thread and seeing if it gets invoked.
  • To work around [coverage] Support native assets in test_with_coverage tools#2237, I've switched the ffigen coverage collection from coverage:test_with_coverage to dart test --coverage_path. This slightly reduces coverage because we don't have as much control over the filtering, so I can't tell it to retain the package:objective_c coverage info gathered during the ffigen tests.

@github-actions
Copy link

github-actions bot commented May 26, 2025

PR Health

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
pkgs/objective_c/example/command_line/lib/main.dart
pkgs/objective_c/lib/src/ns_input_stream.dart

All source files should start with a license header.

This check can be disabled by tagging the PR with skip-license-check.

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 symbol Leaking sources
objective_c _FinalizablePointer internal.dart::_ObjCReference::new::_finalizable

This check can be disabled by tagging the PR with skip-leaking-check.

Breaking changes ⚠️
Package Change Current Version New Version Needed Version Looking good?
objective_c Breaking 9.1.0 9.2.0-dev 10.0.0
Got "9.2.0-dev" expected >= "10.0.0" (breaking changes)
⚠️

This check can be disabled by tagging the PR with skip-breaking-check.

Changelog Entry ✔️
Package Changed Files

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

This check can be disabled by tagging the PR with skip-changelog-check.

@github-actions github-actions bot added the type-infra A repository infrastructure change or enhancement label Jun 13, 2025
@coveralls
Copy link

coveralls commented Jun 18, 2025

Coverage Status

coverage: 87.112% (-0.3%) from 87.428%
when pulling 26fa609 on objc_native
into 9767a50 on main.

@liamappelbe
Copy link
Contributor Author

liamappelbe commented Nov 11, 2025

Mac CI failures are due to running the tests through package:coverage. Need to investigate why that's not finding the dylib.

That sounds like something we should fix before build hooks get to stable! Let me know if you need any help with this.

@dcharkes I haven't been able to find a minimal repro for this, and it's a bit hard to debug as the build system is a bit of a black box to me. When I run ffigen tests that depend on package:objective_c, I get this error where it failed to load package:objective_c's native asset:

Invalid argument(s): Couldn't resolve native function 'DOBJC_initializeApi' in 'package:objective_c/objective_c.dylib' : No asset with id 'package:objective_c/objective_c.dylib' found. Available native assets: . Attempted to fallback to process lookup. dlsym(RTLD_DEFAULT, DOBJC_initializeApi): symbol not found.

The dylib is being built, and exists at the correct path (ffigen/.dart_tool/hooks_runner/shared/objective_c/build/9fb02c5622/objective_c.dylib), so I think it's just not searching the correct directories. Is there a way of enabling logging in the build? I'd like to know what directories it's searching. If there's no logging for that, could you point me to the part of the hooks code where these directories are listed so I can print debug?

@dcharkes
Copy link
Collaborator

dcharkes commented Nov 14, 2025

Available native assets: .

This definitely means no native assets mapping is bundled with the Dart kernel/source file that is being run for the tests.

My hunch would be that something triggers the build hook, and it writes the assets. However, that whatever compiles the test kernel file doesn't pick up on those assets. I had to write some code in package test to ensure the native assets yaml file is picked up when compiling the kernel file https://github.com/dart-lang/test/pulls?q=is%3Apr+author%3Adcharkes+is%3Aclosed. I wouldn't be surprised if you'd need something similar for package coverage.

so I think it's just not searching the correct directories.

It's not supposed to search any directories. The native_assets.yaml file passed the kernel compiler is supposed to specify exactly where the dylib is (either absolute path or relative path to the kernel file).

@liamappelbe liamappelbe requested a review from dcharkes November 18, 2025 03:59
@liamappelbe
Copy link
Contributor Author

@dcharkes I made some changes to hook/build.dart to fix the flutter example build. Do these changes look reasonable?

@dcharkes
Copy link
Collaborator

@dcharkes I made some changes to hook/build.dart to fix the flutter example build. Do these changes look reasonable?

Yes, they look reasonable!

@liamappelbe liamappelbe merged commit 224d93e into main Nov 19, 2025
29 checks passed
@liamappelbe liamappelbe deleted the objc_native branch November 19, 2025 23:05
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