CocoaPods / CocoaPods

The Cocoa Dependency Manager.

Home Page:https://cocoapods.org/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

-fobjc-arc flag passed to tools which don't understand it

amolloy opened this issue · comments

CocoaPods appears to add the -fobjc-arc flag to all compiled sources when requires_arc is true (which is the default now in 0.34), regardless of whether the tool that compiles that source file understands the flag or not. In particular, yacc (bison) will fail, and there are probably others.

Steps:

  • Add a pod which includes a yacc source file and has requires_arc set to true to your podfile.
  • Run pod install
  • Build in Xcode

Expected results:

  • CocoaPods only applies the -fobjc-arc flag to Objective-C source files (*.m, *.mm) and the project builds without error.

Actual results:

  • CocoaPods applies the -fobjc-arc flag to every compiled source file, regardless of file type. This does not cause issues for files compiled using clang, regardless of the actual language, but fails with files compiled with some other tools including yacc/bison.

@amolloy Can you attach an example podspec which causes this problem.

Here is an example offending podspec:

Pod::Spec.new do |s|
  s.name         = "Moment"
  s.version      = "0.0.1"
  s.summary      = "Natural language date parser using Lex/Yacc/C."
  s.homepage     = "https://github.com/kmussel/Moment"
  s.license      = 'MIT'
  s.author       = 'kmussel'
  s.source       = { :git => "https://github.com/kmussel/Moment.git", :commit => "39f21fee0cef410c6d89c9fa94ff5638527ef7bc" }
  s.source_files = 'TimeParser.{c,h}', 'parseIt.ym', 'tokeIt.l'
end

parseIt.ym will fail to compile because bison rejects the -fobjc-arc flag. Interestingly, lex appears to just ignore the flag and handles tokeIt.l with no warnings or errors.

screen shot 2014-09-30 at 16 34 38

I can confirm this one, we should only apply the -fobjc-arc flag only to Objective-C sources. Removing these flags allows this pod to compile.

Yacc Moment/parseIt.ym
    cd /Users/kylef/Desktop/testa/Pods
    export PATH="/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin:/Applications/Xcode.app/Contents/Developer/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin"
    /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/yacc -fobjc-arc -DOS_OBJECT_USE_OBJC=0 -d -b /Users/kylef/Library/Developer/Xcode/DerivedData/testa-cvtzssloqiqzlxebiovfijmnuzdr/Build/Intermediates/Pods.build/Debug-iphonesimulator/Pods-Moment.build/DerivedSources/y /Users/kylef/Desktop/testa/Pods/Moment/parseIt.ym

/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/bison: invalid option -- f
Try `/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/bison --help' for more information.
Command /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/yacc failed with exit code 1

@amolloy, as a temporary work around. You should be able to set requires_arc to false for this spec.

Thanks, I've done that so I'm good for now.

This seems to also be true for subspecs that don't use arc, causing it to add both the -fno-objc-arc flag and the -fobjc-arc one:

screen shot 2014-09-30 at 10 04 47 pm

PodSpec:

{
  "name": "Kiwi",
  "version": "2.2.3",
  "summary": "A Behavior Driven Development library for iOS and OS X.",
  "homepage": "https://github.com/allending/Kiwi",
  "authors": {
    "Allen Ding": "alding@gmail.com",
    "Luke Redpath": "luke@lukeredpath.co.uk",
    "Marin Usalj": "mneorr@gmail.com",
    "Stepan Hruda": "stepan.hruda@gmail.com"
  },
  "license": {
    "type": "MIT",
    "file": "License.txt"
  },
  "source": {
    "git": "https://github.com/allending/Kiwi.git",
    "tag": "2.2.3"
  },
  "ios": {
    "xcconfig": {
      "FRAMEWORK_SEARCH_PATHS": "$(inherited) \"$(SDKROOT)/Developer/Library/Frameworks\" \"$(DEVELOPER_LIBRARY_DIR)/Frameworks\""
    }
  },
  "osx": {
    "xcconfig": {
      "FRAMEWORK_SEARCH_PATHS": "$(inherited) \"$(DEVELOPER_LIBRARY_DIR)/Frameworks\""
    }
  },
  "platforms": {
    "ios": "5.0",
    "osx": "10.7"
  },
  "default_subspec": "SenTestingKit",
  "subspecs": [
    {
      "name": "SenTestingKit",
      "frameworks": "SenTestingKit",
      "dependencies": {
        "Kiwi/ARC": [

        ],
        "Kiwi/NonARC": [

        ]
      },
      "source_files": "SenTestingKit/**/*.{h,m}",
      "prefix_header_contents": "#import <SenTestingKit/SenTestingKit.h>\n"
    },
    {
      "name": "XCTest",
      "frameworks": "XCTest",
      "dependencies": {
        "Kiwi/ARC": [

        ],
        "Kiwi/NonARC": [

        ]
      },
      "prefix_header_contents": "#import <XCTest/XCTest.h>\n"
    },
    {
      "name": "ARC",
      "source_files": "Classes/**/*.{h,m}",
      "requires_arc": true
    },
    {
      "name": "NonARC",
      "source_files": "NonARC/**/*.{h,m}",
      "compiler_flags": "-fno-objc-arc"
    }
  ]
}

I think this is an issue with the "NonARC" subspec, it should specify requires_arc: false, as it'll default to true regardless of the contents of compiler_flags.

For anyone interested in fixing this

It will require a little bit of refactoring. Currently compiler_flags_for_consumer is called for each spec_consumer which results in every "regular file" inside the consumer to have the same build flags. It's being called by add_files_to_build_phases to get the compiler flags which are passed to Xcodeproj when adding the file references to the target. All of this logic lyes in lib/cocoapods/installer/target_installer/pod_target_installer.rb.

target.add_file_references(regular_file_refs, flags)

I'd expect we would need to filter out the Objective-C like (This includes Objective-C++ etc) files which support ARC and add these file_references separate of the ones for non-arc supporting file types.

Here's the relevant two methods:

      def add_files_to_build_phases
        library.file_accessors.each do |file_accessor|
          consumer = file_accessor.spec_consumer
          flags = compiler_flags_for_consumer(consumer)
          all_source_files = file_accessor.source_files
          regular_source_files = all_source_files.reject { |sf| sf.extname == '.d' }
          regular_file_refs = regular_source_files.map { |sf| project.reference_for_path(sf) }
          target.add_file_references(regular_file_refs, flags)
          other_file_refs = (all_source_files - regular_source_files).map { |sf| project.reference_for_path(sf) }
          target.add_file_references(other_file_refs, nil)
        end
      end

      def compiler_flags_for_consumer(consumer)
        flags = consumer.compiler_flags.dup
        if consumer.requires_arc
          flags << '-fobjc-arc'
          platform_name = consumer.platform_name
          spec_deployment_target = consumer.spec.deployment_target(platform_name)
          if spec_deployment_target.nil? || Version.new(spec_deployment_target) < ENABLE_OBJECT_USE_OBJC_FROM[platform_name]
            flags << '-DOS_OBJECT_USE_OBJC=0'
          end
        end
        if target_definition.inhibits_warnings_for_pod?(consumer.spec.root.name)
          flags << '-w -Xanalyzer -analyzer-disable-checker -Xanalyzer deadcode'
        end
        flags * ' '
      end

There is also #2262 which could probably be done a the same time, which means it's file which do not use ARC get the -fno-objc-arcflag instead of files which support arc getting the '-fobjc-arc' flag.

/cc @kattrali

@k0nserv did we fix this?

We had the discussion about what we should do to allow this and the conclusion was to make requires_arc accept a file pattern instead. At least that the last I've heard of it, however I am unsure of the current status as I have been out of the loop the last month.

Regarding this issue the changes I made should solve it since the -fobjc-arc is not passed anymore however now the opposite is going to be a problem, e.g requires_arc set to false

Bump ...

Any idea when this might be fixed? :-) It's causing builds to fail for a number of important specs that use things like yacc, etc and the C libraries.

Is -fobjc-arc still passed? #2769 makes it so that -fobjc-no-arc is passed and the project default becomes CLANG_ENABLE_OBJC_ARC.

@k0nserv I tried https://github.com/Bertrand/handlebars-objc from the linked issues and it lints for me (after fixing an unrelated issue with public_headers in the spec).

CocoaPods never sets CLANG_ENABLE_OBJC_ARC to NO, only appends compiler flags (at least from what I've tried). So if you have source files that are non-arc (one example is the repository @neonichu mentioned), Pods will be unable to build without modifying build settings manually in Xcode and setting that property + removing all compiler flags for non-ObjC files.

Checked, this is still valid in 0.36.x, to repro:

  git clone git@github.com:uranusjr/macdown.git
  cd macdown
  git submodule init
  git submodule update
  pod install