Skip to content

What do do about dynamic libraries when linking? #117

Closed
lukeredpath opened this Issue Feb 10, 2012 · 13 comments
@lukeredpath

I've just written a spec for SocketRocket which requires libicucore.dylib.

As you can see, I've configured the spec libraries, so "-licucore" get's added to the OTHER_LD_FLAGS. This works fine when you are using SocketRocket as a dependency of an app.

Where it doesn't work, is when SocketRocket is a dependency for a static library target (which is what I'm trying to do). In this case, including -licucore causes the build to fail. Here's the errors from libtool:

/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/libtool: can't locate file for: -licucore
/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/libtool: file: -licucore is not an object file (not allowed in a library)

Leaving the linker flag out results in a successful build.

This is of course mainly an issue for development; end users of my library (libPusher) would simply add it to their Podfile for their app; libPusher's podspec will contain the dependency on SocketRocket and their app will get the -licucore flag it needs.

So, what can we do about this? Perhaps we don't need to do anything too clever here (again, this is mainly an issue for people developing their own static libraries). Perhaps we could extend the Podfile DSL to provide direct access to the xcconfig API so we can manipulate it to our own ends (in this case, delete the -licucore flag).

Obviously I can edit the xcconfig file directly but it will just get overwritten when I next run pod install.

@lukeredpath

OK, this is a bit hacky, but I was able to achieve what I wanted with the post_install hook:

post_install do |installer|
  # we don't want to link static lib to the icucore dylib or it will fail to build
  default_target_installer = installer.target_installers.find { |i| i.definition.name == :default }
  config_file_path = File.join("Pods", default_target_installer.xcconfig_filename)

  File.open("config.tmp", "w") do |io|
    io << File.read(config_file_path).gsub(/-licucore/, '')
  end

  FileUtils.mv("config.tmp", config_file_path)
end

I'm going to leave this issue open for the time being for discussion.

@alloy
CocoaPods member
alloy commented Feb 10, 2012

These kinds of things is exactly why we have a post_install hook. Let’s indeed leave the ticket open and see how many people run into this specific issue, before abstracting a solution, though.

A possible solution would be to have a dylib attribute, which outputs the same as library, but would not be added to an xcconfig of a static library target.

@fabiopelosin
CocoaPods member

A possible solution would be to have a dylib attribute, which outputs the same as library, but would not be added to an xcconfig of a static library target.

This approach apparently would require more logic/complexity (inspect the Target) to configure the xcconfig and I don't think that it is worth it.

I'm closing this issue as corner case that can be worked around with the post_install hook. Please reopen if needed.

@mattyohe
mattyohe commented Nov 5, 2012

No need to reopen this, but for a data point I ran into the same issue with this Spec.

I've updated @lukeredpath's code above to work with the changes in podfile.rb

post_install do |installer|
  default_target_installer = installer.target_installers.find { |i| i.target_definition.name == :default }
  config_file_path = File.join("Pods", default_target_installer.target_definition.xcconfig_name)

  File.open("config.tmp", "w") do |io|
    io << File.read(config_file_path).gsub(/-licucore/, '')
  end

  FileUtils.mv("config.tmp", config_file_path)
end

I assume there's still not a way to edit the xcconfig file before it's written?

@nsillik
nsillik commented Mar 10, 2013

FYI, I'm running into this issue as well, any chance there's a less awful way to accomplish this yet?

@brutella

+1 for a better support for dylib linking.

@fabiopelosin fabiopelosin reopened this Mar 18, 2013
@trevorsheridan

+1

My library depends on the Facebook SDK which requires -lsqlite3.0.

@bonebox
bonebox commented Apr 10, 2013

Also ran into this issue. Here is yet another update to the above workaround for CocoaPods 0.17.x and 0.18.x.

def s.post_install(target_installer)
  config_file_path = target_installer.library.xcconfig_path

  File.open("config.tmp", "w") do |io|
    io << File.read(config_file_path).gsub(/-licucore/, '')
  end

  FileUtils.cp("config.tmp", config_file_path)
end
@asarazan
asarazan commented May 1, 2013

+1

I depend on everything from icucore to sqlite to libc++

@streeter

Unfortunately, I'm not able to use the above post_install hooks. Here is what my Podfile looks like for Cocoapods 0.22.2:

platform :ios, '5.0'

xcodeproj 'Project.xcodeproj', 'Appstore' => :release, 'Debug' => :debug

pod 'AFNetworking',      '1.2.0'
pod 'CocoaLumberjack',   '1.6.2'
pod 'DCIntrospect',      '0.0.2'
pod 'DDPageControl',     '0.1'
pod 'Dropbox-iOS-SDK',   '1.3.4'
# others in here
pod 'TestFlightSDK',     '1.2.6'

target 'DebugTools', :exclusive => true do
    platform :ios, '5.0'

    pod 'PonyDebugger', '0.3.0'
end


post_install do |installer_representation|
    installer_representation.libraries.each do |l|
        config_file_path = File.join("Pods", l.target_definition.xcconfig_name)

        File.open("config.tmp", "w") do |io|
            io << File.read(config_file_path).gsub(/-licucore/, '')
        end

        FileUtils.mv("config.tmp", config_file_path)
    end
end

Without the post_install hook, I get the build error that libtool can't locate file for -licucore when trying to build DebugTools. However, I can't seem to get the post_install to work with this latest version of Cocoapods and my Ruby is terrible. Thus I'm having a hard time debugging where this is going wrong. Any help would be much appreciated!

@payotte
payotte commented Jul 24, 2013

There is my version of post_install:

post_install do |installer|
  default_library = installer.libraries.detect { |i| i.target_definition.name == 'Pods' }
  config_file_path = default_library.library.xcconfig_path

  File.open("config.tmp", "w") do |io|
    io << File.read(config_file_path).gsub(/-licucore/, '')
  end

  FileUtils.mv("config.tmp", config_file_path)
end

Hope that will help you.

@fabiopelosin
CocoaPods member

Moved to #1250

@jacielmelnik

For version 0.34 you should change your code and add the version of the xcconfig file you want (Release or Debug).

config_file_path = default_library.library.xcconfig_path('Release')

The code for my lib now looks like this:

post_install do |installer|

    default_library = installer.libraries.detect { |i| i.target_definition.name == 'MyLibName' }

    config_file_path = default_library.library.xcconfig_path('Release')

    File.open("config.tmp", "w") do |io|
        io << File.read(config_file_path).gsub(/-lz/, '')
    end

    FileUtils.mv("config.tmp", config_file_path)
end
@neonichu neonichu added a commit that referenced this issue Oct 25, 2014
@neonichu neonichu Validate URIs before making requests, only catch SocketErrors.
This at least makes sure we do not mask errors (see #117).
9911dc3
@grimmer0125 grimmer0125 pushed a commit to grimmer0125/p2pMessenger that referenced this issue May 17, 2015
@lukeredpath lukeredpath We don't want to link to icucore (a SocketRocket dependency) when bui…
…lding the libPusher static

library otherwise it fails to build. Only apps that use SocketRocket need this linker flag.

I've worked around this with an admittedly hacky post_install hook. 

See CocoaPods/CocoaPods#117 for discussion.
586ab6d
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.