How to escape backslash in $(SolutionDir) in a VS project file? - c#

I'm trying to write a post-build event for a C# project. And I'm using a custom console app (myTool.exe) to do that.
For example, the post-build event is
"$(SolutionDir)tools\myTool.exe" "$(SolutionDir)myProject\bin\" Debug
(All paths is quoted because they could contain whitespaces.)
Before escaping, $(SolutionDir) is D:\Some\MySystem\.
After escaping, it should become D:\\Some\\MySystem\\.
How to escape all the \ in $(SolutionDir) in this way in a csproj file?
I have tried to use this approach, but it seems not working for $(SolutionDir):
<PropertyGroup>
<EscapedSolutionDir>$(SolutionDir.Replace('\\', '\\\\'))</EscapedSolutionDir>
<EscapedTargetDir>$(TargetDir.Replace('\\', '\\\\'))</EscapedTargetDir>
</PropertyGroup>
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
<Exec Command=""$(EscapedSolutionDir)source\\Native\\Output\\NativeLibraryCopier.exe" "$(EscapedSolutionDir)" "$(ConfigurationName)" "$(PlatformName)" "$(TargetDir)"" />
</Target>
PS: See this for why I have to replace the backslash.

How to escape backslash in $(SolutionDir) in a VS project file?
Not sure why you want to replace the "\" with "\\" in the $(SolutionDir). That because this property is common macros for build commands and properties, You can use these macros anywhere in a project's Property Pages dialog box where strings are accepted.
But if you insist on replacing it, you should replace it with $(SolutionDir.Replace('\', '\\')) rather than $(SolutionDir.Replace('\\', '\\\\')). Because the path in the $(SolutionDir) is D:\Some\MySystem\, Only one backslash. When you replace it with double backslashes, MSBuild could not find the double backslashes in the $(SolutionDir).
So the scripts should be:
<PropertyGroup>
<EscapedSolutionDir>$(SolutionDir.Replace('\', '\\'))</EscapedSolutionDir>
<EscapedTargetDir>$(TargetDir.Replace('\', '\\'))</EscapedTargetDir>
</PropertyGroup>
Then I use a target to output the escaped value in the EscapedSolutionDir and EscapedTargetDir, both those value were escaped:
<Target Name="PreBuild" BeforeTargets="PreBuildEvent">
<Message Text="$(EscapedSolutionDir)" Importance="high">
</Message>
<Message Text="$(EscapedTargetDir)" Importance="high">
</Message>
</Target>
The output:

Be aware that some Environ Vars finish with a backslash....
add a "." and then when using them add the "\"
for example I was trying to get a meesage (#pragma message) with a file path and name...
I did it like this:
<PreprocessorDefinitions>INT_DIR=$(IntDir.Replace('', '\')).;%(PreprocessorDefinitions)</PreprocessorDefinitions>
And then
#define MyFile "File.ext"
#pragma message ( TO_STR(INT_DIR) "\\" MyFile "(0) : MESSAGE: File Included")

Related

Msbuild step to generate c# file and then compile it

I have a .csproj named P with a custom task in it.
<UsingTask TaskName="[FullTaskName]" AssemblyFile="$(TargetPath)" />
<Target Name="[CustomTaskName]" BeforeTargets="Build">
<[CustomTask] />
</Target>
This custom task replace the content of an included file F in P. This replacement can lead to errors in F.
However when I build P (and then run the custom task), the build pass whatever the content of F.
How to include the new content of F when building P?
Changing BeforeTargets="Build" to BeforeTargets="BeforeBuild" seems to be working.

How get the "create assembly" output text for post-build script?

I have a SQL Trigger project.
Currently, when I go to "Project->Publish", I can choose "generate script", it will generate a script for me and include my project's assembly via a line:
GO
CREATE ASSEMBLY [MyProject.MyObject]
AUTHORIZATION [dbo]
FROM 0x4F5C8000....
WITH PERMISSION_SET = UNSAFE;
GO
ALTER ASSEMBLY [MyProject.MyObject]
DROP FILE ALL
ADD FILE FROM 0x4D5743....
I want to generate that on build and grab that as text (for Powershell) so i can put it in another file.
I know how to put it in another file via powershell, but how do I generate it on post-build?
Just add you call .ps1 file into .csproj file, write block <propertyGroup> if not exist. It seems like this:
<Target>
...
</Target>
<PropertyGroup>
<PostBuildEvent>Powershell.exe -ExecutionPolicy Unrestricted -file "$(SolutionDir)$(ProjectName)\postbuild.ps1"</PostBuildEvent>
</PropertyGroup>
To do this, I needed two steps in my build script:
#Step 1: Get the file as bytes
$fileBytes = Get-Content -Path $myFilePath -Encoding Byte
#Step 2: Convert it to Hex using a BitConverter
#Step 2a: Remove the dashes it puts in each byte's hex
$fileInHex = [System.BitConverter]::ToString($fileBytes) | ForEach-Object { $_ -replace "-", "" }

How to use the MSBuild command line parameter called Configuration as a conditional compilation symbol?

I would like to display a string that tells user which build configuration was used to build the application. For example:
If the command line resembled this:
msbuild project.sln /t:Build /p:Configuration=Release
And then in the source code, I would like to do this:
Console.Writeline("You are running the " + <get the /p:Configuration value> + " version" );
The user would see this:
You are running the Release version
I know that we can declare conditional compilation symbols (#defines) at the command prompt such as how it is defined in this article and this one. But I want to use the existing variable called Configuration.
There are no way to do this, except as you said = using #if. MSBuild configuration name is just a name for set of configurations in project file to build specific flavor of your project. By default you do not have access to this configuration name from your code.
I see two ways how you can change the string in your code:
a) As you said - you can specify the conditional compilation symbols, so you can do something like
#if DEBUG
const string Flavor = "Debug";
#else
const string Flavor = "Release";
#endif
...
Console.WriteLine("You are running the " + Flavor + " version" );
b) You can play with your project file and include different set of files depending on the Configuration. If you will unload your project and open csproj as just a file - you will see for example
<ItemGroup>
<Compile Include="MyApp.cs" />
</ItemGroup>
You can change to something like:
<ItemGroup>
<Compile Include="MyApp.Release.cs" Condition="'$(Configuration)'=='Release'" />
<Compile Include="MyApp.Debug.cs" Condition="'$(Configuration)'=='Debug'" />
</ItemGroup>
So this is how you will include different set of files for each configuration, where you can specify what configuration user has right now.

CCNET Build Publisher with mutlipe source dir

I'm using CCNet and want to use build publisher to copy from more than one sourcedir, is there any workaround to do that, keep in mind that I want to make the build folder labelled with the build number .
here is my code :
<buildpublisher>
<sourceDir>D:\CCNETTest1\WebApplication1\WebApplication1</sourceDir>
<publishDir>C:\inetpub\wwwroot\CI</publishDir>
<alwaysPublish>false</alwaysPublish>
</buildpublisher>
you could not specify more than one sourcedir in buildpublisher, so if you want to, you have to use before
create a folder that will contain all your sourcedir you want
create nant copy :
<copy todir="${target.dir}\firstsource">
<fileset basedir="firstsource">
<include name="*.*" />
</fileset>
</copy>
<copy todir="${target.dir}\secondsource">
<fileset basedir="secondsource">
<include name="*.*" />
</fileset>
</copy>
and after all your source are in target.dir folder use your buildpublisher but specify for sourceDir , folder that contains all folder you want...
<buildpublisher>
<sourceDir>$(target.dir)</sourceDir>
<publishDir>C:\inetpub\wwwroot\CI</publishDir>
<alwaysPublish>false</alwaysPublish>
</buildpublisher>

Msbuild copy and flatten with unique file names

I'm trying to copy multiple files from a deep source tree that have the same file name. For example TestResults.trx. I want to copy them into a single directory (i.e. flattened). Problem is they just overwrite each other and I just end up with a single TestResults.trx in the directory.
<ItemGroup>
<SilverlightTestResults Include=".\**\*.trx" Exclude=".\TestResults\*" />
</ItemGroup>
<Copy SourceFiles="#(SilverlightTestResults)" DestinationFolder=".\TestResults">
I thought I could do a transform using some well known metadata but there doesn't seem to be anything unique in there to do it (the test results I'm trying to copy live in directories like this: .\SomeProject\bin\debug\TestResults.trx).
Copying to a directory like this like this would be ideal:
.\TestResults\TestResults1.trx
.\TestResults\TestResults2.trx
.\TestResults\TestResults3.trx
I don't care about the actual names as long as they are unique.
Any ideas, looks like a custom task is required?
I can't provide a solution that just uses msbuild - you could either use msbuildtasks
to use the <Add /> task for incrementing a counter.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\MSBuildCommunityTasks\MSBuild.Community.Tasks.Targets"/>
<PropertyGroup>
<FileCounter>0</FileCounter>
</PropertyGroup>
<ItemGroup>
<MySourceFiles SilverlightTestResults Include=".\**\*.trx" Exclude=".\TestResults\*"/>
</ItemGroup>
<Target Name="CopyFiles">
<Math.Add Numbers="$(FileCounter);1">
<Output TaskParameter="FileCounter" PropertyName="FileCounter" />
</Math.Add>
<Copy
SourceFiles="#(MySourceFiles)"
DestinationFiles="#(MySourceFiles->'.\TestResults\%(Filename)_$(FileCounter)%(Extension)')"
/>
</Target>
However you might do better with a custom task or probably executing a powershell script.
Yes, a custom task will be required.
You could look to see what functionality the Move task from the community task project (link here) offers, but if it doesn't do what you want then it is open source, so it will be trivial to check the source and modify it to suit your needs.

Categories

Resources