首页 > 编程语言 >make项目的源码阅读

make项目的源码阅读

时间:2023-05-28 22:36:26浏览次数:64  
标签:Nonzero 阅读 int make unsigned 源码 file target

这里下载https://ftp.gnu.org/gnu/make/make-4.4.tar.gz进行研读。

目标

研读的初始目的,是想看看make打印的构建命令在哪执行的。

构建make

make项目本身的编译,可以用./configure && make来完成。

代码挖呀挖

make中target抽象为struct file,并用链来组织,

struct file
  {
    const char *name;
    const char *hname;          /* Hashed filename */
    const char *vpath;          /* VPATH/vpath pathname */
    struct dep *deps;           /* all dependencies, including duplicates */
    struct commands *cmds;      /* Commands to execute for this target.  */
    const char *stem;           /* Implicit stem, if an implicit
                                   rule has been used */
    struct dep *also_make;      /* Targets that are made by making this.  */
    struct file *prev;          /* Previous entry for same file name;
                                   used when there are multiple double-colon
                                   entries for the same file.  */
    struct file *last;          /* Last entry for the same file name.  */

    /* File that this file was renamed to.  After any time that a
       file could be renamed, call 'check_renamed' (below).  */
    struct file *renamed;

    /* List of variable sets used for this file.  */
    struct variable_set_list *variables;

    /* Pattern-specific variable reference for this target, or null if there
       isn't one.  Also see the pat_searched flag, below.  */
    struct variable_set_list *pat_variables;

    /* Immediate dependent that caused this target to be remade,
       or nil if there isn't one.  */
    struct file *parent;

    /* For a double-colon entry, this is the first double-colon entry for
       the same file.  Otherwise this is null.  */
    struct file *double_colon;

    FILE_TIMESTAMP last_mtime;  /* File's modtime, if already known.  */
    FILE_TIMESTAMP mtime_before_update; /* File's modtime before any updating
                                           has been performed.  */
    unsigned int considered;    /* equal to 'considered' if file has been
                                   considered on current scan of goal chain */
    int command_flags;          /* Flags OR'd in for cmds; see commands.h.  */
    enum update_status          /* Status of the last attempt to update.  */
      {
        us_success = 0,         /* Successfully updated.  Must be 0!  */
        us_none,                /* No attempt to update has been made.  */
        us_question,            /* Needs to be updated (-q is is set).  */
        us_failed               /* Update failed.  */
      } update_status ENUM_BITFIELD (2);
    enum cmd_state              /* State of commands.  ORDER IS IMPORTANT!  */
      {
        cs_not_started = 0,     /* Not yet started.  Must be 0!  */
        cs_deps_running,        /* Dep commands running.  */
        cs_running,             /* Commands running.  */
        cs_finished             /* Commands finished.  */
      } command_state ENUM_BITFIELD (2);

    unsigned int builtin:1;     /* True if the file is a builtin rule. */
    unsigned int precious:1;    /* Non-0 means don't delete file on quit */
    unsigned int loaded:1;      /* True if the file is a loaded object. */
    unsigned int unloaded:1;    /* True if this loaded object was unloaded. */
    unsigned int low_resolution_time:1; /* Nonzero if this file's time stamp
                                           has only one-second resolution.  */
    unsigned int tried_implicit:1; /* Nonzero if have searched
                                      for implicit rule for making
                                      this file; don't search again.  */
    unsigned int updating:1;    /* Nonzero while updating deps of this file */
    unsigned int updated:1;     /* Nonzero if this file has been remade.  */
    unsigned int is_target:1;   /* Nonzero if file is described as target.  */
    unsigned int cmd_target:1;  /* Nonzero if file was given on cmd line.  */
    unsigned int phony:1;       /* Nonzero if this is a phony file
                                   i.e., a prerequisite of .PHONY.  */
    unsigned int intermediate:1;/* Nonzero if this is an intermediate file.  */
    unsigned int is_explicit:1; /* Nonzero if explicitly mentioned. */
    unsigned int secondary:1;   /* Nonzero means remove_intermediates should
                                   not delete it.  */
    unsigned int notintermediate:1; /* Nonzero means a file is a prereq to
                                       .NOTINTERMEDIATE.  */
    unsigned int dontcare:1;    /* Nonzero if no complaint is to be made if
                                   this target cannot be remade.  */
    unsigned int ignore_vpath:1;/* Nonzero if we threw out VPATH name.  */
    unsigned int pat_searched:1;/* Nonzero if we already searched for
                                   pattern-specific variables.  */
    unsigned int no_diag:1;     /* True if the file failed to update and no
                                   diagnostics has been issued (dontcare). */
    unsigned int was_shuffled:1; /* Did we already shuffle 'deps'? used when
                                    --shuffle passes through the graph.  */
    unsigned int snapped:1;     /* True if the deps of this file have been
                                   secondary expanded.  */
  };

update_file
update_file_1 两个函数递归调用来完成target更新。

最终当检测到target的依赖有更新的话,就调用的是remake_file函数,来真实执行命令。
remake_file函数如下,

static void
remake_file (struct file *file)
{
  if (file->cmds == 0)
    {
      if (file->phony)
        /* Phony target.  Pretend it succeeded.  */
        file->update_status = us_success;
      else if (file->is_target)
        /* This is a nonexistent target file we cannot make.
           Pretend it was successfully remade.  */
        file->update_status = us_success;
      else
        {
          /* This is a dependency file we cannot remake.  Fail.  */
          if (!rebuilding_makefiles || !file->dontcare)
            complain (file);
          file->update_status = us_failed;
        }
    }
  else
    {
      chop_commands (file->cmds); //将命令切分成多条

      /* The normal case: start some commands.  */
      if (!touch_flag || file->cmds->any_recurse)
        {
          execute_file_commands (file);
          return;
        }

      /* This tells notice_finished_file it is ok to touch the file.  */
      file->update_status = us_success;
    }

  /* This does the touching under -t.  */
  notice_finished_file (file);
}
struct commands
  {
    floc fileinfo;              /* Where commands were defined.  */
    char *commands;             /* Commands text.  */
    char **command_lines;       /* Commands chopped up into lines.  */
    unsigned char *lines_flags; /* One set of flag bits for each line.  */
    unsigned short ncommand_lines;/* Number of command lines.  */
    char recipe_prefix;         /* Recipe prefix for this command set.  */
    unsigned int any_recurse:1; /* Nonzero if any 'lines_flags' elt has */
                                /* the COMMANDS_RECURSE bit set.  */
  };

最后找到打印命令在src/job.cstart_job_cpmmand 的1359行,

  /* Print the command if appropriate.  */
  if (just_print_flag || ISDB (DB_PRINT)
      || (!(flags & COMMANDS_SILENT) && !run_silent))
    OS (message, 0, "%s\n", p);

看代码的过程学到一些实用的技巧,

  1. make -n不编译,只打印编译的构建过程,而不真正去编译。这个可以用来收集编译过程。执行过程中,被执行的命令往往都有

  2. make命令中每个target下面多行命令默认是放在不同shell中执行的,如下a.out的target是三条名字,第一条对第二条不影响,所以ls得到的文件列表不是home目录下的。有一种one_shellmode可以将同一个target下的所有命令用,详情参看https://www.gnu.org/software/make/manual/html_node/One-Shell.html.

    a.out: a.c
    	cd ~
    	ls
    	gcc a.c	
    

标签:Nonzero,阅读,int,make,unsigned,源码,file,target
From: https://www.cnblogs.com/zwlwf/p/17438575.html

相关文章

  • 《人月神话》阅读笔记七
    1、保持进度透明可见我们的团队在做项目的过程中,总是少不了实时汇报自己负责的部分进度,我们有时可能会担心,如果我们向上级或者负责人汇报了我们的完成进度,就有可能会因为某些问题扰乱我们的进度和计划。其实,如果我们隐瞒不报,就有可能助长我们的侥幸心理,从而在更大程度上影响我......
  • 常见项目——C语言实现2048小游戏(附源码和可执行文件)
    1.实现效果展示1.1界面图片说明:进入下面各页面后均可通过按键“q”来退出。1)菜单页2)开始游戏页3)游戏规则页4)按键说明页5)退出游戏页1.2视频展现戳此处查看视频演示1.3游戏源码及可执行文件(exe)下载支持作者,请关注公众号“优秀物联人”回复“2048小游戏”获取下......
  • 基于JAVA的springboot+vue摄影跟拍预定管理系统,附源码+数据库+论文+PPT
    1、项目介绍困扰管理层的许多问题当中,摄影跟拍预定管理一定是不敢忽视的一块。但是管理好摄影跟拍预定又面临很多麻烦需要解决,例如有几个方面:第一,往往用户人数都比较多,如何保证能够管理到每一用户;第二,如何在工作琐碎,记录繁多的情况下将摄影跟拍预定的当前情况反应给领导......
  • Tomcat请求处理流程与源码浅析
    系列文章目录和关于我一丶Connector在tomcat中,Connector负责开启socket并且监听客户端请求,返回响应数据。其中:Endpoint:tomcat中没有这个接口,只有AbstractEndpoint,它负责启动线程来监听服务器端口,并且在接受到数据后交给Processor处理Processor:Processor读取到客户端请求......
  • [CMake] CMake学习笔记
    自己的学习和使用总结,还不完善,不定时更新。一.简介cmake是一款高级编译配置工具;所有操作都是通过编译CMakeLists.txt来完成的;CMake官方全部推荐使用大写指令;学习目的:为将来处理大型的C/C++、Java项目做准备;环境:Ubuntu:20.04cmake:3.16.3简单尝试:用C++写......
  • CMake Commands
    cmake_minimum_requiredcmake_minimum_required(VERSION<min>[...<policy_max>][FATAL_ERROR])#限制CMake的版本支持范围cmake_minimum_required(VERSION3.16.3)#限制CMake最低版本3.16.3cmake_minimum_required(VERSION3.16.3...3.20.0)#限制CMake版本最低3.16.3,只要C......
  • CMake Variables
    变量说明CMAKE_SOURCE_DIR源代码所在目录就是根cmakelists.txt所在目录CMAKE_BINARY_DIR跑cmake命令的目录CMAKE_BUILD_TYPE构建类型DebugReleaseRelWithDebInfoMinSizeRelCMAKE_MODULE_PATHcmake的模块路径以;分隔RUNTIME_OUTPUT_DIRECTORYCMAKE_C_......
  • 阅读《java并发编程实战》第十章
    例1:简单的加锁顺序导致的死锁:publicclassLeftRightDeadlock{privatefinalObjectleft=newObject();privatefinalObjectright=newObject();publicvoidleftRight(){synchronized(left){synchronized(right){......
  • 如何给以make工具构建的工程中加debug编译选项
    问题描述make可以像bash一样调用很多命令,debug选项属于编译器(以gcc为例),所以这个问题更准确的描述应该是:如何给make工程中gcc传递-g参数。之所以还用上面的名字,是因为最初的诉求冲到脑子的就是上面的样子。一个偷梁换柱的思路首先我们给gcc弄个wrapper程序gcc_wrapper,在这个wr......
  • 阅读《java并发编程实战》第五章
    阅读《java并发编程实战》第五章Semaphore的应用举例Semaphore的应用举例:实现一个固定大小的Set。当容器满了之后,无法add,线程阻塞。publicclassBoundedHashSet{//invariant:sizeofSetalwayslessthanorequaltogivensizeprivatefinalSet<Integer>s......