Um bug na linha de comando do gcc

Dando uma olhada num makefile deparei com algo assim:

CC=gcc
CFLAGS=-O3 -mtune=native
LDFLAGS=-O3 -lm -lGL -lglfw

.PHONY: all clean

all: main

main: main.o

main.o: main.c

clean:
  @-rm *.o main

Olha só o que acontece se eu ‘executar’ chamar o makefile com o gcc 4.8.2:

$ make
gcc -O3 -mtune=native main.c
gcc -O3 -lm -lGL -lglfw -o main main.o
main.o: In function `LoadShaders':
main.c:(.text+0x103): undefined reference to `glCreateShader'
main.c:(.text+0x11a): undefined reference to `glShaderSource'
main.c:(.text+0x12d): undefined reference to `glCompileShader'
main.c:(.text+0x13e): undefined reference to `glGetShaderiv'
main.c:(.text+0x164): undefined reference to `glCreateShader'
main.c:(.text+0x17b): undefined reference to `glShaderSource'
main.c:(.text+0x18e): undefined reference to `glCompileShader'
main.c:(.text+0x19f): undefined reference to `glGetShaderiv'
main.c:(.text+0x1b1): undefined reference to `glCreateProgram'
main.c:(.text+0x1c2): undefined reference to `glAttachShader'
main.c:(.text+0x1d1): undefined reference to `glAttachShader'
main.c:(.text+0x1e5): undefined reference to `glBindAttribLocation'
main.c:(.text+0x1fc): undefined reference to `glBindAttribLocation'
main.c:(.text+0x209): undefined reference to `glLinkProgram'
main.c:(.text+0x21e): undefined reference to `glGetProgramiv'
main.c:(.text+0x25a): undefined reference to `glGetShaderInfoLog'
main.c:(.text+0x29e): undefined reference to `glGetProgramInfoLog'
main.c:(.text+0x2c2): undefined reference to `glGetShaderInfoLog'
main.o: In function `main':
main.c:(.text.startup+0xa): undefined reference to `glfwInit'
main.c:(.text.startup+0x1c): undefined reference to `glfwDisable'
main.c:(.text.startup+0x2b): undefined reference to `glfwOpenWindowHint'
main.c:(.text.startup+0x3a): undefined reference to `glfwOpenWindowHint'
main.c:(.text.startup+0x44): undefined reference to `glfwExtensionSupported'
main.c:(.text.startup+0x5b): undefined reference to `glfwOpenWindowHint'
main.c:(.text.startup+0x97): undefined reference to `glfwOpenWindow'
main.c:(.text.startup+0xa9): undefined reference to `glGetString'
main.c:(.text.startup+0xb6): undefined reference to `glGetString'
main.c:(.text.startup+0xcd): undefined reference to `glfwGetGLVersion'
main.c:(.text.startup+0x11d): undefined reference to `glfwDisable'
main.c:(.text.startup+0x130): undefined reference to `glViewport'
main.c:(.text.startup+0x146): undefined reference to `glClearColor'
main.c:(.text.startup+0x153): undefined reference to `glClearDepth'
main.c:(.text.startup+0x15d): undefined reference to `glEnable'
main.c:(.text.startup+0x167): undefined reference to `glFrontFace'
main.c:(.text.startup+0x171): undefined reference to `glCullFace'
main.c:(.text.startup+0x17b): undefined reference to `glEnable'
main.c:(.text.startup+0x185): undefined reference to `glDepthFunc'
main.c:(.text.startup+0x25b): undefined reference to `glGenVertexArrays'
main.c:(.text.startup+0x266): undefined reference to `glBindVertexArray'
main.c:(.text.startup+0x277): undefined reference to `glGenBuffers'
main.c:(.text.startup+0x287): undefined reference to `glBindBuffer'
main.c:(.text.startup+0x2a2): undefined reference to `glBufferData'
main.c:(.text.startup+0x2ab): undefined reference to `glEnableVertexAttribArray'
main.c:(.text.startup+0x2c6): undefined reference to `glVertexAttribPointer'
main.c:(.text.startup+0x2d6): undefined reference to `glBindBuffer'
main.c:(.text.startup+0x2f1): undefined reference to `glBufferData'
main.c:(.text.startup+0x2fd): undefined reference to `glEnableVertexAttribArray'
main.c:(.text.startup+0x31b): undefined reference to `glVertexAttribPointer'
main.c:(.text.startup+0x328): undefined reference to `glUseProgram'
main.c:(.text.startup+0x331): undefined reference to `glfwSwapBuffers'
main.c:(.text.startup+0x33b): undefined reference to `glClear'
main.c:(.text.startup+0x34c): undefined reference to `glDrawArrays'
main.c:(.text.startup+0x351): undefined reference to `glfwPollEvents'
main.c:(.text.startup+0x35b): undefined reference to `glfwGetKey'
main.c:(.text.startup+0x365): undefined reference to `glfwTerminate'
main.c:(.text.startup+0x380): undefined reference to `glfwOpenWindowHint'
main.c:(.text.startup+0x3af): undefined reference to `glfwTerminate'
collect2: error: ld returned 1 exit status

O que aconteceu foi que, ao tentar linkar main.o no executável main, nenhuma das referências às shared objects libGL.so, libglfw.so e libm puderam ser resolvidas! Mas, como pode isso?

O gcc 4.8.2 parece ter um probleminha com a ordem com que as libs são declaradas. Se, manualmente, eu fizer assim:

$ gcc -o main main.o -O3 -lm -lGL -lglfw

O código é linkado sem problemas. Mas, se eu colocar as opções -l na frente, dá pau… O makefile com a receita implícita faz exatamente isso, dai o erro.

Então o negócio é não confiar no make e declarar a receita para o linker daqui pra frente:

main: main.o
  $(CC) -o $@ $^ $(LDFLAGS)

Estejam avisados!

UPDATE:

Um lembrete para mim mesmo: LEIA SEMPRE A PORCARIA DA DOCUMENTAÇÂO, Fred!

A documentação do GCC diz, claramente:

-llibrary
-l library


It makes a difference where in the command you write this option; the linker searches and processes libraries and object files in the order they are specified. Thus, ‘foo.o -lz bar.o’ searches library ‘z’ after file foo.o but before bar.o. If bar.o refers to functions in ‘z’, those functions may not be loaded

Anúncios

Deixe um comentário

Faça o login usando um destes métodos para comentar:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s