资讯动态

GCC与Makefile

发布时间:2026/9/8 16:08:00 来源:尧图企业网站定制
一个 C/C文件要经过预处理(preprocessing)、编译(compilation)、汇编(assembly)和链接(linking)等 4 步才能变成可执行文件。我们可以通过不同的gcc选项控制这些过程在实际使用的过程中只需要了解以下常用的选项即可实操通过这条命令就可以将.c文件转化为可执行文件其中会经过预处理、编译、汇编和链接gcc -o hello hello.c然后我们就可以直接执行./hellogcc指令可以完整的执行全过程我们可以通过下面的指令来查看这些步骤gcc -o hello hello.c -v当然我们也可以手工执行以下命令体验一下gcc -E -o hello.i hello.c gcc -S -o hello.s hello.i gcc -c -o hello.o hello.s gcc -o hello hello.oMakefile的使用在 Linux 中使用 make 命令来编译程序特别是大程序而 make 命令所执行的动作依赖于 Makefile 文件。最简单的 Makefile 文件如下hello: hello.c gcc -o hello hello.c clean: rm -f hellomake 命令根据文件更新的时间戳来决定哪些文件需要重新编译这使得可以避免编译已经编译过的、没有变化的程序相比较使用gcc将所有的文件都进行编译make可以大大提高编译效率。因此我们可以编写Makefile 文件来制定规则其样式如下目标(target)…: 依赖(prerequiries)… tab命令(command)命令被执行的2个条件依赖文件比目标文件新或是目标文件还没生成。实操a.c文件 #include stdio.h int main() { func_b(); return 0; } b.c文件 #include stdio.h void func_b() { printf(this is b\n); } Makefile文件 test: a.o b.o gcc -o test a.o b.o a.o: a.c gcc -c -o a.o a.c b.o: b.c gcc -c -o b.o b.c通配符但是如果每个文件都写入Makefile当中显然是很麻烦的因此我们可以使用通配符或者其他方式来简化%.o 通配符$表示目标$表示第一个依赖文件$^表示所有依赖文件我们再加入一个c.c文件和b.c几乎一致同时修改Makefile文件test: a.o b.o c.o gcc -o test $^ %.o: %.c gcc -c -o $ $同时我们还可以加入clean其中.PHONY是假想目标的意思test: a.o b.o c.o gcc -o test $^ %.o: %.c gcc -c -o $ $ clean: rm *.o test .PHONY: clean及时变量和延时变量在 GNU make 中对变量的赋值有两种方式延时变量、立即变量。上面语句中变量 A 是延时变量它的值在使用时才展开、才确定。A xxx // 延时变量 B ? xxx // 延时变量只有第一次定义时赋值才成功如果曾定义过此赋值无效 C : xxx // 立即变量 D yyy // 如果 D 在前面是延时变量那么现在它还是延时变量常用函数$(foreach var,list,text) //在text中取出符合patten格式的值 $(filter pattern..., text) //在text中取出不符合patten格式的值 $(filter-out pattern..., text) $(wildcard pattern) //pattern定义了文件名的格式wildcard取出其中存在的文件 $(patsubst pattern,replacement,text) //寻找text’中符合格式pattern’的字用replacement’替换 它们。pattern’和replacement’中可以使用通配符。示例A a b c B $(foreach f, $(A), $(f).o) all: echo B $(B) 输出B a.o b.o c.o C a b c d/ D $(filter %/, $(C)) E $(filter-out %/, $(C)) all: echo D $(D) echo E $(E) 输出 D d/ E a b cMakefile实例objs : main.o sub.o test : $(objs) gcc -o test $^ # 需要判断是否存在依赖文件 # .main.o.d .sub.o.d dep_files : $(foreach f, $(objs), .$(f).d) dep_files : $(wildcard $(dep_files)) # 把依赖文件包含进来 ifneq ($(dep_files),) include $(dep_files) endif %.o : %.c gcc -Wp,-MD,.$.d -c -o $ $ clean: rm *.o test -f distclean: rm $(dep_files) *.o test -f文件IO在Linux上操作文件时有两套函数标准IO、系统调用IO。标准IO的 相关函数是fopen/ fread/ fwrite/ fseek/fflush/fclose等。系统调用IO 的相关函数是open/ read/ write/ lseek/ fsync/ close。标准IO的内部会分配一个用户空间的buffer读写操作先经过这个 buffer。在有必要时才会调用底下的系统调用IO向内核发起操作。所以标准IO效率更高但是要访问驱动程序时就不能使用标准IO而是使用系统调用 IO。文件的IO操作是比较重要的下面仅给出open/ read/ write的相关说明注尽管使用open函数创建文件时可以规定读写权限但其最终结果为(mode ~umask)实操#include sys/types.h #include sys/stat.h #include fcntl.h #include stdio.h #include errno.h #include string.h #include unistd.h int read_line (int fd, char *buffer) { int len 0; while(1) { char ch; int re read(fd, ch, 1); if(re 0) { break; } if(ch ! \n ch ! \r) { buffer[len] ch; } else { //read(fd, ch, 1); break; } } buffer[len] \0; // Null-terminate the string return len; } void process_data(const char *input, char *output) { char name[100]; int scores[3]; int sum; char *levels[] {A, A, B}; int level; if (input[0] 0xef) /* 对于UTF-8编码的文件,它的前3个字符是0xef 0xbb 0xbf */ { strcpy(output, input); } else { sscanf(input, %[^,],%d,%d,%d,, name, scores[0], scores[1], scores[2]); //printf(result: %s,%d,%d,%d\n\r, name, scores[0], scores[1], scores[2]); //printf(result: %s ---get name--- %s\n\r, input, name); sum scores[0] scores[1] scores[2]; if (sum 270) level 0; else if (sum 240) level 1; else level 2; sprintf(output, %s,%d,%d,%d,%d,%s, name, scores[0], scores[1], scores[2], sum, levels[level]); //printf(result: %s, result_buf); } } int main(int argc, char **argv) { int fd_data, fd_result; if(argc ! 3) { printf(err); return 1; } fd_data open(argv[1], O_RDONLY); if(fd_data 0) { printf(err); return 1; } fd_result open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, 0644); if(fd_result 0) { printf(err); return 1; } while(1) { // Read data from the input file char buffer[100]; int len read_line(fd_data, buffer); if(len 0) { break; } else { //printf(Read line: %s\n, buffer); // process the data char processed_data[100]; process_data(buffer, processed_data); // Write the processed data to the output file write(fd_result, processed_data, strlen(processed_data)); write(fd_result, \r\n, 2); // Add a newline after each processed line } } close(fd_data); close(fd_result); return 0; }

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价