【问题标题】:Testing file existence in NMake在 NMake 中测试文件是否存在
【发布时间】:2011-05-27 02:20:10
【问题描述】:

在 GNU Make 的 makefile 中,我使用这个习惯用法来测试文件是否存在:

static:
ifeq ($(wildcard $(FileName)),)
    # do something when the file doesn't exist
else
    # do something different when it does
endif

但它在 NMake (fatal error U1000: syntax error : ')' missing in macro invocation) 中不起作用。我该如何更换它?如果替换在两个构建系统中都有效,那将是完美的。

【问题讨论】:

    标签: makefile nmake


    【解决方案1】:

    csharptest.net 的回答几乎是正确的,但它缺少关于命令和指令之间缩进规则差异的微小细节

    static:
    !if exists($(FileName)) 
        @echo $(FileName) does exist!
    #^^^ DO MIND THE INDENTATION HERE, a command shall fail otherwise!
    #
    !else
    !error $(FileName) does not exist!
    #^^^^^ !directives don't have to be indented, though.
    #
    !endif
    

    奇怪的是,它可以是exist(在官方文档中给出)或exists,效果相同。

    【讨论】:

      【解决方案2】:

      Nmake 可以运行预处理指令:

      http://msdn.microsoft.com/en-us/library/7y32zxwh.aspx

      条件可能不同,但 Exists() 就是其中之一:

      http://msdn.microsoft.com/en-us/library/8t2e8d78.aspx

      !IF EXISTS(foo.txt)
      

      最后你使用命令行,http://msdn.microsoft.com/en-us/library/wkxa7sac.aspx

      !IF [cmd /C IF NOT EXIST "foo.txt" exit 1]
      

      无论哪种方式,这都应该有效,使用上面的任何一个 !IF 都是完整的示例:

      !IF !EXISTS(foo.txt)
      !ERROR Unable to locate foo.
      !ELSE
      !MESSAGE I Found foo!
      !ENDIF
      

      【讨论】:

      • 这应该是公认的答案。它已经在 DDK/WDK 构建过程中使用了很长时间,其中 build.exe 是基于 nmake.exe 的构建过程的包装器。
      【解决方案3】:

      只是为了补充 Jack Kelly 的建议,您可以在 CMD.EXE shell 中进行存在性测试。 NMake 还包括创建临时 .cmd 文件并执行它的能力。

      这是 (n)makefile 语法的一个示例,我将其用于“检查语法”目标。它通过编译检查单个 C# 源文件、多文件项目中的语法。

      check-syntax :
          <<flymake-build.cmd  $(CS_SOURCE)
      SETLOCAL ENABLEDELAYEDEXPANSION
      set errorlevel=
      for %%I in (%*) do if NOT x%%I == x$(FLYMAKE_ORIGINAL) (
         set filesToBuild=!filesToBuild! %%I
      )
      $(_CSC) /t:module $(LIBSREF) $(FLYMAKE_CHECK) !filesToBuild!
      ENDLOCAL && exit /b %errorlevel%
      <<
      

      “flymake-build.cmd”是创建的临时 cmd 文件的名称。双尖括号 (&lt;&lt;) 表示在执行文件之前进入临时文件的内容的开始和结束。

      第一行文件名之后的东西是传递给.cmd文件的参数。在本例中,参数是名为CS_SOURCE 的makefile 变量的内容。就我而言,这只是项目中的文件名列表。 Makefile 变量也将在临时文件的文本中展开。您可以看到我指的是编译器 (_CSC) 和其他一些符号。

      在 .cmd 代码中,您可以执行 for 循环、if 语句以及任何您喜欢的操作。这是一个常规的 .cmd 文件。

      如果您希望 nmake 响应 .cmd 文件中的命令生成的错误(例如,终止构建),那么您需要使用 exit /b 方法来结束 cmd。

      我在某个黑暗的角落找到了这方面的文档,所以我想我会在这里分享它以进行一般说明。 (编辑here's the link。)

      【讨论】:

      • 这真的很简洁,远远超出了我在修补批处理文件时所做的(而且我认为 Bart 的 ModBoot 启动盘很疯狂)。也许您可以针对这些信息提出单独的问题和答案?如果让它消失在互联网的另一个黑暗角落,那就太可惜了。
      • 嘿杰克。是的,我认为这也很有用。我在几个 stackoverflow 答案中引用了这个特性(例如:stackoverflow.com/questions/801778/2813575#2813575stackoverflow.com/questions/3745261/4118794#4118794),其中一个是我自己的问题(stackoverflow.com/q/2806325/48082)。不过,这些问题并不是很受欢迎。这些天来,Nmake 似乎已经过时了,转而支持 msbuild。
      【解决方案4】:

      在 shell 级别而不是 Makefile 级别执行此操作。如果您可以依赖 posix 工具:

      static:
          @if test -f $(FileName); then \
            echo something; \
          else \
            echo some other thing; \
          fi
      

      注意各处的续行标记。

      如果您需要在 CMD.EXE 中执行此操作,那么也许您可以使用 IF EXIST $(FileName) COMMAND ELSE COMMAND 构造执行类似操作。

      【讨论】:

        猜你喜欢
        • 2011-02-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-07-29
        • 2018-12-25
        • 2010-12-28
        • 1970-01-01
        相关资源
        最近更新 更多