web-dev-qa-db-ja.com

共有スタティックライブラリを使用して、xcodeで「シンボルの重複」エラーを回避するにはどうすればよいですか?

Xcodeプロジェクトに編成された静的ライブラリA、B、Cがあります。 AとBはCに依存しています。AとBに依存するiPhoneプロジェクトをビルドすると、AとBで(Cからの)重複するシンボルが検出されたというリンカーエラーが発生します。このエラーが発生せずに他のXcodeプロジェクトにそれらを含めることができますか?

29
richcollins

カールの答えは正しいですが、間違った理由があります。実際にカールの独自のサンプルを使用して確認できるように、静的ライブラリをリンクすることには何の問題もありません。 Carlのサンプルコードを設定してから、次のようにします(Xcodeが使用するため、libtoolを使用します)。

neutron:libtest jamie$ libtool -o a2.a a.a c.a
neutron:libtest jamie$ libtool -o b2.a b.a c.a
neutron:libtest jamie$ gcc main.o a2.a b2.a -o app2
neutron:libtest jamie$ ./app2
a
c
b
c
neutron:libtest jamie$ 

これにより、a2.aおよびb2.aがmain.oにリンクされます。カールによると、これはOPの問題の原因であり、app2はリンクすべきではありません。しかし、もちろんそうです。リンカは、同じファイルの2つのインスタンスを無視できるほどスマートです。 a2.aとb2.aの両方にc.oが含まれていることがわかります。

neutron:libtest jamie$ ar -t a2.a
__.SYMDEF SORTED
a.o
c.o
neutron:libtest jamie$ ar -t b2.a
__.SYMDEF SORTED
b.o
c.o

それでもそれはうまくリンクします。

問題は、PPC/x86ユニバーサルバイナリまたはarmv6/armv7 iPhoneユニバーサルバイナリのいずれかのユニバーサルバイナリにリンクしていると私は考えています。ここでの問題は categories にバグがあり、修正(リンカーフラグに-all_loadを追加)が単一のアーキテクチャでのみ機能する修正であることです。 -all_loadを使用すると、リンカーが複数のアーキテクチャ用に定義されたシンボルを無視する機能が無効になり、重複シンボルエラーが発生します。

私はそれについて書いた here -all_loadを使用するよりも良い解決策を含めました。

26
jamie

この問題は、必ずしもXcodeまたはObjective-Cに関連しているとは限りません。ライブラリを他のライブラリにリンク/アーカイブしないでください。 AとBは、最終リンク時にCにのみ依存し、ビルド時に依存しません。あなたが欲しい:

  1. を建てる
  2. ビルドB
  3. ビルドC
  4. アプリとリンクを作成

ここに私がデモンストレーションするために作ったプロジェクトの例があります:

Makefile:

app: main.o a.a b.a c.a
        gcc $^ -o $@

%.o: %.c
        gcc -Wall -c $^

%.a: %.o
        ar -r $@ $^

clean:
        rm -rf *.o *.a app

交流:

#include <stdio.h>
void c(void);

void a(void)
{
  printf("a\n");
  c();
}

紀元前:

#include <stdio.h>
void c(void);

void b(void)
{
  printf("b\n");
  c();
}

c.c:

#include <stdio.h>

void c(void)
{
  printf("c\n");
}

main.c:

#include <stdio.h>

void a(void);
void b(void);

int main(int argc, char *argv[])
{
  a();
  b();
  return 0;
}

ログをビルドして実行します。

$ make
gcc -Wall -c main.c
gcc -Wall -c a.c
ar -r a.a a.o
ar: creating archive a.a
gcc -Wall -c b.c
ar -r b.a b.o
ar: creating archive b.a
gcc -Wall -c c.c
ar -r c.a c.o
ar: creating archive c.a
gcc main.o a.a b.a c.a -o app
rm a.o b.o c.o
$ ./app 
a
c
b
c
6
Carl Norum

_-all_load_を使用する代わりに、必要なライブラリだけに_-force_load_ "path_to_lib"を使用することもできます。たとえば、-force_load "$(PROJECT_DIR)/libname"のようなものを使用できます。

これにより、実装ファイルを変更する必要のあるJamieのソリューションに対して行う必要のあることが回避されます。

これは、three20プロジェクトで採用されたソリューションです。 http://groups.google.com/group/three20/browse_thread/thread/ec208be4ff8b4dcb/0dccf992a26850df

edit:Xcode 4.3以降、_-all_load_および_-force_load_の必要性がなくなりました。今では_-ObjC_のみが必要です。詳細は https://stackoverflow.com/a/2615407/211292 を参照してください。

6
ThomasW