2012-05-10 27 views
8

Tôi đã có những vấn đề sau đây:Làm thế nào để thực hiện theo thứ tự liên kết khi liên kết với thư viện tĩnh với 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 

Nhưng

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

chạy tốt, nm cho thấy nội dung mong muốn, kiểm tra chạy, tất cả mọi người là hạnh phúc vv

tôi đã tìm kiếm SO và tìm thấy rất nhiều câu trả lời (ví dụ: Linker order - GCC), do đó, rõ ràng rằng mối liên kết hoạt động như nó thực sự cần. Vì vậy, làm thế nào tôi nên sửa đổi makefile của tôi để làm theo thứ tự?

Đây là Makefile cho đến nay:

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 

thử một số điều kỳ lạ và rõ ràng là sai như đệ quy gọi

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

Chạy này trong Debian6 dưới VirtualBox trên Windows7. Thông số hệ thống:

$ 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. từ bài học C The Hard Way của Zed Shaw, exercise 33. Không biết liệu tôi có nên đánh dấu nó là bài tập ở nhà không :)

+0

như thế nào những kết nối? Hai ví dụ đầu tiên (một tốt, một xấu) xây dựng 'list_tests'. Makefile xây dựng 'liblcthw.a'. – wallyk

+1

Thử thêm '-Wl, - no-as-needed' sau' $ (OPTFLAGS) 'trong' CFLAGS' –

Trả lời

6

Bạn không hiển thị quy tắc makefile đang xây dựng tests/list_tests nhưng có vẻ như đây chỉ là quy tắc dựng sẵn. Với GNU Make, bạn có thể in ra quy tắc rằng với -p, mà sẽ chỉ cho bạn:

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

Bằng cách thêm vào thư viện để $(CFLAGS) (thông qua các mục tiêu cụ thể biến tests: CFLAGS+=$(TARGET)), bạn đang đặt nó trước khi $^ trong kết quả chỉ huy. Thay vào đó bạn nên thêm nó vào $(LDLIBS) để nó xuất hiện sau khi các tập tin đối tượng:

tests: LDLIBS+=$(TARGET) 

Tuy nhiên lưu ý rằng dựa vào công tác tuyên truyền của các biến mục tiêu cụ thể như thế này không hoạt động đặc biệt tốt trong thực tế. Khi bạn nhập make tests thì thư viện được sử dụng để xây dựng tests/list_tests et al. Tuy nhiên khi bạn chỉ quan tâm đến một thử nghiệm, bạn sẽ thấy rằng make tests/list_tests không thành công vì thư viện liên kết không được bao gồm trong lệnh. (Xem this answer để biết chi tiết.)

+1

Quy tắc dựng sẵn cũng được [liệt kê trong sách hướng dẫn] (http://www.gnu.org/software/make/manual/html_node/Catalog-of-Rules.html # index-linking_002c-được xác định trước-quy tắc-cho-821). Nếu bạn đoán rằng quy tắc ngầm được xây dựng trong chứa '$ (LDLIBS)' cũng như '$ (LDFLAGS)' chính xác để bạn có thể đặt các thư viện trình tải này vào cuối lệnh, bạn sẽ đúng! –

2

tôi là một Noob, tiến triển thông qua các cuốn sách đó và tôi đã nhận nó để xây dựng theo cách này:

tôi đã thay đổi dòng:

kiểm tra: CFLAGS + = $ (MỤC TIÊU) #I nghĩ dòng này là vô ích tại

để

kiểm tra: CFLAGS + = $ (SO_TARGET)

+0

Để tham khảo trong tương lai của bất kỳ ai thực hiện việc này và thêm '-Wl, - no-as-needed' sau' $ (OPTFLAGS) 'trong dòng đầu tiên của' Makefile' được kích hoạt để biên dịch tập sách này –

Các vấn đề liên quan