2012-05-10 14 views
8

Tengo el siguiente problema:¿Cómo seguir el orden de enlace cuando se enlaza con la biblioteca estática con 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 

Pero

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

corre muy bien, nm muestra el contenido esperado, las pruebas se ejecutan, todo el mundo es feliz, etc.

I' he buscado SO y he encontrado muchas respuestas (por ejemplo, Linker order - GCC), así que está claro que el enlazador funciona como debería. Entonces, ¿cómo debo modificar mi archivo make para seguir el orden?

Aquí está el Makefile hasta ahora:

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 

intentado algunas cosas extrañas y obviamente equivocadas como la llamada recursiva

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

La ejecución de este Debian6 en virtud de VirtualBox en Windows7. Especificaciones del sistema:

$ 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. es de Learn C The Hard Way de Zed Shaw, exercise 33. No sé si debería marcarlo como una tarea :)

+0

¿Cómo están los relacionados? Los primeros dos ejemplos (uno bueno, uno malo) compilan 'list_tests'. El archivo MAKE compila 'liblcthw.a'. – wallyk

+1

Intenta agregar '-Wl, - no-como-necesita' después de' $ (OPTFLAGS) 'en' CFLAGS' –

Respuesta

6

No muestra la regla de archivo MAKE que está compilando tests/list_tests pero parece que es solo la regla incorporada. Con GNU Make, puede imprimir esa regla con -p, que le mostrará:

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

Mediante la adición de la biblioteca para $(CFLAGS) (a través del objetivo específico de la variable tests: CFLAGS+=$(TARGET)), lo va a colocar antes de $^ en el que resulta mando. En su lugar debe añadirlo a $(LDLIBS) para que aparezca después de los ficheros objeto:

tests: LDLIBS+=$(TARGET) 

Sin embargo tenga en cuenta que confiar en la propagación de las variables específicas de la diana como esto no funciona especialmente bien en la práctica. Cuando escribe make tests, la biblioteca se usa para compilar tests/list_tests y otros. Sin embargo, cuando solo está interesado en una prueba, encontrará que make tests/list_tests falla porque la biblioteca de enlaces no está incluida en el comando. (Ver this answer para más detalles.)

+1

La regla incorporada también está [enumerada en el manual] (http://www.gnu.org/software/make/manual/html_node/Catálogo de reglas.html # index-linking_002c-predefined-rule-for-821). Si adivinaste que la regla implícita incorporada contiene '$ (LDLIBS)' así como '$ (LDFLAGS)' precisamente para que puedas poner estas bibliotecas de cargadores al final del comando, ¡estarías en lo cierto! –

2

soy un novato, que progresa a través del mismo libro y lo tengo para construir de esta manera:

me cambió la línea:

pruebas: CFLAGS + = $ (TARGET) #I que esta línea es inútil ahora

a

pruebas: CFLAGS + = $ (SO_TARGET)

+0

Para referencia futura de cualquier persona haciendo esto y agregando '-Wl, - no-como-necesita' después de' $ (OPTFLAGS) 'en la primera línea del' Makefile' habilitado para compilar este ejercicio del libro –

Cuestiones relacionadas