【问题标题】:Failing to link to SFML libraries using Makefile even though it works as a one liner无法使用 Makefile 链接到 SFML 库,即使它可以作为单线使用
【发布时间】:2024-01-24 10:45:01
【问题描述】:

这是我的目录结构:

.
├── a.out
├── assets
│   └── ...
├── build
│   ├── apps
│   └── objects
├── include
│   └── engine
│       └── Class.h
├── Makefile
└── src
    ├── engine
    │   └── Class.cpp
    └── program.cpp

我可以使用以下命令将program.cpp 编译成a.out

g++ src/engine/*.cpp src/program.cpp -Iinclude/ -L/usr/lib -lstdc++ -lm -lsfml-graphics -lsfml-window -lsfml-system -Wall

虽然这行得通,但这个项目可能会发展壮大,显然制作一个严肃的 Makefile 比直接使用单行编译更可取。所以我使用了我以前多次使用过的 Makefile 格式,它工作得非常好,但我过去从未将它链接到外部库。这是我正在使用的 Makefile:

CXX      := -g++
CXXFLAGS := -std=gnu++0x -g -Wall
LDFLAGS  := -L/usr/lib -lstdc++ -lm -lsfml-graphics -lsfml-window -lsfml-system
BUILD    := ./build
OBJ_DIR  := $(BUILD)/objects
APP_DIR  := $(BUILD)/apps
TARGET   := program
INCLUDE  := -Iinclude/
SRC      := $(wildcard src/engine/*.cpp) $(wildcard src/*.cpp)
OBJECTS  := $(SRC:%.cpp=$(OBJ_DIR)/%.o)

all: build $(APP_DIR)/$(TARGET)

$(OBJ_DIR)/%.o: %.cpp
    @mkdir -p $(@D)
    $(CXX) $(CXXFLAGS) $(INCLUDE) -o $@ -c $<

$(APP_DIR)/$(TARGET): $(OBJECTS)
    @mkdir -p $(@D)
    $(CXX) $(CXXFLAGS) $(INCLUDE) $(LDFLAGS) -o $(APP_DIR)/$(TARGET) $(OBJECTS)

.PHONY: all build clean debug release

build:
    @mkdir -p $(APP_DIR)
    @mkdir -p $(OBJ_DIR)

debug: CXXFLAGS += -DDEBUG -g
debug: all

release: CXXFLAGS += -O2
release: all

clean:
    -@rm -rvf $(OBJ_DIR)/*
    -@rm -rvf $(APP_DIR)/*

但是,这会导致编译错误,表现为对 SFML 方法的未定义引用:

./build/objects/src/engine/Class.o: In function `Class::draw()':
/dir/Class.cpp:60: undefined reference to `sf::RenderTarget::getView() const'

我很困惑为什么会发生这种情况,因为上面的一个衬里编译得很好。如果我从我的代码中删除所有对 SFML 的引用,Makefile 也可以正常工作。添加的LDFLAGS 是否还不够,即使它们是使我的一个班轮链接到 SFML 所需的全部?如果是这样,还需要什么?

【问题讨论】:

  • 哇...确实做到了。我什至没有意识到改变这样的事情的顺序可能很重要。我认为这值得在答案中指出。你介意写一下,或者添加一两行关于这里发生的事情吗?我真的很好奇你是怎么想出来的。

标签: makefile compilation linker g++ sfml


【解决方案1】:

来自gcc link options

-llibrary

在命令的哪个位置编写此选项会有所不同;链接器按照指定的顺序搜索和处理库和目标文件。因此,foo.o -lz bar.o 在文件foo.o 之后但在bar.o 之前搜索库z。如果bar.o 引用了z 中的函数,则这些函数可能不会被加载。

所以将库 (-l&lt;lib_1&gt; ... -l&lt;lib_x&gt;) 放在最后一行,在您的目标文件之后。

【讨论】:

  • 我非常感谢您没有在评论中添加“RTFM”,因为我应该得到它 XD 在我的辩护中,我奇迹般地从未遇到过这种情况。在我使用 C++ 的所有岁月中,我一定总是出于偶然的原因以正确的顺序进行链接。
  • @ticster 我实际上复制了您的项目结构并在我注意到之前自己在其中制作了一个小程序:-)
  • 这就是有两个不同的“标准”make 变量用于链接库的确切原因:LDFLAGS 应该包含标志(如 -Ldir/to/foo)和 LDLIBS 应该包含包含库(如-lfoo)。那么默认的链接器配方是(相当于)$(CXX) $(CXXFLAGS) $(CPPFLAGS) $(LDFLAGS) $^ $(LDLIBS) -o $@
  • @MadScientist 感谢您的提示。我会相应地更改我的标志。
  • @ticster 不,恰恰相反。如果file.o 使用func() 并且func() 在库中funcs 然后:file.o -lfuncs 解决它。把它想象成链接器创建了一个未解析函数的列表。每当它看到一个以前没有使用过的函数被使用时,它就会被放入该列表中。如果该函数存在于已扫描的库中,它将被遗漏,但当它扫描以后的库时,它也会检查该函数。
最近更新 更多