gcc使用、Makefile总结


前言

最近在弄一个比赛,要使用到C编程,自己之前一般都是用集成化的IDE进行C的编程,对于使用gcc,g++直接编译代码属实不了解,了解了一下相关使用,并学习了一些基础的makefile语法知识,写下工作总结


一、gcc使用

https://gcc.gnu.org/onlinedocs/gcc-12.1.0/gcc/Overall-Options.html#Overall-Options
官方文档

查看gcc版本

gcc --version

无任何编译选项

编译.c文件,并链接成可执行文件。默认输出名字a.out,输出文件到当前目录下。

gcc main.c

选项 -o

指定输出的文件名字

gcc main.c -o main.o

选项 -E

预处理阶段后停止;不运行编译器。输出采用预处理源代码的形式,发送到标准输出。即会生成.i结尾的文件

预处理功能主要包括宏定义, 文件包含, 条件编译, 去注释等。
预处理指令是以 # 号开头的代码行。
file.c:必须预处理的 C 源代码。
file.i:不应预处理的 C 源代码。
file.ii:不应预处理的 C++ 源代码。

gcc -E main.c -o main.i

选项 -S

编译成汇编语言但不进行链接

gcc -S main.c -o main.s

gcc -S main.i -o main.s 

选项 -c

编译文件到目标文件,但不进行链接

gcc -c main.c -o main.o

链接生成可执行文件

将所有.o文件进行链接,生成可执行文件,默认动态链接

gcc main.o test.o -c main # 将目标文件进行链接
gcc main.c test.c -o main #一步生成可执行文件

-static 此选项对生成的文件采用静态链接

gcc main.c test.c -o main_Static --static

链接分为两种:
动态链接:GCC编译时的默认选项。动态是指在应用程序运行时才去加载外部的代码库,不同的程序可以共用代码库。 所以动态链接生成的程序比较小,占用较少的内存。
静态链接:链接时使用选项 “–static”,它在编译阶段就会把所有用到的库打包到自己的可执行程序中。 所以静态链接的优点是具有较好的兼容性,不依赖外部环境,但是生成的程序比较大。

代码优化 -O

-O0 -O1 -O2 -O3 编译器的优化选项的 4 个级别, -O0 表示没有优化 ,-O3 优化级别最高。-O3的优化会比较暴力,但优化效果很好

gcc main.c -O1 -o main

编译所需文件目录 -I

我们在写代码的时候,为了整个工程的美观性和便于整理代码,一般会将.c和.h分开,-I 目录名称可以让gcc找到需要链接的文件目录

gcc main.c -I ./inc -o main #包含inc中的所有文件

其他

-g 生成调试信息。 GNU 调试器可利用该信息
-lpthread 文件中若包含多线程
pkg-config opencv --libs 包含opencv的C++库


二、Makefile文件

如果我们每次都输入一长串编译的指令的时候,会非常的麻烦,而makefile可以简化我们的需要。
makefile一个最关键的语法规则如下,代表了你需要生成什么目标,其依赖部分是什么,后续执行操作就放在命令中。

目标...: 依赖...
    命令1
    命令2
    ...

一些特殊变量

$@:目标的名字

$^:构造所需文件列表所有所有文件的名字

$<:构造所需文件列表的第一个文件的名字

$?:构造所需文件列表中更新过的文件

具体知识可以参考下面的博客

https://blog.csdn.net/afei__/article/details/82696682
https://blog.csdn.net/BobYuan888/article/details/88640923

先摆一个最近自己用的Makefile文件,以后自己也可以方便用。这里面包含了c++和c语言的混合编译的部分

Makefile例子

BIN_DIR = bin
SRC_DIR = src
INC_DIR = inc
OBJ_DIR = obj

CC = gcc
C++ = g++
LD = gcc #链接所需用的编译器
INC = -I$(INC_DIR)

CFLAGS += $(INC)
OPT = -O1
LDFLAGS = -lm

# C文件
OBJ_FILES_C = $(OBJ_DIR)/main.o \
			  $(OBJ_DIR)/jpeg.o \
			  $(OBJ_DIR)/show.o \
		    $(OBJ_DIR)/huff.o  
# 所有文件
OBJ_FILES = $(OBJ_FILES_C)
#总链接可执行文件gcode的位置 
TARGET = $(BIN_DIR)/gcode
# all代表最终生成文件
all: $(TARGET)

# c文件编译
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
	$(CC) $(CFLAGS) $(OPT) -c $< -o $@ 

# cpp文件编译
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.cpp
	$(C++) $(CFLAGS) $(OPT) -c $< -o $@ 

# 如果要链接别的库的话,必须要在最后所有.o文件链接为一个文件的时候链接opencv库 
# 如果在生成.o文件的时候链接会导致最终找不到该库
$(TARGET) : $(OBJ_FILES_C)
	$(C++) $(LDFLAGS) $(OBJ_FILES_C) $(OPT) -o $@ -lpthread 
	# -lpthread代表代码中包含多线程执行
# $(C++) $(LDFLAGS) $(OBJ_FILES) -o $@ `pkg-config opencv --libs`  #若包含opencv库需要链接
	@echo "> build success <"	

#make clean指令
clean:
	rm -f $(TARGET) $(OBJ_FILES)


三、C和C++混合编程

C++调用C函数

通常为了C代码能够通用,即既能被C调用,又能被C++调用,头文件通常会有如下写法:

#ifdef __cplusplus
extern "C"{
#endif
int add(int x,int y);
#ifdef __cplusplus
}
#endif

//或者

//xx.h
extern int add(...)

//xx.c
int add(){
    
}

//xx.cpp
extern "C" {
    #include "xx.h"
}

C函数调用C++函数

在C语言的头文件中,对其外部函数只能指定为extern类型,C语言中不支持extern "C"声明,在.c文件中包含了extern "C"时会出现编译语法错误。所以使用extern "C"全部都放在于cpp程序相关文件或其头文件中。

//xx.h
extern "C"{
    int add();
}
//xx.cpp
int add(){
    
}
//xx.c
extern int add();

不过与C++调用C接口不同,C++确实是能够调用编译好的C函数,而这里C调用C++,不过是把C++代码当成C代码编译后调用而已。也就是说,C并不能直接调用C++库函数。
放篇博客

https://blog.csdn.net/this_is_me_anyway/article/details/79397018

参考

gcc部分
https://zhuanlan.zhihu.com/p/404682058
https://gcc.gnu.org/onlinedocs/gcc-12.1.0/gcc/Overall-Options.html#Overall-Options
Makefile部分
https://blog.csdn.net/BobYuan888/article/details/88640923
https://blog.csdn.net/afei__/article/details/82696682

猜你喜欢

转载自blog.csdn.net/scarecrow_sun/article/details/125058367
今日推荐