与 Makefile 混淆似乎链接但我无法调用的库

Posted

技术标签:

【中文标题】与 Makefile 混淆似乎链接但我无法调用的库【英文标题】:Confusion with Makefile linking a library that seems to link but I can't call 【发布时间】:2017-05-07 01:07:59 【问题描述】:

我正在尝试为使用 soplex 库(也依赖于 libz 和 libgmp)的项目构建一个 Makefile。 所以我有这个小Makefile:

SOPLEXPATH =../../lib/soplex-3.0.0/lib/
SOPLEXINCLUDE =../../lib/soplex-3.0.0/src/
SOPLEXDEP =../../lib/soplex-3.0.0/src/

CC = g++
CPPFLAGS = -g -std=c++0x -O3 -I $(SOPLEXINCLUDE)
#CPPFLAGS += -DNDEBUG
CPPFLAGS += -pg -ggdb
CPPFLAGS += -Wall -Werror=return-type

LIBS = -L $(SOPLEXPATH) -lz -lgmp -lsoplex 

SRCS = $(wildcard ./src/core/*.cpp) 
OBJS = $(addsuffix .o, $(basename $(SRCS)))
DEPS = $(addsuffix .d, $(basename $(SRCS)))

all : kea

kea : $(OBJS)
    $(CC) $(CPPFLAGS) $(LIBS) -o bin/kea-core $(OBJS)

clean :
    rm -f bin/kea-core $(OBJS) $(DEPS) *~

-include $(DEPS)

%.d: %.c
    @$(CC) -MM -MT  $(subst .d,.o,$@) -MT $@ $(CPPFLAGS) $< > $@

所有似乎都正确编译为目标文件(.o),但是链接器抱怨找不到函数soplex::SoPlex::SoPlex()(SoPlex 的构造函数):

g++  -g -std=c++0x -O3 -I ../../lib/soplex-3.0.0/src/ -pg -ggdb -Wall -Werror=return-type  -c -o src/core/ecircuit.o src/core/ecircuit.cpp
g++  -g -std=c++0x -O3 -I ../../lib/soplex-3.0.0/src/ -pg -ggdb -Wall -Werror=return-type  -c -o src/core/solver_soplex.o src/core/solver_soplex.cpp
g++  -g -std=c++0x -O3 -I ../../lib/soplex-3.0.0/src/ -pg -ggdb -Wall -Werror=return-type  -c -o src/core/main.o src/core/main.cpp
g++ -g -std=c++0x -O3 -I ../../lib/soplex-3.0.0/src/ -pg -ggdb -Wall -Werror=return-type -L ../../lib/soplex-3.0.0/lib/ -lz -lgmp -lsoplex  -o bin/kea-core ./src/core/ecircuit.o ./src/core/solver_soplex.o ./src/core/main.o
./src/core/solver_soplex.o: In function `SolvSoplex::SolvSoplex(ECircuit&, std::vector<std::pair<int, int>, std::allocator<std::pair<int, int> > >&, SolvSoplex::Mode)':
/home/diego/Projects/kea-landscape-tool/src/core/solver_soplex.cpp:9: undefined reference to `soplex::SoPlex::SoPlex()'
/home/diego/Projects/kea-landscape-tool/src/core/solver_soplex.cpp:9: undefined reference to `soplex::SoPlex::~SoPlex()'
collect2: error: ld returned 1 exit status
Makefile:20: recipe for target 'kea' failed
make: *** [kea] Error 1

由于创建了所有 .o 文件,我尝试手动编译: g++ -g -std=c++0x -O3 -I ../../lib/soplex-3.0.0/src/ -Wall -Werror=return-type -pg -ggdb -L/home/diego/Projects/kea-landscape-tool/../../lib/soplex-3.0.0/lib/ -lsoplex -lz -lgmp -o bin/kea-core src/core/main.o src/core/ecircuit.o src/core/solver_soplex.o 它失败并出现同样的错误。

然后我尝试像这样切换-L-l.. 标志的位置,它编译为:g++ -g -std=c++0x -O3 -I ../../lib/soplex-3.0.0/src/ -Wall -Werror=return-type -pg -ggdb -o bin/kea-core src/core/main.o src/core/ecircuit.o src/core/solver_soplex.o -L/home/diego/Projects/kea-landscape-tool/../../lib/soplex-3.0.0/lib/ -lsoplex -lz -lgmp

见状,我尝试将Makefile中的规则改成如下:

kea : $(OBJS)
    $(CC) $(CPPFLAGS) -o bin/kea-core $(OBJS) $(LIBS)

但它只是惨遭失败,在 soplex.cpp 内触发了大约 100 个错误(例如,它依赖于 -lgmp 和 -lz,但它找不到它们?粘贴在这里太长了)

我很困惑,知道如何解决这个问题吗? 谢谢。

【问题讨论】:

【参考方案1】:

尝试将 $LIBS 放在命令的末尾。


改变这个:

LIBS = -L $(SOPLEXPATH) -lz -lgmp -lsoplex

进入这个:

LIBS = -L $(SOPLEXPATH) -lsoplex -lgmp -lz

如果 A 调用 B 中的函数,则始终需要将 B 放在 A 之后。至少使用静态库。

【讨论】:

谢谢!效果很好!你的解释很有道理。我还可以问:只有一个规则 kea: $(OBJS) 和上面指定的 libs 有什么区别,和添加另一个规则 %.o : %.c 和 body $(CC) $(CPPFLAGS) $(LIBS) -o bin/kea-core $(OBJS) 有什么区别?我在其他地方看到过这种规则,但我不确定为什么要这样做。再次感谢! (现在我修复了 LIBS,两者似乎都可以工作,但不知道有什么区别) %.o : %.c 规则告诉“make”如何将 C 源文件编译成目标文件。 Make 默认有这样的规则,所以你不需要给它,除非你需要在那里做一些特别的事情。请注意,默认规则在其编译规则中使用 C_FLAGS 或类似的东西,因此设置标志不是制定自定义规则的借口。我已经看到它用于确定目标文件的写入位置。

以上是关于与 Makefile 混淆似乎链接但我无法调用的库的主要内容,如果未能解决你的问题,请参考以下文章

Makefile 在运行时无法链接库

无法在makefile中调用bash函数

Makefile 链接静态库

将应用程序与包含另一个库的库链接

使用特定链接器进行CMake交叉编译不会将参数传递给armlink

与泛型、接口和扩展混淆