文章目录
Makefile机制规则
目标文件 : 依赖文件1 依赖文件2 …
[TAB]命令
当目标文件不存在或某个依赖文件比目标文件新时则执行指令。
(一)、通配符
$@
目标文件
$^
所有的依赖文件
$<
第一个依赖文件
(二)、PHONY假想目标
#自动检测依赖文件a.o b.o c.o日期是否比目标文件test更新,若是则执行指令编译
test : a.o b.o c.o
gcc -o test $^
#采用通配符%代表编译所有.c依赖文件并生成目标文件
%.o :%.c
gcc -c -o $@ $<
#用于make clean,清空指定文件
clean:
rm *.o test
#定义clean为假想目标(不会判断名为clean的文件是否存在),防止目录下有名为“clean”的文件时导致指令执行错误
.PHONY: clean
(三)、即时变量和延迟变量
- 即时变量:A := xxx #A的值在定义时即刻被确定
- 延迟变量:B = xxx #B的值在使用时才被确定
- 延迟变量:C ?= xxx #如果C第一次被定义则这句生效,否则忽略这句
- 附加数据 A+=xxx #它是即时/延迟变量取决于前面的定义
(四)、make函数
参考文档地址:http://www.gnu.org/software/make/manual/make.html
$(foreach VAR,LIST,TEXT)
功能:取出list中每个元素,赋值给var变量,然后按照text指定格式输出。
e.g.
objs := a b c
output = $(foreach f, $(objs), $(f).o) #output为a.o b.o c.o
$(filter-out PATTERN…,TEXT)
功能:从text中取值,把符合格式pattern的内容,过滤出来。
e.g.
obj := a b c/
dir := $(filter %/, $(obj))#dir为c/
$(filter-out pattern…, $(var))
功能:从text中取值,把不符合格式pattern的内容,过滤出来。
e.g.
obj := a b c/
dir := $(filter %/, $(obj))#dir为a b
$(wildcard PATTERN)
功能:把符合规则pattern且存在的文件列出来。
e.g.
src_files := $(wildcard *.c)#列出当前目录下所有.c文件
$(patsubst PATTERN,REPLACEMENT,TEXT)
功能:从text中取值,把满足规则pattern的内容转换成replacement格式并输出。(pattern substitution)
e.g.
objc := a.c b.c c.o
files = $(patsubst %.c, %.o, $(objc))#files为a.o b.o c.o
(五)、生成依赖文件
在编译时通过gcc添加附加选项-MD -MF实现(前者代表覆写同名文件,后者代表生成依赖文件.d)。
gcc -c -o xx.o xx.c -MD -MF xx.d
输出文件内容如下
xx.o: xx.c /usr/include/stdc-predef.h /usr/include/stdio.h \
/usr/include/x86_64-linux-gnu/bits/libc-header-start.h \
/usr/include/features.h /usr/include/x86_64-linux-gnu/sys/cdefs.h \
/usr/include/x86_64-linux-gnu/bits/wordsize.h \
/usr/include/x86_64-linux-gnu/bits/long-double.h \
/usr/include/x86_64-linux-gnu/gnu/stubs.h \
/usr/include/x86_64-linux-gnu/gnu/stubs-64.h \
/usr/lib/gcc/x86_64-linux-gnu/7/include/stddef.h \
/usr/include/x86_64-linux-gnu/bits/types.h \
/usr/include/x86_64-linux-gnu/bits/typesizes.h \
/usr/include/x86_64-linux-gnu/bits/types/__FILE.h \
/usr/include/x86_64-linux-gnu/bits/types/FILE.h \
/usr/include/x86_64-linux-gnu/bits/libio.h \
/usr/include/x86_64-linux-gnu/bits/_G_config.h \
/usr/include/x86_64-linux-gnu/bits/types/__mbstate_t.h \
/usr/lib/gcc/x86_64-linux-gnu/7/include/stdarg.h \
/usr/include/x86_64-linux-gnu/bits/stdio_lim.h \
/usr/include/x86_64-linux-gnu/bits/sys_errlist.h
e.g.
objs = a.o b.o c.o
#下面这两句是为了查找实际存在的依赖存放在dep_files
dep_files := $(patsubst %, .%.d, $(objs))
dep_files := $(wildcard $(dep_files))
CFLAGS = -Werror -Iinclude
test: $(objs)
gcc -o test $^
ifneq ($(dep_files),)
include $(dep_files)
endif
%.o : %.c
gcc $(CFLAGS) -c -o $@ $< -MD -MF .$@.d
clean:
rm *.o test
distclean:
rm $(dep_files)
.PHONY: clean
字符编码格式转换
GB2312->UTF-8
gcc -finput-charset=GB2312 -fexec-charset=UTF-8 -o test_charset_ansi test_charset_ansi.c
UTF-8->GB2312
gcc -finput-charset=UTF-8 -fexec-charset=GB2312 -o test_charset_utf8 test_charset_utf8.c
交叉编译时的万能指令
./configure --host=arm-buildroot-linux-gnueabihf --prefix=$PWD/tmp
make make install
常用问题解决方法
头文件问题
描述:#include <xxx.h>查找不到头文件。
方法:使用下列指令确认系统目录LIBRARY_PATH(交叉编译时某个include目录),确定目录下是否有该文件或在编译时使用-I dir指定目录。
echo 'main(){}' | arm-buildroot-linux-gnueabihf-gcc -E -v -
库文件问题
描述:undefined reference to ‘xxx’,xxx函数未定义。
方法:写出这个函数或使用库函数,链接时使用-lxxx添加libxxx.so文件
运行时找不到动态链接库
描述:error while loading shared libraries: libxxx.so:
cannot open shared object file: No such file or directory
方法:查看系统目录(/lib或/usr/lib)是否包含该文件;通过命令指定路径export LD_LIBRARY_PATH=/xxx_dir; ./test
或LD_LIBRARY_PATH=/xxx_dir ./test
socket通信(TCP方式)
服务端
设计流程:socket() -> bind() -> listen() -> accept() -> recv()/recvfrom() -> send()/sendto()
#include <sys/socket.h>//用于socket常用函数
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>//用于函数htons
#include <unistd.h>
#include <signal.h>//信号处理,用于父进程解决僵尸子进程
#define SERVER_PORT 1997//服务端端口
#define BACKLOG 10//最大连接数
/*
* int socket(int domain, int type, int protocol);
* int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
* int listen(int sockfd, int backlog);
* int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
* ssize_t send(int sockfd, const void *buf, size_t len, int flags);
* ssize_t recv(int sockfd, void *buf, size_t len, int flags);
* int close(int fd);
*/
int main(int argc, char **argv){
int iSocketServer;//服务端socket
int iSocketClient;//客户端socket
int iErr;//错误码
int iRecvLen;//接收数据长度
int iAddrLen;//地址长度
unsigned char recv_buff[1024];//接收数据缓冲区
struct sockaddr_in tServerSocketAddr;//服务端socket地址
struct sockaddr_in tClientSocketAddr;//客户端socket地址
signal(SIGCHLD,SIG_IGN);//防止产生僵尸进程
iSocketServer = socket(AF_INET, SOCK_STREAM, 0);//创建socket
if(-1 == iSocketServer){
printf("create socket err\n");
return -1;
}
tServerSocketAddr.sin_family = AF_INET;//地址族ipv4
tServerSocketAddr.sin_port = htons(SERVER_PORT);//将端口转换成无符号短整型
tServerSocketAddr.sin_addr.s_addr = INADDR_ANY;//任何地址都可通过端口连接服务器
memset(tServerSocketAddr.sin_zero, 0, 8);//清零reserve区域
iErr = bind(iSocketServer, (const struct sockaddr *)&tServerSocketAddr, sizeof(struct sockaddr));//绑定服务端的socket和地址
if(-1 == iErr){
printf("bind socket err\n");
return -1;
}
iErr = listen(iSocketServer, BACKLOG);//监听该服务器socket,最大连接数为BACKLOG
if(-1 ==