Flexible Project-to-Project References

Flexible Project-to-Project References

Rate This
  • Comments 13

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

  • Your post deals with exactly the problem I've been struggling with.  I'm seeing that the Full Path on the References page specifically references either the Debug or the Release library and does not automatically update when the configuration is switched. Therefore I get linker errors from trying to link a Debug project with a Release project.  (My dependent library is a static library, not a DLL.)

    The solution I found was to set Reference Assembly Output to False. I also set Copy Local to False (since there's no DLL for static libraries) and the two Link Library Dependencies to True. (It's not clear to me how these last two settings relate to the Linker page in the project properties.)

    My full writeup can be found at:

    <a href="http://qualapps.blogspot.com/2010/04/static-library-dependencies-in-visual.html">http://qualapps.blogspot.com/2010/04/static-library-dependencies-in-visual.html</a>

    Did I miss something, or should I be doing this differently?

  • @Jim,

    The experience you mention in your blog is certainly not intended. I can take a look into it if you could share a repro with me at amitmo at micrososft dot com.

    Thanks,

    Amit

  • I can confirm the same problem, in our case (C++) the debug libraries were always getting linked even in release configurations, causing knock-on errors with mismatching options later on (specifically "error LNK2038: mismatch detected for '_ITERATOR_DEBUG_LEVEL': value '2' doesn't match value '0' in blah.obj").

    An example case can be downloaded here: http://sourceforge.net/projects/ogre/files/ogre-dependencies-vc%2B%2B/1.7/OgreDependencies_MSVC_20100501.zip/download - open Dependencies/src/OgreDependencies.VS2010.sln and take a look at the FreeImageLib project, which has project references. The Librarian > Command Line properties will then show you that in the Release configuration, it's pulling in the Debug .libs.

    Turning off the options from the poster above didn't help for me. I had to go back to referencing libs the old-fashioned way.

    Any feedback, please email sinbad AT ogre3d.org

    Thanks

  • Strangely the problem went away for me when I removed and re-added the library dependencies.

    It also seems you can't trust what it says in the Librarian > Command Line property area, because that doesn't change reliably when you switch configurations. The only accurate way to check is to read the lib.command.1.tlog files in the build directories to check the right configurations are used after building. This isn't ideal, it would be good to fix the Librarian > Command Line area so it reflects what the linker will actually do when using these project references.

  • Steve,

    This problem only appears for me when using the Batch Build command. I don't think I've seen the problem happen with the "Build Solution" command.

    Is this what you are seeing?

  • Amit, I have sent you my solution files, which will load into VS2010 and (hopefully) demonstrate the problem in the project settings.

  • @Jim,

    Thanks for the repro project. I am looking into thema nd will get back to you with the result of the investigation.

    Thanks,

    Amit

  • MS VC++ Team,Can't you do sth really useful?

    For years,you just do :

    (1) changes to the compiler what should be done years,years ago.

    (2) BUY some codes from BCG.

    (3) move c++ directories to elsewhere.

    (4) create manifests for binary files then dispose of them.

    (5) create CLI under .net framework,but It Can't be easilly used to develop .net things:asp.net,WPF,Silverlight...

    For these years,you make the most powerfull computer language in the world be out of date.

    You lose aim,and have no enthusiasm on c++.

    Maybe a Web development framework for ISO C++(no cli),is your new start...

  • liangyi:

    Really useful?

    1) So adding C++0x features should have been done years ago? Or are you talking about proper standards compliance? Well, what are you comparing it to for complaincy? I hope not GCC since that is also not fully C99 standards complaint and for the C++ side of things it allows invalid C++ programs to compile with no warnings of extensions used.

    2) BCG? Is that the TB vaccination or the Boston Consulting Group which are there as management consultors?

    3) If you are talking about moving the directories under Tools->Options then obviously you missed the point. It is more flexible now (you can provide a per configuration set of paths) rather than one set per processor architecture. All in all this is a major improvement. My only qualm at this change is the current user interface sucks.

    4) This is mainly down to people just not wanting to learn the new deployment methods. I regularly help people out with manifest problems and the thought of using the vcredist just doesn't cross their minds. For some strange reason the side by side really confused people even though it is usually fixable by installing the latest redist. The only time when I found that manifests could be difficult is in private assembly scenarios.

    5) And after Microsoft tried to push people towards using .NET, the majority of the developers pushed back and said no. So this wasn't Microsoft's choice it was people like us saying we want to use C++ for native application development.

    Whats more, for C++ development, the VS IDE is one of the best. Compare it to others, like Eclipse or Bloodshed and you will see major differences. The only issue I find with VS is that there are some cases where it just takes a while to do some actions.

    For losing aim, the only time when they lost focus was adding managed stuff to C++. After that what has native gotten, TR1, major upgrades to MFC to include Vista/7 support including the Ribbon API, C++0x features, PPL, Open MP and more. Don't forget, VC is not just the compiler, it is all of the libraries which go with it.

  • Why is it that Project Dependency configuration dialog is still available when you say that one should only use Project References ?

    See also: https://connect.microsoft.com/VisualStudio/feedback/details/523470/tries-to-perform-linking-eventhough-it-failed-to-compile-depending-static-library

  • Crescens2k:

    (1) c++0x/1x,standards compliance are useful,but it's not enough to show off,gcc/intel c++ have done more.Actually,if it's the only thing that ms vc++ team can show off,shame on the team!

    (2) for years,on mfc,ms vc++ team have done another GREATE thing,FIND AND REPLACE(ctrl+h): CBCGPRibbonBar to CMFCRibbonBar,CBCGPPropList to CMFCPropertyGridCtrl.... Now you can see,what's the BCG I meant.

    I think,really useful things,that can be done by ms vc++ team:

    (1) a new ui framework beyond mfc,based on directx/opengl,can be ISO C++ version WPF.

    (2) a web development framework(Wt,CppCMS,fastcgi++).

    (3) tools for develop silverlight,we know that,the only things what ISO C++ need are linear memory space with writeable/readable/moveable pointer(Turing Machine) and APIs for silverlight,then,compiler build c++ codes into silverlight binary code...

  • Does anyone know if nested lambda's were fixed for the final release version?

    In the RC the inner lambda would not have access to any scope captured by the 1st lambda.

  • foxtox, according to this blog post (http://blogs.msdn.com/vcblog/archive/2010/04/06/c-0x-core-language-features-in-vc10-the-table.aspx) they were not fixed for release.

Page 1 of 1 (13 items)