I’ve heard these confused in the context of MSBuild, so let’s talk a little about what they are:
* A TARGET is a grouping of tasks (often 1) designed to do a particular job. For example, a Link target would be designed to produce a final binary from object files. Targets can declare other targets that they depend on, and MSBuild will make sure those are run first. At present targets are the unit of incremental build: declaring Inputs and Outputs on a target will cause MSBuild to compare their timestamps and skip the target if the inputs are up to date. Because a target is the unit of build, it is the entity that other parts of the build depend on or invoke (via CallTarget or the MSBuild task from another project). The implementation of a target can be modified later, so long as it’s “contract” (“consume X and Y properties and list of object files O to produce binary Z”) is preserved. A future version will likely have an extensibility model for up-to-date checking, and that will likely plug in at the target level. Once a target has run once in the context of a project, global properties, toolsversion, and build, it will be immediately skipped next time it is invoked, without even checking timestamps. When you write a target, always check that it skips properly in the incremental build case. MSBuild logs information about targets during the build, and any extra logging you want has to happen from a task, especially the <Message>, <Warning>, and <Error> tasks. Targets can be batched, although this is rarely done.
A TASK is a reuseable implementation of some build action. In this case the only task in the Link target would likely be the task named Link. It is fed parameters, including the files to link, does the link, and the build proceeds. At present tasks must be .NET assemblies deriving from the interface Microsoft.Build.Framework.ITask. Tasks can consume and emit items and properties. By design, they have no other insight into the state of the build. They should not discover files on disk – this makes them opaque and less reuseable. PropertyGroup and ItemGroup inside targets can be thought of as tasks, but they have special syntax and powers. If your target is starting to get too “clever”, write a task. We hear loud and clear that not everybody wants to write and compile code to create a task, and we’ll address this future. Tasks can be batched, and this is commonly done either to force a task to run once for each source file (something like Sources=”‘%(Compile.Identity)'”) or to filter out certain input files, by filtering in the condition on metadata on source items.
A TOOL is an implementation detail of some tasks. A Link task may happen to currently wrap a tool named link.exe and it may happen that the parameters on this Link task pretty much wrap 1:1 with the command line switches on this tool named link.exe. However those are implementation details. One day the link task could be modified to load a “link.dll”. Or the owners of link.exe could flip the /clr switch in order to implement ITask themselves. Tasks that wrap tools will want to derive from the ready-made abstract class named Microsoft.Build.Utilities.ToolTask, which provides much of the functionality they will need. Many tasks do not wrap tools. [ Aside: For example, during development of MSBuild v1, we initially implemented resource generation by wrapping resgen.exe. However a key scenario was to build a typical VB or C# project without even having the .NET SDK installed, but resgen.exe did not ship in the .NET Framework and we couldn’t persuade them to move it. So we wrote our own resource generation task in code, called GenerateResource. (Resgen.exe is just a thin wrapper over BCL APIs anyway.) A similar situation exists for al.exe, but we did not write a task to do that without the tool: al.exe is some pretty hairy code. This is why you need VS or the .NET SDK installed to build projects with satellite assemblies. But I digress.]
Unlike makefiles, the inputs and outputs on a Target are not necessarily what the “build action”, ie the task, operates on. The task operates only on the parameters it is given. Typically however the Inputs on the Target would be among the inputs passed to the task, but this is not necessarily true. For example the Link target’s Inputs might include $(MSBuildProjectFullPath), so that the target is forced to run if the project file itself has been edited – yet the Link task would not be passed the project file.