Makefile中的一些小知识点,及常用的makefile举例

编译驱动 xxx.ko 的Makefile,同时也编译出应用程序:


# 1. 使用不同的开发板内核时, 一定要修改KERN_DIR
# 2. KERN_DIR中的内核要事先配置、编译, 为了能编译内核, 要先设置下列环境变量:
# 2.1 ARCH,          比如: export ARCH=arm64
# 2.2 CROSS_COMPILE, 比如: export CROSS_COMPILE=aarch64-linux-gnu-
# 2.3 PATH,          比如: export PATH=$PATH:/home/book/100ask_roc-rk3399-pc/ToolChain-6.3.1/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin 
# 注意: 不同的开发板不同的编译器上述3个环境变量不一定相同,
#       请参考各开发板的高级用户使用手册

KERN_DIR = /home/book/100ask_imx6ull-qemu/linux-4.9.88

all:
	make -C $(KERN_DIR) M=`pwd` modules 
	$(CROSS_COMPILE)gcc -o icm20608App icm20608App.c

clean:
	make -C $(KERN_DIR) M=`pwd` modules clean
	rm -rf modules.order
	rm -f icm20608App

# 参考内核源码drivers/char/ipmi/Makefile
# 要想把a.c, b.c编译成ab.ko, 可以这样指定:
# ab-y := a.o b.o
# obj-m += ab.o

# leddrv.c board_demo.c 编译成 100ask.ko
xcl_spi-y := spi_drv.o 
obj-m	+= xcl_spi.o

一、gcc -s(注意是小写的s)命令是什么意思?为什么用此命令编译后的程序比用优化后的程序还小?

这个参数会把符号表从最终的可执行文件中删除。没有符号表,你就不能用gdb调试了,常见的用法是:
比方说你的程序由 1.c 2.c 3.c 组成,那么你编译的时候应该是这样的
gcc -g -c 1.c
gcc -g -c 2.c
gcc -g -c 3.c
然后链接成可执行文件
gcc -o test 1.o 2.o 3.o
此时生成的 test 是可以用gdb来调试的,因为它包括了符号表等调试信息。
但是如果你用
gcc -s -o test_s 1.o 2.o 3.o
生成的 test_s 就不能调试了,因为-s参数把符号表等信息都从可执行文件中去除了。
此时你比较一下 test 和 test_s ,虽然功能是完全一样的,但是 test_s 的尺寸要小很多,就是因为符号表被去除的原因。

二、编译链接库: -lz -lrt -lm -lc都是什么库

lz 压缩库(Z)
lrt 实时库(real time):shm_open系列
lm 数学库(math)
lc 标准C库(C lib)

三、-I”(大写i),“-L”(大写l),“-l”(小写l)等参数

-I /home/hello/include表示将/home/hello/include目录作为第一个寻找头文件的目录。

-I (大写的i)参数是用来指定头文件目录,/usr/include目录一般是不用指定的,gcc知道去那里找,但是如果头文件不在/usr/include里我们就要用-I参数指定了,比如头文件放在/myinclude目录里,那编译命令行就要加上-I /myinclude参数了,如果不加你会得到一个"xxxx.h: No such file or directory"的错误。-I参数可以用相对路径,比如头文件在当前目录,可以用-I.来指定

-L /home/hello/lib表示将/home/hello/lib目录作为第一个寻找库文件的目录,寻找的顺序是:/home/hello/lib–>/lib–>/usr/lib–>/usr/local/lib

-lsgd表示在上面的lib的路径中寻找libsgd.so动态库文件(如果gcc编译选项中加入了“-static”表示寻找libsgd.a静态库文件),程序链接的库名是sgd,很容易看出,把库文件名的头lib和尾.so去掉就是库名了。

四、一些实用编译选项

Makefile中的一些小知识点,及常用的makefile举例_第1张图片

五、makefile中的notdir,wildcard和patsubst

1、makefile里的函数

makefile里的函数使用,和取变量的值类似,是以一个‘$’开始,然后是一个括号里面是函数名和需要的参数列表,多个变量用逗号隔开,像这样

return = $(functionname arg1,arg2,arg3…)。

可能这里的’$'更像是从某个地址取值类似的操作。

2、 wildcard

使用:SRC = $(wildcard .c ./foo/.c)

搜索当前目录及./foo/下所有以.c结尾的文件,生成一个以空格间隔的文件名列表,并赋值给SRC.当前目录文件只有文件名,子目录下的文件名包含路径信息,比如./foor/bar.c。

3、notdir

使用:SRC = $(notdir wildcard)

去除所有的目录信息,SRC里的文件名列表将只有文件名。
如:./src/mytest.c, 通过notdir之后得到 mytest.c

4、patsubst

使用:OBJ = $(patsubst %.c %.o $(SRC))

patsubst是patten substitude的缩写,匹配替代的意思。这句是在SRC中找到所有.c 结尾的文件,然后把所有的.c换成.o。

5、join

示例 1:
$(join a b , .c .o)

返回值为:“a.c b.o”。
示例 2:
$(join a b c , .c .o)
返回值为:“a.c b.o c”。

6、应用举例
#Makefile

LIBSO:= libskf.so
LIBA := libskf.a

CC = gcc
PP = g++
AR = ar #AR 归档维护程序的名称,默认值为 ar。
CFLAG = -c -g -fPIC -O3  

#选项-c告诉gcc对源文件进行编译汇编,但不进行链接。此时,将生成目标文件,如果没有指定输出文件,就生成同名的.o文件。

SRC_DIR = .

SRCS = $(notdir $(wildcard $(SRC_DIR)/*.c))
OBJS = $(patsubst %.c, %.o, $(SRCS))
OBJN = *.o

%.o: $(join $(SRC_DIR)/, %.c) 
	$(CC) $(CFLAG) $< -o $@     
	# $@:目标文件,$^:所有的依赖文件,$<:第一个依赖文件

all: 	$(OBJS)
	$(PP) -std=c++11 $(CFLAG) CalcMac.cpp GMStruct.cpp Manager.cpp skf.cpp
	$(PP) --share -s -fPIC -lrt -lpthread -o $(LIBSO) $(OBJN) #编译动态库
	$(AR) -r $(LIBA) $(OBJN) #编译静态库
	@echo ".......... OK"
	
	
install:
	cp *.so ../testTool/lib/

clean:
	rm -f *.o
	rm -f *.a
	rm -f *.so

备注:生成静态库

ar 命令是用来将若干 .o 文件打包成(静态)库文件。 按照习惯,库文件后缀名都是 .a
crv 分别是 ar 命令的三个参数,cr的意思是创建指定.a文件(如果不存在),并将.o文件加入到这个.a文件中。 v 的意思是让 ar 命令在执行的时候打印更多的提示信息。
ar crv abc.a $(OBJ) 就是将 abc.o 打包到库文件 abc.a 中的意思。

六、常用Makefile举例

使用Makefile编译代码时需要有一个良好的目录结构,一般头文件放在include目录,库文件放在lib目录,生成的可执行文件放在bin目录,源文件放在src目录。

(1)编译库文件的makefile

ifeq ($(DEBUG),Enable)     # make DEBUG=Enable 会执行该选项    
	CPPFLAGS = -D_DEBUG -g -Wall
else
	CPPFLAGS = -s 
endif 

INCS=-I../include 
LIBS=../lib
OUTDIR=../bin
TARGET=libNSTV-SGD.so
so:
	g++ $(CPPFLAGS) $(INCS) -fPIC -shared Session.cpp Device.cpp Manager.cpp CardManage.cpp NSTV-SGD.cpp -L$(LIBS) -lm -lrt -lpthread -ldl -o $(OUTDIR)/$(TARGET)

all: so

clean:
	rm 	$(OUTDIR)/$(TARGET)

(2)一般使用的Makefile

ifeq ($(DEBUG),Enable)
	CPPFLAGS = -D_DEBUG -g -Wall
else
	CPPFLAGS = -s 
endif 

INCS=-I./include 
LIBS=./lib
OUTDIR=./bin
TARGET=NSTV-Test

exe:
	#gcc $(CPPFLAGS) $(INCS)  functest.c  scriptnucs.c  -L$(LIBS) -lNSTV-SGD -lm -lrt -lpthread -ldl -o $(OUTDIR)/$(TARGET)
	gcc  $(CPPFLAGS) $(INCS) ./*.c   -L$(LIBS)  -lNSTV-SGD  -lm -lrt -lpthread -ldl -o $(OUTDIR)/$(TARGET)

all: exe

clean:
	rm 	$(OUTDIR)/$(TARGET)

(3)稍复杂的Makefile - 同时编译出两个可执行文件

CPPFLAGS = -s 

INCS=-I./include 
OUTDIR=./
LIBS=-L ./

DEPENDENCY = -lpthread

# 渔翁
TARGET_NUCS=nucs-test
DEPENDENCY_NUCS = -lm -lpthread -lnucs

# 国芯
TARGET_GUOXIN=guoxin-test
DEPENDENCY_GUOXIN = -lguoxin

exe:
	@echo -e "\n\033[32;1m Building $(TARGET_NUCS) ...\033[0m\n" #输出一些打印,显示正在编译的目标,带颜色
	gcc $(CPPFLAGS) $(INCS) $(LIBS) -DNUCS\  #可以在Makefile里边进行宏定义
    cs-test.c sunray_test.c util.c \
    function_test.c device_management_api_test.c key_management_api_test.c \
    key_func_test.c asymm_func_test.c symm_func_test.c hash_func_test.c user_file_test.c \
    performance_test.c PerformanceTest.c \
    AutoTest.c  \
    exceptional_test.c  \
    $(DEPENDENCY_NUCS) $(DEPENDENCY) -o $(OUTDIR)/$(TARGET_NUCS)

	@echo
	@ls -lht $(OUTDIR)/$(TARGET_NUCS)  #显示当前目录所有文件大小的命令ls -lht
	@echo
   
    
	@echo -e "\n\033[32;1m Building $(TARGET_GUOXIN) ...\033[0m\n"
	gcc $(CPPFLAGS) $(INCS) $(LIBS) -DGUOXIN \
    cs-test.c sunray_test.c util.c \
    function_test.c device_management_api_test.c key_management_api_test.c \
    key_func_test.c asymm_func_test.c symm_func_test.c hash_func_test.c user_file_test.c \
    performance_test.c PerformanceTest.c \
    AutoTest.c  \
    exceptional_test.c  \
    $(DEPENDENCY_GUOXIN)  $(DEPENDENCY) -o $(OUTDIR)/$(TARGET_GUOXIN)

	@echo
	@ls -lht $(OUTDIR)/$(TARGET_GUOXIN)
	@echo
    
all: exe

clean:
	@rm -f $(OUTDIR)/$(TARGET_NUCS) $(OUTDIR)/$(TARGET_GUOXIN)

(4)编译驱动的Makefile - 暂时未用到,待研究 参考驱动Makefile

 
DRV_CCP903H = 1
DRV_SDF = 1

KERNELDIR=/lib/modules/$(shell uname -r)/build     #内核目录,适用于PC机开发
TARGET := NSTV_CRYPTO
obj-m = $(TARGET).o     # 表示将我们的NSTV_CRYPTO.o编译成一个模块
ccflags-y := -std=gnu99 -Wno-declaration-after-statement
$(TARGET)-objs = jr.o  ccp903_sec.o job.o ccp903_cards.o compate_interface.o ccp903_common.o nsec_cdev.o nsec_operation.o

ifdef DRV_CCP903H
EXTRA_CFLAGS += -DDRV_CCP903H
endif

ifdef DRV_SDF
EXTRA_CFLAGS += -DBAR_CONFIG_IN_COS
endif

INC := -I/$(PWD)/INCLUDE

all:
	#cp ../CCP903_SEC_CORE/job_core.a $(shell pwd)
	#cp ../CCP903_SEC_CORE/Module.symvers $(shell pwd)
	make -C  $(KERNELDIR)  M=$(shell pwd)  $(INC)  modules
	#make -C /lib/modules/4.15.0-041500-generic/build M=$(shell pwd) $(INC) modules
	#make -C $(KERNEL_SRC) M=$(shell pwd) $(INC) modules  
	#make -C /home/zjjin/work/ccfc9000ta/linux-3.4.106.ccore.r1 M=$(shell pwd) modules ARCH=powerpc
clean: 
	rm -rf *.a *.o *.ko *.mod.c *.mod.o modules.* Mod* 


(5)根据不同平台,编译不同代码

## 2021-05-08 sunray 明确编译环境
## x86_64: GCC 4.8.3
## mips64: GCC 4.9.3

SHELL = /bin/bash

KERNEL_VERSION = $(shell uname -srvmpio)
OS_VERSION = $(shell grep ^PRETTY_NAME /etc/os-release | cut -d'"' -f2)
ARCH = $(shell uname -m)
GCC_VERSION = $(shell gcc --version | grep ^gcc)

INCS = -I./ -I../../include -I./include
# libcryptopp.a 目录
LIBS = ./lib
OUTDIR = ../../lib/linux-$(ARCH)

LIBNAME_NUCS  = libnucs.so
LIBNAME_NUCSA = libnucsa.so

## sunray 2021-01-28 完善 soname
## 定义 SDK 的 Linux 标准版本号 以及 so 文件的 soname
MAJOR_VERSION   = 2
MINOR_VERSION   = 0
RELEASE_VERSION = 0
CODE_NAME       = kite
RELEASE_DATE    = $(shell date +"%y%m")

SONAME_NUCS  = $(LIBNAME_NUCS).$(MAJOR_VERSION)
SONAME_NUCSA = $(LIBNAME_NUCSA).$(MAJOR_VERSION)

TARGET_NUCS  = $(SONAME_NUCS).$(MINOR_VERSION).$(RELEASE_VERSION).$(ARCH)
TARGET_NUCSA = $(SONAME_NUCSA).$(MINOR_VERSION).$(RELEASE_VERSION).$(ARCH)

SPECIFY_NUCS_SONAME  = -Wl,-e,__lib_main,-soname,$(SONAME_NUCS)
SPECIFY_NUCSA_SONAME = -Wl,-e,__lib_main,-soname,$(SONAME_NUCSA)

PLATFORM_MACRO  = -DGM_SDF_EXPORTS
#PLATFORM_MACRO += -DKERNEL_VERSION="\"$(KERNEL_VERSION)\""
PLATFORM_MACRO += -DOS_VERSION="\"$(OS_VERSION)\""
PLATFORM_MACRO += -DGCC_VERSION="\"$(GCC_VERSION)\""

# NUCS NUCSA 两个宏用于控制条件编译 nucs.cpp 中的代码
VERSION_MACRO_NUCS  = $(PLATFORM_MACRO) -DVERSION="\"$(TARGET_NUCS)\""  -DSONAME="\"$(SONAME_NUCS)\""  -DNUCS
VERSION_MACRO_NUCSA = $(PLATFORM_MACRO) -DVERSION="\"$(TARGET_NUCSA)\"" -DSONAME="\"$(SONAME_NUCSA)\"" -DNUCSA

## libcryptopp.a 静态连接
## libpthread.so 动态连接,NUCS SDK 需要创建线程
DEPENDENCY = -lcryptopp -lpthread

## 2021-05-08 sunray,设置缺省的函数状态为隐藏
#CPPFLAGS = -g -rdynamic
CPPFLAGS = -s -O3
CPPFLAGS += -std=c++11 -fvisibility=hidden

so:
	@echo -e "\n\033[35;1m Building $(TARGET_NUCS) ...\033[0m\n"

	g++ $(CPPFLAGS) -fPIC -shared \
    $(SPECIFY_NUCS_SONAME) \
    $(VERSION_MACRO_NUCS) \
    $(INCS) -L$(LIBS) \
    nucs.cpp nucs_error.cpp Manager.cpp CommContext.cpp GCM_Aes.cpp SecretKeyMoudle.cpp \
    stvos/stvos.cpp stvlog/stvlog.cpp \
    sm/sm2_util.c sm/sm2.c sm/sm2_sign.c sm/sm2_enc.c sm/sm3.c sm/sm4.c \
    polarssl/bignum.c polarssl/ecp.c polarssl/ecp_curves.c \
    polarssl/md.c polarssl/hmac_drbg.c polarssl/md_wrap.c polarssl/sha256.c \
    $(DEPENDENCY) \
    -o $(OUTDIR)/$(TARGET_NUCS)
    
	@echo -e "\033[35;1m\n"

	@ls -lht $(OUTDIR)/$(TARGET_NUCS)

	@echo -e "\033[0m\n"

	@echo -e "\n\033[35;1m Building $(TARGET_NUCSA) ...\033[0m\n"

	g++ $(CPPFLAGS) -fPIC -shared \
    $(SPECIFY_NUCSA_SONAME) \
    $(VERSION_MACRO_NUCSA) \
    $(INCS) -L$(LIBS) \
    nucs.cpp nucs_error.cpp Manager.cpp CommContext.cpp GCM_Aes.cpp SecretKeyMoudle.cpp \
    stvos/stvos.cpp stvlog/stvlog.cpp \
    sm/sm2_util.c sm/sm2.c sm/sm2_sign.c sm/sm2_enc.c sm/sm3.c sm/sm4.c \
    polarssl/bignum.c polarssl/ecp.c polarssl/ecp_curves.c \
    polarssl/md.c polarssl/hmac_drbg.c polarssl/md_wrap.c polarssl/sha256.c \
    $(DEPENDENCY) \
    -o $(OUTDIR)/$(TARGET_NUCSA)
  
	@echo -e "\033[35;1m\n"

	@ls -lht $(OUTDIR)/$(TARGET_NUCSA)
	@echo -e "\033[0m\n"

all: so

clean:
	@rm -rf	$(LIBS)/$(TARGET_NUCS) $(LIBS)/$(TARGET_NUCSA)

(6)传说中的万能Makefile(没有验证过)

########################################################### 
# Generic makefile  
#  
# by George Foot  
# email: george.foot@merton.ox.ac.uk  
#  
# Copyright (c) 1997 George Foot  
# All rights reserved.  
# 保留所有版權  
#  
# No warranty, no liability;  
# you use this at your own risk.  
# 沒保險,不負責  
# 你要用這個,你自己擔風險  
#  
# You are free to modify and  
# distribute this without giving  
# credit to the original author.  
# 你可以隨便更改和散發這個文件  
# 而不需要給原作者什榮譽。  
# (你好意思?)  
#  
###################################### 

### Customising 
# 
# Adjust the following if necessary; EXECUTABLE is the target 
# executable's filename, and LIBS is a list of libraries to link in 
# (e.g. alleg, stdcx, iostr, etc). You can override these on make's 
# command line of course, if you prefer to do it that way. 
#  
# 如果需要,調整下面的東西。 EXECUTABLE 是目標的可執行文件名, LIBS 
# 是一個需要連接的程序包列表(例如 alleg, stdcx, iostr 等等)。當然你 
# 可以在 make 的命令行覆蓋它們,你願意就沒問題。 
#  

EXECUTABLE := mushroom.exe 
LIBS := alleg 

# Now alter any implicit rules' variables if you like, e.g.: 
# 
# 現在來改變任何你想改動的隱含規則中的變量,例如 

CFLAGS := -g -Wall -O3 -m486 
CXXFLAGS := $(CFLAGS) 

# The next bit checks to see whether rm is in your djgpp bin 
# directory; if not it uses del instead, but this can cause (harmless) 
# `File not found' error messages. If you are not using DOS at all, 
# set the variable to something which will unquestioningly remove 
# files. 
# 
# 下面先檢查你的 djgpp 命令目錄下有沒有 rm 命令,如果沒有,我們使用 
# del 命令來代替,但有可能給我們 'File not found' 這個錯誤信息,這沒 
# 什大礙。如果你不是用 DOS ,把它設定成一個刪文件而不廢話的命令。 
# (其實這一步在 UNIX 類的系統上是多余的,只是方便 DOS 用戶。 UNIX 
# 用戶可以刪除這5行命令。) 

ifneq ($(wildcard $(DJDIR)/bin/rm.exe),) 
RM-F := rm -f 
else 
RM-F := del 
endif 

# You shouldn't need to change anything below this point. 
# 
# 從這裡開始,你應該不需要改動任何東西。(我是不太相信,太NB了!) 

SOURCE := $(wildcard *.c) $(wildcard *.cc) 
OBJS := $(patsubst %.c,%.o,$(patsubst %.cc,%.o,$(SOURCE))) 
DEPS := $(patsubst %.o,%.d,$(OBJS)) 
MISSING_DEPS := $(filter-out $(wildcard $(DEPS)),$(DEPS)) 
MISSING_DEPS_SOURCES := $(wildcard $(patsubst %.d,%.c,$(MISSING_DEPS)) \ 
$(patsubst %.d,%.cc,$(MISSING_DEPS))) 
CPPFLAGS += -MD 

.PHONY : everything deps objs clean veryclean rebuild 

everything : $(EXECUTABLE) 

deps : $(DEPS) 

objs : $(OBJS) 

clean : 
  @$(RM-F) *.o 
  @$(RM-F) *.d 

veryclean: clean 
  @$(RM-F) $(EXECUTABLE) 

rebuild: veryclean everything 

ifneq ($(MISSING_DEPS),) 
$(MISSING_DEPS) : 
  @$(RM-F) $(patsubst %.d,%.o,$@) 
endif 

-include $(DEPS) 

$(EXECUTABLE) : $(OBJS) 
  gcc -o $(EXECUTABLE) $(OBJS) $(addprefix -l,$(LIBS)) 
###

你可能感兴趣的:(Linux,杂记,c++,linux,c语言)