2012-05-10 11 views
8

Mam następujący problem:Jak śledzić kolejność linków podczas łączenia z biblioteką statyczną za pomocą 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 

Ale

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

działa dobrze, nm pokazuje oczekiwana zawartość, testy zakończą, każdy jest zadowolony, itp

I” szukałem SO i znalazłem mnóstwo odpowiedzi (np. Linker order - GCC), więc jasne jest, że linker działa tak, jak powinien. Jak zatem zmodyfikować plik Makefile, aby wykonać zamówienie?

Oto Makefile tak daleko:

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 

Tried dziwne i oczywiście złe rzeczy jak rekurencyjne wywołanie

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

Running to w Debian6 pod VirtualBox na Windows7. Specyfikacje systemu:

$ 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. jej od Zed Shaw's Learn C The Hard Way, exercise 33. Nie wiem, czy powinienem oznaczyć to jako zadanie domowe :)

+0

Jak są te związane? Pierwsze dwa (jeden dobry, jeden zły) przykłady budują 'list_tests'. Makefile tworzy bibliotekę "liblcthw.a". – wallyk

+1

Spróbuj dodać '-Wl, - no-as-needed' po' $ (OPTFLAGS) 'w' CFLAGS' –

Odpowiedz

6

Nie pokazujesz reguły makefile, która buduje tests/list_tests, ale wygląda na to, że jest to tylko wbudowana reguła. Z GNU make, można wydrukować tej zasady z -p, który pokaże:

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

Dodając bibliotekę do $(CFLAGS) (poprzez celowane zmienna tests: CFLAGS+=$(TARGET)), jesteś umieszczając go przed $^ w wynikowym dowództwo. Zamiast tego należy dodać go do $(LDLIBS) tak, że wydaje się po plikach obiektowych:

tests: LDLIBS+=$(TARGET) 

jednak pamiętać, że opierając się na propagację zmiennych docelowych specyficznych jak to nie działa szczególnie dobrze w praktyce. Po wpisaniu make tests biblioteka jest używana do budowania tests/list_tests i innych. Jednak gdy interesuje Cię tylko jeden test, okaże się, że make tests/list_tests nie działa, ponieważ biblioteka linków nie jest zawarta w poleceniu. (Patrz this answer szczegóły.)

+1

Wbudowana reguła jest również [wymieniona w instrukcji] (http://www.gnu.org/software/make/manual/html_node/Catalog-of-Rules.html # index-linking_002c-predefined-rule-for-821). Jeśli zgadłeś, że wbudowana reguła niejawna zawiera '$ (LDLIBS)' oraz '$ (LDFLAGS)' właśnie tak, że możesz umieścić te biblioteki ładujące na końcu polecenia, masz rację! –

2

jestem noob, w dążeniu do tej samej książki i mam go zbudować w ten sposób:

zmieniłem linię:

testy: CFLAGS + = $ (TARGET) #I że ta linia jest teraz

bezużyteczne

testów: CFLAGS + = $ (SO_TARGET)

+0

Dla każdego, kto będzie używał tego w przyszłości, dodając '-Wl, - no-as-needed' po' $ (OPTFLAGS) 'w pierwszym wierszu pliku' Makefile' włączonego do kompilacji tego ćwiczenia z książki –