16946


linuxでmakefileを書く際に、以下のような共有ライブラリのリンクの仕方が分からず、困っています。

【やりたいこと】  
[実行ファイル]-->[libA.so]-->[libB.so] という依存関係  
libA.soを作るためのMakefileに-lBと記述し、実行ファイル側を作るためのMakefileには-lA とだけ記述したい。

【現状】  
私が書いているMakefileだと、実行ファイルを作るためのMakefileに -lA -lBと記述しないとリンクエラーになってしまいます。

シンプルなMakefileのサンプルなどあれば教えていただけないでしょうか。  
よろしくお願いします。


CC BY-SA 3.0
2015-09-26T06:17:20.387
16944
2015-09-27T12:26:19.643
2015-09-26T12:12:25.770
12455
question
linux c makefile
linuxでの共有ライブラリのリンクについて


ld のエラーメッセージに促されるまま -rpath を付けたら通りました。  
こんな感じで。

[code]

    all: exe
    
    exe: main.c liba.so
        gcc -o exe main.c -L. -la
    
    liba.so: a.c libb.so
        gcc -c -fPIC a.c
        gcc a.o -shared -o liba.so -L. -Wl,-rpath,. -lb
    
    libb.so: b.c
        gcc -c -fPIC b.c
        gcc b.o -shared -o libb.so
    
    clean:
        -rm -f exe liba.so libb.so
    
[/code]

gcc 5.2.0, ld 2.25.1 です。


CC BY-SA 3.0
2015-09-26T07:21:06.120
16946
2015-09-26T07:21:06.120
5288
16944
answer


こちらの環境ですと、masm さんの結果と挙動が異なります。

[code]

    $ uname -rvm
    3.19.0-28-generic #30-Ubuntu SMP Mon Aug 31 15:52:10 UTC 2015 i686
    
    $ gcc --version
    gcc (Ubuntu 5.1.1-4ubuntu12) 5.1.1 20150504
    
    $ ld --version
    GNU ld (GNU Binutils for Ubuntu) 2.25
    
[/code]

**a.c**

[code]

    int func1(int n) {
      return 2 * n + 3;
    }
    
[/code]

**b.c**

[code]

    int func2(int n){
      return n * n + 3;
    }
    
[/code]

**main.c**

[code]

    #include <stdio.h>
    
    int func1(int n);
    int func2(int n);
    
    int main(){
      printf("func1: %d\n", func1(10));
      printf("func2: %d\n", func2(10));
    }
    
[/code]

**Makefile**

[code]

    CC = gcc
    
    SRCS = main.c
    LIBA_SRCS = a.c
    LIBB_SRCS = b.c
    LDFLAGS = -Wl,-rpath=. -L.
    
    main: libA.so
        $(CC) $(SRCS) -o $@ $(LDFLAGS) -lA
    
    libA.so: libB.so
        $(CC) $(LIBA_SRCS) -fPIC -shared -o $@ $(LDFLAGS) -lB
    
    libB.so:
        $(CC) $(LIBB_SRCS) -fPIC -shared -o $@
    
[/code]

  

[code]

    $ make main
    gcc b.c -fPIC -shared -o libB.so
    gcc a.c -fPIC -shared -o libA.so -Wl,-rpath=. -L. -lB
    gcc main.c -o main -Wl,-rpath=. -L. -lA
    /usr/bin/ld: /tmp/ccn7p3N0.o: undefined reference to symbol 'func2'
    ./libB.so: error adding symbols: DSO missing from command line
    collect2: error: ld returned 1 exit status
    Makefile:9: recipe for target 'main' failed
    make: *** [main] Error 1
    
[/code]

`libA.so` 内には `func2` が存在しませんのでエラーとなってしまいます。これを解決するには以下のオプションを使います。

> ld(1)
>
> \--copy-dt-needed-entries
>
> This option also has an effect on the resolution of symbols in dynamic
> libraries. With --copy-dt-needed-entries dynamic libraries mentioned on the
> command line will be **recursively searched** , following their DT_NEEDED
> tags to other libraries, in order to resolve symbols required by the output
> binary.

つまり、

[code]

    $(CC) $(SRCS) -o $@ $(LDFLAGS) -lA
    =>
    $(CC) $(SRCS) -o $@ -Wl,--copy-dt-needed-entries $(LDFLAGS) -lA
    
[/code]

とします。

[code]

    $ make main
    gcc b.c -fPIC -shared -o libB.so
    gcc a.c -fPIC -shared -o libA.so -Wl,-rpath=. -L. -lB
    gcc main.c -o main -Wl,--copy-dt-needed-entries -Wl,-rpath=. -L. -lA
    
    $ ./main
    func1: 23
    func2: 103
    
[/code]

ld 2.5.1 では `--copy-dt-needed-entries` がデフォルトなのかもしれません。


CC BY-SA 3.0
2015-09-26T11:53:23.097
16957
2015-09-26T11:53:23.097
16944
answer


最適かどうかはわかりませんが、実行時のライブラリー検索パスを指定できる環境変数 `$LD_LIBRARY_PATH` を利用すればいけますね。

[code]

    CC=     LD_LIBRARY_PATH=. gcc -fPIC -L.
    LDSHARED=   $(CC) -shared
    
    all: exe
    
    exe: main.c liba.so
        $(CC) -o $@ -la main.c
    
    liba.so: a.o libb.so
        $(LDSHARED) -o $@ -lb a.o
    
    libb.so: b.o
        $(LDSHARED) -o $@ b.o
    
    clean:
        -rm -f exe *.so *.o
    
[/code]


CC BY-SA 3.0
2015-09-27T12:10:45.907
16998
2015-09-27T12:26:19.643
2015-09-27T12:26:19.643
3061
3061
16944
answer