|
点击上方“C语言与CPP编程”,选择“关注/置顶/星标公众号”& C4 E# d/ s2 o6 ]( h# n; t
干货福利,第一时间送达!
% @: }5 C9 F$ \6 A3 i* Y! Q! ?1 {. r2 C
gz01dij4rxx64015579530.png
( a2 x2 K% o) V+ `( F. _
最近有小伙伴说没有收到当天的文章推送,这是因为微信改了推送机制,有一部分小伙伴刷不到当天的文章,一些比较实用的知识和信息,错过了就是错过了,建议大家加个星标??,就能第一时间收到推送。
. Q) |1 Y3 O d7 w- a+ P/ {
vzjwxdkqels64015579630.png
5 Y/ l5 S% ^# B8 T0 g
写在前面对于Windows下开发,很多IDE都集成了编译器,如Visual Studio,提供了“一键编译”,编码完成后只需一个操作即可完成编译、链接、生成目标文件。% m% u9 c1 Q$ n8 n
Linux开发与Windows不同,Linux下一般用的的gcc/g++编译器,如果是开发ARM下的Linux程序,还需用到arm-linux-gcc/arm-linux-g++交叉编译器。
7 u6 n8 [) J% l* w6 i2 k2 dLinux下也可以实现“一键编译”功能,此时需要一个编译脚本“Makefile”,Makefile可以手动编写,也可以借助自动化构建工具(如scons、CMake)生成。手动编写Makefile是Linux和Windows程序员的区别之一,一般地一个通用的Makefile能够适合大部分Linux项目程序。
! |/ l% P( e% \1 ?3 {, s# |7 I3个Makefile模板2.1 编译可执行文件MakefileVERSION =1.000 w: {1 |: W& \- a
CC =gcc
' a' y& N! B v6 gDEBUG =-DUSE_DEBUG$ }7 x6 `0 Q" t# p2 ?) S" i
CFLAGS =-Wall3 l+ L/ K7 ]- A, n+ m8 z! C
SOURCES =$(wildcard ./source/*.c)2 s* ]9 `; @ y( J$ L0 X
INCLUDES =-I./include
n$ j4 y- Q9 a/ p. E$ D) Y( h+ a8 LLIB_NAMES =-lfun_a -lfun_so
' G9 A! A) S$ o6 s$ i$ F. X& D& fLIB_PATH =-L./lib) q) z) O" \. \. U; }9 V, J) K" ~
OBJ =$(patsubst %.c, %.o, $(SOURCES))2 ?+ J8 x4 `" I* d
TARGET =app
3 |1 s, ]# F4 y; I6 F7 g#links# F& v* b; `- [' X/ A3 @
$(TARGET):$(OBJ)
7 U: w# `5 e) Y9 q( Y @mkdir -p output$ T; `% b; Y' F+ A% t3 s7 a
$(CC) $(OBJ) $(LIB_PATH) $(LIB_NAMES) -o output/$(TARGET)$(VERSION)
( k, C3 e( o, G- v; O @rm -rf $(OBJ)( `* M& W) S) h* t3 N
( ]$ u. {6 S. Z' J9 Y8 f) n- |#compile
. W; l. q: `" H3 z%.o: %.c: k; c! s2 @' c4 `9 D: m4 }/ y
$(CC) $(INCLUDES) $(DEBUG) -c $(CFLAGS) $ -o $@7 Z) R% n) Q. m9 f5 `" ?: P2 E
.PHONY:clean
' k. C6 A$ k% J$ lclean:3 C3 d! r3 h3 f* D$ H2 U
@echo "Remove linked and compiled files......"
) f) y) h0 _. o/ N rm -rf $(OBJ) $(TARGET) output % D- r2 z3 [3 q) @7 n C D
【要点说明】: Y4 ~3 n. o. `: a# ]- D& e; G N
【1】程序版本. w4 u- q c: Q7 }+ {2 t
开发调试过程可能产生多个程序版本,可以在目标文件后(前)增加版本号标识。" g U! g. O0 r7 ]
VERSION = 1.00
# H) ~& \3 Z. C/ x1 e7 n$(CC) $(OBJ) $(LIB_PATH) $(LIB_NAMES) -o output/$(TARGET)$(VERSION)& k; l" m8 c, n5 _9 N
【2】编译器选择0 l4 K# l# P: T' N
Linux下为gcc/g++;arm下为arm-linux-gcc;不同CPU厂商提供的定制交叉编译器名称可能不同,如Hisilicon“arm-hisiv300-linux-gcc”。
. H* _; L- Z% K8 ]* E) ^5 N9 JCC = gcc
0 a5 v6 T1 C! }【3】宏定义1 C, E% @8 _$ T' Q
开发过程,特殊代码一般增加宏条件来选择是否编译,如调试打印输出代码。-D是标识,后面接着的是“宏”。8 w g- U' F5 m) K0 \& J
DEBUG =-DUSE_DEBUG
" \! D. W5 U4 `, i3 S9 W【4】编译选项# N6 h6 u( \/ @
可以指定编译条件,如显示警告(-Wall),优化等级(-O)。
9 O, f1 [5 t7 Z2 H1 V. f. }2 w% {CFLAGS =-Wall -O
* |, y6 B; f: W" i3 ^+ Z6 @) I【5】源文件
! X$ u5 c' ~. o% ~/ G$ r7 {指定源文件目的路径,利用“wildcard”获取路径下所有依赖源文件。
# g- ]. r& l6 \7 p( @( z+ bSOURCES =$(wildcard ./source/*.c)& M9 H/ Z6 u2 O1 A' |
【6】头文件
9 b) c9 ~3 h: N5 t4 }包含依赖的头文件,包括源码文件和库文件的头文件。 z; E/ E- ~7 F4 x# g8 w# X6 h
INCLUDES =-I./include: `8 L, A$ v) {* o/ y8 ~+ d+ p
【7】库文件名称: j( z9 K# D, X. E0 B& A+ g- k
指定库文件名称,库文件有固定格式,静态库为libxxx.a;动态库为libxxx.so,指定库文件名称只需写“xxx”部分,
4 y W. t3 U d# r5 V2 {- XLIB_NAMES =-lfun_a -lfun_so
/ Y0 a9 k: v/ g2 `3 I, f5 L【8】库文件路径- ~% w' e8 Q, r
指定依赖库文件的存放路径。注意如果引用的是动态库,动态库也许拷贝到“/lib”或者“/usr/lib”目录下,执行应用程序时,系统默认在该文件下索引动态库。
! A7 n* P% F" zLIB_PATH =-L./lib, S2 `/ [% S+ R# j
【9】目标文件
/ e/ S7 [8 A/ ]6 ^0 f! Z调用“patsubst”将源文件(.c)编译为目标文件(.o)。
) r5 ^. X2 a/ b. oOBJ =$(patsubst %.c, %.o, $(SOURCES))
; W! x3 S' `. k【10】执行文件$ U+ e' j4 b9 p0 d5 ]9 D
执行文件名称
( r! r. L3 _( H+ ATARGET =app
4 {0 ^2 K/ f6 S$ n4 t8 o; f【11】编译
& F! i# b' v# F( s, E* F%.o: %.c
* Y( t# w* B$ L) A6 I' k+ q9 a $(CC) $(INCLUDES) $(DEBUG) $(CFLAGS) $ -o $@
+ z( W! X* f' p5 Z$ N' K6 ~【12】链接
1 ~, k7 ^, C' Z2 O) `: U可创建一个“output”文件夹存放目标执行文件。链接完输出目标执行文件,可以删除编译产生的临时文件(.o)。
6 @ D% u2 q, r% p" c) }+ T2 a2 P( v$(TARGET):$(OBJ)
6 G7 R& ]2 k- O @mkdir -p output- |- s, o8 f8 q" M/ X1 f
$(CC) $(OBJ) $(LIB_PATH) $(LIB_NAMES) -o output/$(TARGET).$(VERSION)
- a8 J/ q4 d1 a8 N2 l& o @rm -rf $(OBJ)
/ l$ H: T0 {* @9 X【13】清除编译信息
$ e6 z2 n& T' Q. f+ H5 w0 S9 f执行“make clean”清除编译产生的临时文件。1 m5 c# |" B* R7 ~6 L% Y. N4 x
.PHONY:clean
6 q( {+ h/ n. z4 H2 }/ `( s8 {clean:
# h6 z: S+ f% H @echo "Remove linked and compiled files......"- J; b$ |; j; R# ]
rm -rf $(OBJ) $(TARGET) output ( Y3 ?$ H% ]5 o7 T& i1 ]% E/ y
2.2 编译静态库MakefileVERSION =' B# I1 i+ G1 C8 r" s# ?5 c3 a
CC =gcc
) @. C' n0 b. o! W" o8 NDEBUG =, Y, M2 Q4 J8 W4 s
CFLAGS =-Wall2 t0 a; U$ P; F6 A4 o
AR =ar
7 J% g# z3 B4 P3 rARFLAGS =rv
- U- B# E) `* L, t7 vSOURCES =$(wildcard *.c)
$ Y& ]) @2 a: ~, c/ m6 P" sINCLUDES =-I.
; G/ E/ o Z$ a! tLIB_NAMES =- O# y* ?9 e0 i6 j
LIB_PATH =( D0 D% e0 S4 T* z
OBJ =$(patsubst %.c, %.o, $(SOURCES))/ \# R/ X$ R+ M7 _
TARGET =libfun_a& D; y( Z1 }# n* Q7 @3 T
#link
5 u7 [4 _7 o( [& ?: A( N( z$ S$(TARGET):$(OBJ)
1 l: r( j+ r4 M7 [) P) l [7 ?9 n @mkdir -p output( V) k8 C) p/ g: _ S
$(AR) $(ARFLAGS) output/$(TARGET)$(VERSION).a $(OBJ)" k) ?( @5 `3 f
@rm -rf $(OBJ)
; l4 m) o7 {0 M3 o* R#compile$ b" j( N8 F0 c2 `# W2 J O2 [' R
%.o: %.c
3 \9 ]* _% o8 s& b2 L: u $(CC) $(INCLUDES) $(DEBUG) -c $(CFLAGS) $ -o $@
& L+ A0 E9 n3 I3 b) \' v 3 S5 [/ k0 Y9 B* ~8 A3 z8 k8 I2 R0 I
.PHONY:clean
) ]9 R: R- k7 u' U$ eclean:: t: Q( S9 y- m' ?8 c; e
@echo "Remove linked and compiled files......"1 w& f4 s+ i2 }! b) d* w
rm -rf $(OBJ) $(TARGET) output
4 u* c' l( C% B7 L5 ?: z【要点说明】7 @( p+ q/ G8 `6 Z, L) ^4 n, ]
基本格式与“编译可执行Makefile”一致,不同点包括以下。/ |3 m. D. B( v2 @% E$ W* O. q. [
【1】使用到“ar”命令将目标文件(.o)链接成静态库文件(.a)。静态库文件固定命名格式为:libxxx.a。
+ Z' J/ m8 H6 Z2.3 编译动态库MakefileVERSION =/ o6 K( O: _; ^7 Q: }( D$ Q
CC =gcc0 B; a. S2 n) S) J
DEBUG =% R8 `/ N* p3 D0 ~8 x. Y4 P5 r p
CFLAGS =-fPIC -shared
8 |, J$ P; A4 G( c$ i- a1 M; {+ D. XLFLAGS =-fPIC -shared
# Y# d* ^: U4 d: @( k0 J6 VSOURCES =$(wildcard *.c)
3 D; q6 P; s8 \# ]0 N) V# Z9 QINCLUDES =-I.4 Y; V7 I0 }6 F% ~
LIB_NAMES =
g. ^$ U- C* z0 Z# r% Q2 n GLIB_PATH =
1 L+ J* m7 K' @OBJ =$(patsubst %.c, %.o, $(SOURCES)), Z; p' @( R7 s; O( \/ \
TARGET =libfun_so1 I( i. a. z2 E$ e2 T/ s( P! w5 K
#link
5 n5 I4 f, [) m$(TARGET):$(OBJ)
2 a9 ] \: h6 s% Q. ] @mkdir -p output4 @9 z# g$ N3 c, T+ w, U
$(CC) $(OBJ) $(LIB_PATH) $(LIB_NAMES) $(LFLAGS) -o output/$(TARGET)$(VERSION).so
4 Q/ r& X& o* y, ]; T4 m8 @ @rm -rf $(OBJ)* D) \* [* T9 T$ G/ Y9 Q4 u! v# w# y
& F$ C- U. v" C/ k; Z/ f
#compile
7 `: p8 F/ G( E1 f" X7 O/ V%.o: %.c
. d$ H5 l4 @; E. J $(CC) $(INCLUDES) $(DEBUG) -c $(CFLAGS) $ -o $@; p: U! _) |) w8 e! N9 j
.PHONY:clean0 d# R; h/ {1 K' i2 W2 q
clean:
& F! k d: x. J @echo "Remove linked and compiled files......"" {: }1 i, Y# {! a; Q8 o
rm -rf $(OBJ) $(TARGET) output , P3 @8 ?, n- H5 s; w( o( X
【要点说明】3 u' l/ K7 J- O! I+ R W
基本格式与“编译可执行Makefile”一致,不同点包括以下。" U7 I# E5 D6 v: p
【1】编译选项和链接选项增加“-fPIC -shared ”选项。动态库文件固定命名格式为libxxx.so。5 ~& D& [" l R, Y6 b Y' y
Demo3.1 编译应用程序编写测试例程,文件存放目录结构如下,头文件存放在“include”目录,库文件存放在“lib”目录,源文件存放在“source”目录,Makefile在当前目录下。 |
|