编写一个makefile
前言:C++小白,突发奇想在window下用vs2017用c语言写的执行程序在linux也能用的;以下是记录,第一次记录makefile自己遇到问题。
原材料:1个头文件 txtFileParser.h,2个cpp文件 main.cpp和txtFileParser.cpp。(简单说明:txtFileParser.h构造了一个类,txtFileParser.cpp自然是那个类的内部函数的定义什么的;)
实现功能:解析一个txt文件,找到并检查nSequence后面的数字是否递增;txt文件如下图:
window下没什么问题,功能实现。主要记录在linux下第一次写makefile。
步骤:
1.把.cpp和.h文件拷到Linux环境下,把环境都安装好,“工具准备齐全”。
2.不写makefile,一步一步编译,链接。多说一句 把写好的.cpp/.c文件变成机器能看懂的中间代码文件,表示为.o文件,这一步是编译;把一系列.o文件合成为最终的执行文件,固义思名就是链接;类试在window下.exe;这是最简单的情况,要生成静态库(.a文件,window下叫lib)和动态链接库,这里不做记录了。
期待滴写第一句:因为是cpp文件,我用g++编译,g++和gcc区别可以百度具体了解一下;我自己也是百度的,gcc和g++的主要区别
-
对于 .c和.cpp文件,gcc分别当做c和cpp文件编译(c和cpp的语法强度是不一样的)
-
对于 .c和.cpp文件,g++则统一当做cpp文件编译
-
使用g++编译文件时,g++会自动链接标准库STL,而gcc不会自动链接STL
-
gcc在编译C文件时,可使用的预定义宏是比较少的
[root@localhost project2]# g++ -c main.cpp
In file included from main.cpp:1:0:
txtFileParser.h:22:2: 错误:‘int64_t’不是命名空间‘std’中的一个类型名
std::int64_t getLonglonng(const char* val)
^
txtFileParser.h:28:2: 错误:‘int64_t’不是命名空间‘std’中的一个类型名
std::int64_t seqline=0;
日常打脸没什么问题,用到了C++11标准,修改一下:
[root@localhost project2]# g++ -std=c++11 -c main.cpp
[root@localhost project2]# ll
总用量 280548
-rw-r--r--. 1 root root 287260665 14月 18 10:10 log.txt
-rw-r--r--. 1 root root 156 16月 18 09:51 main.cpp
-rw-r--r--. 1 root root 3688 16月 18 11:31 main.o
-rw-r--r--. 1 root root 229 16月 18 11:27 makefile
-rw-r--r--. 1 root root 1656 16月 18 10:09 txtFileParser.cpp
-rw-r--r--. 1 root root 549 16月 18 09:50 txtFileParser.h
显然,看到了main.o文件了,按部就班:
[root@localhost project2]# g++ -std=c++11 -c txtFileParser.cpp
[root@localhost project2]# g++ -std=c++11 -o seq_txt main.o txtFileParser.o
[root@localhost project2]# ll
总用量 280584
-rw-r--r--. 1 root root 287260665 16月 18 10:10 log.txt
-rw-r--r--. 1 root root 169 16月 18 13:15 main.cpp
-rw-r--r--. 1 root root 3704 16月 18 13:16 main.o
-rw-r--r--. 1 root root 249 16月 18 11:37 makefile
-rwxr-xr-x. 1 root root 16808 16月 18 13:17 seq_txt
-rw-r--r--. 1 root root 1656 16月 18 10:09 txtFileParser.cpp
-rw-r--r--. 1 root root 572 16月 18 11:42 txtFileParser.h
-rw-r--r--. 1 root root 15856 16月 18 11:42 txtFileParser.o
[root@localhost project2]# ./seq_txt
The traversing begined!
Sequece error,prev [10188174] now [0]!
Sequece error,prev [10188219] now [10188221]!
Sequece error,prev [10188221] now [10188221]!
得到了执行文件seq_txt;可以执行,执行的时候会有赋权的情况,先记下来命令
chmod +x seq_txt
,嘿嘿,迈出一小步;
3.写makefile
先删除之前编好了,重新来,删除 :rm;建一个记事本 vi makefile.txt(我一直以为是txt),把刚刚的 代码放到文件里,CV大法。然后make。
seq_txt:mian.o txtFileParser.o
g++ -std=c++11 -o seq_txt main.o txtFileParser.o
main.o:main.cpp txtFileParser.h
g++ -std=c++11 -c main.cpp
txtFileParser.o:txtFileParser.cpp txtFileParser.h
g++ -std=c++11 -c txtFileParser.cpp
clean:
rm *.o seq_txt
'''日常打脸没什么问题,一共改了3个问题,bug不是一次全部显示;
1)[root@localhost project2]# make
make: *** 没有指明目标并且找不到 makefile。 停止。
解决:makefile.txt重命名为makefile
2)[root@localhost project2]# make
makefile:2: *** 遗漏分隔符 。 停止。
解决:命令语句要用tab键;CV大法日常打脸。重新手撸,防止刚刚拷贝进什么特殊字符;
3)手撸之后,
[root@localhost project2]# make
make: *** 没有规则可以创建“seq_txt”需要的目标“mian.o”。 停止。
解决:把手剁了;剁之前把mian改成main;
seq_txt:main.o txtFileParser.o
g++ -std=c++11 -o seq_txt main.o txtFileParser.o
main.o:main.cpp txtFileParser.h
g++ -std=c++11 -c main.cpp
txtFileParser.o:txtFileParser.cpp txtFileParser.h
g++ -std=c++11 -c txtFileParser.cpp
clean:
rm *.o seq_txt
成功。结果跟上面一致;这个代码还可以改进:
其中# 后面的内容为注释。
#格式还是上面的格式,把常量换成变量,跟C语言写函数类试
#变量的定义 CXX X Y 都是变量名 \ 告诉机器这一行我写不下了,写下一行了,你接
#的时候注意点。
CXX=g++ -std=c++11
Y = main.o \
txtFileParser.o
X = seq_txt
#函数 注意格式
$(X) : $(Y)
$(CXX) -o $(X) $(Y)
clean:
rm $(X) $(Y)
成功。结果跟上面一致;有疑惑,为啥对于-o的编译不写进去,没事,make会隐式连接,自动推导,初学者都加上吧,有助于对整个工程的理解。