1
votes

I would like to avoid hard coding the dll and folder names in the AfterClean target, is there a dynamic way to do this? Ideally it would only delete the files and folders created by the Copy in the AfterBuild target.

I tried to simplify this by changing the DestinationFolder to include a subdirectory in the OutputPath. The AfterClean target would only have to remove that subdirectory at this point. However, some of the library's DLLImport paths don't take that subdirectory into consideration which results in a crash.

<?xml version="1.0" encoding="utf-8"?> 
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 
  <Target Name="AfterBuild"> 
    <ItemGroup> 
      <NativeLibs Include="$(MSBuildThisFileDirectory)..\lib\native\**\*.*" />
    </ItemGroup> 
    <Copy SourceFiles="@(NativeLibs)" DestinationFolder="$(OutputPath)\%(RecursiveDir)" /> 
  </Target> 
  <Target Name="AfterClean">
    <Delete Files="$(OutputPath)\LumiAPI.dll" /> 
    <Delete Files="$(OutputPath)\LumiCore.dll" /> 
    <Delete Files="$(OutputPath)\LumiInOpAPI.dll" /> 
    <RemoveDir Directories="$(OutputPath)\SPM" />
    <RemoveDir Directories="$(OutputPath)\plugin" />
  </Target> 
</Project>

Project Structure:

src

  • ConsumingProject

    • ConsumingProject.csproj
  • ConsumingProject.sln

  • packages

    • my-project.5.7.0.12

      • build

      • lib

        • native

          • plugin

            • VenusDvc.dll
          • SPM

            • sSPM_1.bin
          • LumiAPI.dll

          • LumiCore.dll

          • LumiInOpAPI.dll

        • net45

      • my-project.5.7.0.12.nupkg

Essentially I want to delete all the files and folders that were copied from the native folder to the output of the project (ie LumiAPI.dll, LumiCore.dll, SPM (folder), eSPM_1.bin, etc). However I want it to be generic enough so that if I add another folder to the native directory, it will delete those folders/files as well.

1

1 Answers

1
votes

Use a seperate target which lists input and output files, then use that list in both other targets. Note this uses the DestinationFiles attribute from the Copy task instead of DestinationFolders. And it might print some messages about non-existing directories being passed to RemoveDir because the top directory gets removed already before child directories.

update since you don't want to remove the root output directory as it still has files, figured applying the 'only remove output directory if it's empty' principle for any destination directory is probably the safest way to go. Credits go to the answer here.

<Target Name="GetMyOutputFiles">
  <ItemGroup>
    <NativeLibs Include="$(MSBuildThisFileDirectory)..\lib\native\**\*.*" />
    <!--Now add some metadata: output dir and output file-->
    <NativeLibs>
      <DestinationDir>$(OutputPath)\%(RecursiveDir)</DestinationDir>
      <Destination>$(OutputPath)\%(RecursiveDir)%(FileName)%(Extension)</Destination>
    </NativeLibs>
  </ItemGroup>
</Target>

<Target Name="AfterBuild" DependsOnTargets="GetMyOutputFiles">
  <!--Copy one-to-one-->
  <Copy SourceFiles="@(NativeLibs)" DestinationFiles="@(NativeLibs->'%(Destination)')" />
</Target>

<Target Name="AfterClean" DependsOnTargets="GetMyOutputFiles">
  <Delete Files="@(NativeLibs->'%(Destination)')" />

  <!--Find number of files left in each destination directory-->
  <ItemGroup>
    <NativeLibs>
      <NumFiles>0</NumFiles>
       <!--Condition is to avoid errors when e.g. running this target multiple times-->
      <NumFiles Condition="Exists(%(DestinationDir))">$([System.IO.Directory]::GetFiles("%(DestinationDir)", "*", System.IO.SearchOption.AllDirectories).get_Length())</NumFiles>
    </NativeLibs>
  </ItemGroup>

  <!--Only remove empty directories, use 'Distinct' to skip duplicate directories-->
  <RemoveDir Directories="@(NativeLibs->'%(DestinationDir)'->Distinct())" Condition="%(NumFiles)=='0'" />
</Target>