编译驱动 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
这个参数会把符号表从最终的可执行文件中删除。没有符号表,你就不能用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 压缩库(Z)
lrt 实时库(real time):shm_open系列
lm 数学库(math)
lc 标准C库(C lib)
-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里的函数使用,和取变量的值类似,是以一个‘$’开始,然后是一个括号里面是函数名和需要的参数列表,多个变量用逗号隔开,像这样
return = $(functionname arg1,arg2,arg3…)。
可能这里的’$'更像是从某个地址取值类似的操作。
使用:SRC = $(wildcard .c ./foo/.c)
搜索当前目录及./foo/下所有以.c结尾的文件,生成一个以空格间隔的文件名列表,并赋值给SRC.当前目录文件只有文件名,子目录下的文件名包含路径信息,比如./foor/bar.c。
使用:SRC = $(notdir wildcard)
去除所有的目录信息,SRC里的文件名列表将只有文件名。
如:./src/mytest.c, 通过notdir之后得到 mytest.c
使用:OBJ = $(patsubst %.c %.o $(SRC))
patsubst是patten substitude的缩写,匹配替代的意思。这句是在SRC中找到所有.c 结尾的文件,然后把所有的.c换成.o。
示例 1:
$(join a b , .c .o)
返回值为:“a.c b.o”。
示例 2:
$(join a b c , .c .o)
返回值为:“a.c b.o c”。
#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编译代码时需要有一个良好的目录结构,一般头文件放在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))
###