引言
当下流行的IDE,将源代码生成可执行文件的过程都封装起来,对于开发着来说方便使用。
但是对于初学者来说,蒙蔽了源代码到可执行文件过程。源代码预处理,编译,打包,链接等步骤,
才能形成IDE中的一步到位的可执行文件target。而Makefile是直白的描述一个源代码如何被操作
才能成为target的一种文件格式。而CMake是一种可以通过配置的方式生成Makefile的脚本.
如果只是简单的开发一个.cpp进行测试,Makefile是首选。
本文中不对Makefile的基本语法进行介绍,要学习基本语法可以参看陈皓老师的Makefile中文教程进行学习。
Makefile
ifeq
和ifneq
之后要有个空格,否则不识别
ifeq ($(UNAME), linux)
$(info "")
else
$(warning "")
$(error $(HAVE_SSHSERVER))
endif
定义变量
HAVE_THE_VALUE :=
# 新定义一个变量
HAVE_THE_VALUE ?=
# 如果没有定义,则定义一个新变量
HAVE_THE_VALUE +=
# 往变量中append数据
这个地方有点像pascal,不要与shell中混淆了
变量赋值
后面一定不要有空格,回车之类的空白符号,否则可能会将你整疯了的。
就拿caffe中的Makefile.config中
USE_LEVELDB := 1
USE_LEVELDB := 1
这两行的区别在于,第二行赋值操作后面有一个空格。在Makefile中通过如下代码进行添加编译需要的宏。
ifeq ($(USE_LEVELDB), 1)
CXX_FLAGS += -DUSE_LEVELDB
endif
结果编译的时候打开的开关会与设想的不一样。
Makefile案例
#! Makefile
SRCS := PAPI_flops.c
OBJECTS := $(patsubst %.c, %.o, $(SRCS))
STATIC_LIB := /usr/local/lib/libpapi.a
INCLUDE_DIR := -I/usr/local/include
CC := gcc
all: PAPI_flops
PAPI_flops: $(OBJECTS)
$(CC) -O0 $< $(STATIC_LIB) -o $@
$(OBJECTS): $(SRCS)
$(CC) $(INCLUDE_DIR) -O0 -c $<
test:
echo "----Running the PAPI_flops-----"
@./PAPI_flops
clean:
rm -rf PAPI_flops
rm -rf *.o
makefile中调用.a库的编写
#!Makefile
CC = g++
TINYCV_DIR = /home/cwl/TinyCV
TINYCV_INCLUDE_DIR = $(TINYCV_DIR)/include
LIB_DIR = $(TINYCV_DIR)/build
CXX_FLAG = -O3 -std=c++11 -Wall -Werror -fPIC
all: main
main: main.o
$(CC) $< $(CXX_FLAG) -I$(TINYCV_INCLUDE_DIR) -L$(LIB_DIR) -ltinycv -o $@
main.o: main.cpp
$(CC) $(CXX_FLAG) -I$(TINYCV_INCLUDE_DIR) -c $<
clean:
rm -f *.o main
需要注意的是下面这句中$<
是指输入文件main.o,此处紧跟gcc
main: main.o
$(CC) $< $(CXX_FLAG) -I$(TINYCV_INCLUDE_DIR) -L$(LIB_DIR) -ltinycv -o $@
但是如果变为如下情形,就会出现后面中的错误
main: main.o
$(CC) $(CXX_FLAG) -I$(TINYCV_INCLUDE_DIR) -L$(LIB_DIR) -ltinycv -o $@ $<
错误:
caowenlong@Server-NF5280M3:~/Test$ make
g++ -O3 -std=c++11 -Wall -Werror -fPIC -I/home/cwl/TinyCV/include -c main.cpp
g++ -O3 -std=c++11 -Wall -Werror -fPIC -I/home/cwl/TinyCV/include -L/home/cwl/TinyCV/build -ltinycv -o main main.o
main.o:在函数‘main’中:
main.cpp:(.text.startup+0x3b):对‘tinycv::imread(std::string const&, int)’未定义的引用
main.cpp:(.text.startup+0x43):对‘tinycv::Mat<unsigned char>::Mat()’未定义的引用
main.cpp:(.text.startup+0x63):对‘double tinycv::threshold<unsigned char>(tinycv::Mat<unsigned char> const&, tinycv::Mat<unsigned char>&, double, double, int)’未定义的引用
collect2: error: ld returned 1 exit status
make: *** [main] 错误 1
makefile中的全局自变量
$@
目标文件名
@^
所有前提名,除副本
@+
所有前提名,含副本
@<
一个前提名
@?
所有新于目标文件的前提名
@*
目标文件的基名称
是否输出执行过程
#! Makefile
SAMPLE_ENABLE ?= 1
ifeq ($(SAMPLE_ENABLE), 1)
EXEC ?= @echo "[@]"
endif
target: target2
echo "hehe, this is target"
target2:
echo "this is target2"
clean:
rm -rf out.o
CMake
CMake 入门案例
PROJECT(sdk_common_samples)
cmake_minimum_required(VERSION 3.0)
# 查找已经安装的包
FIND_PACKAGE(OpenCV 2)
# SET 指令的语法是:
# SET(VAR [VALUE] [CACHE TYPE DOCSTRING [FORCE]])
SET(
SDK_COMMON_INCLUDE_D