Solution Wide Compiler Directives

Continuing with my legacy migration of an application developed using Leadtools Medical Suite v14 to utilise Leadtools Medical suite v19 I blogged a few days ago about how I was attacking it using Conditional syntax dependant upon the library I was compiling against. My primary reason for doing this is that if I have issues with regard to the codebase I can easily revert to testing against the previous codebase using EXACTLY the same code and thus eliminate new issues from pre-existing ones. There are several ways that compiler directives can be utilised none of which entirely suit my needs and I thought I would share how I addressed this issue with y’all.

OK, So method 1 for declaring a Compiler directive is at file level thus:-

#define LEADTOOLS14

And then somewhere later in the code you would use the following Compiler Instructions

#if LEADTOOLS14
    'Legacy Code
#elif LEADTOOLS19
    'New Code
#end

Great, but not really that useful in this circumstance as I have a large project and would have to define these in every file that was touched by this split code which would make switching between code-bases…. time consuming to say the least.

The next option is to make the compiler directives project level as per the example below:-

CaptureBetter, but still the same issue to a lesser degree as I have about 8 projects in my solution. We would therefore have to access the properties for each project and add the required compiler directive saving the details before compiling.

So I came across a few interesting Stack Overflow articles which detailed how to specify compiler directives in just one place. The results are less than satisfactory for reasons I’ll discuss later but they do at least work. The concept is quite simple, we create a file containing the compiler directive we wish to use and we then tell all projects within the solution that they need to include this compiler directives file. Without further ado at solution level we create a new xml file called CommonSettings.targets to which we add the following xml snippet (note that for *cough* Visual Basic projects you must omit the semi colon) :-

    
        $(DefineConstants);LEADTOOLS19
    

Nice and simple, You can see my LEADTOOLS19 compiler directive in there. Now, the more complex and fiddly bit. Its a widely known secret that studio .csproj files can be handcrafted to do more than the Visual Studio UI will allow you to achieve via the UI, this is one of those instances. So using your favourite text editor you need to open each of the  projects that you wish to utilise these compiler directives. Within the xml you then insert the following red snippet of xml:-

  
  
  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
       Other similar extension points exist, see Microsoft.Common.targets.
  
  
  
  
  -->

Simple enough, all you are doing is adding the settings file you created earlier as a reference to your project. You then save these files and reload your project. Voila, your compiler directives should now be operational! There are however a few slight issues with this as far as I can tell:-

  1. You have to reload the solution every time you change the directive.
  2. Compiled code does not always show as ‘compilable’. It is being compiled correctly but just not shown correctly in the editor with intellisense etc. I found that I had to break it outside of the compiler #if statements to write the code and then move it in when finished.
  3. Intellisense seems to crash quite often meaning you need to reload more.
  4. Visual Basic *cough* can be a bit useless and sometimes not ‘see’ the constant. in such cases it is necessary to manually ‘pretend to edit it’ and then save the details.

Even with all of these caveats I think the solution is certainly very usable and much preferable to maintaining two code bases during the migration codebase.

Peace out .Netters.