VS2010/MSBuild 4.0 building external projects - visual-studio-2010

It seems that since VS2010 and MSBuild 4.0, VisualStudio and MSBuild are able to resolve and build project references that are not located within the solution.
Let us create an example to be more concrete. Create a solution called Solution1 with a C# project named A and another project called B. In project B, add a reference to project A. Now create a new solution called Solution2 and click "Add Existing project" and select Project B. There is a warning that can be seen in Solution Explorer and the Warning List.
The trick is that even with "warning as error" we are able to build Solution2.sln. Actually, project A is found
and built by Visual Studio or MSBuild. Let us verify this by opening a VS2010/VS2012 command line and execute the following commands:
msbuild <dirPathToSolution1> Solution1.sln /t:clean **cleaning up solution1 with project A"
msbuild <dirPathToSolution1> Solution2.sln /t:build
ProjectA is effectively built and worse: the warning mentioned above is not even raised there. With previous versions of Visual Studio such situation could not happen (I have tested it with msbuild 3.5 and VS2008).
However, in our situation we would like to prevent such things. Indeed, we have a large source repository with several solutions and many committers. We are reorganizing our dependencies aiming finally to the extraction of smaller repositories. Meanwhile, we do not want developers to add hidden project dependencies without seeing it. We would like to allow only project references "inside" a solution, leaving other dependencies to assembly references.
So the question is "Is there a way, to prevent such solution such as Solution2 to build ?". Ideally, it should not compile with both VS2012 and MSBuild. However a solution involving only the MSBuild command line would do thanks to our Continous Integration.

edit I checked Microsoft.Common.Targets and there does not seem any way to achieve what you want. Either project references are built, or they are not (this is for instance influenced by the BuildProjectReferences flag of my original answer). There is no way to build them selectively depending on which solution they are in unless I'm missing something - which is mainly because project references are set on the project level, not on the solution level: in your project file there is an MsBuild ItemGroup named ProjectReferences and that is used. (Actually this makes some sense: if you ask MsBuild to build projectB.csproj, and B says it references A, then no solution comes into play and you could expect it to build A, after all you are referencing it).
Now as I understand it, you want to prohibit referencing across directories whose structure happens to be represented by solutions. If that is the case, and you really need this, you could probably get away with a tool that parses the MsBuild log and looks for lines like
Project "somedir\projectB.csproj" (2) is building "someOtherDir\projectA.csproj" (3) ...
then extract the directory info from it and make the tool raise an error when they do not match. Then incorporate the tool in your CI server and feed it with the msbuild log files.
original answer
Try with /p:BuildProjectReferences=false on the command line. As the name suggests it will disable building of referenced projects. When building solution1, this should not be a problem since projectA will be built anyway as it is in the solution. However when building solution2, it won't build projectA and you'll get a build error.

Related

Visual Studio Build does not download all NuGet packages without a project reference

I'm trying to understand why removing a project reference prevents my build from downloading all the NuGet packages it needs. This is with Visual Studio 2019
Application A (.NET 5) holds a project reference to Assembly B.
Assembly B uses a NuGet package C.
When the build starts, NuGet Package C get downloaded automatically.
This is all vanilla expected, .NET stuff.
But then I realized that A does not actually use any B-specific types. B is a Prism Module that only loads dynamically if the user has a license for it and clicks a button. So A doesn't even always load "B".
So I removed A's project reference to B. I don't want some future developer to accidentally think they can start referring to types in B. (We don't ship all modules all the time). Technically now, there is no project in the solution that holds a reference to B. But it's still part of the build. I did set up the build dependencies so that B would still build before A but there's no longer a project reference..
Then I did a clean build. Visual Studio said it completed successfully. And I see Assembly B got built. But the build process did NOT retrieve NuGet package C (that B depends on). Testing has revealed it will not retrieve C unless application A actually holds a project reference to B.
Is there some way around this? If I'm building all assemblies, why would MSBuild not download all assemblies dependent NuGet packages. Is there some setting I can change to make it happen.
Answering my own question in case anyone else ever has this problem:
I asked this question of Microsoft. They said that this behavior is by design: If a DLL-generating assembly ("B") uses a NuGet package, then the only way that package will be downloaded at build time is if an assembly that generates an EXE has a project reference to B. Merely having a build dependency is not enough.
No explanation as to why. I still think the behavior should be different for reasons I mentioned in the question and comments above. They said it is a question for the .NET team and referred it to them. I finally got a reply that said, I can make this behavior happen by adding an attribute (named CopyLocalLockFileAssemblies) to my Assembly B's project file.
So I did. Added this:
<PropertyGroup>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
</PropertyGroup>
And it worked. With this attribute set to true, an assembly that requires a NuGet package will get that assembly in the output folder regardless of whether or not anyone has a project reference to it.
(One could argue that this is a RTFM sort of question. But learning MSBuild and its ins-and-outs is one of many things I "eventually need to do" on my plate)

Does MSBuild resolve project to project references when building a solution?

MSDN docs Visual Studio Integration (MSBuild) state:
Building Solutions
Within Visual Studio, the solution file and project build ordering are
controlled by Visual Studio itself. When building a solution with
msbuild.exe on the command line, MSBuild parses the solution file and
orders the project builds. In both cases the projects are built
individually in dependency order, and project to project references
are not traversed. In contrast, when individual projects are built
with msbuild.exe, project to project references are traversed.
With my Visual Studio 2010, when building a .sln file with MSBuild from the command line, project to project references are all built, regardless whether they occur in the solution.
What did I miss here? Or are the docs plain wrong?
You are correct that msbuild.exe will sort out all project references whether or not they are part of the solution in contrast to building within Visual Studio 2010/2012/2013/2015 (and possibly later versions) where you will get a build failure if a referenced project is not part of the solution or built beforehand.
In short, yes, the documentation seems a bit off.
You can ignore the build of project to project reference by running msbuild Solution.sln /t:ProjectName /p:BuildProjectReferences=false this explain the sentence in msdn.

Visual Studio build successful, MSBuild fails

I am trying to clean and rebuild a solution file with multiple projects from the command line using MSBUILD. For some reason my build fails (about 10% of the built projects fail) and I get multiple errors which all look like:
error CS0234: The type or namespace name 'foo' does not exist in the namespace 'bar' (are you missing an assembly reference?)
Now if I clean and rebuild the same solution file from Visual Studio 2010 with the exact same configurations it will build successfully with no errors.
Is there a difference in the setup or configuration of MSBuild from Visual Studio that needs to be changed that I am not aware of?
I just had to deal with this issue and it turns out that msbuild likes to move built binaries into the binaries\release directory and reference those instead of the projects themselves when it builds things. After building it copies the files to this directory. This explains why it works in visual studio and not msbuild (I'm currently using TFS 1010).
In my case I had an old binary version of a dll being referenced by a project that was being built after the one that should have generated the correct file. The old one (binary) was overwriting the new one (built from source) as the solution referencing the binary one was being built later in the build.
I assume there's a difference in how the project is built, because Visual Studio does not run MSBuild, as it rather hosts the build engine itself.
This was answered here.
However, I've had similar problem.
In my case the project referenced an external library, which was placed in the project's child directory, unluckily named "packages".
After running MSBuild the folder's content was deleted, supposedly to be downloaded again by Nuget.
The obvious solution was to rename the folder and it worked.
Summary: Set Debug/Release mode in Visual Studio to the same settings as MSBuild to check for compilation errors.
I encountered the same problem:
Tried deleting all "bin" and "obj" folders.
Made sure all related projects are indeed being referenced and not just liked to compiled dlls. ex. Project B references A. Remove A from solution. Then add again. B would then reference A but via compiled dll only. Remove reference and re-add the project.
Finally switched to "Release" in Visual Studio. Turns out I had conditional compilation in some code (eg. #if DEBUG). So what was running in MSBuild and Visual Studio were actually different hence the error "The type or namespace name 'foo' does not exist in the namespace 'bar' (are you missing an assembly reference?)"
Try checking the paths to the references that MSBuild can't find in the non-building library's project file. Sometimes when you use VS or ReSharper to automatically add a reference for you the path ends up being to the \obj directory. VS seems able to cope with this, but MSBuild not so much.
For me the problem was that the some projects in the solution were not included in the build configuration for the solution. Those projects were dependencies for the projects in the build configuration, so all the projects in the solution failed.
After marking the dependcies projects with build in the solution configuration the msbuild ran successfully.
My issue was found in the solution file.
Remove all lines which reference 'ANY' for CPU and leave the 64 bit ones in.
In my case I had one PCL referencing another PCL with different targets. Visual Studio showed me a warning in the references list of the first library, but compiled the solution, whereas MSBUILD refused to compile. I fixed the problem by retargeting the PCL. Hope this helps somebody.
See my answer here.
Basically - Try running msbuild in a new cmd window everytime as a temporary workaround.
I was facing a similar issue. But after spending a lot of time, I finally came up with a solution (that performs similar to VS)
Use the following command to build your solution
"msbuild.exe project.sln /restore /t:Build /p:Configuration="Release";RunCodeAnalysis=False;RestorePackagesConfig=true”

Visual Studio: How to make one solution depend on another?

Is it possible to make a solution in VS depend on (i.e. include) an entire other solution? I've seen some stuff about "Solution Folders", but these don't seem to be the same thing....? Thanks! (BTW, I'm using VS 2008)
Not really. You'd have to do one of the following:
Make a build script that builds the solutions in the correct order.
Pre-build solution A, and only reference the built binary outputs from it in solution B.
Make a third solution containing all of the projects from both solutions.
The first two items are the most common, where I personally prefer the second.
This post is old, but these days you can easily reuse dependencies in other solutions by building nuget packages for all of them. VS 2015 has nuget package building built in but is currently a Release Candidate. In Visual Studio 2013 you can use the Nuget.Packaging nuget package to allow your project to build as a Nuget Package.
Then you can just publish new versions of your packages to a local network share and configure it as a Repository in Visual Studio.
Then your other solution's projects can depend on that package.
For example, say you have a reusable Utility DLL in a Solution Called "Core Framework" and you want to use a utility in there on a WebSite you are building in a solution called "XYZEcosystem".
In the CoreFramework solution you would build a nuget package for the Utility Project that compiles to the utility dll and include the dll and it's pdb file in the package.
Then you publish that to your network share.
So let's say your package has an ID like "XYZ.Core.Utilities" with a version of 1.0.0.0.
Now in XYZEcosystem you would use the package manager console, set the repository drop down to your repository and type "Install-Package XYZ.Core.Utilities" and it will install the latest version of XYZ.Core.Utilities.
If you make a change to XYZ.Core.Utilities you can run Update-Package XYZ.Core.Utilities on XYZEcosystem and it will pick up the new version.
Take a look here: https://learn.microsoft.com/en-us/archive/blogs/habibh/walkthrough-adding-an-existing-visual-studio-solution-to-another-solution
Actually the method described adds all projects from another solution to the current solution, not quite what we want, but at least this saves time adding all of the projects manually one by one.
A solution is a collection of assemblies that build to create some kind of executable or dll. Having one solution depend on another does not make sense. The output assembly (executable/dll) depends on the assemblies that it references. If your solution depends on other assemblies, then reference them. You can add projects to your solution (File>Add>Existing Project) and then you can add refences these projects from your output project.
You cannot do that. And why would you want to?
Simply add all the projects that you depend on (the projects in the 'other' solution) to the solution.
Then use project references (not file references) between the projects.

What do you do about references when unloading a project in Visual Studio?

When you unload a project in Visual Studio, any referencing projects get warning triangles on their reference to the unloaded project. I've written myself a macro to do clever stuff (detect add/remove of project and transform any references from-to file/project dependency), but I can't believe that I'm not missing something much simpler. How can the unload function be any use if I have to go around manually changing references (and it breaks the 'personal solutions/shared projects' team development paradigm).
(This question is related to answers to this question about structuring large solutions in Visual Studio - some answers mentioned having solutions with lots of projects, but 'unloading' unused projects to improve performance.)
For my projects, I create an assemblies folder which the projects automatically copy into from a set location to which other projects copy builds.
Post-build for referenced assembly's project:
if not exist "C:\builds\Project1" md "C:\builds\Project1\"
copy "$(TargetDir)$(TargetName).*" "C:\builds\Project1\"
Pre-build for referencing projects:
if exist "c:\builds\Project1\" copy "c:\builds\Project1*.*" "$(ProjectDir)assemblies"
The project file points to its assemblies subfolder for references so even if the source projects are unloaded from the solution, the last-built assemblies will be used without the performance problems of having the whole project in memory while developing.
What are the advantages of having projects in the same solution if you use file references?
If your app.exe uses utils.dll and you change the code for utils.dll, then if it's in the same solution VS will notice the dependency and recompile both. If it's not in the solution you'll have to jump out, recompile utils.dll seperately, then jump back in and recompile app.exe.
This becomes either more or less important depending on how many other dll's your exe is referencing, and how often they change (in team environments shared dll's change often in my experience).
There is also the side effect that if you have 100 projects in VS it will take a long time to process them all just to figure out if they need recompiling or not.
Unloading projects is meant to be a temporary action so you can edit the actual project file as XML (text). If you want to completely remove a project from your solution, you should use the "Remove" menu option, which will take care of removing any references to that project.
One advantage to using project references is that it allows you to easily debug through the code. It also automatically ensures that you are using the correct configuration build (ie, if you are building in "Debug" mode it will use the Debug version of the assembly). That being said, you loose some determinisim about which version/build of the dependent project you will pick up - project references mean you always use the latest.
Yes, for Visual Studio to determine build dependencies it must be able to see and build all of the projects which would mean project references.
I've just had a eureka moment reading through MSDN doc on structuring solutions and projects.
What I hadn't noticed is that in a multi-project solution, the context menu in the Solution Explorer proposes a Project Dependencies popup. Here you can define the project dependencies manually, if you haven't defined them by project references between projects.
See here (MSDN link, so will self destruct after a few weeks)

Resources