【发布时间】:2020-11-20 17:22:23
【问题描述】:
我是 C++ 新手,我无法理解 Makefile 如何使用 g++ 编译器完成它们的工作。
我已经成功安装了犰狳库(通过apt)并有一个非常简单的c++程序test.cpp,如下所示:
#include <iostream>
#include <armadillo>
using namespace std;
int main()
{
arma::mat A;
A << -1 << 2 << arma::endr
<< 3 << 5;
cout << A << endl;
arma::fmat B;
B.randu(4,5);
cout << B;
return 0;
}
如果我像这样手动编译,这会很好:
g++ src/test.cpp -std=c++11 -Wall -o test -DARMA_DONT_USE_WRAPPER -lopenblas -llapack
我可以手动运行程序,它会按预期提供矩阵。
另一方面,我有来自 VSCode C/C++ 扩展的 Makefile 模板,我稍微修改了它以包含 LAPACK 和 BLAS Fortran 库:
########################################################################
####################### Makefile Template ##############################
########################################################################
# Compiler settings - Can be customized.
CC = g++
CXXFLAGS = -std=c++11 -Wall
LDFLAGS = -DARMA_DONT_USE_WRAPPER -lopenblas -llapack
# Makefile settings - Can be customized.
APPNAME = test
EXT = .cpp
SRCDIR = src
OBJDIR = obj
############## Do not change anything from here downwards! #############
SRC = $(wildcard $(SRCDIR)/*$(EXT))
OBJ = $(SRC:$(SRCDIR)/%$(EXT)=$(OBJDIR)/%.o)
DEP = $(OBJ:$(OBJDIR)/%.o=%.d)
# UNIX-based OS variables & settings
RM = rm
DELOBJ = $(OBJ)
# Windows OS variables & settings
DEL = del
EXE = .exe
WDELOBJ = $(SRC:$(SRCDIR)/%$(EXT)=$(OBJDIR)\\%.o)
########################################################################
####################### Targets beginning here #########################
########################################################################
all: $(APPNAME)
# Builds the app
$(APPNAME): $(OBJ)
$(CC) $(CXXFLAGS) -o $@ $^ $(LDFLAGS)
# Creates the dependecy rules
%.d: $(SRCDIR)/%$(EXT)
@$(CPP) $(CFLAGS) $< -MM -MT $(@:%.d=$(OBJDIR)/%.o) >$@
# Includes all .h files
-include $(DEP)
# Building rule for .o files and its .c/.cpp in combination with all .h
$(OBJDIR)/%.o: $(SRCDIR)/%$(EXT)
$(CC) $(CXXFLAGS) -o $@ -c $<
################### Cleaning rules for Unix-based OS ###################
# Cleans complete project
.PHONY: clean
clean:
$(RM) $(DELOBJ) $(DEP) $(APPNAME)
# Cleans only all files with the extension .d
.PHONY: cleandep
cleandep:
$(RM) $(DEP)
#################### Cleaning rules for Windows OS #####################
# Cleans complete project
.PHONY: cleanw
cleanw:
$(DEL) $(WDELOBJ) $(DEP) $(APPNAME)$(EXE)
# Cleans only all files with the extension .d
.PHONY: cleandepw
cleandepw:
$(DEL) $(DEP)
我已通过LDFLAGS = -DARMA_DONT_USE_WRAPPER -lopenblas -llapack 下所需的库。然而,这个解决方案不起作用。在我看来,编译器无法找到犰狳库,所以我一定是错误地链接了它。它提供:
g++ -std=c++11 -Wall -o test obj/test.o -DARMA_DONT_USE_WRAPPER -lopenblas -llapack
/usr/bin/ld: obj/test.o: in function `TLS wrapper function for arma::arma_rng_cxx11_instance':
test.cpp:(.text._ZTWN4arma23arma_rng_cxx11_instanceE[_ZTWN4arma23arma_rng_cxx11_instanceE]+0x25): undefined reference to `arma::arma_rng_cxx11_instance'
collect2: error: ld returned 1 exit status
make: *** [Makefile:36: test] Error 1
所以,除了显而易见的问题(为什么这不起作用?),如果有人能帮助我澄清以下方面,我将不胜感激:
一方面,从消息错误看来,命令运行g++ -std=c++11 -Wall -o test obj/test.o -DARMA_DONT_USE_WRAPPER -lopenblas -llapack 不包括我编写的cpp 文件的名称(而不是在我的手动编译中,它在其中工作)。不过,如果我不使用犰狳,上面的 Makefile 配方就可以了。我看到 Makefile 以某种方式在源代码文件夹 SRC = $(wildcard $(SRCDIR)/*$(EXT)) 中查找所有 cpp 文件,但我看不到它在哪里转发给编译器。有人可以帮我吗?
另一件事是,在我的手动编译中,将 LAPACK 和 BLAS 库作为CXXFLAGS 或LDFLAGS 传递似乎没有什么区别,这意味着以下两个命令:
g++ src/test.cpp -std=c++11 -Wall -DARMA_DONT_USE_WRAPPER -lopenblas -llapack -o test
和
g++ src/test.cpp -std=c++11 -Wall -o test -DARMA_DONT_USE_WRAPPER -lopenblas -llapack
工作得很好。据我所知,我理解-o 之前的标志用于编译器,之后的标志用于“链接器”(无论是什么)。有人能解释一下CXXFLAGS 和LDFLAGS 之间的主要区别是什么吗?为什么这两种组合都有效?什么是链接器?
非常感谢您的帮助。
最好的,
D.
【问题讨论】:
标签: c++ c++11 makefile armadillo