Project references have a dual role in MSBuild. They ensure the correct build order, and allow a project to locate the outputs of other projects to reference them.
Visual Studio allows creating project dependencies in solution (.sln
) files. These are stored in the solution file and are only respected when building a solution or inside Visual Studio. If you build a single project, this type of dependency is ignored.
TODO: transformed into ProjectReference
s
The common MSBuild targets used in most project types express dependencies between projects using ProjectReference
items. The Include
value of the item is a path to the project to reference, and metadata on the project controls aspects of the referencing process.
TODO: this doesn't work in VS. Except maybe Properties do, somehow? See https://twitter.com/onovotny/status/1052219278173396992
By default, the output of projects from ProjectReference
s is treated as a Reference
in the current project--for example, if you reference A.csproj
which produces A.dll
, A.dll
will be passed to the compiler as an assembly reference.
If the metadatum ReferenceOutputAssembly
is set to false
, the dependency is considered "build ordering only", and the output of the referenced project will not be automatically added to the current projects Reference
s.
If no Targets
metadata is specified, the default target of the referenced project (usually Build
) will be built and its output referenced in the current project.
If you would like to build a different target (or targets), specify them as a semicolon-delimited list in the Targets
metadatum.
NOTE: Specifying a nonstandard target usually also needs ReferenceOutputAssembly=false
, unless the target returns the primary output assembly of the referenced project.
When set, the output of the project is put into the specified item, in addition to the default Reference
(which can be disabled with ReferenceOutputAssembly
). It is sometimes useful to set <OutputItemType>Content</OutputItemType>
to copy the output of the other project as a "plain file" rather than a .NET assembly reference.
WARNING: global properties are INFECTIOUS, so be careful with this
SetConfiguration
SetPlatform
GlobalPropertiesToRemove
Properties
AdditionalProperties
UndefineProperties
When using SDK-style projects, a single project may be built for different TargetFrameworks
, resulting in multiple, incompatible outputs for the project. When such a project is a ProjectReference
, the common targets automatically select the most appropriate TargetFramework
to reference.
NuGet's asset-compatibility matrix (TODO LINK) is used to select the best available TargetFramework
of the referenced project. If no compatible TargetFramework
is available, an error like
TODO
will be emitted from the referencing project.
The AssetTargetFallback
property of the referencing project is considered when selecting a compatible framework.
SetTargetFramework="TargetFramework=.."
SkipGetTargetFrameworkProperties=true
implies there's a single TF or you want the outer build
Hopefully, the following information will help fill in some TODOs or someone else who ends up here trying to figure out how to control build order with non-matching frameworks.
Example of TargetFramework negotiation error:
The following worked for me to create a build dependency from a multi-target project to a single target project:
Without
<UndefineProperties>TargetFramework</UndefineProperties>
the error wasWithout
<SkipGetTargetFrameworkProperties>true</SkipGetTargetFrameworkProperties>
the error was