Flexible Project-to-Project References

My name is Amit Mohindra and I am a Program Manager with the Visual C++ IDE team. In this post I would like to talk about project-to-project references. In VS2010 release we moved the C++ build and project system to be based on MSBuild. There is an excellent article written by Marian Luparu detailing the change and advantages of the new build/project system (http://blogs.msdn.com/vcblog/archive/2008/11/20/printf-hello-msbuild-n.aspx).


Project to Project references have existed ever since Visual Studio 6. However the term has evolved over the years. Native technologies used Project dependencies to define references prior to Visual Studio 8. With Visual Studio 8 native projects were able to define project to project references.


“Project to Project references” defines the mechanism in which Project A creates a reference to Project B, by which Project A consumes the output of Project B to deliver on its functionality.  This feature is consumed by users who have large source code bases, a solution with many large projects and input of one project is driven by the output of another project.


Traditionally, there are three variables that control how project references work:


·         Ignore Import Library (Set On the Referenced project)


Tells the linker not to try to link any .lib output generated from this build into any dependent project. This allows the project system to handle .dll files that do not produce a .lib file when built. If a project is dependent on another project that produces a DLL, the project system automatically will link the .lib file produced by that child project. This may not be needed by projects that are producing COM DLLs or resource-only DLLs; these DLLs do not have any meaningful exports. If a DLL has no exports, the linker will not generate a .lib file. If no export .lib file is present on the disk, and the project system tells the linker to link with this (missing) DLL, the link will fail.


Use “Ignore Import Library to resolve this problem. When set to “Yes, the project system will ignore the presence or absence of that .lib file and cause any project that is dependent on this project to not link with the nonexistent .lib file.


·         Link Library Dependencies (Set On the Referencing project)


Gives you the choice of linking in the .lib files that are produced by dependent projects. Typically, you will want to link in the .lib file. If you don’t want to consume the .lib file generated then just set this Linker setting to “False”.


·         Use Library Dependency Inputs (Set On the Referencing project)


In a large project, when a dependent project produces a .lib file, incremental linking is disabled. If there are many dependent projects that produce .lib files, building the application can take a long time. When this property is set to Yes, the project system links in the .obj files for .libs produced by dependent projects, thus enabling incremental linking.


In this design however there were limitations and the design wasn’t very flexible in allowing the project defining the reference to control the behavior. Consider the following very simple example:



 


          Project A defines project-to-project references to Project B and Project C (both Project B and C create .lib outputs). Project A wants to only consume the library output of Project B and not for Project C.


o   In VS2008, this was achieved by creating references to Project A with “Link Library Dependency” property set to “Yes” for Project A and subsequently setting “Ignore Import Library” for Project B to “No”.


§  This approach however had a disadvantage in that if there was another Project D referencing Project B it would be limited by the “Ignore Import Library” property being set to “No”. The scenario shown in diagram above was not achievable in VS2008.


In VS2010 we have enabled the above scenario by supporting reference level metadata on the project references. Now you can set “Link Library Dependencies” and “Use Library Dependency Inputs” properties at the project reference level. To achieve the scenario above:


          Project A will create a project reference to Project B and Project C


          For the Project B set the “Link Library Dependencies” property to “False”


          Project D will create a project reference to Project B and Project C. In this case the global defaults for the properties (“Link Library Dependencies” set to “True” and “Use Library Dependency Inputs” set to “False”) will define the behavior.


To set these properties you can use the “Framework and References” tab in the property page of the parent project (Project A) as follows:


 





 



 



It looks like the following in Project A.vcxproj:


<ItemGroup>


    <ProjectReference Include=..\Project B\Project B.vcxproj>


      <Project>{fcefddd7-fc28-490a-a937-ee8ce39c43d7}</Project>


      <Private>true</Private>


      <ReferenceOutputAssembly>true</ReferenceOutputAssembly>


      <CopyLocalSatelliteAssemblies>false</CopyLocalSatelliteAssemblies>


      <LinkLibraryDependencies>false</LinkLibraryDependencies>


      <UseLibraryDependencyInputs>false</UseLibraryDependencyInputs>


    </ProjectReference>


    <ProjectReference Include=..\Project C\Project C.vcxproj>


      <Project>{687d125d-f004-4901-8654-725f65c93528}</Project>


    </ProjectReference>


</ItemGroup>


 


This results in the following command-line for Project A:



 



Similarly for Project D:


 



 


It looks like the following in Project D.vcxproj:




  <ItemGroup>


    <ProjectReference Include=..\Project B\Project B.vcxproj>


      <Project>{fcefddd7-fc28-490a-a937-ee8ce39c43d7}</Project>


    </ProjectReference>


    <ProjectReference Include=..\Project C\Project C.vcxproj>


      <Project>{687d125d-f004-4901-8654-725f65c93528}</Project>


    </ProjectReference>


  </ItemGroup>


 


This results in the following command-line for Project D:


 


 


 



Thanks,


Amit Mohindra