C:Unix SDL2库:未定义的引用,Makefile中的问题?

时间:2016-02-29 23:20:58

标签: c linux ubuntu sdl

我正在寻找一个可以在Unix上编译C程序的Makefile(Ubuntu)。 Makefile应该包括SDL库(2.0)以及SDL_image。

所以这是我目前的Makefile:

CC = gcc
OBJECTS = $(patsubst %.c,%.o,$(wildcard *.c))
EXEC = main

LDFLAGS = `sdl2-config --libs` -L/usr/lib -lSDL2_image
CCFLAGS = `sdl2-config --cflags` -I/usr/include/SDL_image.h

$(EXEC): $(OBJECTS)
    $(CC) $(LDFLAGS) $< -o $@

%.o: %.c
    $(CC) -c $(CCFLAGS) $< -o $@

.PHONY: clean

clean:
    rm -f $(OBJECTS) $(EXEC)

这是我当前的代码(仅用于测试Makefile的最小代码):

#include <stdio.h>
#include <SDL.h>
#include <SDL2/SDL_image.h>

int main(int argc, char **argv) {

    SDL_Window* window = NULL;
    SDL_Surface* screenSurface = NULL;

    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        printf("Initialization error: %s\n",SDL_GetError());
        return 1;
    }

    window = SDL_CreateWindow("Test",SDL_WINDOWPOS_UNDEFINED,
    SDL_WINDOWPOS_UNDEFINED,640, 480,SDL_WINDOW_SHOWN);

    SDL_Quit();
    return 0;
}

所以当我写命令时:make

我在所有SDL功能上都出错了。 这是一个例子:未定义的对“SDL_Init”的引用

我尝试了很多东西(比如Makefile中Include和Link的路径不同),但似乎没什么用。

所以我的问题是:如何解决这些对SDL2函数的未定义引用?

3 个答案:

答案 0 :(得分:2)

您正在以错误的顺序指定链接器标志。

这是错误的:

LDFLAGS = `sdl2-config --libs` -L/usr/lib -lSDL2_image
$(EXEC): $(OBJECTS)
    $(CC) $(LDFLAGS) $< -o $@

这是正确的:

LIBS = `sdl2-config --libs` -L/usr/lib -lSDL2_image
$(EXEC): $(OBJECTS)
    $(CC) $(LDFLAGS) $^ $(LIBS) -o $@

使用GNU Binutils,库的顺序很重要。库必须在具有对这些库中的符号的未定义引用的对象之后。它太糟糕了,这很愚蠢,但这就是GNU Binutils的工作方式而你却坚持下去。

其他修正

  • 您希望$^代替$<,因为$<只是第一个依赖关系。

  • 可能最好使用可以找到SDL2_image的pkg-config

    LIBS = `pkg-config --libs sdl2 SDL2_image`
    
  • 调用shell程序时,您可能希望:=不是=,这会将变量展开一次,而不是每次都使用它:

    LIBS := $(shell pkg-config --libs sdl2 SDL2_image)
    CFLAGS := $(shell pkg-config --cflags sdl2 SDL2_image)
    

完整示例

这是一个清理过的例子,接近我写的方式:

# use := not =
# convention: objects, exec are lower-case because they're private
objects := $(patsubst %.c,%.o,$(wildcard *.c))
CFLAGS := $(shell pkg-config --cflags sdl2 SDL2_image)
LIBS := $(shell pkg-config --libs sdl2 SDL2_image)

# Don't define CC, because the default (cc) is fine
# It's probably linked to gcc on your system anyway

# = or := doesn't matter here
exec = main

# must use = here
depflags = -MF $(patsubst %.o,%.d,$@) -MMD -MP
-include $(wildcard *.d)

$(exec): $(objects)
    $(CC) $(LDFLAGS) $^ $(LIBS) -o $@

%.o: %.c
    $(CC) $(depflags) -c $(CCFLAGS) $< -o $@

.PHONY: clean
clean:
    rm -f *.o *.d $(exec)

答案 1 :(得分:1)

您反转了一些编译器/链接器选项:

# linker options
LDFLAGS = `sdl2-config --libs` -I/usr/include/SDL_image.h
# compiler options
CCFLAGS = `sdl2-config --cflags` -L/usr/lib -lSDL2_image

应该是:

# linker options
LDFLAGS = `sdl2-config --libs` -L/usr/lib -lSDL2_image
# compiler options
CCFLAGS = `sdl2-config --cflags` -I/usr/include

详细说明:

-L Is to indicate to the linker where to find .so files
-l Is to link to a given library
-I Is to indicate to the compiler where to find .h files

答案 2 :(得分:0)

Catalogue of Built-In Rules

中可以看出
  

链接单个目标文件

     

n是通过运行链接器(通常称为n.o自动生成的   ld)通过C编译器。使用的精确配方是:

$(CC) $(LDFLAGS) n.o $(LOADLIBES) $(LDLIBS)

Variables Used by Implicit Rules

  

LDFLAGS

     

当编译器应该调用链接器时给出的额外标志,   ld,例如-L。应将库(-lfoo)添加到LDLIBS变量中   代替。

因此,在这种情况下,应将-lSDL2_image设置或添加到LDLIBS,而不是LDFLAGS。