MSBuild OutDir relative to executed location rather than project location - msbuild

I'm using MSBuild 15.0 (VS 2017 Enterprise) and trying to get MSBuild's OutDir path to be relative to the current folder.
I have the following folders:
C:\MyProject\Tests (contains the command to build the project)
C:\MyProject\Projects (contains the VS solution/projects)
I have the following in C:\MyProject\Tests\rebuild_all.cmd:
msbuild ..\Projects\MySln.sln /t:Rebuild p:/Configuration=Debug;OutDir=\Debug\
This puts a Debug folder in each VS project folder rather than in the \Tests\Debug folder.
Can I instruct MSBuild to output to a path relative to the current executing environment path, or will it always build relative to the project?
Actually, my final target(s) would be a folder for each project under a relative path of the executing folder:
C:\MyProject\Tests\Debug\Project1\(output)
C:\MyProject\Tests\Debug\Project2\(output)
C:\MyProject\Tests\Debug\Project3\(output)

Related

dotnet cli creating folders within projects doesn't get added to solution

I've used dotnet cli to create a solution and subsequent projects inside.
As part of the exercise i am also trying to create folders within the projects to store different type of classes.
I use mkdir to create the folder, which works however when i open VS2019 the folders don't appear in the solution.
How can i create the folders and link them to the solution?
EXAMPLE of my cli code. (This is done on Win10 machine)
dotnet new sln -n TestService -o TestService
cd TestService
dotnet new webapi -n TestAPI
cd TestAPI
mkdir TempFolder
cd ..
dotnet sln TestService.sln add TestAPI\TestAPI.csproj
Open in VS2019, the TempFolder is not in the solution view, however does exist in Folder view.
Project folders
In modern .NET Core projects (using the .NET SDK), files are automatically added based on a global file pattern. For example, any .cs file anywhere within your project directory is by default automatically configured to be a part of your project that needs to be compiled. This pattern however only applies to files, not directories.
Directories are not an explicit part of a project by default. Instead, they are only there if they are “needed” for a path to a file. That’s why you won’t see folders within Visual Studio until there is a file that is part of the project.
If you are within your project folder and then add a folder there, you will not see the folder there. But as soon as you add a file to that folder (echo '' > TempFolder\Test.cs), it should automatically be picked up by Visual Studio:
You can also enable the “Show all files“ option in the solution explorer, to make folders that are not part of the project appear in the solution folder:
As you can see, the folder appears as a transparent item because it is not part of the project itself. You can then right click on the item and choose “Include In Project“ to make this folder an explicit part of the project. This action will add the following section to the project file:
<ItemGroup>
<Folder Include="TempFolder\" />
</ItemGroup>
This basically tells Visual Studio that the folder is part of the project even though it does not contain any files. As soon as you do add any file to the folder, Visual Studio will remove that configuration though since the folder is now again an implicit part of the project.
Solution folders
Visual Studio solutions don’t show the actual directories within your solution directory but rather a virtual directory as configured within the .sln file. Projects being located within subdirectories will not automatically be located within such a folder within the solution structure, and similarly non-project folders will also need to be added to the solution file first.
There is no mechanism to manage the solution folders with the dotnet sln command though. The only thing that you can do is add a project into a particular virtual folder within the solution:
dotnet sln add path/to/project.csproj --solution-folder VirtualFolder
This would add the project.csproj inside the VirtualFolder solution folder within the Visual Studio solution.
If you want to manage the solution folders otherwise, you should do that with Visual Studio.

MSBuild output in subfolder for each targetframework when using OutDir

When using the new SDK style csproj format, it is possible to use a <targetframeworks> element for a semicolon-separated list of target frameworks to build the project for.
This results in one subfolder per target framework in the build output folder:
However, when passing the OutDir property on the msbuild command line, it does NOT create the subfolders, and the built assemblies are all placed in the same folder.
Command line that works, but doesn't allow output location:
msbuild projectfile.csproj
Command line that selects output directory, but places built assemblies in same folder (effectively overwriting the target framework assemblies that are built first):
msbuild projectfile.csproj /p:OutDir=buildtemp
Is there a way to place the build output in a non-default folder while still retaining the targetframwork subfolders?
The property that is now used is OutputPath, however setting it from the CLI makes it a global property and overrules the automatic appending of the output path. The workaround is to make an intermediate property that is global and consume it from the project.
Add this to your project file inside a PropertyGroup:
<OutputPath>$(BaseOutputPath)</OutputPath>
Then you can set this property globally when calling the build command:
martin.ullrich#martins-imac:~/tmp$ dotnet build /p:BaseOutputPath=bin/foo
tmp -> /Users/martin.ullrich/tmp/bin/foo/netstandard1.4/tmp.dll
tmp -> /Users/martin.ullrich/tmp/bin/foo/netstandard1.6/tmp.dll
The problem here is that the SDK tries to change the OutputPath property based on TargetFramework and AppendTargetFrameworkToOutputPath. But if the value is specified via CLI, the project logic cannot overwrite it.
Also note that BaseOutputPath is actually used in the SDK defaults (defaulted to bin\), but it will try to append the configuration name by default..

Set location of binaries in wixproj file

I am using Wix 3.9 and when I run a continuous integration build in TFS I get an error
heat.exe: The directory could not be found because TFS is putting binaries in a different location to my local machine, so the project will build locally but not on TFS.
In my wixproj file I have a location set for the binaries which works locally
Dir=$(SolutionDir)\ProjectName\bin\$(Configuration).
Is there anything I can set this to which will find the binaries both on my local machine and TFS?
I am looking for something like the project reference variable $(var.MyProject.TargetDir), but this doesn't seem to work in wixproj files.
I worked around this issue by changing my project files to output the binaries to the same location as Team Foundation Build. That way both desktop and continuous integration builds can use the same reference to the common binaries directory.
If you are using Team Foundation Build 2012 or earlier your directory reference would be: Dir=$(SolutionDir)..\Binaries\$Configuration. The corresponding output path in a C# project would be ..\..\Binaries\Release or ..\..\Binaries\Debug (assuming the project folder is located in the root of the sources directory).
If you are using Team Foundation Build 2013, the same technique can be used, but the Binaries folder becomes bin. Your directory reference becomes: Dir=$(SolutionDir)..\bin\$Configuration. A similar change is required to the project output folders.
Team Foundation Build 2013 has additional options to control the output location, where you can put the output binaries in the same layout as your project structure. I've not used that personally but that might provide a solution.

$(MSBuildProjectDirectory) and "program files (x86)" folder

I'm using the property MSBuildProjectDirectory with MSBuild.
The project is located in:
C:\Program Files (x86)\Jenkins\workspace\MyProject
During build MSBuildProjectDirectory is instead evaluated as:
C:\Program Files %28x86%29\Jenkins\workspace\MyProject
and I get a "The system cannot find the file specified" error.
Do I need to move to a different folder or can I get the right path?
If you are using Visual Studio 2010 / MSBuild 4.0, this will happen with certain properties that contain parentheses. Microsoft admitted that this was a regression error from VS2008 to VS2010, when using MSBuild 4.0:
http://connect.microsoft.com/VisualStudio/feedback/details/532677/msbuild-4-0-usingtask-cannot-have-a-path-with-parentheses
According to the above link, the following have an issue with parentheses:
UsingTask
MsBuildProjectDirectoryNoRoot
MsBuildProjectDirectory
MsBuildProjectFullPath
Resolution: For now, when using MSBuild 4.0, change the location to a path that does not contain parentheses.
Use
$([MSBuild]::Unescape('$(MSBuildProjectDirectory)'))
instead of
$(MSBuildProjectDirectory)

How do I set input path for binaries in WIX project to MSBuild output path on TFS?

I want MSBuild to build WIX 3.5 project containing static files and binaries from another project's output folder. While with static files it all works just fine: I just set Source attribute of File element to "..\AnotherProject\Static\StaticFile.ext", I can't reference binaries, because they aren't in "..\AnotherProject\bin\Release\" folder, they're in MSBuild output folder which I don't know how to reference.
The only way to do so is set some variable in .wixproj file in for Release build configuration and then use it, but it seems wrong. What do I miss?
You want "bind paths". The documentation isn't great about this but you can specify BindInputPaths on the Light MSBuild Task. Any File/#Source or #SourceFile that starts with "SourceDir\" or is a relative path (doesn't start with an "X:\" or "\") will be searched in those bind paths. You can use MSBuild variables to get the BindInputPaths set correctly.
Tried $(var.Web.TargetDir) - working.