Makefile的相关用法

 1.示例1

#Makefile
CXXFLAGS    := -O3 -g -Wall -shared std=c++11 -pthread -fPIC
CPPCOMP     := g++
CCOMP       := gcc
LINK_RPATH  := ......
#动态库.so的路径用-L指定,库的名称用-l指定,之间可以没有空格
LINKFLAGS   := -Wl,rpath=$(LINK_RPATH)/bin -L./bin -lstaticfb -lraw_fea -lconv_addnoise -lmvad -lfftw3f -lm -lcudart -lcufft

PYINCLUDE   := $(shell python -m pybind11 --includes)
#头文件的路径用-I指定,之间可以没有空格
INCLUDEPATH := $(PYINCLUDE) -I. -I./static_fb/include -I./fftw-3.2.2 -I./raw_fea -I./conv_timerand
#.a和.so共同链接成可执行二进制文件
build: pybind.o libconv_addnoise.a libfftw3f.a
    $(CPPCOMP) -o _C$(shell python3-config --extension-suffix) $(CXXFLAGS) pybind.o $(LINKFLAGS)
#编译生成.o文件
pybind.o:
    $(CPPCOMP) -c -std=c++11 -fPIC $(INCLUDEPATH) pybind.cpp
#编译生成.a静态库,需要进入conv_timerand文件夹并执行其中的Makefile
libconv_addnoise.a:
    @cd conv_timerand && make
    @cd ..

clean:
    -@rm -rf *.o
    -@cd conv_timerand && make clean

上面Makefile是上一级目录的,与他同级目录有个conv_timerand目录,其中也有一个Makefile,在上面提到会进入该文件夹并执行该文件夹下的Makefile。

conv_timerand目录最终会生成一个.a的静态库,静态库就是简单的打包所有的.o的文件,所以在.a文件中不能链接.so动态库。

.a和.so文件应该被共同链接成可执行二进制文件。

#conv_timerand/Makefile
CXXFLAGS    := -O3 -g std=c++11 -fPIC
CPPCOMP     := g++
CCOMP       := gcc
CONV_OBJ    := complextion.o conv_addnoise.o fft_1.o cufft.o

libconv_addnoise.a: $(CONV_OBJ)
    @ar -cr ../bin/libconv_addnoise.a $(CONV_OBJ)
#将cuda文件编译成.o,注意cuda编译的版本和运行版本要保持相同
$(CONV_OBJ):
    nvcc --compiler-options -fPIC -c cufft.cu -I/opt/lib/cuda-10.1/include
    $(CPPCOMP) $(CXXFLAGS) -I./conv_timerand -I../fftw-3.2.2 -c *.cpp
    $(CCOMP) $(CXXFLAGS) -I../fftw-3.2.2 -c *.cpp

clean:
    @rm -rf *.o
    @rm -rf ../bin/libconv_addnoise.a
.PHONY: clean

这个Makefile就是生成libconv_addnoise.a

2.示例2

生成.o文件之间可以没有顺序。所以SOURCE变量中当前文件夹的cpp文件和CORE文件夹的cpp文件哪一个在前都可以。

CORE = $(PWD)/core
#wildcard表示将core文件夹和当前文件夹下的所有cpp文件展开
SOURCE = $(wildcard $(CORE)/*.cpp ./*cpp)
#patsubst表示将SOURCE变量中所有.cpp结尾的文件名替换成.o结尾的文件名
OBJS = $(patsubst %.cpp, %.o, $(SOURCE))

INCLUDES = -I./core -I.

libnccf_reaper.a : $(OBJS)
    @ar -cr ../bin/libnccf_reaper.a $(OBJ)

$(OBJ) : %.o : %.cpp
    g++ -std=c++11 $(INCLUDES) -c -fPIC $< -o $@
#$@表示目标文件,$^表示所有依赖文件,$<表示第一个依赖文件
#上一条语句表示将所有的cpp文件编译成.o文件
.PHONY : clean
    rm -rf $(OBJ)
    rm ../bin/libnccf_reaper.a

3.undefined reference to错误

假如有一个main.cpp,调用了qnnorm.cpp中的qnnorm函数,qnnorm函数又调用了utils.cpp中的utils函数。调用关系如下图:

文件目录如上图左,根目录的Makefile如上图右。首先在生成main.o的文件时要注意包含头文件和qnnorm静态库文件,其次在生成main二进制文件时,要注意包含两个静态库文件(第一行),且最被依赖的文件应该放在最后(第二行),最后要注意的是生成main两个库的顺序不影响(第一行),生成main.o那一行不需要包含静态库文件,编译两个库上下顺序也不影响。

另外尤其需要注意的一个坑是make -j,如果库之间存在依赖关系,不可以使用make -j,make -j表示启动多少个线程并行编译,虽然有的文章表示不会影响依赖关系,,但是我的Makefile确实会因为这个编不过,而且make是不限制启动线程个数的意思,但是就是可以编译过,可能是和机器配置有关,这个目前还没有完全搞懂。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值