Akata Works

東京エンジニア。主にRuby,Go,たまにAWSとiOS。ゲーム音楽が好きです。連絡はTwitterかakata.onen@gmail.comまで

今更ながらXcode 7のBitcodeについてまとめてみた

タイトルにあるように今更ながら、Xcode 7でいろいろあったBitcodeについてまとめてみました。

まずはじめに、BitcodeとはXcodeのビルドフローにおける中間言語(LLVM IR)のバイナリ表現です。 LLVM IRにはテキスト表現とバイナリ表現の2種類がありますが、そのうちのバイナリ表現になります。

また、Xcodeの基本的なビルドフローは以下のようになります。

  1. フロントエンドのClangがソースコード中間言語(LLVM IR)に変換する
  2. バックエンドのLLVMLLVM IRをマシン語に変換する

で、Xcode 7以降はデフォルトでBitcodeを含んだデータを生成するようになった感じです(もちろんBuild Settingsで無効にできます。詳しくはこの記事を)

Bitcodeを有効にすることでApple側でアーキテクチャに合ったコンパイルをしてくれるなど、メリットがあるのでなるべく有効にしておくといいと思います。


ちなみに、フレームワーク製作者の方はBitcodeに対応する場合、Build Settingsで有効にするだけだと駄目かもしれないです。詳しくは参考URLにあるのですが、xcodebuildOTHER_CFLAGS="-fembed-bitcode"を設定すると多分いけると思います。

また、実際にアプリケーションに導入してテストする際に、通常のビルドではなくアーカイブまでしてください。じゃないとBitcodeのチェックが入らないので気付かないかもしれませんよ(経験済み)

Bitcodeに対応できていない場合、以下のようなエラーが出ます。

ld: bitcode bundle could not be generated because ~ was built without full bitcode. All object files and libraries for bitcode must be generated from Xcode Archive or Install build for architecture ~
clang: error: linker command failed with exit code 1 (use -v to see invocation)

参考URL

stackoverflow.com

コンテンツ単位でボットからのアクセスを無視する

自身のサイトに訪れたユーザのアクセス情報をイベント単位で取得し、レポートを作成したり、Mixpanelを使用するとき、
クローラなどのボットが凄まじいノイズっぷりを発揮し、
レポートがメチャクチャになります。

サイト単位やページ単位でボットのアクセスをスルーする場合は、"robots.txt"ファイルを作成すればOKですが、検索結果から消滅されると困ります。

"robots.txt"については参考URLを参照してください。


そこで別の手段として、さらに細かいコンテンツ単位で指定する場合や、
"robots.txt"ファイルを無視するボット対策として、
ユーザエージェントで判断する方法があります。

例えばGooglebotの場合は、ユーザエージェントに"Googlebot"が含まれるため、 以下のコードで簡単にスルーできます。

if !request.env["HTTP_USER_AGENT"].match("Googlebot")
  # TODO:
end

同様の方法で"libwww"も簡単にスルーできたりします。

ちなみにGoogleアナリティクスには、ロボットをフィルタリングするための設定があるようですね。

参考URL

Xcodeで遭遇したエラーたち・・(逐次更新)

見つかる度に逐次更新していく予定です。

duplicate symbol OBJC_CLASS$_ (2015-09-18)

duplicate symbol _OBJC_CLASS_$_#{hoge}

同じ名前のクラスや変数,メソッドなどが定義されていれば発生します。本来はIDEの恩恵ですぐに気付くと思いますが、僕の場合はCompile Sourcesに同じファイルが含まれていたことによって発生しました。

ファイルの作り直しとかをしてたら遭遇するかもしれません。

importで"*.m"ファイルを間違えて読み込んでも発生するそうです(参考URLはてブより)

ARC forbids explicit message send of (2015-09-28)

ARC forbids explicit message send of #{'autorelease' | 'release'} 

メモリ管理方式でARCが有効になっているのに、autoreleaseメソッドやreleaseメソッドが記述されていると発生します。

TARGETSの設定からBuild Settings => Apple LLVM - Language - Objective C => Objective-C Automatic Reference CountingをNoにすることで解消します。

古いカウンタ管理方式を用いているアプリケーションを、新しいXcodeで編集したことによって発生しました。

Include of non-modular header inside framework module ${module_name} (2015-10-22)

Include of non-modular header inside framework module #{module_name}

フレームワークのモジュール内に非モジュールのヘッダファイルがインクルードされていると発生します。

TARGETの設定からBuild Settings => Apple LLVM - Language- Modules => Allow Non-modular includes in Framework ModulesをYesにし、
読み込みを許可することで解消できますが、
もしあなたがフレームワークの開発者ならば、ちゃんとmodulemapで対応したほうがいいと思います。

App Transport Security has blocked a cleartext HTTP (2015-11-19)

iOS 9からHTTPS通信が推奨されるようになったため、HTTP通信を行うとこのエラーに遭遇するかも知れません。
でも、Appleが推奨しているので、できればHTTPSに切り替えるほうがいいと思います。

一応、ATSを無効にすることでHTTPでも通信は可能です(詳しくは参考URLを見てください)

ld: bitcode bundle could not be generated because was built without full bitcode. (2015-12-07)

ld: bitcode bundle could not be generated because #{framework_path} was built without full bitcode.

使っているフレームワークがBitcodeに対応していないのに、Bitcodeを有効にしていると発生します。
Bitcodeに対応するのを待つか、TARGETSの設定からBuild Settings => Build Options => Enable BitcodeをNoにすることで無効にできます。

Xcode 7から有効になったので、Xcode 6で作ったアプリケーションをXcode 7で起動した人は見たことがあるんじゃないでしょうか?

また、Bitcodeについては別記事にまとめていますので、よかったらそちらも御覧ください。

was built for newer ios version than being linked (2018-08-09)

was built for newer ios version (${xxx}) than being linked (${yyy})

これに関しては実際に起ったものを解決したわけではないので、調べた限りでのあくまでも予想ですmm

  • xxx: リンクしているあるライブラリ中のDeployment Target
  • yyy: リンクしているあるライブラリ中またはアプリ自体のDeployment Target?

Deployment Targetに関しては過去に記事を書いたのでそれを見てもらえると......

アプリに使用するライブラリの最小動作保証バージョンがxxxなのに、アプリまたはそれ以外のライブラリでより古いバージョンの動作を保証しているってことだと思う。
なので、アプリ自体またはライブラリのDeployment Targetを調整すれば直るかな?

なおライブラリ自体のDeployment Targetを調べるには以下のコマンドを実行する。

otool -lv #{library_filepath} | less
Load command 1
      cmd LC_VERSION_MIN_IPHONEOS
  cmdsize 16
  version 7.0
      sdk n/a

参考URL

プログラミング雑記: duplicate symbol エラー

Xcodeのキャッシュのせいでエラーが出ていた

Tipsレベルですが・・

Xcodeでとあるフレームワークを入れたり消したり、バージョンを上げたり下げたりしていたら、 バージョンAを参照してるつもりが、バージョンBが参照されていました。

ちゃんとFramework Search Pathもフレームワークのパスも確認したが、 やっぱりバージョンAのものになっていました。

どうしようもなくなってしまったので先輩社員に泣きついたところ、 Xcodeが生成するキャッシュにバージョンBのものが残っており、それが利用されていることが原因かもしれないとのこと。

試しに"/Users/${user_name}/Library/Developer/Xcode/DerivedData/"ディレクトリにあるプロジェクトごとのキャッシュから、 該当するプロジェクトのディレクトリをまるごと削除したところ無事にエラーを解消することができました。

いやー先輩マジ偉大っす

みなさんもよく分からないエラーが出たらとりあえずキャッシュを消してみるといいかもしれません。


追記

どうもXcode上からでも削除することができるようです。先人の皆様ありがとうございますm( )m

Homebrewで"configure: error: cannot run C compiled programs"が出た

最近、iOS 9の開発のためにMac OSXをEl Capitan 10.11 Betaに、
XcodeXcode 7 Beta変えたところ、
しばらく使っていたら、急にtigが使えなくなりました・・

なんか依存ライブラリのReadlineが死んでいたっぽいので、
再インストールしてみました。

$ brew install readline

すると下のエラーが出ました。

==> ./configure --prefix=/usr/local/Cellar/readline/6.3.8 --enable-multibyte
checking for suffix of executables...
checking whether we are cross compiling... configure: error: in `/private/tmp/readline20150915-84835-wmsgny/readline-6.3':
configure: error: cannot run C compiled programs.
If you meant to cross compile, use `--host'.
See `config.log' for more details

取り敢えず、brew doctorコマンドで診察してみたところ、
どうも心当たりのある警告が出ていました。

Warning: Your Xcode (6.4) is outdated
Please update to Xcode 7.0.
Xcode can be updated from
  https://developer.apple.com/xcode/downloads/

あれ?Xcode入れたんだけどな

と思って、xcode-select

$ xcode-select -p
/Applications/Xcode 6.4.app/Contents/Developer
sudo xcode-select -s /Applications/Xcode-beta.app/Contents/Developer/

どうやらxcode-selectの参照がXcode 6.4になっていたことが原因だったみたいです。
Xcode 7 Betaにしたところ、インストールすることができました。

これに限らず、iOS 9の開発でバージョン上げてから何かと詰まることが多いなあ・・(´・ω・`)ショボーン

Rubyのスコープと変数定義で「What!?」ってなった話

最近になって急に、開発言語がPerlからRubyObjective-Cに早変わりして大変です。

そして、Perlの感覚でRubyを書いていると「What!?」ってなったことがあったので、
久しぶりに記事にしてみました。

下記はPerlのコードです。

#!/usr/bin/env perl

use strict;
use warnings;

use utf8;

if (0) {
  my $message = 'hoge';
}
print "$message\n";

が、当然エラーは出ます。

Global symbol "$message" requires explicit package name at..
Execution of.. aborted due to compilation errors.

message変数のスコープがIfブロック内なので当たり前ですよね。


下記はRubyのコードです。

#!/usr/bin/env ruby

if false
  message = 'hoge'
end

puts "#{message}"

が、エラーは出ません

(何も表示されない)

どうやら、RubyにおいてIfやFor,Whileブロックはスコープを生成しないらしいです。


そのため、PerlRubyでは以下の様な違いが出ます。

Ruby

#!/usr/bin/env ruby

hoge = 10
puts hoge

if true
  hoge = 100
  puts hoge
end

puts hoge
10
100
100

Perl

#!/usr/bin/env perl

use strict;
use warnings;

use utf8;

my $hoge = 10;
print "$hoge\n";

if (1) {
  my $hoge = 100;
  print "$hoge\n";
}

print "$hoge\n";
10
100
10

それでは、話を下記のコードに戻します。

#!/usr/bin/env ruby

if false
  message = 'hoge'
end

puts "#{message}"

さて、Ifブロックがスコープを生成しないため、Ifブロック外で変数が見えていることは分かりましたが、
何故、undefined local variable or methodエラーが出ない理由が分かりません。

実際にmessage変数のクラスを表示するとNilClassになっています。

#!/usr/bin/env ruby

if false
  message = 'hoge'
end

puts "#{message.class}";
NilClass

理由は簡単で、ちゃんと定義されているからです。

どうも、Rubyのパーサは代入を見つけた時点で、勝手に変数を定義するようになっているそうです。

知っていれば当たり前なのかも知れませんが、
慣れていない自分からすると、
初期化されていない気がして不安になってしまいます(||゚Д゚)ヒエー!!

参考URL

未変更のファイルが変更扱いになっていた問題(サブモジュール編)

最近、git addしてもgit checkoutしても、変更扱いされているファイル(以下hoge)がありました。
僕としてはhogeをまったく変更した記憶がないんですが・・

同じような現象としてファイルモードの問題があったので、
下記URLを参考に解決しようと思ったのですが、
あんまり関係ありませんでした(ノ゚゚Д゚゚)ノオラァッ!!


その後・・

たまたまgit submodule initgit submodule updateしたときにhogeに対して下記エラーが発生しました。

No submodule mapping found in .gitmodules for path hoge

なんかサブモジュールになってる・・
工エエェェ(´д`)ェェエエ工

どうやら「インデックスに紐付いていないサブモジュールがあるぞい」というエラーらしいです。

サブモジュールはファイルモードが160000になっているため、
以下コマンドでインデックス一覧を確認できます。

git ls-files --stage | grep 160000

インデックス一覧と".gitmodules"ファイルを比べたときに一覧にしかないインデックスがあったので、git rmすることで無事に解決しました。
--cachedオプションを付けなければファイルごとサヨナラします。注意しましょう。

git rm --cached hoge

サブモジュールェ・・


追記

実はhogeは拾ってきたZshプラグインで、こいつがコミット時にディレクトリエントリとみなされたことが原因でした。
git cloneしたものをリポジトリに含むときにはちゃんとサブモジュールにしましょう。

参考URL

Git - サブモジュール