trinhngocthuyen / cocoapods-spm

A CocoaPods plugin to add SPM dependencies to CocoaPods-based projects
MIT License
53 stars 10 forks source link

[Bug] Framework not found #42

Closed jhoongo closed 7 months ago

jhoongo commented 7 months ago

What happened?

When defining SPM dependencies

in .podspec

s.spm_dependency 'Package/Product1'
s.spm_dependency 'Package/Product2'

in target's Podfile

spm_pkg "Package",
     :url => "https://github.com/",
     :branch => "main",
     :products => ["Product1", "Product2"],
     :linkage => :dynamic

I've setup the project as above, and when it compiles, the build fails complaining that ld: framework not found.

When looking at the DerivedData folder, the target compiles the dependent framework with .o .swiftmodule, but the .framework files are missing.

Is there anything that I'm missing to setup the podspec?

CocoaPods environment

No response

Anything else?

No response

trinhngocthuyen commented 7 months ago

Hi @jhoongo May I know what package you were using (if you're comfortable sharing it)?

I notice that in your case, you're using :linkage => :dynamic. Please note that this :linkage option must match the library type declared in Package.swift.

let package = Package(
  ...
  products: [
    .library(name: "Foo", targets: ["Foo"]),                // <-- static
    .library(name: "Bar", type: .dynamic, targets: ["Bar"]) // <-- dynamic
  ]
)

image

In this case, I doubt that the library you're using might be static, not dynamic. If so, please remove the option :linkage => :dynamic in Podfile.

jhoongo commented 7 months ago

@trinhngocthuyen Thanks for your prompt answer. I'm sorry that I should've clarified. I tried both static/dynamic option and you were right that I was using dynamic whereas it defines them as static in their package definition. However, it still fails to build. I'm using opentelemetry-swift SDK.

With static, it fails with

Undefined symbols for architecture arm64:
  "_$s13SwiftProtobuf7MessagePAAE14serializedData7partial10Foundation0E0VSb_tKF", referenced from:
      _$s33OpenTelemetryProtocolExporterHttp04OtlpeD4BaseC13createRequest4body8endpoint10Foundation10URLRequestV13SwiftProtobuf7Message_p_AG3URLVtF in OpenTelemetryProtocolExporterHTTP.o
      _$s33OpenTelemetryProtocolExporterHttp26StableOtlpHTTPExporterBaseC13createRequest4body8endpoint10Foundation10URLRequestV13SwiftProtobuf7Message_p_AG3URLVtF in OpenTelemetryProtocolExporterHTTP.o
  "_$s13SwiftProtobuf7MessagePAAE4withyxyxzKXEKFZ", referenced from:
      _$s33OpenTelemetryProtocolExporterHttp04Otlpe3LogD0C6export10logRecords15explicitTimeout0aB3Sdk12ExportResultOSayAG08ReadableG6RecordVG_SdSgtF in OpenTelemetryProtocolExporterHTTP.o
      _$s33OpenTelemetryProtocolExporterHttp04Otlpe3LogD0C5flush15explicitTimeout0aB3Sdk12ExportResultOSdSg_tF in OpenTelemetryProtocolExporterHTTP.o
      _$s33OpenTelemetryProtocolExporterHttp04Otlpe6MetricD0C6export7metrics12shouldCancel0aB3Sdk0gD10ResultCodeOSayAG0G0VG_SbycSgtF in OpenTelemetryProtocolExporterHTTP.o
      _$s33OpenTelemetryProtocolExporterHttp04Otlpe6MetricD0C5flush0aB3Sdk0gD10ResultCodeOyF in OpenTelemetryProtocolExporterHTTP.o
      _$s33OpenTelemetryProtocolExporterHttp020StableOtlpHTTPMetricD0C6export7metrics0aB3Sdk12ExportResultOSayAF0F10MetricDataVG_tF in OpenTelemetryProtocolExporterHTTP.o
      _$s33OpenTelemetryProtocolExporterHttp020StableOtlpHTTPMetricD0C5flush0aB3Sdk12ExportResultOyF in OpenTelemetryProtocolExporterHTTP.o

[...]

clang: error: linker command failed with exit code 1 (use -v to see invocation)

Any thought or suggestion would be really appreciated. Thank you!

jhoongo commented 7 months ago

Also, I notice that the SPM package update isn't reflecting easily 🤔 . For example, if I switch to a different branch/version or different repo, the resolved package in the project isn't resolving to the latest target. Is this related to cocoapods-spm?

jhoongo commented 7 months ago

So, it turns out that if I fork the repo and switch the library type to dynamic, it works fine 🤔 . But with static linking, it still throws an error mentioned above.

trinhngocthuyen commented 7 months ago

Yes, dynamic works fine. The root cause of this problem is that dependencies of a package were not linked. In this case, for example, OpenTelemetrySdk depends on OpenTelemetryApi. OpenTelemetryApi needs to be linked as well. So, in Pods-App.debug.xcconfig, we should have OTHER_LDFLAGS as follows:

- OTHER_LDFLAGS = $(inherited) -ObjC -l"OpenTelemetrySdk.o"
+ OTHER_LDFLAGS = $(inherited) -ObjC -l"OpenTelemetrySdk.o" -l"OpenTelemetryApi.o"

This is a plugin's bug indeed.

trinhngocthuyen commented 7 months ago

There are a few options to tackle this bug:

1/ Link products with the "Link Binary With Libraries" in the build phases

2/ Detect nested dependencies and add them to the linker flags (as above)

jhoongo commented 7 months ago

Sounds good, and thanks for the clarification @trinhngocthuyen . I think I'm okay on my end as it is for now; if the plugin can handle the static framework and its dependency, that would be nice. Feel free to close the issue.

pablords commented 7 months ago

I'm trying to use a library that only supports SPM and I received the same error as above "Framework not found". I followed the steps described in https://github.com/trinhngocthuyen/cocoapods-spm/issues/42#issuecomment-2038921046 and now I'm getting the error: "205 duplicate symbol"

library that I'm trying to install in my pod: https://github.com/Telefonica/mistica-ios/blob/main/Package.swift

my podfile:


source "https://github.com/material-components/material-components-ios.git"
source 'https://github.com/CocoaPods/Specs.git'

# Plugin que converte SPM em Cocoapds
plugin "cocoapods-spm"

# Resolve react_native_pods.rb with node to allow for hoisting
require Pod::Executable.execute_command('node', ['-p',
  'require.resolve(
    "react-native/scripts/react_native_pods.rb",
    {paths: [process.argv[1]]},
  )', __dir__]).strip

platform :ios, min_ios_version_supported
prepare_react_native_project!

# Plugin que converte SPM em Cocoapds
config_cocoapods_spm(
  dont_prebuild_macros: true,
  default_macro_config: "debug"
)

# If you are using a `react-native-flipper` your iOS build will fail when `NO_FLIPPER=1` is set.
# because `react-native-flipper` depends on (FlipperKit,...) that will be excluded
#
# To fix this you can also exclude `react-native-flipper` using a `react-native.config.js`
# ```js
# module.exports = {
#   dependencies: {
#     ...(process.env.NO_FLIPPER ? { 'react-native-flipper': { platforms: { ios: null } } } : {}),
# ```
flipper_config = ENV['NO_FLIPPER'] == "1" ? FlipperConfiguration.disabled : FlipperConfiguration.enabled

linkage = ENV['USE_FRAMEWORKS']
if linkage != nil
  Pod::UI.puts "Configuring Pod with #{linkage}ally linked Frameworks".green
  use_frameworks! :linkage => linkage.to_sym
end

target 'MisticaReactNativeExample' do
  config = use_native_modules!

  # use_frameworks!

  # $RNFirebaseAsStaticFramework = true
  # $RNGoogleMobileAdsAsStaticFramework = true
  # $RNAdMobAsStaticFramework = true
  # use_frameworks! :linkage => :static

  # use_modular_headers!

  spm_pkg "Mistica", :url => "https://github.com/Telefonica/mistica-ios.git", 
          :tag => "29.7.3",
          :products => ["Mistica", "MisticaCommon", "MisticaSwiftUI"]
  spm_pkg "SDWebImage", :url => "https://github.com/SDWebImage/SDWebImage.git", :tag => "5.19.1"
  spm_pkg "SDWebImageSVGCoder", :url => "https://github.com/SDWebImage/SDWebImageSVGCoder.git", :tag => "1.7.0"
  spm_pkg "Lottie", :url => "https://github.com/airbnb/lottie-ios.git", :tag => "4.4.1"
  # spm_pkg "SnapshotTesting", :url => "https://github.com/pointfreeco/swift-snapshot-testing.git", :tag => "1.8.2"

  pod 'MaterialComponents/Buttons', '~> 124.2.0', :modular_headers => true
  pod 'MaterialComponents/TextControls+FilledTextAreas', '~> 124.2.0', :modular_headers => true
  pod 'MaterialComponents/TextControls+FilledTextFields', '~> 124.2.0', :modular_headers => true
  pod 'MaterialComponents/TextControls+OutlinedTextAreas', '~> 124.2.0', :modular_headers => true
  pod 'MaterialComponents/TextControls+OutlinedTextFields', '~> 124.2.0', :modular_headers => true

  use_react_native!(
    :path => config[:reactNativePath],
    # Enables Flipper.
    #
    # Note that if you have use_frameworks! enabled, Flipper will not work and
    # you should disable the next line.
    # :flipper_configuration => flipper_config,
    # An absolute path to your application root.
    :app_path => "#{Pod::Config.instance.installation_root}/.."
  )

  target 'MisticaReactNativeExampleTests' do
    inherit! :complete
    # Pods for testing
  end

  post_install do |installer|
    # https://github.com/facebook/react-native/blob/main/packages/react-native/scripts/react_native_pods.rb#L197-L202
    react_native_post_install(
      installer,
      config[:reactNativePath],
      :mac_catalyst_enabled => false
    )

    # installer.pods_project.targets.each do |target|
    #   target.build_configurations.each do |config|
    #     # Force CocoaPods targets to always build for x86_64
    #     config.build_settings['ARCHS[sdk=iphonesimulator*]'] = 'x86_64'
    #   end
    # end

  end
end

my podspec

require "json"

package = JSON.parse(File.read(File.join(__dir__, "package.json")))
folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32'

Pod::Spec.new do |s|
  s.name         = "mistica-react-native"
  s.version      = package["version"]
  s.summary      = package["description"]
  s.homepage     = package["homepage"]
  s.license      = package["license"]
  s.authors      = package["author"]

  s.platforms    = { :ios => min_ios_version_supported }
  s.source       = { :git => "https://github.com/pablords/mistica-react-native.git", :tag => "#{s.version}" }

  s.source_files = "ios/**/*.{h,m,mm,swift}"

  s.dependency 'MaterialComponents/Buttons'
  s.dependency 'MaterialComponents/TextControls+FilledTextAreas'
  s.dependency 'MaterialComponents/TextControls+FilledTextFields'
  s.dependency 'MaterialComponents/TextControls+OutlinedTextAreas'
  s.dependency 'MaterialComponents/TextControls+OutlinedTextFields'

  s.spm_dependency "Mistica/Mistica"
  s.spm_dependency "SDWebImage/SDWebImage"
  s.spm_dependency "SDWebImageSVGCoder/SDWebImageSVGCoder"
  s.spm_dependency "Lottie/Lottie"
  # s.spm_dependency "SnapshotTesting/SnapshotTesting"

  # Use install_modules_dependencies helper to install the dependencies if React Native version >=0.71.0.
  # See https://github.com/facebook/react-native/blob/febf6b7f33fdb4904669f99d795eba4c0f95d7bf/scripts/cocoapods/new_architecture.rb#L79.
  if respond_to?(:install_modules_dependencies, true)
    install_modules_dependencies(s)
  else

  s.dependency "React-Core"

  # Don't install the dependencies when we run `pod install` in the old architecture.
  if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then
    s.compiler_flags = folly_compiler_flags + " -DRCT_NEW_ARCH_ENABLED=1"
    s.pod_target_xcconfig    = {
        "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\"",
        "OTHER_CPLUSPLUSFLAGS" => "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1",
        "CLANG_CXX_LANGUAGE_STANDARD" => "c++17"
    }
    s.dependency "React-RCTFabric"
    s.dependency "React-Codegen"
    s.dependency "RCT-Folly"
    s.dependency "RCTRequired"
    s.dependency "RCTTypeSafety"
    s.dependency "ReactCommon/turbomodule/core"
   end
  end  

end
Screenshot 2024-04-07 at 04 57 11
trinhngocthuyen commented 7 months ago

@pablords Thanks for reporting. I'm working on a fix to detect recursive dependencies in the liking process (approach 2 in https://github.com/trinhngocthuyen/cocoapods-spm/issues/42#issuecomment-2038921046). That would solve the problem for cases like OpenTelemetrySdk.

In your case, you're not using use frameworks!. I'm not sure if the fix I'm working on fits your case. I'm wondering if we could have a simplified demo project to reproduce the issue for follow-up fixes. Thank you!

trinhngocthuyen commented 7 months ago

Hi @jhoongo The fix for transitive deps not being linked has been available. Could you please try again with the latest from main? I have updated the example project with this package (ie. opentelemetry-sdk) as well: examples/Podfile#L39-L42. Thank you!

trinhngocthuyen commented 7 months ago

Closing this issue as it's fixed on the latest. Feel free to reopen if it persists