sentry-cocoa icon indicating copy to clipboard operation
sentry-cocoa copied to clipboard

feat: Add support for dynamic library

Open mrtnrst opened this issue 3 years ago • 15 comments

:scroll: Description

This PR adds support for using a dynamic library. Keeping it an additive change, and not breaking, I added a new library product that generates Sentry-Dynamic.

:bulb: Motivation and Context

The motivation behind this work is personal. I am working on a project that utilizes a private framework within the same Xcode project. With nested frameworks like this, Xcode fails to compile the duplication.

Relevant Swift forum thread: https://forums.swift.org/t/swift-packages-in-multiple-targets-results-in-this-will-result-in-duplication-of-library-code-errors/34892

:green_heart: How did you test it?

After adding in the project there are two frameworks now listed under the Sentry category: Sentry and Sentry-Dynamic image

image

:pencil: Checklist

  • [x] I reviewed the submitted code
  • [ ] I added tests to verify the changes
  • [ ] I updated the docs if needed
  • [x] Review from the native team if needed
  • [x] No breaking changes

:crystal_ball: Next steps

mrtnrst avatar Mar 28 '22 15:03 mrtnrst

Thanks, @mrtnrst, for opening this PR. After reading the thread you pointed out I'm not convinced that adding a new .dynamic target is the solution. I don't find this in any other open-source libraries supporting SPM. It seems to me that this is more of an issue with Xcode. Can you maybe be more specific, about why you think your change is necessary?

philipphofmann avatar Mar 29 '22 14:03 philipphofmann

Thanks, @mrtnrst, for opening this PR. After reading the thread you pointed out I'm not convinced that adding a new .dynamic target is the solution. I don't find this in any other open-source libraries supporting SPM. It seems to me that this is more of an issue with Xcode. Can you maybe be more specific, about why you think your change is necessary?

I can get a sample application tonight to help demonstrate what I am talking about. For other repos that support this, here are two that my team is actively using: https://github.com/DataDog/dd-sdk-ios/blob/1c3e2b0395864c8764812226b74797866d7ff0d4/Package.swift#L11-L37 https://github.com/ReactiveX/RxSwift/blob/693a6218e0800753cb54e55f278d050ae9a15938/Package.swift#L46-L60

mrtnrst avatar Mar 29 '22 14:03 mrtnrst

Thanks for the update, @mrtnrst. A sample application would be excellent. Ideally, we would like to validate the dynamic library in CI similar to https://github.com/getsentry/sentry-cocoa/blob/2e5882cec6275de1c4fc0c7e47ff6a54da7dfe9c/.github/workflows/build.yml#L109-L124

Your sample app could maybe be a starting point to achieve this.

philipphofmann avatar Mar 31 '22 15:03 philipphofmann

@philipphofmann sorry for the delay here, work is a little busy. I will try to get back to this later in the week 🙏🏽

mrtnrst avatar Apr 13 '22 13:04 mrtnrst

That's actually the only way to support dynamic frameworks via SPM:

  • Carthage: it is possible to modify build settings for the Sentry target by manually changing MACH_O_TYPE to dylib
  • CocoaPods: AFAIK they build dynamic frameworks by default, unless you specify static_framework: true for those targets, where you expect to have static linkage, or by providing some global parameter instead of !use_frameworks
  • Swift Package Manager: ???
    • type can only be specified in the Package.swift file and can't be overridden by a consumer
    • no way to modify build settings
    • not an easy way to maintain a separate repository with source files, but with a modified Package.swift that has dynamic type

balavor avatar Apr 27 '22 13:04 balavor

We're using a dynamic library in Unity, for macOS: https://github.com/getsentry/sentry-unity/pull/710 I wonder if this would simplify things there. @vaind would know best

bruno-garcia avatar May 06 '22 12:05 bruno-garcia

We're using a dynamic library in Unity, for macOS: getsentry/sentry-unity#710 I wonder if this would simplify things there. @vaind would know best

Yeah I've had a look at this PR but didn't get what this actually changes - the Sentry library that's inside a built Sentry.framework is already a dynamic library - e.g. in the Unity SDK, I'm just copying it & renaming - needs to be a plain *.dylib file, not a .framework for Unity to be willing to include it in a project build.

vaind avatar May 06 '22 13:05 vaind

This pull request has gone three weeks without activity. In another week, I will close it.

But! If you comment or otherwise update it, I will reset the clock, and if you label it Status: Backlog or Status: In Progress, I will leave it alone ... forever!


"A weed is but an unloved flower." ― Ella Wheeler Wilcox 🥀

github-actions[bot] avatar May 28 '22 00:05 github-actions[bot]

Hey @mrtnrst, do you have time to add the sample application for validation in CI, maybe?

philipphofmann avatar Jun 10 '22 08:06 philipphofmann

This pull request has gone three weeks without activity. In another week, I will close it.

But! If you comment or otherwise update it, I will reset the clock, and if you label it Status: Backlog or Status: In Progress, I will leave it alone ... forever!


"A weed is but an unloved flower." ― Ella Wheeler Wilcox 🥀

github-actions[bot] avatar Jul 07 '22 00:07 github-actions[bot]

Hey @mrtnrst, do you have time to add the sample application for validation in CI, maybe?

Hi! Apologies for the terrible delay (I kept staring at this notification and just scared myself into not opening it 😅).

What kind of example project were you wanting? Something that passes and runs through CI? Or something that demonstrates the issue I am having?

mrtnrst avatar Jul 13 '22 18:07 mrtnrst

Hey @mrtnrst, please see my comment above https://github.com/getsentry/sentry-cocoa/pull/1726#issuecomment-1084727579.

philipphofmann avatar Jul 18 '22 08:07 philipphofmann

Thanks, @mrtnrst, for adding the sample. I will get back to this PR later.

philipphofmann avatar Jul 20 '22 14:07 philipphofmann

Hi @mrtnrst, I'm just looking for some clarification on how you have your project set up (and per https://github.com/getsentry/sentry-cocoa/pull/1726#issuecomment-1183546409, I think it would be helpful to have a MVP that mimics your actual setup, which can then also be used to validate).

AIUI, you have an app target and a static library target, and both of them link in Sentry, so that statically linking your library into your app results in duplicate Sentry symbols from both targets. You'd like to be able to declare your app and library to link Sentry dynamically at runtime instead of at build time to avoid the duplication. Is that right?

    graph LR;
      App--static-->Lib;
      App--static-->Sentry;
      Lib--static-->Sentry;

I tried setting this up using only Xcode targets but couldn't force a duplicate symbol error, so it must be something specific to how SPM does things. I tried using SPM based on the example you provided but the project it creates for me crashes Xcode as soon as I try to build 😰

armcknight avatar Jul 29 '22 00:07 armcknight

Hi @mrtnrst, I'm just looking for some clarification on how you have your project set up (and per #1726 (comment), I think it would be helpful to have a MVP that mimics your actual setup, which can then also be used to validate).

AIUI, you have an app target and a static library target, and both of them link in Sentry, so that statically linking your library into your app results in duplicate Sentry symbols from both targets. You'd like to be able to declare your app and library to link Sentry dynamically at runtime instead of at build time to avoid the duplication. Is that right?

I tried setting this up using only Xcode targets but couldn't force a duplicate symbol error, so it must be something specific to how SPM does things. I tried using SPM based on the example you provided but the project it creates for me crashes Xcode as soon as I try to build 😰

I'll see if I can get a more exact replica of what I am experiencing here. And to answer you other question, that is correct. The framework project we create cannot import the Sentry target without creating the duplicate references so the change to make it dynamic (to allow the import without embed) gives us that freedom. We would still want to use the static embedded framework on the main project, not the dynamic library.

mrtnrst avatar Aug 01 '22 19:08 mrtnrst

This pull request has gone three weeks without activity. In another week, I will close it.

But! If you comment or otherwise update it, I will reset the clock, and if you label it Status: Backlog or Status: In Progress, I will leave it alone ... forever!


"A weed is but an unloved flower." ― Ella Wheeler Wilcox 🥀

github-actions[bot] avatar Aug 23 '22 00:08 github-actions[bot]

I'm going to merge this after releasing the hotfix 7.24.1.

philipphofmann avatar Sep 05 '22 13:09 philipphofmann

It seems to me that Sentry-Dynamic is building an empty framework?

$ ( cd /Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Products/Debug-iphonesimulator/PackageFrameworks/Sentry-Dynamic.framework; find . )
.
./_CodeSignature
./_CodeSignature/CodeResources
./_CodeSignature/CodeDirectory
./_CodeSignature/CodeRequirements-1
./_CodeSignature/CodeSignature
./_CodeSignature/CodeRequirements
./Info.plist

Build of Sentry-Dynamic:

Showing All Messages
Build target Sentry-Dynamic
MkDir /Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Products/Debug-iphonesimulator/PackageFrameworks/Sentry-Dynamic.framework (in target 'Sentry-Dynamic' from project 'Sentry')
    cd /Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/SourcePackages/checkouts/sentry-cocoa
    /bin/mkdir -p /Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Products/Debug-iphonesimulator/PackageFrameworks/Sentry-Dynamic.framework

WriteAuxiliaryFile /Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Intermediates.noindex/Sentry.build/Debug-iphonesimulator/Sentry-Dynamic\ product.build/empty-Sentry-Dynamic.plist (in target 'Sentry-Dynamic' from project 'Sentry')
    cd /Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/SourcePackages/checkouts/sentry-cocoa
    write-file /Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Intermediates.noindex/Sentry.build/Debug-iphonesimulator/Sentry-Dynamic\ product.build/empty-Sentry-Dynamic.plist

ProcessInfoPlistFile /Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Products/Debug-iphonesimulator/PackageFrameworks/Sentry-Dynamic.framework/Info.plist /Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Intermediates.noindex/Sentry.build/Debug-iphonesimulator/Sentry-Dynamic\ product.build/empty-Sentry-Dynamic.plist (in target 'Sentry-Dynamic' from project 'Sentry')
    cd /Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/SourcePackages/checkouts/sentry-cocoa
    builtin-infoPlistUtility /Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Intermediates.noindex/Sentry.build/Debug-iphonesimulator/Sentry-Dynamic\ product.build/empty-Sentry-Dynamic.plist -producttype com.apple.product-type.framework -expandbuildsettings -format binary -platform iphonesimulator -o /Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Products/Debug-iphonesimulator/PackageFrameworks/Sentry-Dynamic.framework/Info.plist

CodeSign /Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Products/Debug-iphonesimulator/PackageFrameworks/Sentry-Dynamic.framework (in target 'Sentry-Dynamic' from project 'Sentry')
    cd /Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/SourcePackages/checkouts/sentry-cocoa
    
    Signing Identity:     "-"
    
    /usr/bin/codesign --force --sign - --timestamp\=none --generate-entitlement-der /Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Products/Debug-iphonesimulator/PackageFrameworks/Sentry-Dynamic.framework

RegisterExecutionPolicyException /Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Products/Debug-iphonesimulator/PackageFrameworks/Sentry-Dynamic.framework (in target 'Sentry-Dynamic' from project 'Sentry')
    cd /Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/SourcePackages/checkouts/sentry-cocoa
    builtin-RegisterExecutionPolicyException /Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Products/Debug-iphonesimulator/PackageFrameworks/Sentry-Dynamic.framework

Touch /Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Products/Debug-iphonesimulator/PackageFrameworks/Sentry-Dynamic.framework (in target 'Sentry-Dynamic' from project 'Sentry')
    cd /Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/SourcePackages/checkouts/sentry-cocoa
    /usr/bin/touch -c /Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Products/Debug-iphonesimulator/PackageFrameworks/Sentry-Dynamic.framework

Causes a failure trying to use the framework:


Showing All Messages
Ld /Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Products/Debug-iphonesimulator/LoggingCore.framework/LoggingCore normal (in target 'LoggingCore' from project 'hubstaff-ios')
    cd /Users/hubstaff/Developer/hubstaff/ios
    /Applications/Xcode-14.1.0.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang -target arm64-apple-ios15.0-simulator -dynamiclib -isysroot /Applications/Xcode-14.1.0.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator16.1.sdk -L/Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Intermediates.noindex/EagerLinkingTBDs -L/Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Products/Debug-iphonesimulator -F/Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Intermediates.noindex/EagerLinkingTBDs -F/Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Products/Debug-iphonesimulator/PackageFrameworks -F/Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Products/Debug-iphonesimulator/PackageFrameworks -F/Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Products/Debug-iphonesimulator/PackageFrameworks -F/Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Products/Debug-iphonesimulator/PackageFrameworks -F/Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Products/Debug-iphonesimulator/PackageFrameworks -F/Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Products/Debug-iphonesimulator/PackageFrameworks -F/Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Products/Debug-iphonesimulator/PackageFrameworks -F/Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Products/Debug-iphonesimulator/PackageFrameworks -F/Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Products/Debug-iphonesimulator/PackageFrameworks -F/Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Products/Debug-iphonesimulator/PackageFrameworks -F/Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Products/Debug-iphonesimulator/PackageFrameworks -F/Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Products/Debug-iphonesimulator/PackageFrameworks -F/Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Products/Debug-iphonesimulator/PackageFrameworks -F/Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Products/Debug-iphonesimulator/PackageFrameworks -F/Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Products/Debug-iphonesimulator/PackageFrameworks -F/Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Products/Debug-iphonesimulator/PackageFrameworks -F/Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Products/Debug-iphonesimulator/PackageFrameworks -F/Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Products/Debug-iphonesimulator/PackageFrameworks -F/Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Products/Debug-iphonesimulator/PackageFrameworks -F/Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Products/Debug-iphonesimulator/PackageFrameworks -F/Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Products/Debug-iphonesimulator/PackageFrameworks -F/Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Products/Debug-iphonesimulator -filelist /Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Intermediates.noindex/hubstaff-ios.build/Debug-iphonesimulator/LoggingCore.build/Objects-normal/arm64/LoggingCore.LinkFileList -install_name @rpath/LoggingCore.framework/LoggingCore -dead_strip -Xlinker -object_path_lto -Xlinker /Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Intermediates.noindex/hubstaff-ios.build/Debug-iphonesimulator/LoggingCore.build/Objects-normal/arm64/LoggingCore_lto.o -Xlinker -export_dynamic -Xlinker -no_deduplicate -Xlinker -objc_abi_version -Xlinker 2 -fobjc-link-runtime -L/Applications/Xcode-14.1.0.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/iphonesimulator -L/usr/lib/swift -Xlinker -add_ast_path -Xlinker /Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Intermediates.noindex/hubstaff-ios.build/Debug-iphonesimulator/LoggingCore.build/Objects-normal/arm64/LoggingCore.swiftmodule -lc++ -framework UIKit -framework Security -framework StoreKit -lsqlite3 -lc++ -lz -lz -framework StoreKit -lsqlite3 -lc++ -lz -lz -lc++ -framework SystemConfiguration -framework SystemConfiguration -framework CoreTelephony /Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Products/Debug-iphonesimulator/PackageFrameworks/Sentry-Dynamic.framework/Sentry-Dynamic -framework HubstaffCore -framework FirebaseAnalytics -framework GoogleAppMeasurement -Xlinker -no_adhoc_codesign -compatibility_version 1 -current_version 1 -Xlinker -dependency_info -Xlinker /Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Intermediates.noindex/hubstaff-ios.build/Debug-iphonesimulator/LoggingCore.build/Objects-normal/arm64/LoggingCore_dependency_info.dat -o /Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Products/Debug-iphonesimulator/LoggingCore.framework/LoggingCore -Xlinker -add_ast_path -Xlinker /Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Intermediates.noindex/Firebase.build/Debug-iphonesimulator/FirebaseCoreInternal.build/Objects-normal/arm64/FirebaseCoreInternal.swiftmodule

clang: error: no such file or directory: '/Users/hubstaff/Library/Developer/Xcode/DerivedData/hubstaff-gzrfwrxonhprdsgrwcthjbfooayp/Build/Products/Debug-iphonesimulator/PackageFrameworks/Sentry-Dynamic.framework/Sentry-Dynamic'
Command Ld failed with a nonzero exit code

Command Ld failed with a nonzero exit code

lhunath avatar Jan 19 '23 20:01 lhunath

@lhunath, please open a new issue for your problem above.

philipphofmann avatar Jan 23 '23 15:01 philipphofmann

I tried yesterday, but half-way through collecting facts around the issue my problem disappeared and the Sentry-Dynamic framework started receiving its binary. I could not find out what the repro is. I will come back to a new issue if I have more reliable details.

lhunath avatar Jan 23 '23 16:01 lhunath

I'm happy that the problem disappeared. Thanks for the update, @lhunath 🙏.

philipphofmann avatar Jan 24 '23 16:01 philipphofmann