【linux】Linux项目自动化构建工具-make/Makefile

简介: 【linux】Linux项目自动化构建工具-make/Makefile

make/makefile

背景

会不会写makefile,从一个侧面说明了一个人是否具备完成大型工程的能力

一个工程中的源文件不计数,其按类型、功能、模块分别放在若干个目录中,makefile定义了一系列的规则来指定,哪些文件需要先编译,哪些文件需要后编译,哪些文件需要重新编译,甚至于进行更复杂

的功能操作makefile带来的好处就是——“自动化编译”,一旦写好,只需要一个make命令,整个工程完全自动编译,极大的提高了软件开发的效率。

make是一个命令工具,是一个解释makefile中指令的命令工具,一般来说,大多数的IDE都有这个命令,比如:Delphi的make,Visual C++的nmake,Linux下GNU的make。可见,makefile都成为了一种在工程方面的编译方法。

make是一条命令,makefile是一个文件,两个搭配使用,完成项目自动化构建。

1.创建文件makefile

2.vim 操作makefile写入内容

3.vim 操作obj.c写入内容

4.make操作

make操作是一个命令,执行第一个依赖方法

6.查看内容myobj

7.make clean (删除myobj)


总结:make是一个命令,makefile是一个文件。

2.make会根据makefile的内容,完成编译或者清理的工作。


这里的.PHONY怎么理解呢??

先看一段程序

1.make使用两次,他会报myobj可执行程序是最新的,再次编译的时候编译器会拦截不然你在编译,当我们vim修改了obj.c的时候,又可以make了

2.为什么makefile对最新的可执行程序,默认不想重新生成呢?

这样可以提高编译效率,假如说一家大公司一个项目代码很多,编译起码要一两个小时,如果不断的编译的话,编译效率会很低。

3.makefile怎么知道我的程序需要被编译了呢?

对比可执行文件最近修改时间和源文件最近的修改时间,谁更新。如果源文件修改时间更新的话,可以继续编译make,反之,就会体现你可执行程序是最新的了。

所以我们.PHONY:依赖文件列表,这样就不会提醒可执行程序最新了


2.makefile还能怎么玩??

3.还能这么玩?

我们可以用变量代替目标文件,依赖文件列表,并且将依赖方法的功能可以起名一个别称

4.makefile/make会自动根据文件中的依赖关系,进行自动推导,帮助我们执行所有相关的依赖方法

我们要生成my.exe,必须要找到my.o的依赖方法,makefile会向下执行找my.o

这里类似于递归,直到翻译都执行完了。

如果顺序是乱的,务必把目标文件my.exe放第一个

Linux第一个小程序-进度条

准备工作

1.bar.h用于函数声明

2.bar.c用于函数定义

3.main.c用于测试

4.makefile 用于文件的编译以及清理

版本1

代码分析

我们要实现一个进度条,首先有个字符数组来充当进度条,先对其进行初始化,全部初始化为反斜杠0,防止打印时候出现乱码,大小为101,最后一个为字符串结尾反斜杠0,然后定义logo变量,用来进度条显示,routh字符常量数组用来模拟进度条后面旋转的.(上面图片里面的求routh数组长度的改为srelen,写错了)

进度条

版本2(模拟下载问题)

代码分析:

doneload函数中定义了一个要下载文件的总大小,一个当前已经下载了的大小,一个下载的速度,循环中,已经下载的大小小于总大小说明还没下完,doneload函数会给bar函数提供一个filesize,和current,可以让bar函数直到当前下载了百分之多少,下载了百分之多少就循环多少次,也就是字符串中+了多少个#,假如说当前是30%,那么count=30,循环30次,字符串lenth中有30个#,然后打印即可,如果下次到31%,cnt又重新开始从0开始。

版本3(多文件下载问题)

多文件下载

代码分析:通过

根据不同文件大小不同,传参文件大小

版本4(进度条加载通讯录里面)

进度条2

contanct.cpp

#include"contanct.h"
//#include<windows.h>
#include<graphics.h>//包含图形库头文件
//#include<mmsystem.h>//包含多媒体设备接口头文件
//#pragma comment(lib,"winmm.lib")//加载静态库
void DestroyContanct(pp* p)
{
  free(p->arr);
  p->arr = NULL;
  p->size = 0;
  p->sz = 0;
  printf("销毁成功\n");
}
void Addbig(pp* p)
{
  if (p->sz == p->size)
  {
    peoinfo* tmp = (peoinfo*)realloc(p->arr, (p->size + 2) * sizeof(peoinfo));
    if (tmp != NULL)
    {
      p->arr = tmp;
    }
    p->size+= 2;
    printf("增容 + 2\n");
    
  }
}
void Loadcontact(pp* p)
{
  FILE* fp=fopen("contact.txt", "r");
  if (fp == NULL)
  {
    perror("Loadcontact:");
    return;
    }
  peoinfo tmp = { 0 };
  while (fread(&tmp,sizeof(peoinfo),1,fp))
  {
    Addbig(p);
    p->arr[p->sz] = tmp;
    p->sz++;
    }
  fclose(fp);
  fp = NULL;
}
void Savecontact(pp* p)
{
  FILE* fp = fopen("contact.txt", "wb");
  if (fp == NULL)
  {
    perror("Savecontact:");
    return;
  }
  int i = 0;
  for (i = 0; i < p->sz; i++)
  {
    fwrite(p->arr+i, sizeof(peoinfo), 1, fp);
  }
  
  fclose(fp);
  fp = NULL;
  printf("保存成功\n");
}
void Initcontanct(pp* p)
{
  /*p->sz = 0;
  memset(p->arr, 0, sizeof(p->arr));*/
  p->sz = 0;
  p->size = SIZE;
   p->arr = (peoinfo*)malloc(p->size * sizeof(peoinfo));
   if (p->arr == NULL)
   {
     perror(" Initcontanct:malloc");
     return;
   }
   memset(p->arr, 0, p->size * sizeof(peoinfo));
   Loadcontact(p);
}
void Addcontanct(pp* p)
{
  Addbig(p);
  printf("请输入姓名\n");
  scanf("%s", p->arr[p->sz].name);
  printf("请输入性别\n");
  scanf("%s", p->arr[p->sz].sex);
  printf("请输入年龄\n");
  scanf("%d", &(p->arr[p->sz].age));
  printf("请输入电话\n");
  scanf("%s", p->arr[p->sz].tel);
  printf("请输入地址\n");
  scanf("%s", p->arr[p->sz].addr);
  p->sz++;
  printf("录入成功\n");
}
void Printcontanct(pp* p)
{
  int i = 0;
  printf("******************************************************\n");
  printf("%-10s %-5s %-5s %-12s %-20s\n", "姓名", "性别", "年龄", "电话", "地址");
  printf("******************************************************\n");
  for (i = 0; i < p->sz; i++)
  {
    printf("%-10s %-5s %-5d %-12s %-20s\n", p->arr[i].name, p->arr[i].sex, p->arr[i].age, p->arr[i].tel, p->arr[i].addr);
    printf("******************************************************\n");
  }
}
int find(pp* p, char name[])
{
  int i = 0;
  for (int i = 0; i < p->sz; i++)
  {
    if (!strcmp(p->arr[i].name, name))
      return i;
  }
  return -1;
}
void Delcontanct(pp* p)
{
  char name[MAX_NAME];
  printf("请输入要删除朋友的名字\n");
  scanf("%s", name);
  if (find(p, name) == -1)
  {
    printf("查无此人\n");
  }
  else
  {
    int k = find(p, name);
    for (int j = k; j < p->sz - 1; j++)
    {
      p->arr[j] = p->arr[j + 1];
    }
    p->sz--;
    printf("删除成功\n");
  }
}
void findcontanct(pp* p)
{
  char name[MAX_NAME];
  if (p->sz == 0)
  {
    printf("通讯录为空\n");
    return;
  }
  printf("请输入要查找朋友的名字\n");
  scanf("%s", name);
  if (find(p, name) == -1)
  {
    printf("查无此人\n");
  }
  else
  {
    int k = find(p, name);
    printf("******************************************************\n");
    printf("%-10s %-5s %-5s %-12s %-20s\n", "姓名", "性别", "年龄", "电话", "地址");
    printf("%-10s %-5s %-5d %-12s %-20s\n", p->arr[k].name, p->arr[k].sex, p->arr[k].age, p->arr[k].tel, p->arr[k].addr);
    printf("******************************************************\n");
  }
}
void modifycontanct(pp* p)
{
  char name[MAX_NAME];
  printf("请输入修改朋友的名字\n");
  scanf("%s", name);
  if (find(p, name) == -1)
  {
    printf("查无此人\n");
  }
  else
  {
    int k = find(p, name);
    printf("请输入要修改朋友的信息\n");
    printf("修改性别->");
    scanf("%s", p->arr[k].sex);
    printf("修改年龄->");
    scanf("%d", &(p->arr[k].age));
    printf("修改电话->");
    scanf("%s", p->arr[k].tel);
    printf("修改地址->");
    scanf("%s", p->arr[k].addr);
    printf("修改成功\n");
  }
}
int int_cmp_age(const void* p1, const void* p2)//按年龄比较
{
  return ((struct peoinfo*)p1)->age - ((struct peoinfo*)p2)->age;
}
void Sortcontanct(pp* p)
{
  qsort(p->arr, p->sz, sizeof(peoinfo), int_cmp_age);
  printf("按年龄排序成功,快去打印吧\n");
}
void bgm()
{    //打开音乐
  mciSendString("open ./music.MP3", 0, 0, 0);//后面参数不用管
  //播放音乐
  mciSendString("play ./music.MP3", 0, 0, 0);//后面参数不用管
}
void bar(double total, double current)
 {char lenth[105];
  char logo = '>';
  const char* routh ="-/|\\";
 int len = strlen(routh);
   int cnt = 0;
   memset(lenth,'\0',105);
   double rate = (current * 100.0) / total;
   int count = (int)rate;
   while (cnt <= count)
   {lenth[cnt++] = logo; }
    printf("[%-101s][%.1lf%%][%c]\r", lenth, rate, routh[cnt % len]);
     fflush(stdout);
   }

contanct.h

#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include<windows.h>
#include<graphics.h>//包含图形库头文件
#include<mmsystem.h>//包含多媒体设备接口头文件
#include<stdio.h>
#include <string.h>
#include <stdlib.h>
#pragma comment(lib,"winmm.lib")//加载静态库
#define MAX_NAME 20
#define MAX_SEX 6
#define MAX_TEL 12
#define MAX_ADDR 20
#define SIZE 3
enum opion
{
  EXIT,
  ADD,
  DEL,
  SEARCH,
  MODIFY,
  SORT,
  PRINT,
  SAVE,
  MUSIC,
  DESTROY
};
typedef struct peoinfo {
  char name[MAX_NAME];
  char sex[MAX_SEX];
  int age;
  char tel[MAX_TEL];
  char addr[MAX_ADDR];
}peoinfo;
typedef struct pp {
  struct peoinfo *arr;
  int sz;
  int size;
}pp;
void Initcontanct(pp* p);
void Addcontanct(pp* p);
void Printcontanct(pp* p);
void Delcontanct(pp* p);
void findcontanct(pp* p);
void modifycontanct(pp* p);
void Sortcontanct(pp* p);
void Addbig(pp* p);
void Loadcontact(pp* p);
void Savecontact(pp* p);
void bgm();
void DestroyContanct(pp* p);
void bar(double total, double current);

test.cpp

#include"contanct.h"
#include <string.h>
double width = 4;
void doneload(double filesize)
{
  double  current = 0;
  while (current <= filesize)
  {
    bar(filesize, current);
    current += width;
    Sleep(1);
  }
  printf("\n");
}
void menu()
{
  printf("#######################################\n");
  printf("#*********    1.add    ***************#\n");
  printf("#*********    2.del    ***************#\n");
  printf("#*********    3.search ***************#\n");
  printf("#*********    4.modify ***************#\n");
  printf("#*********    5.sort   ***************#\n");
  printf("#*********    6.print  ***************#\n");
  printf("#*********    7.save   ***************#\n");
  printf("#*********    8.music  ***************#\n");
  printf("#*********    9.Destroy***************#\n");
    printf("##########    0.exit   ################\n");
}
void test()
{
  pp pro;
  Initcontanct(&pro);
  int input;
  do {
    menu();
    scanf_s("%d", &input);
    doneload(1024);
    system("cls");
    switch (input)
    {
    case  ADD:
      Addcontanct(&pro);
      break;
    case DEL:
      Delcontanct(&pro);
      break;
    case SEARCH:
      findcontanct(&pro);
      break;
    case MODIFY:
      modifycontanct(&pro);
      break;
    case SORT:
      Sortcontanct(&pro);
      break;
    case PRINT:
      Printcontanct(&pro);
      break;
    case SAVE:
      Savecontact(&pro);
      break;
    case MUSIC:
      bgm();
      break;
    case DESTROY:
      DestroyContanct(&pro);
      break;
    case EXIT:
      printf("退出通讯录\n");
      break;
    default:
      printf("输入错误,请重新输入\n");
      break;
    }
  } while (input);
}
void main()
{
  test();
}
目录
相关文章
|
1月前
|
测试技术
自动化测试项目学习笔记(五):Pytest结合allure生成测试报告以及重构项目
本文介绍了如何使用Pytest和Allure生成自动化测试报告。通过安装allure-pytest和配置环境,可以生成包含用例描述、步骤、等级等详细信息的美观报告。文章还提供了代码示例和运行指南,以及重构项目时的注意事项。
170 1
自动化测试项目学习笔记(五):Pytest结合allure生成测试报告以及重构项目
|
1月前
|
测试技术 Python
自动化测试项目学习笔记(四):Pytest介绍和使用
本文是关于自动化测试框架Pytest的介绍和使用。Pytest是一个功能丰富的Python测试工具,支持参数化、多种测试类型,并拥有众多第三方插件。文章讲解了Pytest的编写规则、命令行参数、执行测试、参数化处理以及如何使用fixture实现测试用例间的调用。此外,还提供了pytest.ini配置文件示例。
26 2
|
1月前
|
测试技术 Python
自动化测试项目学习笔记(二):学习各种setup、tearDown、断言方法
本文主要介绍了自动化测试中setup、teardown、断言方法的使用,以及unittest框架中setUp、tearDown、setUpClass和tearDownClass的区别和应用。
61 0
自动化测试项目学习笔记(二):学习各种setup、tearDown、断言方法
|
1月前
|
Linux C++
Linux c/c++之makefile的基础使用
Linux下C/C++项目中makefile的基本使用,包括基础、进阶和高级用法,以及如何创建和使用makefile来自动化编译过程。
15 0
Linux c/c++之makefile的基础使用
|
1月前
|
Linux 开发工具
【Linux快速入门(二)】Linux与ROS学习之编译基础(make编译)
【Linux快速入门(二)】Linux与ROS学习之编译基础(make编译)
|
3月前
|
jenkins 测试技术 持续交付
解锁.NET项目高效秘籍:从理论迷雾到实践巅峰,持续集成与自动化测试如何悄然改变游戏规则?
【8月更文挑战第28天】在软件开发领域,持续集成(CI)与自动化测试已成为提升效率和质量的关键工具。尤其在.NET项目中,二者的结合能显著提高开发速度并保证软件稳定性。本文将从理论到实践,详细介绍CI与自动化测试的重要性,并以ASP.NET Core Web API项目为例,演示如何使用Jenkins和NUnit实现自动化构建与测试。每次代码提交后,Jenkins自动触发构建流程,通过编译和运行NUnit测试确保代码质量。这种方式不仅节省了时间,还能快速发现并解决问题,推动.NET项目开发迈向更高水平。
49 8
|
3月前
|
持续交付 C# 敏捷开发
“敏捷之道:揭秘WPF项目中的快速迭代与持续交付——从需求管理到自动化测试,打造高效开发流程的全方位指南”
【8月更文挑战第31天】敏捷开发是一种注重快速迭代和持续交付的软件开发方法,通过短周期开发提高产品质量并快速响应变化。本文通过问题解答形式,探讨在Windows Presentation Foundation(WPF)项目中应用敏捷开发的最佳实践,涵盖需求管理、版本控制、自动化测试及持续集成等方面,并通过具体示例代码展示其实施过程,帮助团队提升代码质量和开发效率。
72 0
|
3月前
|
Java Spring UED
Spring框架的异常处理秘籍:打造不败之身的应用!
【8月更文挑战第31天】在软件开发中,异常处理对应用的稳定性和健壮性至关重要。Spring框架提供了一套完善的异常处理机制,包括使用`@ExceptionHandler`注解和配置`@ControllerAdvice`。本文将详细介绍这两种方式,并通过示例代码展示其具体应用。`@ExceptionHandler`可用于控制器类中的方法,处理特定异常;而`@ControllerAdvice`则允许定义全局异常处理器,捕获多个控制器中的异常。
51 0
|
3月前
|
数据采集 SQL 前端开发
Java SpringBoot自动化网页爬虫项目
这是一个基于Java Spring Boot的自动化网页爬虫平台,采用图形化界面定义爬虫流程,无需编写代码。该平台高度灵活且可配置,支持Xpath、JsonPath、CSS选择器及正则表达式等多种提取方式,兼容JSON、XML和二进制格式,并支持通过代理服务器访问。它还具备自动管理Cookie、保存数据至数据库或文件、自定义函数和SQL脚本等功能,同时集成了任务监控和日志记录系统。此外,平台支持HTTP接口调用和动态网页抓取,可通过Selenium模拟真实浏览器行为。用户可通过直观的操作界面轻松完成复杂的数据抓取任务。
|
3月前
|
jenkins Java 持续交付
自动化魔法:用Jenkins打造Java项目的持续部署流水线
【8月更文挑战第13天】在软件开发中,自动化部署是提高效率与减少错误的关键。Jenkins作为一款强大的持续集成工具,支持Java项目的自动化构建、测试与部署。通过配置Jenkins及其丰富的插件生态(如Git和Maven插件),可实现从代码提交到上线的全自动化流程。此流程包括从GitHub自动拉取代码、使用Maven构建项目,并通过如`mvn clean install`命令执行构建,最后利用插件如“Publish Over SSH”将制品部署至远程服务器。此外,还可配置邮件通知等后处理动作确保发布的稳定可靠。借助Jenkins,开发者能显著加速软件交付周期,同时减少手动操作带来的风险。
149 0