How to have msbuild copy files to output directory across references? - visual-studio

Suppose we have a project A with output directory bin/ and a project B with output directory test/bin/. Project A needs to have a certain configuration file copied to its output directory. Currently, this is being done by adding a pre-build event that looks like
COPY /Y "$(ProjectDir)..\config.ini" "$(TargetDir)"
Project B has A as dependency. When project B builds, the binary resulting from A is correctly copied to the output directory of B, but the config file isn't!
How can we achieve that all files that A needs to have are also copied to the output directory of B?

What you want is a Link File. I've used these before to ensure that connection.config files are copied to multiple projects.
I created a sample solution that mimics your described scenario as seen below. The ConsoleApplication1 references the ClassLibrary1 project. In the solution, I created a solution folder config and added the shared config that needs to be copied.
In order to have a single file that is copied across multiple projects, you must create a single file, and then add it as a link to the projects that need it. This can be done by right clicking on the project, and choosing Add -> Existing Item.... You will see a dialog as show below and you want to choose the Add as Link option from the dropdown instead of just Add.
Finally, edit the properties for the linked file to copy it to the output directory.

Related

VSTS Copy and Publish Build Artifacts copying the whole project instead of the necessary files

I am trying to copy my build to a particular drop location. But instead of copying the some important files and directories it is copying all the solution file and directories there like .csproj files and .csfiles and also all the folders present there.
I only want to copy dlls(projects dlls and references dlls of the project) and some data Folders and files to drop location so that I can use them to execute my test cases. But it ends up copying the whole solution.
Below are the setting I am using to copy and publish build artifacts.
Can Anyone tell me how can it be done?
Note: when I tried to put $(build.sourcesdirectory)\bin in the copy root it gave me an error that "Cannot bind argument to parameter 'Path' because it is null".
I also tried putting only **.dll in my contents but then it copies nothing. The folder created in drop location comes empty.
You're telling it to publish **/*test*.dll, from the root of the build agent. That minmatch pattern is saying "find everything in every subfolder that matches test.dll", so the results you're getting aren't surprising.
What you probably want to do is specify the path to the binary output location of your test projects. Without seeing the structure of your code or what MSBuild variables you're providing/overriding, it's impossible to give more guidance. Look at the documentation on pre-defined variables and that should give you some ideas.
In general, you want to set your output folder (via MSBuild arguments) to $(Build.ArtifactStagingDirectory), so only build outputs go there. Then you can use that as your Copy Root.

Copy app.publish folder in VSTS Build/Release

Similar to the question here: Copy one file in target directory on deploy from visual studio team services, I am trying to copy the contents of the app.publish directory of a ClickOnce application via VSTS build/release.
This is the Copy Publish Artifact step of the Build
This obviously outputs everything in the bin folder to the drop folder on the server share.
This is the Copy Files step of the Release
This copies only the files in the app.publish folder but it builds out the entire hierarchy to the folder app.publish folder; however, it builds out the full folder structure. i.e. bin\Release\app.publish or bin\Debug\app.publish.
I like the idea of being able to publish and store different configurations (debug/release) but I don't like that I'm having to specify the InstallUrl in the msbuild arguments in order to pick up debug/release in the folder path. Even if I didn't try to maintain multiple configurations, the configuration would still be in the path.
So my question is: Is there a way to use the copy files task to just copy the app.publish folder and/or the contents to another location, without it creating the full hierarchy?
You need to specify the copy root in Source Folder of Copy Files, in your example, the copy root should be like:
Source Folder: $(System.DefaultWorkingDirectory)\$(Build.DefinitionName)\bin\$(BuildConfiguration)\
Contents: **\app.publish\**
In this way, you should only have app.publish in your Target Folder.
Configure the "Copy Root" of "Copy Publish Artifacts" step in your build definition to the path of build configuration folder and "Content" to "**".
For example, if the path of your build output is:
C:\a\1\s\SolutionFolder\ProjectFolder\bin\Relase\app.publish...
You can set the Copy Root to:
$(build.sourcesdirectory)\SolutionFolder\ProjectFolder\bin\$(BuildConfiguration)
And Content set to:
**

Best Way To Copy All Projects EXE And DLL Files In A Solution To One Common Folder?

I have a C# Visual Studio solution with about 15 projects. When I build the solution I want all DLL and EXE files for each project to go to a common folder (called Deploy).
The way I was thinking about doing it was, for each project's Post-build Event Command Line section put the following commands:
IF NOT EXIST $(SolutionDir)Deploy (
'If directory does not exist, create it
MKDIR $(SolutionDir)Deploy
) ELSE (
'Delete directory to make sure it's "clean"
RMDIR /F /S /Q $(SolutionDir)Deploy
MKDIR $(SolutionDir)Deploy
)
'Copy executable and required DLLs to Deploy directory
COPY /Y $(TargetPath) $(SolutionDir)Deploy
COPY /Y $(TargetDir)*.dll $(SolutionDir)Deploy
The problem with doing it this way, however, is I have 15 projects and would have put this in each individual project's post build event section and also, every time I add a new project, I would have to remember to do the same for it.
I checked the solution file properties and did not see a way to set a solution-wide post build event to copy all the files so I did a few Google searches.
One page said to use a C++ Makefile project. I added this type of project to my solution and clicked on the project properties page and found that there is a section under Configuration Properties->NMake with the following:
Build Command Line
Rebuild All Command Line
Clean Command Line
Using the Makefile project's Command Line option poses a similar problem to above. Many different commands to copy each of my 15 project's output files such as:
COPY /Y $(SolutionDir)Project1\bin\$(ConfigurationName)\*.exe $(SolutionDir)Deploy
COPY /Y $(SolutionDir)Project2\bin\$(ConfigurationName)\*.exe $(SolutionDir)Deploy
...
COPY /Y $(SolutionDir)Project15\bin\$(ConfigurationName)\*.exe $(SolutionDir)Deploy
There is another apparent problem with doing it this way. As you can see I took advantage of the $(SolutionDir) and $(ConfigurationName) macros but I had to hard-code each project name.
I didn't see any macros like $(AllProjects), $(AllProjectDirs), etc.
Also, it appears that command line commands for Makefile projects are for building, not post-build events, so I gave up on this idea altogether.
I then tried using a Visual Studio Installer project. After adding the project to my solution I right-clicked the project and saw that there was an Add->Project Output... option. This brought up a dialog allowing me to add one of my other project's Primary Output. I repeated this for each of my other projects and rebuilt.
What resulted was an .MSI file in the output folder. I then opened installer project properties and changed the Package files option to As loose uncompressed files and rebuilt. The output folder now contained all my project's EXE and DLL files!
Most people would be satisfied at this point and move on but I am the kind of person who likes to find the best way to do things.
There was one thing I didn't like about using the installer project option, the fact that, besides copying the files from all my projects, it also created an MSI file (which I don't need) and I didn't see any option tell it not to create one.
Can anyone recommend a another/better way to accomplish my goal of copying all project output files to a single folder?
Thank you.
P.S. I was thinking I could just make a batch file to search and copy all the EXE and DLL files to the Deploy folder but I would have to run the batch file outside of the Visual Studio IDE and also hard-code the configuration folder (Debug or Deploy).
Can't you just change the Output Directory of the C++ projects? See How to: Change the Build Output Directory.
On the menu bar, choose Project, Properties.
Expand the Configuration Properties node, and choose General.
Change the Output Directory value to the new output directory.
If you want both options, you can also create multiple configurations for your VS projects and solutions, similar to the standard "Debug" and "Release" ones. Create a new configuration from one of the existing ones, then change the output directory and save. Now you can just switch the configuration at the solution level to build into another directory. See this link for detailed steps:
How to: Create and Edit Configurations

Relative paths with MSBuild project vs solution

I have a number of projects which are joined into a solution. Every project has it's own directory structure, and csproj files are located on diferrent level of folder structure.
Every csproj has OutputPath property specified. OutputPath - is a relative path and it varies from project to project in such a way so all projects have the same output dir.
It is work OK if I build a separate project. But everything changes if I try to build solution file. In this case every project output folder differs (depends on a number of '..\' in that project's OutputPath).
I do know, that before some moment all was working fine. Nobody changed build.cmd neither any sln or csproj files. But now I have situation described above.
So my question is - what affects how relative path is evaluated? I mean how can I force relative OutputPath to be evaluated starting from folder where csproj file of that particular project is located. Not from folder where .sln file is.
Let's assume I have following directory structure:
dir1
a.sln
dir2
a.csproj
dir21
dir3
b.csproj
a.csproj has output path set to '../../_bin' which is just above dir1 if counted from a.csproj folder
b.csproj has output path set to '../../../_bin' which is same - just about dir1 if counted from b.csproj
a.sln contains both - a.csproj and b.csproj.
When I run msbuild I get a project build to 'dir1/../../_bin' and b project to 'dir1/../../../_bin' - both relative paths of projects files are counted from solution file location, not project files.
Well, I was able to find out what was causing this. That was custom .targets file, which was inferring SolutionDir property at the start of any msbuild.
I did find out that by using MSBuild Explorer. The tool proved to be very useful in my case - I was not aware of third party .target files on my system.
From Msbuild Import Element description
Relative paths in imported projects are interpreted relative to the
directory of the importing project. Therefore, if a project file is
imported into several project files in different locations, the
relative paths in the imported project file will be interpreted
differently for each imported project.
All MSBuild reserved properties that relate to the project file, for example, MSBuildProjectDirectory
and MSBuildProjectFile, that are referenced in an imported project are
assigned values based on the importing project file.
If you add more details or few samples to your question - it will be easier to understand exact problem.
Edit:
Okay, lets try to pinpoint that mystery. First of all - OutputPath could be affected by Environment variables.
2nd - during build sln file transformed into msbuild project file format and stored in temp file. You can get that temporary file if you execute in cmd "set msbuildemitsolution=1" and then trigger build via command line. There you can check that file and see how your individual projects called. But I suppose you will see multiple .csproj /> entries. And global msbuild properties inherited by that calls.
So I suspect if everything was fine before some point and no changes were made - you are missing OutputPath environment variable or some other variable that contributed to construction of OutputPath.
BTW - I think if you want to fix your issue with forcing relative dir - you also can use $(MSBuildProjectDirectory). This is one of msbuild reserved properties (from here), but this will require yo adjust your OutputPath in each csproj file. What i, personally, prefer to avoid, because it could affect some other targets and introduce subtle issues.

How can I remove files from a QtCreator project

Might be a very newbie question, but I can't find a way to remove files from my projects in QtCreator. Thanks!
If your project is generated from CMake, the file list is determined by the CMakeLists.txt file, and you cannot add or remove files manually from the source tree in QtCreator. Especially if your CMakeLists file specifies the glob operator for a project's file list, you must manually remove the files from disk and re-run CMake from within QtCreator by going to Build->Run CMake (QtCreator 3.3.0). This will update the file list but also regenerate the project (cbp) file - re-running CMake outside of QtCreator will not update the project file and you will have ghost entries of deleted files showing up in the source tree if you deleted them from disk.
Right-click the file you want to remove, and choose "Remove File..."
Checking the "Delete file permanently" check box will delete the file, otherwise it will just be removed from the project.
Find your project file .pro in qt creator or other text editor
Find the file/folder name you want to remove in the .pro file
Delete all the files you want to remove
save and close the project
Reload the project
DONE
Could not find one-touch action as in Eclipse to delete a class:
1) Press right click on the file/class, and then choose "remove file..."; (u can tick "permanently" to remove from HDD if you like).
2) Do it to .CPP and .H files.
3) Then check in your .pro file the class are not there anymore.
Note: Some compilers will keep searching for this file/class in compilation. Just delete the compilation directory and compile again.
If you mess up like me and accidentally add a lot of files to the qml.qrc, it might help to know that these are listed in the actual qml.qrc file which you can edit to remove these files.
I also run into this problem.
I wanted to remove a header file.
But remove action in context menu was disabled I didn't know why.
The file name was qtextdocument.h.
I wanted to change the name to textdocument.h.
I tried to do various ways, but the filename was strictly fixed.
My removal procedure was as follows:
I dare to add an empty file to the file directory (in header file directory).
Anyway, I set the file name as textdocument.h when Qt Creator asked me to set the filename.
A confirmation warning popped up.
(Qt Creator cannot add the file automatically, we must add the file name to CMakeTextLists.txt)
I changed the filename in CMakeTextLists.txt from 'qtextdocument.h' to 'textdocument.h' in the row of set(PROJECT_SOURCES).
Finally, the update was confirmed. 'qtextdocument.h' was removed and the name is changed to 'textdocument.h'.
If you only want to remove a file, only you have to do is to delete the filename when you are in step 3.
After updating the project tree, the actual file is in your computer.
If you want to delete the file completely, you select file system and remove the file, not from project.
I don't know why, but in the case of filesystem mode, remove action is enabled.
So I might & should have told you that you select "filesystem mode" and remove the file at the first time...
(Sorry I have found out this fact later.)
Both of the two ways, I think we must rewrite the contents of CMakeTextLists.txt.
I also run into the case , the update removed the filename as soon as I deleted the filename from CMakeTextLists.txt.
I believe this case I directly make a file in the actual directory. On the contrary, above case is the files are added from Project menus.
go directly delete the project folder from your hdd.
For Linux, edit ~/.config/QtProject/QtCreator.ini
Under [ProjectExplorer], delete the project name and its corresponding configuration file from the following two lists:
RecentProjects\DisplayNames
RecentProjects\FileNames
e.g., given the following
RecentProjects\DisplayNames=proj1, proj2, proj3
RecentProjects\FileNames=<proj1_dir>/CMakeLists.txt, <proj2_dir>/proj2.pro, <proj3_dir>/proj3.pro
to delete proj1 from the qtcreator startup page, edit the above two lists as
RecentProjects\DisplayNames=proj2, proj3
RecentProjects\FileNames=<proj2_dir>/proj2.pro, <proj3_dir>/proj3.pro

Resources