All works so magically. Once you have PostSharp installed on your computer, your build process automatically invokes PostSharp when it thinks it should. Most of the cases, it works and it's enough. But if you have a complex build process (especially one that does not use MSBuild), you could ask: how does this work? And how can I integrate PostSharp in my non-MSBuild projects?
Getting Inserted in the MSBuild Process
Most of the stuff is in the file PostSharp-1.0.targets, a file typically installed in the directory C:\Program Files\PostSharp 1.0. From the moment you install PostSharp on your system (that is, using the Microsoft Installer package), this file is included in any project.
There is absolutely no hack in that; it uses extension points of MSBuild especially designed for this purpose (although badly documented). At the very beginning of the file C:\Windows\Microsoft.NET\Framework\v2.0.50727\Microsoft.Common.targets, you will see the following code:
This means that the build process loads the file c:\Program Files\MSBuild\v2.0\Custom.After.Microsoft.Common.targets, if present. He some program wants to be plugged into the standard MSBuild process, it just have to modify this file. And that's exactly what does PostSharp!
Our installer just edits this file and imports our PostSharp-1.0.targets, which gives us the opportunity to insert PostSharp tasks in the build process. How? Here also, using quite standard extension points.
Have a look, in the file Microsoft.Common.targets, at the
All its dependencies are contained in the
property CompileDependsOn. And we want to modify the
compilation process, we modify this property from our PostSharp-1.0.targets:
As you can see, we have inserted three targets after other
compilation targets: PostSharpInspectConstants,
PostSharpInspectReferences, and PostSharp.
Invoking PostSharp Only Relevantly
We could invoke PostSharp in every single project you build on your machine, but it would not last a long time before you uninstall it, isn't it? So we have to decide, in some way, whether PostSharp should be invoked.
This is the role of the targets PostSharpInspectConstants and
PostSharpInspectReferences. Let's begin with the last one, which is also
the most important.
The objective of the PostSharpInspectReferences target is to enable
PostSharp whenever the current project is has direct or indirect references to
the assembly PostSharp.Public.dll. The heuristic works in most cases:
if your assembly references PostSharp.Public.dll, it's probably because
it uses an aspect, so it requires to be post-processed. But it does not work
always: if you develop a PostSharp plug-in or aspect library, you will
surely reference PostSharp.Public.dll, but your plug-in won't need to
be transformed. True, but if you develop a plug-in or an aspect library for
PostSharp, you are more probable to have read the documentation, and you know
how to disable automatic enabling of PostSharp based on references.
And this is one of the role of the target PostSharpInspectConstants:
detecting the presence of the constant SkipPostSharp in your
project. So if you want to skip PostSharp in your project, or only in a
particular build configuration, simply define the SkipPostSharp
constant (aka compilation symbol), and you are done!
PostSharp Has Projects, Too
Like MSBuild, PostSharp has its own notion of project: *.psproj
files. And like MSBuild, PostSharp projects are based on tasks and plug-ins: a
PostSharp project describes all steps that need to be performed to properly
analyze and transform assemblies. You cannot just "execute PostSharp against an
assembly", you always need to provide it a project.
Hopefully, PostSharp comes with a default project: Default.psproj.
The default project automatically detects what is has to do based on custom
attributes present in the assembly. That's why the default project is so
flexible that most users don't need to be aware of this concept.
But this is an advanced post, so let's go on.
What's important here is not how automatic detection of tasks works (it is
documented), but to point out that the default project must take a lot of
properties from the environment, in this case from MSBuild. Here are they:
||Full path of the output assembly.
||Directory by reference to which relative paths in the psproj
will be resolved. We pass the root directory of the project (i.e. the
directory containing your csproj
||Debug or Release, typically. It is
not used by Default.psproj.
||Any, typically. It is not used by Default.psproj.
||Comma-separated list of directories that have to be added to the
search path while looking for plug-ins or referenced assemblies. We pass
the output directory (i.e. bin\debug) as well as all
reference paths defined in user-level project properties.
||Tells PostSharp where to put its own intermediate stuff. We pass
||Whether PostSharp should clean its intermediate files after execution.
We pass false.
||Full path of the MSBuild project file (the csproj or
vbproj). This is to solve relative paths that users could
pass in custom attributes.
||Determines whether the assembly should be signed. We take this value
||Location of the private key. We take this value from MSBuild.
All this stuff is of course passed automatically to PostSharp, so most of the
time you don't have to worry about this. However, if you need to invoke
PostSharp manually, this will surely interest you.
If you are not happy with the default integration of PostSharp in the build
process, there are many ways to do it differently.
If your project is built using MSBuild, you have the following options:
- Do not install PostSharp globally, but insert it manually in each
project. You will have to import PostSharp-1.0.targets
in all C# or VB (or other) project requiring PostSharp. Yup, there is
currently no binary package other than the installer
performing global registration. But you can
do this package yourself by zipping C:\Program Files\PostSharp 1.0
- Do not use our MSBuild targets, but use our
- Use the command-line utility (see below).
If you don't use MSBuild you can use the command line utility. And there is
already a NAnt task in the 1.1 branch!
PostSharp from the Command Line
PostSharp comes with a command line utility. Its syntax is very simple,
because nearly everything is passed as named properties:
Usage: postsharp [<options>] <project> <input> [<options>]
/P:name=value Sets a property.
/Attach Gives the opportunity to attach a debugger to the process.
So here is how a call to the command line may look like:
I've explained how PostSharp is invoked from MSBuild and/or Visual Studio,
and described the properties that are passed from MSBuild to PostSharp.
Finally, I've shown how to invoke PostSharp on your own, eventually from the
I hope this has been usefull to some of you and...