Dynamic Library cannot call exposed C function

This is a lengthy one. I have basically compiled a Rust binary into a dylib and packaged into a .xcframework that contains per arch .frameworks. This loads correctly when run from Xcode into a real iOS device. However, when deployed to TestFlight the app crashes.

Here is what is a bit different, the dylib is not fully self-contained. It tries to reach in an use C functions I have exposed in my library code. Calling functions that are just within the dylib and just return works fine, but the moment it tries to call one of the exposed functions it crashes.

A full in-depth step by step of how I packaged the binaries can be found in my website: https://ospfranco.com/complete-guide-to-dylibs-in-ios-and-android

When I look at the TestFlight crash report there are no symbols but the termination cause via WatchDog is:

Termination Reason: CODESIGNING 2 Invalid Page

I have declared my functions as such:

OBJC_EXTERN void ios_prepare_request(const char *url)
#define EXPORT __attribute__((visibility("default"), used, retain))

extern "C" {

EXPORT void ios_prepare_request(const char *url) {
  NSString *urlString = [NSString stringWithUTF8String:url];
  request =
      [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlString]];
}

}

// Function used to prevent optimization
void force_symbol_registration() {
  // Force these symbols to be included in the binary by referencing them
  volatile void *ptrs[] = {(void *)ios_prepare_request,};

  // Prevent compiler from optimizing away the array
  (void)ptrs;
}

And I load my framework as:



  opacity::force_symbol_registration();

  // NSBundle *dylib_bundle =
  //     [NSBundle bundleWithIdentifier:@"com.opacitylabs.sdk"];
  // NSString *dylib_path = [dylib_bundle pathForResource:@"sdk" ofType:@""];

  // // Load the dynamic library
  // void *handle = dlopen([dylib_path UTF8String], RTLD_NOW | RTLD_GLOBAL);
  // if (!handle) {
  //   NSString *errorMessage = [NSString stringWithUTF8String:dlerror()];
  //   *error =
  //       [NSError errorWithDomain:@"OpacitySDKDylibError"
  //                           code:1002
  //                       userInfo:@{NSLocalizedDescriptionKey :
  //                       errorMessage}];
  //   return -1; // or appropriate error code
  // }

  // Make sure the main executable's symbols are available
  dlopen(NULL, RTLD_NOW | RTLD_GLOBAL);

  NSBundle *frameworkBundle =
      [NSBundle bundleWithIdentifier:@"com.opacitylabs.sdk"];
  if (![frameworkBundle isLoaded]) {
    BOOL success = [frameworkBundle load];
    if (!success) {
      NSString *errorMessage = @"Failed to load framework";
      *error =
          [NSError errorWithDomain:@"OpacitySDKDylibError"
                              code:1002
                          userInfo:@{NSLocalizedDescriptionKey : errorMessage}];
      return -1;
    }
  }
  • As you can see, I have also tried dlopen both work when run from Xcode but crash when deployed on testflight.
  • I have tried re-signing the xcframework/frameworks on a pre build step but it doesn't work
  • As stated, I can call the functions inside the dylib, but once they try to call my exposed code it crashes

Is this achievable at all or just a limitation of the iOS sandbox?

Answered by DTS Engineer in 851910022

When you build your app for release, what does the on-disk structure look like. For example, here’s what I see when I build a project I created rom one of Xcode’s built-in templates:

% find "Test795348 04-08-2025, 10.47.xcarchive/Products/Applications/Test795348.app"
…/Test795348.app
…/Test795348.app/_CodeSignature
…/Test795348.app/_CodeSignature/CodeResources
…/Test795348.app/Test795348
…/Test795348.app/embedded.mobileprovision
…/Test795348.app/Info.plist
…/Test795348.app/PkgInfo

Specifically, I’m interested in the final disposition of your Mach-O images. Feel free to elide anything that’s not directly related to that, such as your resources.

Also feel free to redact any private info you don’t want to share. In Posting a Crash Report I describe a simple redaction scheme that I’ve found works well for artefacts.


The reason I’m asking this is that iOS imposes some strict limits on how you can embed code within an iOS app. See Placing Content in a Bundle for info about that. And, quoting that doc:

If you put content in the wrong location, you may encounter hard-to-debug code signing and distribution problems.

Which is exactly where you’re at |-:

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

I have played around a bit more with the code:

  • I tried passing pointers to the functions themselves
  • Making sure the callbacks are called from the mainthread

But nothing seems to work. I did stumble into this page though

https://developer.apple.com/documentation/xcode/investigating-memory-access-crashes#Use-VM-Region-Info-to-locate-the-memory-in-your-apps-address-space

And it's useful to understand the crash logs. My full crash is:

Exception Type:  EXC_BAD_ACCESS (SIGKILL)
Exception Subtype: KERN_PROTECTION_FAILURE at 0x0000000000000000
Exception Codes: 0x0000000000000002, 0x0000000000000000
VM Region Info: 0 is not in any region.  Bytes before following region: 4307271680
      REGION TYPE                 START - END      [ VSIZE] PRT/MAX SHRMOD  REGION DETAIL
      UNUSED SPACE AT START
--->  
      __TEXT                   100bbc000-100bc0000 [   16K] r-x/r-x SM=COW  /var/containers/Bundle/Application/D7CA13B9-71D1-467E-882D-317F9AF57049/OpacityPod_Example.app/OpacityPod_Example
Termination Reason: CODESIGNING 2 Invalid Page

So it's clearly a pointer exception error but it's not a bad acess but a KERN_PROTECTION_FAILURE so it could be indeed a iOS protection system to not be able to call a callback

When you build your app for release, what does the on-disk structure look like. For example, here’s what I see when I build a project I created rom one of Xcode’s built-in templates:

% find "Test795348 04-08-2025, 10.47.xcarchive/Products/Applications/Test795348.app"
…/Test795348.app
…/Test795348.app/_CodeSignature
…/Test795348.app/_CodeSignature/CodeResources
…/Test795348.app/Test795348
…/Test795348.app/embedded.mobileprovision
…/Test795348.app/Info.plist
…/Test795348.app/PkgInfo

Specifically, I’m interested in the final disposition of your Mach-O images. Feel free to elide anything that’s not directly related to that, such as your resources.

Also feel free to redact any private info you don’t want to share. In Posting a Crash Report I describe a simple redaction scheme that I’ve found works well for artefacts.


The reason I’m asking this is that iOS imposes some strict limits on how you can embed code within an iOS app. See Placing Content in a Bundle for info about that. And, quoting that doc:

If you put content in the wrong location, you may encounter hard-to-debug code signing and distribution problems.

Which is exactly where you’re at |-:

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Here is what I get from my latest sent .xcarchive. It's fine to share almost everything about this app, it's just a small demo app.

 ...Products/Applications/OpacityPod_Example.app
$ tree
.
|_____CodeSignature
| |____CodeResources
|____en.lproj
| |____InfoPlist.strings
|____AppIcon60x60@2x.png
|____Base.lproj
| |____Main.storyboardc
| | |____whP-gf-Uak-view-TpU-gO-2f1.nib
| | |____UIViewController-whP-gf-Uak.nib
| | |____Info.plist
| |____LaunchScreen.storyboardc
| | |____01J-lp-oVM-view-Ze5-6b-2t3.nib
| | |____UIViewController-01J-lp-oVM.nib
| | |____Info.plist
|____Assets.car
|____.env
|____OpacityPod_Example
|____Frameworks
| |____libswift_Concurrency.dylib
| |____sdk.framework
| | |_____CodeSignature
| | | |____CodeResources
| | |____sdk
| | |____Info.plist
|____embedded.mobileprovision
|____Info.plist
|____PkgInfo


Any news here @DTS Engineer ?

Thanks for the @ mention. I wasn’t notified of your earlier reply )-:

So your layout looks pretty reasonable. In comparison, here’s what I see when I use Xcode to build a trivial app with an embedded framework:

% find Test795348.app 
Test795348.app
Test795348.app/_CodeSignature
Test795348.app/_CodeSignature/CodeResources
Test795348.app/Test795348
Test795348.app/Base.lproj
Test795348.app/Base.lproj/Main.storyboardc
…
Test795348.app/Base.lproj/LaunchScreen.storyboardc
…
Test795348.app/Frameworks
Test795348.app/Frameworks/FFF.framework
Test795348.app/Frameworks/FFF.framework/_CodeSignature
Test795348.app/Frameworks/FFF.framework/_CodeSignature/CodeResources
Test795348.app/Frameworks/FFF.framework/FFF
Test795348.app/Frameworks/FFF.framework/Info.plist
Test795348.app/embedded.mobileprovision
Test795348.app/Info.plist
Test795348.app/PkgInfo

The only obviously wonky thing in your set up is that .env file. I suspect you don’t want to ship that. However, that’s unlikely to cause this crash.

So, on to other things.


Please post a full crash report for the crash. See Posting a Crash Report for details on how to do that.


Please tell me you’ve not enabled arm64e here, right?

You can check that using file. For example, in my test app:

% file Test795348.app/Test795348
Test795348.app/Test795348: Mach-O 64-bit executable arm64
% file Test795348.app/Frameworks/FFF.framework/FFF
Test795348.app/Frameworks/FFF.framework/FFF: Mach-O 64-bit dynamically linked shared library arm64

This loads correctly when run from Xcode into a real iOS device. However, when deployed to TestFlight the app crashes.

Are you sure that this only shows up in TestFlight? One common thing I see is that folks have a Debug vs Release build configuration issue, but they only notice it in TestFlight because that’s the first time they run their Release build configuration.

I explain one way to tease these apart in Isolating Code Signing Problems from Build Problems.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Yes, the .env is just for testing purposes. This entire app is just a tester app, so some quirks are fine and indeed the file does not cause any issues.


Here is the crash report of my latest build


Here is the output of the file command

$ file OpacityPod_Example
OpacityPod_Example: Mach-O 64-bit executable arm64


$ file Frameworks/sdk.framework/sdk
Frameworks/sdk.framework/sdk: Mach-O 64-bit dynamically linked shared library arm64

I'm sure I have ran the app with the Release config (done via changing the scheme and selecting run → release).

I just tried the Isolating Code Signig Problems from Build Problems you shared. The development option is not there in Xcode 26, but I chose debugging that generated an .ipa which I installed in my device by dragging and dropping. The crash persists on that version.

@DTS Engineer

@DTS Engineer as an aside for extra info. I'm adding the xcframework via cocoapods and I have tried to modify the signing of the framework via the following script in the podspec. I know Apple might not encourage the usage of Cocoapods but this is needed so we can distribute our library through several platforms

  s.script_phase = {
    :name => 'Sign Framework Binary',
    :execution_position => :before_compile,
    :script => <<-SCRIPT
      echo "🟦🟦🟦🟦🟦🟦🟦 Framework Binary Signing Script ==="
      
      # Use BUILT_PRODUCTS_DIR which points to BuildProductsPath
      FRAMEWORK_DIR="${BUILT_PRODUCTS_DIR}/../XCFrameworkIntermediates/${PRODUCT_NAME}/sdk.framework"
      
      # Debug: Print the expected path
      echo "Looking for framework at: $FRAMEWORK_DIR"
      
      if [ -d "$FRAMEWORK_DIR" ]; then
        # Try different ways to get signing identity
        SIGN_IDENTITY="$EXPANDED_CODE_SIGN_IDENTITY"
        if [ -z "$SIGN_IDENTITY" ] || [ "$SIGN_IDENTITY" = "-" ]; then
          SIGN_IDENTITY="$CODE_SIGN_IDENTITY"
        fi
        if [ -z "$SIGN_IDENTITY" ] || [ "$SIGN_IDENTITY" = "-" ]; then
          # Use the first available distribution identity
          SIGN_IDENTITY=$(security find-identity -v -p codesigning | grep "Apple Distribution" | head -1 | awk '{print $2}')
        fi
        if [ -z "$SIGN_IDENTITY" ] || [ "$SIGN_IDENTITY" = "-" ]; then
          # Fallback to development identity
          SIGN_IDENTITY=$(security find-identity -v -p codesigning | grep "Apple Development" | head -1 | awk '{print $2}')
        fi

        if [ -z "$SIGN_IDENTITY" ] || [ "$SIGN_IDENTITY" = "-" ]; then
          echo "🟥🟥 No valid signing identity found"
          exit 1
        fi

        echo "Using identity: $SIGN_IDENTITY"
        
        codesign --force --sign "$SIGN_IDENTITY" "$FRAMEWORK_DIR"
        echo "🟩 Binary signed successfully"
      else
        echo "🟥 Framework not found at: $FRAMEWORK_DIR"
        exit 1
      fi
    SCRIPT
  }

Even with this script, the crash in TestFlight and via the debugging distribution still happens though.

@DTS Engineer I just tried the SPM version of the package and found out that on release config, it crashes with a undefined symbol. I guess cocoapods masqueraded the issue. When ran with the debug scheme then it runs fine.

The Package.swift is defined as follows

// swift-tools-version: 5.8
import PackageDescription

let package = Package(
  name: "OpacityCore",
  platforms: [
    .iOS(.v13)
  ],
  products: [
    .library(
      name: "OpacityCore",
      targets: ["OpacityCoreObjc", "OpacityCoreSwift"])
  ],
  dependencies: [],
  targets: [
    .binaryTarget(
      name: "sdk",
      path: "sdk.xcframework"
    ),
    .target(
      name: "OpacityCoreObjc",
      dependencies: ["sdk"],
      path: "src/objc",
      publicHeadersPath: ".",
      cSettings: [
        .headerSearchPath("../../include")
      ],
      linkerSettings: [
        .linkedFramework("CoreTelephony"),
        .linkedFramework("CoreLocation"),
        .linkedFramework("WebKit"),
      ]
    ),
    .target(
      name: "OpacityCoreSwift",
      dependencies: ["OpacityCoreObjc"],
      path: "src/swift"
    ),
  ]
)

Thanks for the crash report.

The standard DTS mantra is “Always ask for a crash report first.” I failed to do that in this case, to my own detriment )-:

The crash report snippet in your original post, and the discussion of Rust and so on, confused me into thinking that this problem is more complex than it is. However, your crash report makes it clear as to exactly what’s going on:

Thread 3 name:
Thread 3 Crashed:
0   ???                           	0x0000000000000000 0x0 + 0
1   sdk                           	0x0000000105931ec0 0x105820000 + 1121984

This isn’t a weird code signing issue. Rather, your code has simply jumped to nil.

I guess cocoapods masqueraded the issue.

Possibly. I often see cross-platform code deploy the -undefined linker option, which has a tendency to turn build-time errors into run-time errors. Needless to say, I’m not a fan [1].

If you’re curious about how Mach-O symbols work, I talk about that extensively in Understanding Mach-O Symbols. That’s linked to by An Apple Library Primer, which is chock full of useful info for folks in your situation.

it crashes with a undefined symbol.

Looking at your first screenshot it seems to suggest that your code is calling nil. Specifically, I suspect that __lldb_unnamed_symbo116479 is a stub function that’s calling an imported symbol that failed to import correctly. That seems to be inside your sdk framework, so your Swift package setup isn’t relevant. What matters is how you built the sdk Mach-O image. Specifically, you want to check:

  • The build process for the -undefined linker option.
  • The resulting image for weak references or weak definitions.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] The only thing worse is folks who force the entire process to run in a flat namespace. Yuck!

@DTS Engineer you are right, the KERN_PROTECTION_ERROR really through me off. I updated today to Xcode 26 beta 5 and with my dylib compiled with debug symbols all of the sudden I can see where the null invocation is happening

However, I don't have any idea why the compiler is stripping this symbols when packaging for TestFlight/Debugging. I've already added a lot of preprocessor directives to try to keep the symbols intact. Any idea what could I try?

#define EXPORT __attribute__((visibility("default"), used, retain))

extern "C" {

EXPORT void ios_prepare_request(const char *url) {
  NSString *urlString = [NSString stringWithUTF8String:url];
  request =
      [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlString]];
}

void force_symbol_registration() {
  // Force these symbols to be included in the binary by referencing them
  volatile void *ptrs[] = {(void *)ios_prepare_request,
    (void *)ios_set_request_header,
    (void *)ios_present_webview,
    (void *)ios_close_webview,
    (void *)ios_get_browser_cookies_for_current_url,
    (void *)ios_get_browser_cookies_for_domain,
    (void *)get_ip_address,
    (void *)is_rooted,
    (void *)is_wifi_connected,
    (void *)is_location_services_enabled,
    (void *)get_os_name,
    (void *)get_os_version,
    (void *)is_emulator,
    (void *)get_battery_level,
    (void *)get_battery_status
  };

  // Prevent compiler from optimizing away the array
  // (void)ptrs;
  // Actually use the pointers to prevent optimization
  for (int i = 0; i < 6; i++) {
    if (ptrs[i] == NULL) {
      printf("Symbol %d is NULL\n", i);
    }
  }
}

// Add this to ensure symbols are not stripped
__attribute__((constructor)) static void ensure_symbols_retained() {
  force_symbol_registration();
}

static void *__attribute__((used)) symbol_references[] = {
    (void *)ios_prepare_request,
    (void *)ios_set_request_header,
    (void *)ios_present_webview,
    (void *)ios_close_webview,
    (void *)ios_get_browser_cookies_for_current_url,
    (void *)ios_get_browser_cookies_for_domain,
  (void *)get_ip_address,
    nullptr};

EXPORT void ensure_symbols_loaded() {
  volatile void **ptr = (volatile void **)symbol_references;
  while (*ptr) {
    // Just touch the memory to ensure it's loaded
    ptr++;
  }
}

When my library is loaded I do:

  opacity::force_symbol_registration();
  opacity::ensure_symbols_loaded();

  // Make sure the main executable's symbols are available
  dlopen(NULL, RTLD_NOW | RTLD_GLOBAL);

  NSBundle *frameworkBundle =
      [NSBundle bundleWithIdentifier:@"com.opacitylabs.sdk"];
  if (![frameworkBundle isLoaded]) {
    BOOL success = [frameworkBundle load];
    if (!success) {
      NSString *errorMessage = @"Failed to load framework";
      *error =
          [NSError errorWithDomain:@"OpacitySDKDylibError"
                              code:1002
                          userInfo:@{NSLocalizedDescriptionKey : errorMessage}];
      return -1;
    }
  }

  // Validate function pointers before registration
  void *functions[] = {(void *)opacity::ios_prepare_request,
                       (void *)opacity::ios_set_request_header,
                       (void *)opacity::ios_present_webview,
                       (void *)opacity::ios_close_webview,
                       (void *)opacity::ios_get_browser_cookies_for_current_url,
                       (void *)opacity::ios_get_browser_cookies_for_domain,
                       (void *)opacity::get_ip_address};

  for (int i = 0; i < 6; i++) {
    if (functions[i] == NULL || functions[i] == (void *)0x1) {
      NSString *errorMessage = [NSString
          stringWithFormat:@"Invalid function pointer at index %d", i];
      *error =
          [NSError errorWithDomain:@"OpacitySDKCallbackError"
                              code:1004
                          userInfo:@{NSLocalizedDescriptionKey : errorMessage}];
      return -1;
    }
  }

  __sync_synchronize();

On my podspec linker flags I have added

  s.pod_target_xcconfig = {
    'OTHER_LDFLAGS' => '-undefined dynamic_lookup -Wl,-keep_private_externs -Wl,-no_deduplicate'
  }

Have you investigating moving off -undefined dynamic_lookup? A better option is to create a .tbd file and feed that into the static linker. That’ll let the static linker record the identity of the library to import these symbols from, which improves both correctness and performance.

The problem with -undefined dynamic_lookup is that the dynamic linker has to search all Mach-O images for the symbols. That’s obviously not good for performance, but the more serious issue is correctness:

  • Any failures result in a runtime error rather than a link-time error.
  • If you happen to export the same symbol from two different images, it’s undefined which one you end up with.
However, I don't have any idea why the compiler is stripping this symbols when packaging for TestFlight/Debugging.

The best way to control the symbols exported by a dynamic library is to pass a .exp file to the static linker using the -exported_symbols_list option. This give you complete control.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Good news first. With the following config in my podspec the functions are not stripped and it works (🎉) both with debugging archive/TestFlight:

  s.pod_target_xcconfig = {
    'OTHER_LDFLAGS' => '-undefined dynamic_lookup -Wl,-keep_private_externs -Wl,-no_deduplicate -all_load -rdynamic',
    'STRIP_INSTALLED_PRODUCT' => 'NO',
    'DEPLOYMENT_POSTPROCESSING' => 'NO',
    'DEAD_CODE_STRIPPING' => 'NO',
    'GCC_SYMBOLS_PRIVATE_EXTERN' => 'NO',
    'STRIP_STYLE' => 'non-global',
    'COPY_PHASE_STRIP' => 'NO'
  }
  
  # Force these settings for all configurations
  s.user_target_xcconfig = {
    'STRIP_INSTALLED_PRODUCT' => 'NO',
    'DEPLOYMENT_POSTPROCESSING' => 'NO',
    'DEAD_CODE_STRIPPING' => 'NO'
  }

However, zero dead code stripping is not ideal ofc. I tried the .exp approach and it doesn't work.

Maybe I'm misunderstanding something. I tried the .exp approach but it still gets stripped.

Just to be clear, it's not the symbols from the dylib that fail to be executed. It's when the dylib tries to call to the functions in my library code that it fails.

I've added the following to my podspec

  s.resource_bundles = {
    'OpacityCore' => ['exports.exp']
  }
  
  s.pod_target_xcconfig = {
    'OTHER_LDFLAGS' => '-undefined dynamic_lookup -exported_symbols_list "${PODS_TARGET_SRCROOT}/exports.exp"',
  }

The exports.exp file:

_ios_prepare_request

All of this symbols come from src/Helper.mm which is part of my ios library code:

#define EXPORT __attribute__((visibility("default"), used, retain)) extern "C"

EXPORT void ios_prepare_request(const char *url) {
...
}

It's the dylib that once loaded tries to reach in and call those functions. In any case, the code above does not work.

@DTS Engineer I just went a bit through the docs trying to understand really what do the linker flags do and I completely misunderstood what -undefined dynamic_lookup and export_symbols_list do. They are meant for the pod/library to expose it's interface to the outside world. This is not the issue I'm having.

I tried completely removing the linker flags and the app is still working when ran directly from Xcode, with only this function that forces the compiler not to strip the dead code:


#define EXPORT __attribute__((visibility("default"), used, retain)) extern "C"

EXPORT void ios_prepare_request(const char *url) {
...
}

void force_symbol_registration() {
  // Force these symbols to be included in the binary by referencing them
  volatile void *ptrs[] = {(void *)ios_prepare_request,};

  // Actually use the pointers to prevent optimization
  for (int i = 0; i < sizeof(ptrs); i++) {
    if (ptrs[i] == NULL) {
      printf("Symbol %d is NULL\n", i);
    }
  }
}

The linking issue I'm having is internal to the library and the dylib it contains.

@DTS Engineer after much tweaking I've managed to reduce the working configuration to:

  s.user_target_xcconfig = {
    'STRIP_STYLE' => 'non-global'
  }

This works but sets the stripping style of the whole user project. I took a look at the output of Xcode build phases for the pod target and -exported_symbols_list doesn't work with cocoapods (out of the box) because cocoapods generates static lib by default. However setting s.static_framework = false did produce a dynamic framework but the symbols still are stripped.

I'm not sure what other consequences STRIP_STYLE would have... sounds like a setting this only for my library is a bad idea, but I'm out of ideas on how to keep the symbols. I also tried passing each symbol directly to the linker and that also did not work

  s.user_target_xcconfig = {
    'OTHER_LDFLAGS' => '$(inherited) -Wl,-u,_ios_prepare_request -Wl,-u,_ios_set_request_header -Wl,-u,_ios_present_webview -W...'
}
They are meant for the pod/library to expose it's interface to the outside world. This is not the issue I'm having.

It kinda is. If you want to be able to look up the symbol dynamically, using dlsym, the symbol has to be exported to the dynamic linker. If it’s not so-exported, dlsym won’t find it.

Additionally, something that’s exported to the dynamic linker will never be dead stripped.

OTOH, if you don’t want to look up the symbols dynamically then whether they’re exported or not doesn’t matter, because the symbols get resolved when you statically link. In that case the trick is to not use -undefined dynamic_lookup and instead either:

  • Supply all the relevant object files at static link time, or
  • Supply a .tbd file to get the static linker to record the correct place to search for these symbols.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Dynamic Library cannot call exposed C function
 
 
Q