Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Directory.Build.targets for project files without targets in Visual Studio

If my project file doesn't have any targets, and I have Directory.Build.targets file (with appropriate targets) in appropriate directory, Visual Studio cannot build project. Version of VS is 2019RC, but I don't think this is problem of particular version

Is that expected behavior, and why?

UPDATE - the full structure of the project. In general, this is modified project from "Data Connector Project" template of "Power Query SDK" - https://marketplace.visualstudio.com/items?itemName=Dakahn.PowerQuerySDK

The project name is PQExtensionTest. It has typical folder structure - PQExtensionTest solution directory, inside PQExtensionTest.sln file and PQExtensionTest project directory with PQExtensionTest.mroj and Directory.build.targets files.

PQExtensionTest.sln file:

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.28010.2046
MinimumVisualStudioVersion = 10.0.40219.1
Project("{4DF76451-A46A-4C0B-BE03-459FAAFA07E6}") = "PQExtensionTest", "PQExtensionTest\PQExtensionTest.mproj", "{6DEC2A2E-C380-4701-AA12-5052284223E4}"
EndProject
Global
    GlobalSection(SolutionConfigurationPlatforms) = preSolution
        Debug|x86 = Debug|x86
        Release|x86 = Release|x86
    EndGlobalSection
    GlobalSection(ProjectConfigurationPlatforms) = postSolution
        {6DEC2A2E-C380-4701-AA12-5052284223E4}.Debug|x86.ActiveCfg = Debug|x86
        {6DEC2A2E-C380-4701-AA12-5052284223E4}.Debug|x86.Build.0 = Debug|x86
        {6DEC2A2E-C380-4701-AA12-5052284223E4}.Release|x86.ActiveCfg = Release|x86
        {6DEC2A2E-C380-4701-AA12-5052284223E4}.Release|x86.Build.0 = Release|x86
    EndGlobalSection
    GlobalSection(SolutionProperties) = preSolution
        HideSolutionNode = FALSE
    EndGlobalSection
    GlobalSection(ExtensibilityGlobals) = postSolution
        SolutionGuid = {50EB6857-946A-4D05-B65C-B99E4D39BEDD}
    EndGlobalSection
EndGlobal

PQExtensionTest.mroj file:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <ProjectGuid>{6dec2a2e-c380-4701-aa12-5052284223e4}</ProjectGuid>
  </PropertyGroup>
  <ItemGroup>
    <Compile Include="PQExtensionTest.pq">
      <SubType>Code</SubType>
    </Compile>
    <Content Include="PQExtensionTest.query.pq">
      <SubType>Code</SubType>
    </Content>
  </ItemGroup>
</Project>

Directory.Build.targets file:

<Project DefaultTargets="BuildExtension" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
    <SchemaVersion>2.0</SchemaVersion>
    <ProjectGuid>{a9cd1ca9-92e5-493d-8065-377910605c30}</ProjectGuid>
    <OutputType>Exe</OutputType>
    <RootNamespace>MyRootNamespace</RootNamespace>
    <AssemblyName>MyAssemblyName</AssemblyName>
    <EnableUnmanagedDebugging>False</EnableUnmanagedDebugging>
    <AllowNativeQuery>False</AllowNativeQuery>
    <AsAction>False</AsAction>
    <FastCombine>False</FastCombine>
    <ClearLog>False</ClearLog>
    <ShowEngineTraces>False</ShowEngineTraces>
    <ShowUserTraces>False</ShowUserTraces>
    <LegacyRedirects>False</LegacyRedirects>
    <SuppressRowErrors>False</SuppressRowErrors>
    <SuppressCellErrors>False</SuppressCellErrors>
    <MaxRows>1000</MaxRows>
    <ExtensionProject>Yes</ExtensionProject>
    <Name>PQExtensionTest</Name>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
    <DebugSymbols>false</DebugSymbols>
    <!--Should be true, fix this when the debugger is implemented -->
    <OutputPath>bin\Debug\</OutputPath>
  </PropertyGroup>
  <PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
    <DebugSymbols>false</DebugSymbols>
    <OutputPath>bin\Release\</OutputPath>
  </PropertyGroup>
  <ItemGroup>
    <Reference Include="mscorlib" />
    <Reference Include="System" />
    <Reference Include="System.Data" />
    <Reference Include="System.Xml" />
  </ItemGroup>
 <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
  <UsingTask TaskName="BuildExtension" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v12.0.dll">
    <ParameterGroup>
      <InputDirectory ParameterType="System.String" Required="true" />
      <OutputFile ParameterType="System.String" Required="true" />
    </ParameterGroup>
    <Task>
      <Reference Include="System.IO.Compression" />
      <Reference Include="System.IO.Compression.FileSystem" />
      <Using Namespace="System.Globalization" />
      <Using Namespace="System.IO.Compression " />
      <Code Type="Fragment" Language="cs"><![CDATA[    
    using(FileStream fileStream = File.Create(OutputFile))
    using(ZipArchive archiveOut = new ZipArchive(fileStream, ZipArchiveMode.Create, false))
    {
        foreach(string fullPath in Directory.EnumerateFiles(InputDirectory))
        {
            string filename = Path.GetFileName(fullPath);

            archiveOut.CreateEntryFromFile(fullPath, filename, CompressionLevel.Optimal);
        }
    }
]]></Code>
    </Task>
  </UsingTask>
  <Target Name="BuildExtension" DependsOnTargets="ExtensionClean">
    <ItemGroup>
      <PQFiles Include="@(Compile)" Condition="'%(Extension)' == '.pq'" />
    </ItemGroup>
    <ItemGroup>
      <NonPQFiles Include="@(Compile)" Condition="'%(Extension)' != '.pq'" />
    </ItemGroup>
    <MakeDir Directories="$(IntermediateOutputPath)" />
    <MakeDir Directories="$(OutputPath)" />
    <Copy SourceFiles="@(NonPQFiles)" DestinationFolder="$(IntermediateOutputPath)" />
    <Copy SourceFiles="@(PQFiles)" DestinationFiles="@(PQFiles->'$(IntermediateOutputPath)%(RecursiveDir)%(FileName).m')" />
    <BuildExtension InputDirectory="$(IntermediateOutputPath)" OutputFile="$(OutputPath)\$(ProjectName).mez" />
  </Target>
  <Target Name="ExtensionClean">
    <!-- Remove obj folder -->
    <RemoveDir Directories="$(BaseIntermediateOutputPath)" />
    <!-- Remove bin folder -->
    <RemoveDir Directories="$(OutputPath)" />
<Message Text="MyM: $(aProperty)" />
   </Target>

like image 387
Andrey Minakov Avatar asked Nov 07 '25 01:11

Andrey Minakov


1 Answers

Is that expected behavior, and why?

It depends.

1. First, according to this doc,the Directory.Build.targets only works after the Microsoft.Common.props calls it.

So if you haven't imported the Microsoft.Common.props (or .targets) in a project file, the build will fail.

In this situation,it's a expected behavior that we can't build project with no targets in project file.

2. As you mentioned "I have Directory.Build.targets file (with appropriate targets)", please make sure you have <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> in your project file. Without it, the build can't work for your situation (with no custom targets in project file).

Make sure you've imported Microsoft.CSharp.targets in project file. And for your targets in Directory.Build.targets, add an attribute <Target BeforeTargets="..."> or <Target AfterTargets="..."> to make it work.

Example for my Directory.Build.targets:

<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
...
  </PropertyGroup>
  <Target Name="Test" AfterTargets="build">
    <Message Text="..."/>
  </Target>
</Project>

Only when you've met these points can you build successfully in your situation.So please check it.

Update:

For a custom .proj file. We must have a target defined directly in .proj file or have a target imported with other targets files.

Since there is no targets in your proj file, and no targets in your Imported targets will be run, MSBuild will throw the error MSB4040 (There is no target in Project). Because if no target runs, then it doesn't make sense for the MSBuild process. This is the feature by design.

Update2

In a test.sln, I have a Directory.build.props in the solution directory:

<Project  xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Target Name="Today">
    <Message Text="JustForTest"/>
  </Target>
</Project>

And a quite simple .csproj file in project dir:

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
</Project>

If I build the test.csproj, the build can succeed and run the Today Target to output "JustForTest". And if I comment out the Import Microsoft.Common.Props, the build will fail with MSB4040. Cause in .NET, the Directory.build.props can not be imported implicitly without the Microsoft.Common.Props.

Update3

I've checked the content of microsoft.common.props and microsoft.Csharp.targets. In M.C.P file, there has definition and calls about Directory.build.props. While in M.C.T file, it defines the standard build process of C#. So I agree that there must be something in your project file which calls Directory.build.props, but that can't be microsoft.Csharp.targets or microsoft.VB.targets. enter image description here

like image 63
LoLance Avatar answered Nov 10 '25 16:11

LoLance



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!