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>
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.

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