dev c++显示源文件未编译_linux学习(C++程序编译及makefile编写)
1.最基本的编译过程此时有一个a.cpp文件,文件中内容如下:#include <iostream>using namespace std;int main(){cout<<"hello world"<<endl;return 0;}第一步:预处理,将所有的#include头文件以及宏定义替换成其真正的内容,输入命令g++ -E a...
1.最基本的编译过程
此时有一个a.cpp文件,文件中内容如下:
#include <iostream>
using namespace std;
int main()
{
cout<<"hello world"<<endl;
return 0;
}
第一步:预处理,将所有的#include头文件以及宏定义替换成其真正的内容,输入命令
g++ -E a.cpp >> a.i
如果不输入>>a.i,只会在终端中显示预处理以后的结果,不会生成.i文件
第二步:编译,将经过预处理之后的程序转换成特定汇编代码(assembly code)的过程,输入命令
g++ -S a.i
这样就可以生成汇编的.s文件
这里有个参数-o,如果不加-o,则生成的文件名为cpp的文件名,如果不想要这个文件名,就可以使用如下命令,生成想要的目标文件名
g++ -S a.i -o xxx
第三步:汇编,汇编过程将上一步的汇编代码转换成机器码(machine code),也就是二进制。输入命令
g++ -c a.s
这样就可以生成二进制的.o文件
这里有个参数-o,如果不加-o,则生成的文件名为cpp的文件名,如果不想要这个文件名,就可以使用-o参数,生成想要的目标文件名(同上)
第四步:链接,链接过程将多个目标文以及所需的静态链接库文件(.a等)链接成最终的可执行文件(executable file)。输入命令
g++ a.o
生成可执行文件
这里有个参数-o,如果不加-o,则生成的文件名为a.out,如果不想要这个文件名,就可以使用-o参数,生成想要的目标文件名(同上)
注意:并不是需要严格执行每一步才可以,比如想直接生成汇编文件,也就是.s文件。可以直接使用命令
g++ -S a.cpp
相当于系统帮你自动执行了预处理步骤,生成.s文件。
2.常用编译方法
在第一点中讲到的整个编译过程并不是每次编译都需要用到,一般常用的是直接生成可执行文件,比如
g++ a.cpp -o helloworld
然后输入
./helloworld
得到如下的结果
当程序中有非标准库中的头文件时,只编译cpp文件会显示找不到头文件,所以需要用到参数 -i
命令格式
g++ hello.cpp -o hello -I (路径)
其他参数列表
注意:包含头文件的参数-I是大写的i,指定库名的参数是小写的L,不要搞混了。
另一个常用命令是输出二进制文件.o的命令,由于在制作动态和静态库时,需要使用到这个。
g++ -c a.cpp
3.用makefile写编译指令
简单的makefile主要掌握1条规则,2个函数,3个变量即可
以一个简单的情况为例,现在有如下六个文件
整个编译过程应该是如下命令:
gcc -c itcast_asn1_der.c -o itcast_asn1_der.o 预处理、编译、汇编
gcc -c itcastderlog.c -o itcastderlog.o 预处理、编译、汇编
gcc -c keymng_msg.c -o keymng_msg.o 预处理、编译、汇编
gcc -c keymng_msg_test.c -o keymng_msg_test.o 预处理、编译、汇编
gcc itcast_asn1_der.o itcastderlog.o keymng_msg.o keymng_msg_test.o -o a.out 链接
1 条规则:
目标:依赖
命令
要求,目标必须晚于依赖条件生成时间。如果不满足,则更新目标。
如果依赖不存在,寻找新的规则生成依赖。
将如上的五条命令生成五条规则如下:
itcast_asn1_der.o:itcast_asn1_der.c
gcc -c itcast_asn1_der.c -o itcast_asn1_der.o
itcastderlog.o:itcastderlog.c
gcc -c itcastderlog.c -o itcastderlog.o
keymng_msg.o:keymng_msg.c
gcc -c keymng_msg.c -o keymng_msg.o
keymng_msg_test.o:keymng_msg_test.c
gcc -c keymng_msg_test.c -o keymng_msg_test.o
a.out:itcast_asn1_der.o itcastderlog.o keymng_msg.o keymng_msg_test.o
gcc itcast_asn1_der.o itcastderlog.o keymng_msg.o keymng_msg_test.o -o a.out
2 个函数:
$(wildcard 参): 获取指定类型特征的文件、
src = $(wildcard *.c)
$(patsubst 参1, 参2, 参3):根据执行类型变量,获取新变量。
$(patsubst %.c, %, $(src)): 将参数3 中,包含参数1的部分,替换成参数2。
对应到例子中
#src = itcast_asn1_der.c itcastderlog.c keymng_msg.c keymng_msg_test.c
src = $(wildcard *.c)
#obj = itcast_asn1_der.o itcastderlog.o keymng_msg.o keymng_msg_test.o
obj = $(patsubst %.c, %.o, $(src))
3 个自动变量:
$@: 在规则的 命令中, 表示目标。
$^: 在规则的 命令中, 表示 所有依赖条件
$<: 在规则的 命令中, 表示 第一个依赖条。 如果是模式规则,会将依赖条件依次取出。 执行命令。
4个符号:
= 是最基本的赋值
:= 是覆盖之前的值
?= 是如果没有被赋值过就赋予等号后面的值
+= 是添加等号后面的值
可以参考博客:https://blog.csdn.net/b876144622/article/details/80372161
其他关键词:
1. filter-out可以把一些源文件剔除
比如:
FILES := $(wildcard $(PATH)/src/*.cc)//现获得所有的源文件
SRC_FILES += $(filter-out $(PATH)/src/a.cc $(PATH)/src/b.cc, $(FILES))//剔除一些不想要的源文件
注意:filter-out的语法是filter-out 剔除的内容, 剔除的目标文件
上面那个例子中,就是从FILES中剔除掉http://a.cc和http://b.cc
2. @echo可以查看makefile中的变量
debug:
@echo $(srcc)#显示srcc变量的内容
可以利用刚才的规则将五条规则简化为如下两条规则
#表示终极目标
ALL:app
#使用变量的方式$(变量名),下面这条是把所有的.c文件变成.o文件
app:$(obj)
gcc $^ -o $@
#这句话是将所有的.c文件生成.o文件,前面加$(obj)是静态模式规则,obj变量会执行这个模式规则,而其他变量则不会执行这一规则,模式规则就是将所有满足条件的文件依次取出执行这一语句,%.o是目标文件,%.c是依赖文件
$(obj):%.o : %.c
gcc -c $< -o $@
注意:这里的模式规则是指如果目标有多个,并且依赖条件也不一样的情况下,如果依赖条件和目标在名称上有对应关系,可以把多个目标生成语句合并为一个条规则。具体可以看下面这个例子
下面是将c文件放到src文件夹下,头文件放到inc文件夹下,并要求生成的文件放到obj文件夹下,生成的最终的makefile编译文件
#src = itcast_asn1_der.c itcastderlog.c keymng_msg.c keymng_msg_test.c
src = $(wildcard ./src/*.c)
#obj = itcast_asn1_der.o itcastderlog.o keymng_msg.o keymng_msg_test.o
obj = $(patsubst ./src/%.c, ./obj/%.o, $(src))
#百分号就类似shell指令当中的通配符*,在makefile中这两种通配符都可以使用,但有些情况下不能使用,可以参考这篇文章:https://www.cnblogs.com/warren-wong/p/3979270.html
target = app
inc_path = ./inc
#上面是定义的两个变量
#表示终极目标
ALL:$(target)
#使用变量的方式$(变量名),下面这条是把所有的.c文件变成.o文件
$(target):$(obj)
gcc $^ -o $@
#模式规则开头不仅仅有目标文件和依赖文件,还会多一个目标集合(个人理解)
#前面加$(obj)就是目标文件集合,将所有满足条件的文件依次取出执行这一语句,
#./obj/%.o是目标文件,./src/%.c是依赖文件,并且其中%是一样的
#其中gcc -c itcast_asn1_der.c -o itcast_asn1_der.o -I ./inc就是这个目标规则中会执行的一句命令
$(obj):./obj/%.o : ./src/%.c
gcc -c $< -o $@ -I $(inc_path)
clean:
-rm -rf $(obj) $(target)
.PHONY: clean ALL
#表示clean和ALL是一种声明符号,不是规则中的目标文件
如果不止是c源文件,还有C++源文件,makefile如下
srcc = $(wildcard ./src/*.c)
srccpp = $(wildcard ./src/*.cpp)
objc = $(patsubst ./src/%.c, ./obj/%.o, $(srcc))
objcpp = $(patsubst ./src/%.cpp, ./obj/%.o, $(srccpp))
target = app
inc_path = ./inc
ALL:$(target)
#多个依赖可以直接在后面接着写
$(target):$(objc) $(objcpp)
g++ $^ -o $@
$(objc):./obj/%.o : ./src/%.c
gcc -c $< -o $@ -I $(inc_path)
$(objcpp):./obj/%.o : ./src/%.cpp
g++ -c $< -o $@ -I $(inc_path)
clean:
-rm -rf $(objc) $(objcpp) $(target)
debug:
@echo $(srcc)#显示srcc变量的内容
.PHONY: clean ALL
注意:
- 凡是一个名称加冒号,这一行后面就没有的,都是自定义的命令,比如clean,debug(但是ALL特殊),使用的方法就是在终端输入make +名称,比如make clean,make debug。但是ALL并不是命令,而是指终极目标,我理解是Makefile文件只能生成一个目标,如果有多个,就是设定一个ALL目标,让这些目标都成为这个ALL目标的依赖即可。并且ALL也不符合命令的格式。
- .PHONY:后面跟的是目标,是可以重复生成的,比如ALL不加在后面,那么如果已经编译生成了ALL,那么如果ALL没有删除,就不可以再次编译ALL。
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)