Skip to content
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

IOS Release running error: Failed to lookup symbol #17

Open
yiv opened this issue Jan 26, 2021 · 10 comments
Open

IOS Release running error: Failed to lookup symbol #17

yiv opened this issue Jan 26, 2021 · 10 comments
Labels
help wanted Extra attention is needed

Comments

@yiv
Copy link

yiv commented Jan 26, 2021

When I compile and run in deubg mode on ios, everything works fine. But when I switch to release, I got the error like below:

2021-01-26 20:36:03.466780+0800 Runner[26430:9877639] Metal API Validation Enabled
2021-01-26 20:36:03.669728+0800 Runner[26430:9877805] [VERBOSE-2:ui_dart_state.cc(177)] Unhandled Exception: Invalid argument(s): Failed to lookup symbol (dlsym(RTLD_DEFAULT, store_dart_post_cobject): symbol not found)
#0      DynamicLibrary.lookup (dart:ffi-patch/ffi_dynamic_library_patch.dart:31)
#1      _store_dart_post_cobject (package:full_search/ffi.dart)
#2      _store_dart_post_cobject (package:full_search/ffi.dart)
#3      store_dart_post_cobject (package:full_search/ffi.dart:263)
#4      SearchEngine.setup (package:full_search/full_search.dart:12)
#5      _MyAppState.initSearchEngine (package:full_search_example/main.dart:38)
#6      _MyAppState.initState (package:full_search_example/main.dart:31)
#7      StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:4822)
#8      ComponentElement.mount (package:flutter/src/widgets/framework.dart:4659)
#9      Element.inflateWidget (package:flutter/src/widgets/framework.dart:3625)
#10     Element.updateChild (package:flutter/src/widgets/framework.dart:3390)
#11     RenderObjectToWidgetElement._rebuild (package:flutter/src/widgets/binding.dart:1208)
#12     RenderObjectToWidgetElement.mount (package:flutter/src/widgets/binding.dart:1179)
#13     RenderObjectToWidgetAdapter.attachToRenderTree.<anonymous closure> (package:flutter/src/widgets/binding.dart:1121)
#14     BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2731)
#15     RenderObjectToWidgetAdapter.attachToRenderTree (package:flutter/src/widgets/binding.dart:1120)
#16     WidgetsBinding.attachRootWidget (package:flutter/src/widgets/binding.dart:960)
#17     WidgetsBinding.scheduleAttachRootWidget.<anonymous closure> (package:flutter/src/widgets/binding.dart:941)
#18     _rootRun (dart:async/zone.dart:1178)
#19     _CustomZone.run (dart:async/zone.dart:1090)
#20     _CustomZone.runGuarded (dart:async/zone.dart:994)
#21     _CustomZone.bindCallbackGuarded.<anonymous closure> (dart:async/zone.dart:1034)
#22     _rootRun (dart:async/zone.dart:1186)
#23     _CustomZone.run (dart:async/zone.dart:1090)
#24     _CustomZone.bindCallback.<anonymous closure> (dart:async/zone.dart:1018)
#25     TickerFuture.whenCompleteOrCancel.thunk (package:flutter/src/scheduler/ticker.dart:399)
#26     _Timer._runTimers (dart:isolate-patch/timer_impl.dart:395)
#27     _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:426)
#28     _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:184)
@shekohex
Copy link
Owner

you need to include allo-isolate crate.
or that means that Xcode tree-shaking process decided to strip your static library.

to solve this issue, there is a workaround this to force Xcode Link to your library.
what should do is creating a no-op function let's call it link_me_please something like this

#[no_mangle]
pub extern "C" fn link_me_please() {}

and then in your package/ios add a dommy method in your class that calls this function.
here is an example from this repo:
https://github.com/shekohex/flutterust/blob/master/packages/adder_ffi/ios/Classes/SwiftAdderPlugin.swift#L13

note that your Makefile.toml the cargo make script should also copy the binding.h (the generated header file) to Classes folder .. which I guess is set to that by default.

@yiv
Copy link
Author

yiv commented Jan 26, 2021

Right now, I did like this

https://github.com/shekohex/flutterust/blob/master/packages/scrap_ffi/ios/Classes/SwiftScrapPlugin.swift

public static func dummyMethodToEnforceBundling() {
    last_error_length()
  }

It works well in ios debug mode, async function works well too.

And I found a releated issue in another project. brickpop/flutter-rust-ffi#7

I'm sorry to be late on this, but where the readme says add a dummy method in SwiftMylibPlugin.swift that uses at least one of the native functions, it should say add a dummy call for every single one of them.

For some unexplainable reason:

In Debug mode, XCode will bundle the entire library if at least one library function is used.
In Release mode, XCode will do tree shaking, and only bundle the native functions and the callees that you explicitly reference
I learnt it the hard way myself, I'm updating the Readme right now.

@yiv
Copy link
Author

yiv commented Jan 26, 2021

And I'm confused. There is no store_dart_post_cobject function in binding.h, how can it be called? And it work fine in IOS debug mode.

@shekohex
Copy link
Owner

the store_dart_post_cobject is function exported from allo-isolate package.
so one way to make it exported is to re-export it again or use something like this:

use allo_isolate::ffi;

#[no_mangle]
pub unsafe extern "C" fn store_dart_post_cobject(
    ptr: ffi::DartPostCObjectFnType,
) {
    allo_isolate::store_dart_post_cobject(ptr);
}

@shekohex
Copy link
Owner

@yiv
Copy link
Author

yiv commented Jan 27, 2021

iOS symbols stripped
When creating a release archive (IPA) the symbols are stripped by Xcode.

In Xcode, go to Target Runner > Build Settings > Strip Style.
Change from All Symbols to Non-Global Symbols.

After did like above.

This time, I am trying to build and run flutterust project directly in IOS release mode.
Also facing the same error.

2021-01-27 10:22:42.684201+0800 Runner[27043:10106244] Metal API Validation Enabled
2021-01-27 10:22:43.004687+0800 Runner[27043:10106378] flutter: Invalid argument(s): Failed to lookup symbol (dlsym(RTLD_DEFAULT, store_dart_post_cobject): symbol not found)
2021-01-27 10:22:43.008625+0800 Runner[27043:10106378] flutter: #0      DynamicLibrary.lookup (dart:ffi-patch/ffi_dynamic_library_patch.dart:31)
2021-01-27 10:22:43.008682+0800 Runner[27043:10106378] flutter: #1      _store_dart_post_cobject (package:scrap/ffi.dart)
2021-01-27 10:22:43.008705+0800 Runner[27043:10106378] flutter: #2      _store_dart_post_cobject (package:scrap/ffi.dart)
2021-01-27 10:22:43.008723+0800 Runner[27043:10106378] flutter: #3      store_dart_post_cobject (package:scrap/ffi.dart:63)
2021-01-27 10:22:43.008741+0800 Runner[27043:10106378] flutter: #4      Scrap.setup (package:scrap/scrap.dart:10)
2021-01-27 10:22:43.008760+0800 Runner[27043:10106378] flutter: #5      _MyHomePageState.initState (package:flutterust/main.dart:37)
2021-01-27 10:22:43.008776+0800 Runner[27043:10106378] flutter: #6      StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:4822)

@shekohex
Copy link
Owner

Unfortunately, I don't have access to a macOS Machine right now to do tests and try to fix this issue, but feel free if you got it to work correctly to Open a PR for README to add steps to fix this issue.
Thanks :)

@Aaron009
Copy link

Aaron009 commented Feb 11, 2021

You can pull this project from me and it has been resolved.
https://github.com/Aaron009/flutter-rust-ffi

the reason:
brickpop/flutter-rust-ffi#23

@trueb2
Copy link

trueb2 commented Feb 8, 2022

I separated a plugin for just the basics like lazy initialization of the RUNTIME and linking of the store_dart_post_cobject symbol. In the Swift plugin header, I have added a declaration

In packages/runtime_ffi/ios/Classes/RuntimePlugin.h:

#import <Flutter/Flutter.h>

void* store_dart_post_cobject(void*);

@interface RuntimePlugin : NSObject<FlutterPlugin>
@end

In a static function that I don't call, I call all of the methods that I would like linked.
In packages/runtime_ffi/ios/SwiftRuntimePlugin.swift:

import Flutter
import UIKit

public class SwiftRuntimePlugin: NSObject, FlutterPlugin {
  public static func register(with registrar: FlutterPluginRegistrar) {
    let channel = FlutterMethodChannel(name: "runtime", binaryMessenger: registrar.messenger())
    let instance = SwiftRuntimePlugin()
    registrar.addMethodCallDelegate(instance, channel: channel)
  }

  public func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
    result("iOS " + UIDevice.current.systemVersion)
  }

  public static func dummyMethodToEnforceBundling() {
    store_dart_post_cobject(nil)
    runtime_setup()
    last_error_length()
    error_message_utf8(nil, 0)
  }
}

This is all with Non-Global Symbols set for iOS
Screen Shot 2022-02-08 at 3 12 48 PM

I believe that any other symbols that could have this issue would be in Rust code that you add. Those symbols should be trivial to find and add to dummyMethodToEnforceBundling for each package plugin.

@trueb2
Copy link

trueb2 commented Feb 9, 2022

I found that even though this allows the build to succeed, this is not a fix. The POST_COBJECT is never stored correctly and is always None during post calls even after setup.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

4 participants