调整 Makefile 以包含 SDL2

Adapting a Makefile to include SDL2

我正在编译一个使用 SDL2 库的简单程序。
MWE(Lazy Foo's tutorial 的简化版):

// main.cpp
#include <SDL.h>
int main(int argc, char* args[])
{
  SDL_Window* window = NULL;
  SDL_Surface* screenSurface = NULL;
  SDL_Init(SDL_INIT_VIDEO);
  window = SDL_CreateWindow("The exciting white window", DL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, SDL_WINDOW_SHOWN);
  screenSurface = SDL_GetWindowSurface(window);
  SDL_FillRect(screenSurface, NULL, SDL_MapRGB( screenSurface->format, 0xFF, 0xFF, 0xFF));
  SDL_UpdateWindowSurface(window);
  SDL_Delay(2000);
  SDL_DestroyWindow(window);
  SDL_Quit();
  return 0;
}

我想修改 this tutorial 的 Makefile 来处理它。
这是我试过的:

program_NAME := main
program_CXX_SRCS := $(wildcard *.cpp)
program_CXX_OBJS := ${program_CXX_SRCS:.cpp=.o}
program_OBJS := $(program_CXX_OBJS)
program_INCLUDE_DIRS := /usr/include/SDL2
program_LIBRARY_DIRS :=
program_LIBRARIES := SDL2

CPPFLAGS += $(foreach includedir,$(program_INCLUDE_DIRS),-I$(includedir))
LDFLAGS += $(foreach librarydir,$(program_LIBRARY_DIRS),-L$(librarydir))
LDFLAGS += $(foreach library,$(program_LIBRARIES),-l$(library))

.PHONY: all clean distclean

all: $(program_NAME)

$(program_NAME): $(program_OBJS)
    $(LINK.cc) $(program_OBJS) -o $(program_NAME)

clean:
    @- $(RM) $(program_NAME)
    @- $(RM) $(program_OBJS)

distclean: clean

但是,我遇到了几个链接器错误:

$ make
g++  -I/usr/include/SDL2  -c -o main.o main.cpp
g++  -I/usr/include/SDL2  -lSDL2  main.o -o myprogram
main.o: In function `main':
main.cpp:(.text+0x25): undefined reference to `SDL_Init'
main.cpp:(.text+0x4a): undefined reference to `SDL_CreateWindow'
main.cpp:(.text+0x5a): undefined reference to `SDL_GetWindowSurface'
main.cpp:(.text+0x7d): undefined reference to `SDL_MapRGB'
main.cpp:(.text+0x90): undefined reference to `SDL_FillRect'
main.cpp:(.text+0x9c): undefined reference to `SDL_UpdateWindowSurface'
main.cpp:(.text+0xa6): undefined reference to `SDL_Delay'
main.cpp:(.text+0xb2): undefined reference to `SDL_DestroyWindow'
main.cpp:(.text+0xb7): undefined reference to `SDL_Quit'
collect2: error: ld returned 1 exit status
Makefile:18: recipe for target 'myprogram' failed
make: *** [myprogram] Error 1

我从 this answer 了解到参数的顺序现在很重要。调用

$ g++ -I/usr/include/SDL2 -c -o main.o main.cpp
$ g++ main.o -lSDL2 -o main

直接从命令行工作。

最后我的问题正确调整 Makefile 的方法是什么? ("correct" 我的意思是避免上述 Makefile 教程中提到的陷阱类型。)

您找到的教程 makefile 中有错误。要修复 makefile,请替换行:

LDFLAGS += $(foreach library,$(program_LIBRARIES),-l$(library))

与:

LDLIBS += $(foreach library,$(program_LIBRARIES),-l$(library))

并替换行:

$(LINK.cc) $(program_OBJS) -o $(program_NAME)

与:

$(LINK.cc) $(program_OBJS) -o $(program_NAME) $(LDLIBS)

或更正常的样式:

$(LINK.cc) $^ -o $@ $(LDLIBS)

(参见 10.5.3 Automatic Variablesthe manual)

教程 makefile 中的错误是它不正确 使用(或解释)规范生成变量 LDFLAGSLDLIBS。它 将所有链接器的库选项 (-l<name>) 捆绑到 LDFLAGS 的值中。 他们不应该去那里。他们应该输入 LDLIBS.

的值

预定义的 make 变量 LINK.cc 扩展为:

LINK.cc = $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH)

包含$(LDLIBS),正是因为 GNU 链接器,如 在大多数 GCC 发行版(包括你的)中使用,需要目标文件出现 在链接序列中比它们所依赖的库更早,并且将 在序列中不解析任何符号的位置忽略库 链接器 已经需要解析的引用

如果 LDLIBS 被正确地用于 -l 选项,并在链接配方中正确使用 - 如上面更正的链接配方 - 然后所有库将安全地出现在所有目标文件之后。

通过将 -l 选项捆绑到 $(LDFLAGS),教程获取所有库 在所有目标文件之前;所以在你的链接中, -lSDL2 被忽略了,你的 如观察到的那样,链接失败。

这是典型的 GNU make 变量的摘要 在 C 或 C++ 编译和链接中运行:

CC 调用 C 编译器的命令(默认 cc

CXX 调用 C++ 编译器的命令(默认 g++

CPPFLAGS C/C++ 预处理器的选项

CFLAGS C 编译器的选项

CXXFLAGS C++ 编译器的选项

LDFLAGS 您的链接选项,不包括库和库 (-l) 选项

LDLIBS你的链接库或库(-l)选项

除非另有说明,否则默认值为空。

10.2 Catalogue of Built-In Rules 了解这些变量如何在 make 的内置规则中工作。或者保存输出 make --print-data-base 到一个文件并研究它。