2012-05-10 71 views
8

我有以下問題:如何在使用gnu-make連接靜態庫時遵循鏈接順序?

cc -g -O2 -Wall -Wextra -Isrc -rdynamic -DNDEBUG build/liblcthw.a tests/list_tests.c -o tests/list_tests 
/tmp/ccpvGjZp.o: In function `test_create': 
~/lcthw/tests/list_tests.c:12: undefined reference to `List_create' 
collect2: ld returned 1 exit status 
make: *** [tests/list_tests] Error 1 

cc -g -O2 -Wall -Wextra -Isrc -rdynamic -DNDEBUG tests/list_tests.c build/liblcthw.a -o tests/list_tests 

運行良好,nm顯示預期的內容,測試運行,大家樂等

我我找到了很多答案(例如Linker order - GCC),所以很明顯,鏈接器的工作原理應該如此。那麼,我應該如何修改我的makefile以遵循命令?

這裏的Makefile文件至今:

CFLAGS=-g -O2 -Wall -Wextra -Isrc -rdynamic -DNDEBUG $(OPTFLAGS) 
LIBS=$(OPTLIBS) 
PREFIX?=/usr/local 
BUILD=build 

SOURCES=$(wildcard src/**/*.c src/*.c) 
OBJECTS=$(patsubst %.c,%.o,$(SOURCES)) 

TEST_SRC=$(wildcard tests/*_tests.c) 
TESTS=$(patsubst %.c,%,$(TEST_SRC)) 

TARGET=$(BUILD)/liblcthw.a 
TARGET_LINK=lcthw 
SO_TARGET=$(patsubst %.a,%.so,$(TARGET)) 

#The Target Build 
all: $(TARGET) $(SO_TARGET) tests 

dev: CFLAGS=-g -Wall -Isrc -Wall -Wextra $(OPTFLAGS) 
dev: all 

$(TARGET): CFLAGS += -fPIC 
$(TARGET): build $(OBJECTS) 
    ar rcs [email protected] $(OBJECTS) 
    ranlib [email protected] 

$(SO_TARGET): $(TARGET) $(OBJECTS) 
    $(CC) -shared -o [email protected] $(OBJECTS) 

build: 
    @mkdir -p $(BUILD) 
    @mkdir -p bin 

#The Unit Tests 
.PHONY: tests 
tests: CFLAGS+=$(TARGET)  #I think this line is useless now 
tests: $(TESTS) 
    sh ./tests/runtests.sh 

#some other irrelevant targets 

嘗試了一些奇怪,顯然是錯誤的東西像遞歸調用

$(TESTS): 
    $(MAKE) $(TESTS) $(TARGET) 

Windows7 VirtualBox的下Debian6運行此。系統規格:

$ uname -a 
Linux VMDebian 2.6.32-5-686 #1 SMP Mon Mar 26 05:20:33 UTC 2012 i686 GNU/Linux 
$ gcc -v 
Using built-in specs. 
Target: i486-linux-gnu 
Configured with: ../src/configure -v --with-pkgversion='Debian 4.4.5-8' --with-bugurl=file:///usr/share/doc/gcc-4.4/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.4 --enable-shared --enable-multiarch --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.4 --libdir=/usr/lib --enable-nls --enable-clocale=gnu --enable-libstdcxx-debug --enable-objc-gc --enable-targets=all --with-arch-32=i586 --with-tune=generic --enable-checking=release --build=i486-linux-gnu --host=i486-linux-gnu --target=i486-linux-gnu 
Thread model: posix 
gcc version 4.4.5 (Debian 4.4.5-8) 

P.S.它來自Zed Shaw的Learn C The Hard Way,exercise 33。不知道我是否應該將它標記爲作業:)

+0

如何連接那些?前兩個(一個好的,一個壞的)示例構建'list_tests'。 makefile建立'liblcthw.a'。 – wallyk

+1

嘗試在'CFLAGS'的'$(OPTFLAGS)'之後添加'-Wl, - 不需要的' –

回答

6

您不顯示構建tests/list_tests的makefile規則,但它看起來好像只是內置規則。隨着GNU做,你可以打印出的規則與-p,它會告訴你:

# default 
LINK.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH) 
[...] 
.c: 
# recipe to execute (built-in): 
    $(LINK.c) $^ $(LOADLIBES) $(LDLIBS) -o [email protected] 

通過所產生的庫添加到$(CFLAGS)(通過目標特定變量tests: CFLAGS+=$(TARGET)),你把它放在前$^命令。相反,你應該把它使其顯示的目標文件後添加到$(LDLIBS)

tests: LDLIBS+=$(TARGET) 

但是請注意,依靠這樣的特定目標變量的傳播並沒有在實際工作特別好。當你輸入make tests時,庫被用來構建tests/list_tests等。但是,當您只對一個測試感興趣時,您會發現make tests/list_tests失敗,因爲鏈接庫不包含在該命令中。 (見this answer瞭解詳細信息。)

+1

內置規則也列在手冊中(http://www.gnu.org) /軟件/製作/手動/ html_node /目錄-的規則。HTML#指數linking_002c預定義規則換821)。如果您猜測內置的隱式規則恰好包含「$(LDLIBS)」和「$(LDFLAGS)」,以便您可以將這些加載器庫放在命令末尾,那麼您就是對的! –

2

我是小白,通過同一本書取得進展,我把它打造這樣:

我改了行:

測試:CFLAGS + = $( TARGET)#我想現在

這條線是沒用的,

測試:CFLAGS + = $(SO_TARGET)

+0

對於任何人的將來參考做到這一點,並在啓動'Makefile'的第一行'$(OPTFLAGS)'後面添加'-Wl, - no-as-needed'來編譯本書的練習 –