Convert a PreBuildEvent to a Target with a Conditi

2019-09-13 12:12发布

问题:

I have a project called cryptdll.vcxproj. cryptdll depends on artifacts from two other projects in the solution. The other projects are cryptlib and cryptest. For those interested in the layout of elements in cryptdll, it is located at cryptdll.

The dependencies are somewhat unusual and not easily expressed in the Visual Studio editor. They are unusual because policy requires Win32\Output\Debug\cryptest.exe always be used to perform a PostBuildEvent cryptdll.

I found I could add the following to cryptdll to get things working as expected:

<!-- Win32/Debug cryptest.exe for DLL MAC'ing -->
<ItemDefinitionGroup Condition="!Exists('Win32\Output\Debug\cryptest.exe')" Label="MAC tool">
  <PreBuildEvent>
    <Message>Creating Win32/Debug cryptest.exe for MAC computation</Message>
    <Command>
      msbuild /t:Build /p:Configuration=Debug;Platform=Win32 cryptlib.vcxproj
      msbuild /t:Build /p:Configuration=Debug;Platform=Win32 cryptest.vcxproj
    </Command>
  </PreBuildEvent>
</ItemDefinitionGroup>

When I attempted to convert it to a Target it stopped working. Below is the target rule.

<!-- Win32/Debug cryptest.exe for DLL MAC'ing -->
<Target Condition="!Exists('Win32\Output\Debug\cryptest.exe')" Name="MAC tool" Label="MAC tool">
  <MSbuild
    Projects="cryptlib.vcxproj"
    Properties="Configuration=Debug;Platform=Win32;"/>
  <MSbuild
    Projects="cryptest.vcxproj"
    Properties="Configuration=Debug;Platform=Win32;"/>
</Target>

My question is, what is wrong with the code converted to a Target, and how do I fix it?


For completeness, I want what the Makefile folks call a Prerequisite. The best I can tell from searching, every result for "MSBuild prerequisite" is irrelevant.


Here is what the Target'd output looks like. Notice the task is skipped as if it did not exist.

>del /q /s Win32 x64
...

>msbuild /t:build /p:Configuration=Release;Platform=x64 cryptdll.vcxproj
Microsoft (R) Build Engine version 4.6.1055.0

Build started 10/6/2016 11:40:26 AM.
Project "c:\cryptopp\cryptdll.vcxproj" on node 1 (build target(s)).
PrepareForBuild:
  Creating directory "x64\cryptdll\Release\".
  Creating directory "x64\DLL_Output\Release\".
InitializeBuildStatus:
  Creating "x64\cryptdll\Release\cryptdll.unsuccessfulbuild" because "AlwaysCre
  ate" was specified.
CustomBuild:
  Performing Custom Build Tools
   Assembling: c:\cryptopp\x64dll.asm
ClCompile:
  c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin\AMD64\CL.exe /c /Z
  i /nologo /W4 /WX- /O2 /Ob2 /Oi /Oy /D NDEBUG /D CRYPTOPP_EXPORTS /D CRYPTOPP
  _ENABLE_COMPLIANCE_WITH_FIPS_140_2=1 /D USE_PRECOMPILED_HEADERS /D _WINDLL /G
  F /Gm- /EHsc /MT /GS /Gy /fp:precise /Zc:wchar_t /Zc:forScope /Yc"pch.h" /Fp"
  x64\cryptdll\Release\cryptopp.pch" /Fo"x64\cryptdll\Release\\" /Fd"x64\cryptd
  ll\Release\vc100.pdb" /Gd /TP /errorReport:none pch.cpp
  pch.cpp
  ...

  <rest of the DLL is built>

PostBuildEvent:
  Description: Adding MAC to DLL

          Win32\output\debug\cryptest.exe mac_dll "cryptopp\x64\DLL_Output\Rele
  ase\cryptopp.dll"
          IF %ERRORLEVEL% EQU 0 (echo mac done > "x64\DLL_Output\Release\"\cryp
  topp.mac.done)

  :VCEnd
  The system cannot find the path specified.
C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\Microsoft.CppCommon.targets(1
13,5): error MSB3073: The command "\r [c:\cryptopp\cryptdll.vcxproj]
C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\Microsoft.CppCommon.targets(1
13,5): error MSB3073:         Win32\output\debug\cryptest.exe mac_dll "c:\crypt
opp\x64\DLL_Output\Release\cryptopp.dll"\r [c:\cryptopp\cryptdll.vcxproj]
C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\Microsoft.CppCommon.targets(1
13,5): error MSB3073:         IF %ERRORLEVEL% EQU 0 (echo mac done > "x64\DLL_O
utput\Release\"\cryptopp.mac.done)\r [c:\cryptopp\cryptdll.vcxproj]
C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\Microsoft.CppCommon.targets(1
13,5): error MSB3073:       \r [c:\cryptopp\cryptdll.vcxproj]
C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\Microsoft.CppCommon.targets(1
13,5): error MSB3073: :VCEnd" exited with code 3. [c:\cryptopp\cryptdll.vcxproj
Done Building Project "c:\cryptopp\cryptdll.vcxproj" (build target(s)) -- FAILE
D.

Build FAILED.

回答1:

When I attempted to convert it to a Task You mean a Target, that is not the same as a Task: the first contains the latter.

Notice the task is skipped as if it did not exist. Well you don't tell msbuild anywhere what to do with the target so it cannot possibly know when to invoke it. You want it called before the build so you must express that somehow. Here, the BeforeTargets attribute (documentation in same link above) is the canonical way:

<Target Condition="!Exists('Win32\Output\Debug\cryptest.exe')"
        Name="MAC tool"
        BeforeTargets="Build">

sidenote: why bother adding a Label to a target which just duplicates the name?