Check if variable is defined in PostBuildEvent

Viewed 2182

I am using the following PostBuildEvent

<PostBuildEvent>
  IF DEFINED $(MyEnvVar) (
   mkdir "C:\tmp\"
   copy "$(TargetPath)" "$(MyEnvVar)/Addins/Software/bin/$(PlatformName)/$(TargetFileName)"
 )
</PostBuildEvent>

This event works if my MyEnvVar is defined. However, I get an error MSB3073 (exited with code 255) if the variable is not defined.

How can I define my PostBuild task to do some cmd operations, (create folders copy files as shown above), if the variable exists, or do nothing if it not?

3 Answers

You should not really be using post build events, at all, ever. Just create a target and have it run after the build target. In that target, have it copy the files you want. Something like this:

<Target Name="CopyMyStuff" AfterTargets="Build" Condition="exists('$(MyEnvVar)')" >
   <Copy SourceFiles="$(TargetPath)" DestinationFolder="$(MyEnvVar)\Addins\Software\bin\$(PlatformName)\" SkipUnchangedFiles="true" />
</Target>

I think this copy task will create the directory if it doesn't exist. A nice bonus.

Visual Studio replaces all occurrences of $(Variable) by the string of the Visual Studio variable in value of XML element PostBuildEvent before creating a batch file with the PostBuildEvent text for temporary execution after compilation and link process finished successfully.

If a referenced Visual Studio variable like MyEnvVar does not exist at all, its reference $(Variable) is replaced by an empty string. This results here in the command line:

IF DEFINED  (

Windows command processor executing the batch file expects the name of an environment variable after DEFINED on this IF condition and not an opening parenthesis. That is a syntax error detected by cmd.exe on evaluating the arguments of command IF resulting in exiting processing of the batch file.

One solution is using:

<PostBuildEvent>
  set "MyEnvVar=$(MyEnvVar)"
  if defined MyEnvVar (
   mkdir "C:\tmp\"
   copy "$(TargetPath)" "$(MyEnvVar)\Addins\Software\bin\$(PlatformName)\$(TargetFileName)"
 )
</PostBuildEvent>

The first line assigns current string value of Visual Studio variable MyEnvVar to environment variable MyEnvVar. Therefore environment variable MyEnvVar is either defined with a string because of set "MyEnvVar=string value" or definitely not defined (anymore) after this first line in case of Visual Studio variable MyEnvVar does not exist or has an empty string resulting in execution of set "MyEnvVar=".

The command IF is always of valid syntax because now the name of the environment variable to check for definition is always specified on this command line independent on existence and string value of Visual Studio variable MyEnvVar.

Additional note: The directory separator on Windows is \ and not / as used in target path. The Windows file system accessing kernel functions automatically replace all / by \ in full qualified target file name as part of an automatic file path correction. But it is better to write the post build event code with 100% correct syntax and do not depend on automatic error corrections on file path.

I copied your script and met the same issue. According to the error message The syntax of the command is incorrect, something is wrong with the syntax, maybe a space, a new-line which I'm not certainly sure:(

How can I define my PostBuild task to do some cmd operations, (create folders copy files as shown above), if the variable exists, or do nothing if it not?

As a workaround: Maybe you can remove the Judgment statement from inside the PostBuildEvent. Then use msbuild condition to judge if the variable is defined or not, try using a script like this:

  <!--<PropertyGroup>
    <MyEnvVar>C:\Test</MyEnvVar>
  </PropertyGroup>-->
  <PropertyGroup>
    <PostBuildEvent Condition="$(MyEnvVar)!=''">
      IF NOT EXIST "C:\tmp\" mkdir "C:\tmp\"
      IF NOT EXIST "$(MyEnvVar)\Addins\Software\bin\$(PlatformName)\" mkdir "$(MyEnvVar)\Addins\Software\bin\$(PlatformName)\"
      copy "$(TargetPath)" "$(MyEnvVar)\Addins\Software\bin\$(PlatformName)\"
    </PostBuildEvent>
  </PropertyGroup>

In vs, right-click project and add the script into it, the location should be:

<Project...>
    ...
  <!--<PropertyGroup>
    <MyEnvVar>C:\Test</MyEnvVar>
  </PropertyGroup>-->

  <PropertyGroup>
    <PostBuildEvent Condition="$(MyEnvVar)!=''">
      IF NOT EXIST "C:\tmp\" mkdir "C:\tmp\"
      IF NOT EXIST "$(MyEnvVar)\Addins\Software\bin\$(PlatformName)\" mkdir "$(MyEnvVar)\Addins\Software\bin\$(PlatformName)\"
      copy "$(TargetPath)" "$(MyEnvVar)\Addins\Software\bin\$(PlatformName)\"
    </PostBuildEvent>
  </PropertyGroup>
</Project>

Then right-click the project and choose reload project and check if it helps to achieve your original goal.

1.The PostBuildEvent will work only when MyEnvVar is defined and has its value.

2.The two mkdir command will be called when the C:\tmp\ and $(MyEnvVar)\Addins\Software\bin\$(PlatformName)\ directory not exists

3.Then the copy command will copy the output of your project to Destination Folder, I remove the $(TargetFileName) because it represents xxx.exe or xxx.dll, I think it's not necessary or maybe what you really want is $(AssemblyName). Please let me know if it helps resolve your issue:)

Related