Qt学习(5)

 

Qt学习(5)——Hello Word

 

      这里以经典的C++ Hello Word程序介绍一下使用MinGW(Linux上是GNU工具集)环境编译程序的过程,并且示范一下简单Makefile的使用。

1、简单的Hello Word

      一般将编写的程序代码文件要放到不含中文、特殊字符和空格的路径里面建立工程。否则会对程序编译不方便。

      现在进入E:\QtProjects\ch2\helloworld文件夹,新建一个helloworld.cpp(本人使用Notepad++ 6.8.7),编写如下代码:

      // helloworld.cpp

      #include<iostream>

      using namespace std;

     

      int main ( )

      {

           cout << " Hello World " << endl;

           return 0;

      }

打开MinGW命令行环境:开始菜单—>Qt5.5.0—>5.5—>MinGW 4.9(32bit)—>Qt 5.5 for Desktop(MinGW 4.9.2 32bit),打开该命令行工具,就能使用MinGW和Qt库进行编译程序。

      cd /d E:\QtProjects\ch2\helloworld
      g++ helloworld.cpp -o helloworld

上面第一句命令是进入 helloworld 文件夹,第二句命令是使用 g++ 编译 helloworld.cpp , -o 代表输出文件名为  helloworld (默认扩展名 .exe)。 执行该目标程序的命令为:helloworld

 

这时候进入 D:\QtProjects\ch02\helloworld 文件夹,可以看到目标程序 helloworld.exe ,大小是48 KB, 这是使用动态链接库的程序,体积比较小,如果双击它,会出现提示“没有找到 libgcc_s_dw2-1.dll (GCC  异常处理库),因此这个应用程序未能启动。重新安装应用程序可能会修复此问题”, 这是因为之前 MinGW 命令行配置好了 PATH 环境变量,MinGW  命令行环境有该 dll 文件, 而操作系统的 PATH 环境变量没有该 dll 。另外该 helloworld.exe 还依赖  libstdc++-6.dll (C++标准库), 动态链接的程序就是这样,需要相应的 dll 才能正常执行。可以找到这两个 dll 复制到 helloworld 文件夹里, 或者使用如下静态编译命令:

g++ helloworld.cpp -static -o hellostatic

新的静态链接版本程序 hellostatic.exe 是 1427 KB,比较大,双击运行不会报错,打印完字符串后会一闪而过, 普通的 CMD 命令行里可以直接运行该程序显示结果。 MinGW 编译程序的大概过程就是先用 g++ 编译器生成目标文件 *.o , 然后 g++ 自动调用了 ld  工具链接 *.o 和库文件,生成了 .exe 文件。 g++ 默认情况下生成的都是 Release 版可执行程序,  如果希望在可执行程序里加入 Debug 调试信息以供 gdb 调试,那需要在 g++ 编译时加一个 -g 选项,比如    

g++ helloworld.cpp -g -static -o hellodebug
 
2、复杂一些的Hello Rect
 
       进入E:\QtProjects\ch2文件夹里面,新建一个hellorect文件夹,进入文件夹,新建一个rect.h,编写代码:
//rect.h 

class Rect { private: double m_dblWidth; double m_dblHeight; public: Rect(double dblWidth, double dblHeight); double GetWidth(){ return m_dblWidth; } double GetHeight(){ return m_dblHeight; } //Functions
    double CalcDiagonal(); double CalcArea(); };

然后新建一个rect.cpp,编写如下代码:

//rect.cpp 
 #include <cmath> #include "rect.h"
using namespace std; Rect::Rect(double dblWidth, double dblHeight) { m_dblWidth = abs(dblWidth); m_dblHeight = abs(dblHeight); } double Rect::CalcDiagonal() { return sqrt(m_dblWidth*m_dblWidth + m_dblHeight*m_dblHeight); } double Rect::CalcArea() { return m_dblWidth * m_dblHeight; }


再建一个hellorect.cpp,编写如下代码:

//hellorect.cpp 
 #include <iostream> #include "rect.h"
using namespace std; int main(int argc, char **argv) { Rect arect(3.0, 4.0); cout<<"Diagonal Length is "<<arect.CalcDiagonal()<<endl; cout<<"Area is "<<arect.CalcArea()<<endl; return 0; }

上述代码定义了一个非常简单的类 Rect,然后计算了对角线长度 CalcDiagonal 和面积 CalcArea, 在 MinGW 命令行进入 hellorect 文件夹,编译两个 cpp 文件的命令如下:

g++ -c rect.cpp -o rect.o

g++ -c hellorect.cpp -o hellorect.o

g++ -c的意思为编译生成目标代码文件*.o , 而不进行链接。链接*.o文件和链接库生成可执行程序的命令为:

g++ rect.o hellorect.o -lm -static -o hellorect

g++ 会自动调用链接器链接 .o 文件和系统里的链接库,-lm 是链接数学库,-static 是生成静态链接的程序,-o 是指定生成的输出文件名。然后执行 hellorect 就可以看到结果:

 

 

 3、给Hello Rect编写简单的Makefile

    简单程序可以自己一句句敲 g++ 命令,如果项目复杂起来,代码太多了,自己敲命令编译就很麻烦,而且一个 .cpp 文件修改后就得重新生成目标文件 *.o,因此实际开发项目时都是借助 make 工具 (MinGW 的是 mingw32-make),编写好Makefile 之后,只需要在项目文件夹执行一句 make 命令,其他生成目标文件、链接目标文件和库以及自动根据源代码改动重新生成等,这些事情全交给 make ,而程序员就不用操心构建程序的具体过程。
    Makefile 文件可以自己编写,其实绝大多数的集成开发环境都可以根据项目文件自动生成相应的Makefile,所以实际中很多都是集成开发环境自动完成的。这里示范一个简单的 Makefile,体会一下生成器 make 是如何工作的。
    上面 hellorect文件夹里新建一个文件,命名为 Makefile,不要带扩展名。使用记事本或 Notepad2 工具打开该 Makefile 文件,里面输入如下脚本:

 

# Makefile for building: hellorect CC = gcc CXX = g++ LINKER = g++ LFLAGS = -lm -static OBJECTS = rect.o hellorect.o DSTTARGET = hellorect # Default rule all: $(DSTTARGET) $(DSTTARGET): $(OBJECTS) $(LINKER) $(LFLAGS) -o [email protected] $(OBJECTS) hellorect.o: hellorect.cpp $(CXX) -c -o [email protected] $< rect.o: rect.cpp $(CXX) -c -o [email protected] $< clean: rm $(OBJECTS) hellorect.exe

       这里解释一下上面脚本意思(# 打头的是注释,忽略掉): 中间带有等于号的都是定义变量,引用变量的方式就是 $(变量名) , 脚本里 CC 是 C 语言编译器,CXX 是 C++ 编译器,LINKER 是链接器, LFLAGS 是链接器的参数。OBJECTS 是编译得到的目标文件,DSTTARGET 是可执行的目标程序。接下来是 Makefile 的生成规则,Makefile 的基本规则是:

生成目标: 依赖文件
[tab字符] 系统命令

       示例的 Makefile 中    

all: $(DSTTARGET)

是默认生成规则,依赖文件 $(DSTTARGET) ,它的下一行没有命令。 而如何生成 $(DSTTARGET) 呢,继续往下找

$(DSTTARGET): $(OBJECTS)

生成 $(DSTTARGET) 需要 $(OBJECTS),有了目标文件之后执行命令

	$(LINKER)  $(LFLAGS)  -o [email protected]  $(OBJECTS)

即调用链接器 $(LINKER),根据链接器参数 $(LFLAGS) 和 $(OBJECTS),生成 [email protected][email protected]  就是上一行冒号左边的要生成的目标。注意系统命令 $(LINKER) 之前一定要有制表符 tab 字符, 不能用 4 个空格代替,否则 make 时会出现没有分隔符(separator)的错误。 接下来的四句:    

hellorect.o: hellorect.cpp  
	$(CXX) -c  -o  [email protected]  $<
 
    
rect.o: rect.cpp
	$(CXX) -c  -o  [email protected]  $<

是使用编译器生成目标文件 hellorect.o 和 rect.o ,[email protected] 是上一行冒号左边的目标,$< 是上一行冒号右边第一个依赖文件。     hellorect.o 和 rect.o就是链接器需要的 $(OBJECTS) 。 最后的两句是清除规则:    

clean:
	rm  $(OBJECTS)  hellorect.exe

      rm 是删除命令,如果 Windows 系统里没有 rm 命令,请安装一个 msysgit 工具( http://msysgit.github.io/), 然后系统环境变量里面会有 msysgit 工具路径,里面有 rm 工具。clean 做的事情就是删除项目生成的 .o 和 .exe 文件。(注:Linux 系统里可执行程序没有 .exe 后缀,需要去掉 .exe 后缀。)
      编辑好 Makefile 文件之后,那么如何使用 make 工具呢?如果要生成项目,就在项目文件夹 hellorect 里执行:        

mingw32-make

如果要清理项目就执行:    

mingw32-make clean

      MinGW 里面是用 mingw32-make 生成程序。(注:Linux 系统里直接用 make 。)    在 MinGW 环境的命令示范如下: