I have 2 solutions that contain test related code. One is for UI automation and another for API. I combined both solutions and I am able to build and run tests from both but:
Each one of those contains similar configs that I would like to combine under one project. No need to have the same thing in both obviously. I removed configs from project2 and created references from Proj1 to Proj2. I build Project1 and artifacts are generated fine from Project1, but it does not contain all artifacts from Proj2.
Previously, when I build projects separately, It would generate say 60 files in the build folder, but now its much less.
Question:
If I decide to add project #3 and add configs to it. How can I build project 3 and combine artifacts from all of them in bin folder of project #3.
I hope I'm making this clear.
Essentially I want to be able to build 1 project which will trigger builds for remaining 2 and pull all artifacts to together.
As Ziggler suggests, you can change the build output folder to combine all artifacts from all of them in bin folder of project #3.
And you can do this by passing $(OutputPath) property in command-line. It seems that you're using something like TeamCity, Azure Devops or what in your environment.
For these tools, we can add msbuild parameter like: /p:OutputPath="Path to project3's bin folder" if you're using msbuild to build whole solution(msbuild xx.sln). See Global Property.
And about the build order, you can add project dependency to control the build order. Msbuild will recognize project dependency and project reference and then choose the right order automatically. Hope it helps :)
Related
I created bunch of targets in msbuild project. Lets call this project TopLevelProject. Lets say this has a target called CollectNZip. TopLevelProject depends on SubProjectA, SubProjectB and SubProjectC.
I have a solutions targets file Directory.Solution.targets that contains all the projects below its folder including TopLevelProject.
As part of a target in this file say BuildAll, I like to invoke CollectNZip target of TopLevelProject. So I added TopLevelProject:CollectNZip as dependency.
When I invoke BuildAll, I do see TopLevelProject is invoked with target CollectNZip. But this sucker as part of dependency started invoking SubProjectA:CollectNZip, SubProjectB:CollectNZip etc. As those sub projects don't have CollectNZip, the buildall target is failing.
What is the trick to invoke a target of a project, but don't invoke the sub projects as part of the invocation?
If I understand the scenario:
There is a solution file with a set of projects. Let's say the solution is named 'MySolution.sln'.
I assume the solution file was created by either Visual Studio or the dotnet tool.
The set of projects in the solution include: 'TopLevelProject.csproj', 'SubProjectA.csproj', 'SubProjectB.csproj', and 'SubProjectC.csproj'.
I assume the project files were created as C# projects by either Visual Studio or the dotnet tool.
The project 'TopLevelProject' has ProjectReferences to 'SubProjectA', 'SubProjectB', and 'SubProjectC'.
The project 'TopLevelProject' also has a target named 'CollectNZip'.
There is a 'Directory.Solution.targets' file that is a peer of 'MySolution.sln' or in a parent directory.
'Directory.Solution.targets' contains a 'BuildAll` target.
The 'Directory.Solution.targets' file is ignored by Visual Studio so the 'BuildAll' target is only available when running from the command line.
Projects can be added to a solution file (SLN) but can't be added to an MSBuild file. The 'Directory.Solution.targets' file is an MSBuild file. It can't be a container for projects. I don't know what the following statement means:
I have a solutions targets file Directory.Solution.targets that contains all the projects below its folder including TopLevelProject.
Note that the Import element is a textual include. It doesn't "add" a project; it adds the content of the file in the Project attribute into the content of the current project.
From the command line, you can invoke the 'CollectNZip' target of project 'TopLevelProject' via the solution file.
e.g.
msbuild MySolution.sln /t:TopLevelProject:CollectNZip
This will invoke only the 'CollectNZip' target on only the TopLevelProject project. It will not run other projects from the solution.
I don't know what the following statement means:
As part of a target in this file say BuildAll, I like to invoke CollectNZip target of TopLevelProject. So I added TopLevelProject:CollectNZip as dependency.
The <ProjectName>:<TargetName> syntax is supported for the command line /target switch. It is not supported within the code of an MSBuild file. TopLevelProject:CollectNZip can't be a dependency of a target.
MSBuild doesn't have any notion of "sub projects" although there are two mechanisms which can add dependencies between projects.
A project dependency can be added to the solution file. The solution level project dependency effects the build order -- and does nothing else. It does not share files.
A ProjectReference can be added to a project file. The ProjectReference is an ItemGroup and is part of the C# project build system that is built on the general MSBuild build engine. ProjectReference is specific to certain targets of the C# build system, most importantly the build and clean targets. build and clean will evaluate the ProjectReference ItemGroup, will run the referenced projects, and on a build will copy in the product of the referenced project.
If I add a target named 'Fred' to all the projects and I invoke 'Fred' on one project via the solution, 'Fred' will not be called on projects in the ProjectReference ItemGroup.
A project is an encapsulation. It doesn't know its 'caller' and, excepting ProjectReference, it doesn't know about other projects.
The described behavior is not how MSBuild works and I'm guessing that the description is imprecise and/or there is pertinent code not shown.
If 'CollectNZip' should only run within the 'TopLevelProject' project, then only add the target to that project. If you want to be able to build with and without 'CollectNZip', define a property that can be used as a flag, e.g. add an 'EnableCollectNZip' property and add a Condition on the target that tests the value of the 'EnableCollectNZip' property.
This is the basics of the problem I am having (of course it is oversimplified for the sake of the question):
I have 2 projects in a solution stored in mono-repository:
Project1 - outputs a library
Project2 - outputs an executable
When Project2 references Project1.
I would like to move to multi-repository where Project1 will be stored in different Repository from Project2.
Project1 will output a nuget package and Project2 will reference it instead the project itself.
The issue I am facing: in current situation (mono-repository) when during development I introduce a feature in
Project2 that also requires a change in Project1 it is not a problem. If there are problems I can discover it
during development time.
In a new way (multi-repository) I first need to make a change to Project1, create nuget and push it to nuget
store, then update reference in Project2. If I would have problems in Project1, I must go back to Project1,
fix the issue and push it again, update reference in Project2 and so on. Also, losing the benefit of debugging
both projects.
Is there a solution to this approach? To focus my question: if I have source codes of both projects on my dev machine,
is it possible somehow to instruct Visual Studio to use source code instead of referenced Nuget for debugging?
Hope I explained it right and clear as possible...
If you have two different projects and both of them are in different repositories, you could add the library as a submodule of the first project. I'm assuming you're using git. You could do this simply by:
git submodule add <link for the other repo>
In visual studio you just add the project to the same solution and then reference library from the executable. I'm not sure if that would do the trick for you, but I hope that works.
We have the exact same problem in our company.
This is 2 part problem.
First part is to have both repositories near each other... There are more options, we were deciding between these 2:
git submodule
meta repository (it is a compromise between mono-repository and multi-repository) you have 2 repositories you want to connect, so you create 3rd repository as a meta-repository via https://github.com/mateodelnorte/meta
Second part is how to connect those 2 repositories so that they are debuggable, but still apart each other... We though of these 3 ways:
new .sln in meta repository that will reference both projects (this didn't cut it, because we already been in a position when we had multiple .sln files and maintaining them is not that easy, because when you add some project into one, you have to add it to the other solutions and this goes sideways really quick)
using Reference and PackageReference with Condition - locally for debugging when .dll is build in ProjA then the ProjB would use "Reference", if not the ProjB would use PackageReference => this was our main solution to our problem until we did it like that... (Because we have more than 2 projects ProjA -> ProjB -> ProjC.. The problem here was when it was built locally, referenced via Reference DLL, then ProjA was not visible from ProjC, but when built via CI and referenced via PackageReference, then ProjA was visible from ProjC)
using only Nugets - Every build of ProjA it will create nuget locally (pre-release) and in ProjB, we would reference that via wild-cards. This works, until you make a second change into ProjA, because ProjB will cache that nuget in C:/Users//.nuget/packages :( so when building ProjA and packing the nuget we clear the newly built nuget from this packages folder. You have to restore ProjB every time you make change into ProjA, but this is where we landed as a final solution for now.
So the final solution for us is:
meta-repository for like 5 other repositories
for debugging we use locally built nugets with constant version of "major.minor.patch.65534-local"
for CI we use the same nuget packaging but we override the local version with
feature branches "major.minor.patch.build_number-branch_name" (having -something after the version makes that nuget pre-release)
master/main branch "major.minor.path.build_number"
I'm hoping someone can help me with this. I have a solution that consists of two Web sites and two class libraries. One of the class libraries is a shared library for use within many of our projects so its output is stored a shared location (D:\Applications\SharedLibraries\Bus_logic) so we can reference the dll from there. We have this directory structure on our local machines and build server.
This works perfectly fine on my local machine. Building the solution locally pushes the updated dll to the local D:\Applications\SharedLibraries\Bus_logic folder. Our old CCNet builds would do the very same on the build server.
However, with TFS the output path of a class library doesn't seem to matter. I have a CI build for the solution and the class libraries never get outputted to that path. They're just grouped together in the drop folder.
Is there any easy way to make sure the build copies those dlls to their rightful locations, or do I have to create a custom build template for every one of my solutions that compiles shared libraries so that the dlls get copied to the right directory?
I've been doing a but with TFS builds recently so I hope the following helps.
Before you do any of the following I recommend you create a new build definition and new build template (via Edit Build Definition -> Process -> New Template -> Copy from existing) to test this works.
TFS provides a custom path for the OutDir argument to MSBuild, the variable passed for this is called outputDirectory. The step where this is set is deep within the default build template here, open it and navigate you way to Run On Agent -> Try Compile, Test and Associate -> Sequence -> Compile, Test and Associate -> Try Compile and Test -> Compile and Test -> For Each Configuration -> Compile and Test -> Initialize Variables, once there you'll find a task called Initialize OutputDirectory which by default is set to the 'BinariesDirectory/Platform/Configuration' folder. You could change this to your own custom logic.
It might be an easier way be to set the OurDir argument to nothing on the Run MSBuild task as I assume this will then use the projects default paths. This can be found here in the template, Run On Agent -> Try Compile, Test and Associate -> Sequence -> Compile, Test and Associate -> Try Compile and Test -> Compile and Test -> For Each Configuration -> Compile and Test -> If BuildSettings.HasProjectsToBuild -> For Each Project -> Try to Compile the Project -> Compile the Project.
There is probably a more elegant way via tinkering with the solution or project files but I am not aware of that just yet.
There are really two good ways to make this light up.
Check the dll's in - you can create a folder in source with the files that you depend on checked in. Then add a mapping in the build to get them to a well known location.
You can have the DLL's packaged as a NuGet package and take a dependency on that.
1 is cheap and cheerful and proan ro error, but not as much as your current solution. #2 is the right way to do things. NuGet was designed to solve these sorts of issues.
I am having problems getting my C# Solution to build "Fresh". If I clean the solution and build it again it will not build (I can do it a few times and it will build). It has an error about the azure project getting build before the worker and web projects that it is dependent on. Also about how most of the projects in the solution are looking for
WAT070 : The referenced assembly {...}/Worker.dll was not found.
Please make sure to build the role project that produces this assembly before building this Windows Azure Cloud Service Project.
{...}\VisualStudio\v12.0\Windows Azure Tools\2.2\Microsoft.WindowsAzure.targets 1252 5 AzureProjectName
Now if I build the projects in the order listed in the Project Dependencies -> Build Order everything works. Also, the web and work role are listed before Azure Project.
Solution is very simple.
You can set your project build order by right click on 'Project Solution' and select "Select Project Build Order" option.
For Example, I have a WpfFormApplicaiton1 and two class with title "ClassLibrary1" and "ClassLibrary2". By default Visual Studio sets it as follow:
My requirement is such as "ClassLibrary2" will be used by "ClassLibrary1" & "ClassLibrary1" will be used by "WpfFormApplication1". So, in order to fulfill this requirement I have to change the default project build order.
Go to Project Dependencies; Select the "ClassLibrary1" and set the "ClassLibrary2" as its dependency.
Similary, select the "WpfFormApplication1" and set the "ClassLibrary1" as its dependency.
Now, the desired project build order is set; confirmed by Project Build Order's options.
Solution is taken from my blog.
Your issue may be that the Dependencies are not defined. Even though the Build Order shows the order in which projects are built, if you do not define the dependencies for each one under Project Dependencies, msbuild will not know to wait for the dependencies build to complete before moving on.
To clarify: Unless you actually check the box that an item is a dependency, the projects in the build order list may build in parallel and not sequentially.
You can see under Tools->Options->Project and Solutions->Build and Runthat there is a default value for the number of parallel projects to build.
So to make the build process wait for dependencies to build make sure that all of the "Depends on" fields are checked for the projects needed under Project Dependencies -> Dependencies.
We had an issue where the project guids differed in case. Editing the project files solved the issue. We changed all Guids to uppercase
I just had this issue too. In my case the issue was that I had several project references within the solution. The other projects were using a different version of the framework to my Worker Role (4.5.1 vs 4.5).
When I changed all projects to use the same version of the framework the solution builds and runs successfully.
I had this issue. In my case, the solution's project build order, as determined by VS.Net, was not correct. Specifically, my web project was listed above three of its dependencies.
These three dependencies were listed under in the References node of the web project in the Solution Explorer. However, in the dialogue Project Dependencies, the web project did not depend on any project.
Also, I noticed that the web project had a small blue exclamation mark, with hoover-over message "The Web project '' requires SQL Server Express, which is not installed on this computer. ...". After fiddling with the web.config, based on ASP.NET Web Api: Project requires SQL Server Express and reloading the project, the exclamation disappeared and the project dependencies were correctly checked in the dialogue Project Dependencies and the build order reflected this correctly. However, when I reverted the changes to the web.config, as a test, the dependencies were not removed, so I am quite unsure what fixed my issues.
Anyway, in the dialogue Project Dependencies, you can manually check any project which was not automatically identified as a dependency.
Check to make sure there aren't any residual old files in your working folder. These can cause confusions with MSBuild. To avoid that, simply blow away all the old files in the path and get latest.
This has probably been posted before, but I'm not sure what search terms to look for!
Quick explanation.
I have code that is shared between a few projects. This code is still work-in-progress itself. The issue is that whenever I need to update this code for whatever, I don't want to have to do it 3 times, this will become a nightmare.
Is there a way to add it to a project, without copying it into the project folder?
i.e. I want the shared class to be linked into my 3 projects as
C:\code repository\sharedclass.cs NOT \eachproject\bin\sharedclass.cs
Do I have to create it as it's own library project? It would be much better if the compiler could compile it as 'external' code.
Cheers.
As others have said, you can simply right-click on your solution in the solution explorer, select Add > Existing Project, and browse to the common project's .csproj file, and it will be included in the solution from its original location.
There are two problems with this however, which may or may not be an issue, depending on the size of your team:
The common project will be included in each solution with a relative path to the solution file (i.e.: ...\CommonProject\Common.csproj). This means all developers have to have the same working file structure or they will get errors when they try to open the main project.
In the scenario that the common project is referenced by multiple projects (say two - A and B) and a developer working on project A has to make changes to the common project as part of their task, there is no way for that developer to know if the changes they have made will break project B without them actually checking out project B and compiling it. As more and more projects reference the common project, the risk of this happening increases to the point where it becomes unmanageable.
Again, as others have said, there is no 'correct' way to do this. However, the approach I have taken is as follows:
Use continuous integration such as Cruise Control to manage the building of the projects and put the common project as a standalone project on the server.
Create a directory under your source control to house built common DLLs. Have this directory checked out on your build machine and whenever the common project builds, it copies the output DLL into the DLL folder and commits these changes to source control.
Use environment variables on all developers' machines and the build server to control the location of the common DLL folder and reference the DLLs using that variable rather than the hard-coded path. (i.e.: rather than C:\Source\MyCommonProjectDLLS\Common.dll, use $(MyCommonLocation)\Common.dll with the variable 'MyCommonLocation' set to C:\Source\MyCommonProjectDLLS)
For any project which references the common DLL, set up a CI trigger on the build server for that project to watch the common DLL folder. Whenever changes are committed to it, the build server should then build all consuming projects.
This immediately lets you know if you are committing breaking changes for any other project. The only drawback is that, in this model, consuming projects are forced to take updates to the common DLL as soon as they are made. An alternative is to version the Common DLL from the source control revision when it is built, and place each version in its own sub directory under the common DLL folder. So you would end up with:
Common DLLs
-1.0.0.1234
-1.0.0.1235
-1.0.0.1236
And so on. The advantage of this is that each project can then choose when to take updates to the common DLL by simply referencing the new version of the code. However, it cuts both ways as this can mean that some projects are left with older versions of the common code for longer than they should, which can increase the work involved when the time comes to finally bring in those changes.
Yes.
You can add a project from anywhere on your hard drive to a solution. So put the shared code into a class library and add that to your three projects.
Microsoft has been supporting an open source project which comes built into VS now, its called NuGet, you can output your shared project as a nuget file and consume it in your other projects.
It will actually deploy all the files you specify in the package upon build.
This is how .Net supports dependencies now. You will notice that even things like EF come through NuGet packages. You can even host it for free on places like MyGet.org I use this and it works quite well.
http://nuget.org/
I use git submodules to achieve this.
Create a new git repository for each module (project) that you want to share between solutions. I usually also include unit tests for that project in a separate project but in the same git repository.
Add a submodule to the git repository of the solution that will use the shared code. Adding a submodule creates a link to a specific commit of an external repository. When the code in the submodule is updated you will be able to pull the updates to your parent solution, which is essentially the same as updating the reference to the submodule commit. I find that the process is easier to visualise using an app like SourceTree.
Adding the submodule and pulling the latest commit will create a copy of the shared project inside the parent solution folder. Import the project into the parent Visual Studio solution by right-clicking on the solution and selecting "Add existing project".
Add a reference to the shared project in the other projects that will be using it by right-clicking on the project and selecting "Add Reference" and finding the shared project in the "Solution" tab.
Now that the shared project is included in the solution you will be able to push and pull changes to the submodule and these changes will automatically be incorporated into the solution. You will also be able to see the changes in other git repositories that reference the submodule.
Yes, put the code which need to be shared in a separate class library project, build it and reference the DLL created from this build into your other projects.
It is better to extract common part into a separate project library and add reference of this project to all the solutions/dependent projects.
Otherwise you can Add code/file/item as Link.