导致GNU Make出局的原因

时间:2014-07-01 09:06:59

标签: makefile

GNU如何决定是直接从规则运行一行还是通过批处理文件?我在Windows Server 2008平台上使用GNU Make v3.80,所以我的shell是cmd.exe。

打开调试(-d)并注意到规则中的某些行不是通过子shell运行的(在我的情况下是使用cmd.exe批处理),但似乎是由make直接调用。

见下面的例子。查看xcopy命令如何直接运行:

CreateProcess(C:\Windows\system32\xcopy.exe,xcopy /?,...)

但是echo命令是通过批处理文件运行的:

Creating temporary batch file C:\Users\fbloggs\AppData\Local\Temp\95\make732002.bat

示例makefile:

stackoverflow :
    xcopy /?
    @echo Done

完整的dDebug输出:

GNU Make 3.80 Tool Version v1.3  build for Linux on 20060503
Copyright (C) 2002  Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
find_and_set_shell path search set default_shell = C:/Windows/System32/cmd.exe
Reading makefiles...
Reading makefile `..\..\..\pi_scripts\make\make_shell.mak'...
Updating makefiles....
 Considering target file `..\..\..\pi_scripts\make\make_shell.mak'.
  Looking for an implicit rule for `..\..\..\pi_scripts\make\make_shell.mak'.
  No implicit rule found for `..\..\..\pi_scripts\make\make_shell.mak'.
  Finished prerequisites of target file `..\..\..\pi_scripts\make\make_shell.mak'.
 No need to remake target `..\..\..\pi_scripts\make\make_shell.mak'.
Updating goal targets....
Considering target file `stackoverflow'.
 File `stackoverflow' does not exist.
 Finished prerequisites of target file `stackoverflow'.
Must remake target `stackoverflow'.
xcopy /?
CreateProcess(C:\Windows\system32\xcopy.exe,xcopy /?,...)
Putting child 0x025dc670 (stackoverflow) PID 39739552 on the chain.
Live child 0x025dc670 (stackoverflow) PID 39739552 
Copies files and directory trees.

NOTE: Xcopy is now deprecated, please use Robocopy.

XCOPY source [destination] [/A | /M] [/D[:date]] [/P] [/S [/E]] [/V] [/W]
                           [/C] [/I] [/Q] [/F] [/L] [/G] [/H] [/R] [/T] [/U]
                           [/K] [/N] [/O] [/X] [/Y] [/-Y] [/Z] [/B]
                           [/EXCLUDE:file1[+file2][+file3]...]

  source       Specifies the file(s) to copy.
  destination  Specifies the location and/or name of new files.
<snip>
Reaping winning child 0x025dc670 PID 39739552 
Creating temporary batch file C:\Users\fbloggs\AppData\Local\Temp\95\make732002.bat
CreateProcess(C:\Users\fbloggs\AppData\Local\Temp\95\make732002.bat,C:\Users\fbloggs\AppData\Local\Temp\95\make732002.bat,...)
Live child 0x025dc670 (stackoverflow) PID 39739552 
Done
Reaping winning child 0x025dc670 PID 39739552 
Cleaning up temp batch file C:\Users\fbloggs\AppData\Local\Temp\95\make732002.bat
Removing child 0x025dc670 PID 39739552 from chain.
Successfully remade target file `stackoverflow'.

1 个答案:

答案 0 :(得分:4)

有趣的问题。虽然我没有机会验证我的答案,因为我没有设置环境来重现这个,我会根据源代码读取尝试一下。作为参考,下面的行是从GNU make源文件job.c复制的。

首先,该代码表示​​何时直接执行命令以及何时通过shell执行命令。

3470 /* Figure out the argument list necessary to run LINE as a command.  Try to
3471    avoid using a shell.  This routine handles only ' quoting, and " quoting
3472    when no backslash, $ or ' characters are seen in the quotes.  Starting
3473    quotes may be escaped with a backslash.  If any of the characters in
3474    sh_chars[] is seen, or any of the builtin commands listed in sh_cmds[]
3475    is the first word of a line, the shell is used.

对于您的环境,这两个字符串数组似乎是:

2625   static char sh_chars_dos[] = "|&<>";
2626   static char *sh_cmds_dos[] = { "assoc", "break", "call", "cd", "chcp",
2627                                  "chdir", "cls", "color", "copy", "ctty",
2628                                  "date", "del", "dir", "echo", "echo.",
2629                                  "endlocal", "erase", "exit", "for", "ftype",
2630                                  "goto", "if", "if", "md", "mkdir", "move",
2631                                  "path", "pause", "prompt", "rd", "rem", "ren",
2632                                  "rename", "rmdir", "set", "setlocal",
2633                                  "shift", "time", "title", "type", "ver",
2634                                  "verify", "vol", ":", 0 };

上面列表中的任何命令都由&#34; shell&#34;执行。 - 但是,在你的情况下,这并不意味着调用任何shell,而是像你提到的那样创建这个临时批处理文件。在函数construct_command_argv_internal()中,可以找到以下注释和代码:

3139 #ifdef WINDOWS32
3140         else    /* non-Posix shell (cmd.exe etc.) */
3141           {
3142             const char *f = line;
3143             char *t = line;
3144             char *tstart = t;
3145             int temp_fd;
3146             FILE* batch = NULL;
3147             int id = GetCurrentProcessId ();
3148             PATH_VAR(fbuf);
3149
3150             /* Generate a file name for the temporary batch file.  */
3151             sprintf (fbuf, "make%d", id);
3152             *batch_filename = create_batch_file (fbuf, 0, &temp_fd);
3153             DB (DB_JOBS, (_("Creating temporary batch file %s\n"),
3154                           *batch_filename));

这与make运行的输出一致。也许您可以尝试sh_cmds_dos列表中的一些命令,以检查这是否是正确的分析......