Friday, December 20, 2013

Visual Studio Solution dependent code sections

If you have a Visual Studio project that is part of several solution files (which in most cases is a bad practice - if conditions allow it, rather build a DLL that could be referenced from any solution), you may want to implement solution specific code fragments. In my case, I had a COM interface class that needed to specify a unique CLSID in its IMPLEMENT_OLECREATE call.

The solution: Create a solution specific preprocessor directive. This has been tested in C++ on VS2010:
  1. Define the parameter SOLUTION_$(SolutionName) in Project properties - Configuration Properties - C/C++ - Preprocessor - Preprocessor definitions. Note that the term $(SolutionName) should be written exactly as you see it here - these are MsBuild style variables.
  2. Now in your code, add #ifdef sections checking for the solution name.
  3. If you need to render an error in case none of the solution names defined are found, include a #define SOLUTION_FOUND inside each of your sections and check that it is defined afterwards. If not generate an #error to stop the compiler.
The code will look something like:

#undef SOLUTION_FOUND
#ifdef SOLUTION_MySolutionName1
     (some code specific to that solution)
     #define SOLUTION_FOUND
#endif
#ifdef SOLUTION_MySolutionName2
     (some code specific to that solution)
     #define SOLUTION_FOUND
#endif
#ifndef SOLUTION_FOUND
     #error None of the defined solutions were found. Build can not continue.
#endif

Wednesday, December 11, 2013

Source files missing from project, but still there (Linking error)

Situation: Some .cpp and .h files shared between several Visual Studio Project files in different VS solutions (I know - bad practice, but it was not my idea and I could not change it) were being relocated to a separate directory beside the solution dir of the project I was working on. By unloading the project in VS, then manually editing the .vcxproj file, it was a simple task to search and replace string entries like:

     ClCompile Include="folder\
with
     ClCompile Include="($SolutionDir)..\folder 

Since the job involved much more reorganizing, and there was a lot of other files in the project as well, it was not unexpected that several referencing and linker errors occurred along the way. 

Symptom: In the end I was faced with a linker problem I was not able to get rid of. LNK2001 and LNK2019 errors were filling my screen. I diffed the old and the new .vcxproj files to search for what I had lost along the way, but found no apparent problem at first. Not until I closely examined what reference the linker could not find, making sure that both a header entry and an implementation body (usually in a corresponding .cpp file) were actually present in the project. Somehow some of the files were not!

Problem: It turns out that for file references, the .vcxproj file simply ignores files written with MsBuild variable references like my ($SolutionDir)..\folder\file.cpp -They show up when you view the .vcxproj file in a text editor, but not from within Solution Explorer. Update: Seems like the MsBuild variable actually sometimes works (see the strikeout above), but not in the combination with double dots for jumping one step up in the folder hierarchy. Needs verification what conditions are for this problem to occur.


Solution: Once I had replaced the ($SolutionDir)..\folder entries in the .vcxproj file with the more boring and less flexible ..\..\folder, everything was fine.