四、make

  • 什么是make

make,常指一条计算机指令 ,可以从一个名为Makefile的文件中获得如何构建你所写程序的依赖关系。通常项目的编译规则就定义在makrfile 里面,比如: 规定先编译哪些文件,后编译哪些文件… 当编写一个程序时,可以为它编写一个makefile文件,不过在windows下的很多IDE 工具,内部都集成了这些编译的工作,只需要点击某一个按钮,一切就完成了。换算到手动操作的话,就需要编写一个makefile文件,然后使用make命令执行编译和后续的安装。

  • 关于程序编译

1. 简单入门

  • 什么是make

make,常指一条计算机指令 ,可以从一个名为Makefile的文件中获得如何构建你所写程序的依赖关系。通常项目的编译规则就定义在makrfile 里面,比如: 规定先编译哪些文件,后编译哪些文件… 当编写一个程序时,可以为它编写一个makefile文件,不过在windows下的很多IDE 工具,内部都集成了这些编译的工作,只需要点击某一个按钮,一切就完成了。换算到手动操作的话,就需要编写一个makefile文件,然后使用make命令执行编译和后续的安装。

  • 关于程序编译
  • makefile 的规则

如果项目的文件很多,那么makefile的内容也会很多,但是最核心的规则即是下面的几行语句。

target: 表示生成目标文件

prerequisites : 生成目标文件以来的文件

command: 表示命令,也就是从右到左的命令是什么。

target ... : prerequisites ...
    command
    ...
    ...
  • 如果要编译的是一个单一的main.c 文件,那么makefile的规则应该是这样

target: 表示生成目标文件 main.o , 文件的编译来源是 main.cpp g++: 表示编译 c++代码 , 如果编译c代码,使用 cc(其实就是 gcc) 编译。

main.o : main.c
	g++ main.c
  • 为什么需要makefile

在最初的非常简单的c++工程,由于源文件很少,所以可以直接手动使用gcc编译,如下所示。 但是如果一个项目的文件很多,那么命令将会变得很长,难以编写。所以通常的做法是,定义一个makefile文件,用于登记编译的文件、以及如何编译。

#include <iostream>

int main(){
	std::cout << "打印日志" << endl;
	return 0 ;
}

//编译
g++ Test.cpp -o Test
  • 什么是cmake

cmake 其实是一个工具,类似的工具有GNU Make QT的qmake , 微软的MS nmake … 但是这些工具遵循着不同的规范、在面对跨平台的问题下,就显得捉襟见肘了, 在每一种标准下写一次makefile . 为了解决这些问题,Cmake应运而生。

  1. 允许开发者编写一种平台无关的 CMakeList.txt 文件来定制整个编译流程
  2. 然后再根据目标用户的平台进一步生成所需的本地化 Makefile 和工程文件,如 Unix 的 Makefile 或 Windows 的 Visual Studio 工程。从而做到“Write once, run everywhere”。

2. Cmake

对于简单的项目,只需要两行CMakeLists.txt文件。这将是我们教程的起点。CMakeLists.txt文件看起来像这样的。

# 表示cmake的最低版本
cmake_minimum_required (VERSION 2.6)

# 表示目前编译的项目
project (Tutorial)

# 表示项目的执行程序,通常是入口文件
add_executable(Tutorial tutorial.cxx)
  • 配置头文件

CMakeLists.txt 文件也允许在里面定义一些常量,然后在源文件或者头文件中使用,这使得编译代码变得更加灵活。试想一下,如果代码是其他人写好了,交给不同的组织或个人来编译,每个组织或者个人可以根据自己的情况在 CMakeLists.txt 文件定义各自的数据。

cmake_minimum_required (VERSION 2.6)
project (Tutorial)
# 定义两个变量
set (Tutorial_VERSION_MAJOR 1)
set (Tutorial_VERSION_MINOR 0)
 
# 指定头文件的数据来自于TutorialConfig.h.in, TutorialConfig.h并不需要我们去创建
# cmake会帮我们创建
configure_file (
  "${PROJECT_SOURCE_DIR}/TutorialConfig.h.in"
  "${PROJECT_BINARY_DIR}/TutorialConfig.h"
  )
 
# add the binary tree to the search path for include files
# so that we will find TutorialConfig.h
include_directories("${PROJECT_BINARY_DIR}")
 
# add the executable
add_executable(Tutorial tutorial.cxx)
  • 定义TutorialConfig.h.in文件

获取cmakelist.txt文件中定义的变量,有两种方式: @变量名@ | ${变量名} , define关键字的意思是宏定义,意思是声明一个变量 Tutorial_VERSION_MAJOR,它对一个的值是:@Tutorial_VERSION_MAJOR@

// the configured options and settings for Tutorial
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@
  • 在源文件中读取
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "TutorialConfig.h"
 
int main (int argc, char *argv[]){
  if (argc < 2){
    fprintf(stdout,"%s Version %d.%d\n",
            argv[0],
            Tutorial_VERSION_MAJOR,
            Tutorial_VERSION_MINOR);
    fprintf(stdout,"Usage: %s number\n",argv[0]);
    return 1;
    }
  double inputValue = atof(argv[1]);
  double outputValue = sqrt(inputValue);
  fprintf(stdout,"The square root of %g is %g\n",
          inputValue, outputValue);
  return 0;
}