Why won't MSBuild build a project with a dot in the name? - msbuild

The Story So Far
I've got a nice solution with a desktop application project, a few library projects, and a couple of development tools projects (also desktop applications). At the moment, my build server outputs all of the code into one OutputPath. So we end up with
drop-x.y.z\
Company.MainApplication.exe <-- main application
Company.MainApplicationCore.dll <-- libraries
Helper.exe <-- developer tools
Grapher.exe
Parser.exe
... <-- the rest of the output
But, we're growing up and people outside of our team want access to our tools. So I want to organize the output. I decided that what we would want is a different OutputPath per executable project
drop-x.y.z\
Company.MainApplication\
Company.MainApplication.exe <-- main application
Company.MainApplicationCore.dll <-- libraries
... <-- application specific output
Helper\
Helper.exe <-- developer tools
... <-- tool specific output
Grapher\
Grapher.exe
...
Parser\
Parser.exe
...
What I Did
I found this simple command. I like it because it retains all the Solution working-dir context that makes msbuild a pain.
msbuild /target:<ProjectName>
For example, from my solution root as a working directory, I would call
PS> msbuild /target:Helper /property:OutputPath="$pwd\out\Helper"
I'm testing this from PowerShell, so that $pwd resolves to the full path to my working directory, or the Solution root in this case. I get the output I desire.
However, when I run this command
PS> msbuild /target:Company.MainApplication /property:OutputPath="$pwd\out\Company.MainApplication"
I get the following error output (there's no more information, I ran with /verbosity:diagnostic)
The target "Company.MainApplication" does not exist in the project.
What I Need
The command fails on any project with a dot or dots in the name. I tried with many combinations of working directories and properties. I tried several ways of escaping the property values. I also tried running the command from a <Task> in a targets file.
I need to know either
A) How to fix this command to work property
B) How to achieve the same output with minimal friction

Try using an underscore as an escape character for the dot in the target parameter, e.g.
msbuild /target:Company_MainApplication /property:OutputPath="$pwd\out\Company.MainApplication"

Specify the target after the -target: switch in the format :. If the project name contains any of the characters %, $, #, ;, ., (, ), or ', replace them with an _ in the specified target name.
https://learn.microsoft.com/en-us/visualstudio/msbuild/how-to-build-specific-targets-in-solutions-by-using-msbuild-exe?view=vs-2019
Dan Nolan's answer and comments are correct. Just want to supplement the Microsoft documentation.

The /targets: switch is to identify a <Target to run in the project file. You need to supply your .csproj file as a an argument that is not prefixed by a /xx option marker.
You might also want to work based on the .sln file. In that case, you still dont specify the project in the .sln to build in this manner. I'll leave you to search up the correct syntax in case that's what you end up doing.

Related

cmake - Troubleshooting LINK_DIRECTORIES

My cmake file contains this statement:
link_directories("C:/path/to/lib")
In the properties of the generated Visual Studio solution I see:
/LIBPATH:"C:/path/to/lib"
/LIBPATH:"C:/path/to/lib/Release"
I am not sure where that second LIBPATH is coming from.
Within the cmake file I would like to print out the LINK_DIRECTORIES property, how would I do that? I have tried various things along the lines of...
cmake_print_properties(DIRECTORIES xxx PROPERTIES LINK_DIRECTORIES)
...but I am not sure what parameters to pass.
Edit OK this worked:
cmake_print_properties(DIRECTORIES . PROPERTIES LINK_DIRECTORIES)
It prints out:
Properties for DIRECTORY .:
..LINK_DIRECTORIES = "C:/path/to/lib"
So where is that second LIBPATH coming from? I don't know whether it is generated by cmake somehow, or added later by Visual Studio.

CMake: How to set different variable value for different build configuration?

In my project I need to include different files for different build configurations and thus far I've been unable to find a way to do it via CMake.
My build command looks the following way:
cmake -DCMAKE_CONFIGURATION_TYPES=Debug2017;Debug2018;Debug2019;Release2017;Release2018;Release2019 -G"Visual Studio 14 2015" #and so on
In my CMakeLists.txt I want to have something that looks like:
if ($<$<CONFIG:Debug2017>: )
set (MAYA_DIRECTORY "C:/Program Files/Autodesk/Maya2017" )>
endif()
if ($<$<CONFIG:Debug2018>: )
set (MAYA_DIRECTORY "C:/Program Files/Autodesk/Maya2018" )>
endif()
#and so on; obviously script above don't work. I posted it just as an example of what I want to achieve
variable MAYA_DIRECTORY is used later on to set different other variables that are used for include_directories(…) and link_directories(…) calls.
If there is a way to do this by something other than generator expressions that would also work.
Thanks!
You don't. It is possible for single config generators to use CMAKE_BUILD_TYPE but that strategy fails for for multi-config generators like Visual Studio. This is mixing up what happens at configuration time and build time. The active configuration happens at build time.
Therefore you need a separate MAYA_DIRECTORY for each build config. Then you need to include each Maya into the build (I'm guessing they are external projects or something). Then you need to use a generator expressions to pick which Maya you want to use in the executable.
It would be something like this.
target_include_directories(myApp PRIVATE
$<$<CONFIG:Debug2016>:${MAYA_2016_INCS}>
$<$<CONFIG:Debug2017>:${MAYA_2017_INCS}> )
target_link_libraries(myApp PRIVATE
$<$<CONFIG:Debug2016>:${MAYA_2016_LIBS}>
$<$<CONFIG:Debug2017>:${MAYA_2017_LIBS} )
FYI, If you are creating multiple configuration types you need to seed them properly. That is make sure you create a *_Debug2017 with the debug flags and so on.

How to copy and rename multiple files in CMake with wildcards?

I have a CMake project and I need to copy files from one folder to another and do some additional renaming with the following pattern:
"xy-1" will be "abcd1",
"xy-2" will be "abcd2",
...,
"xy-123" will be "abcd123"
Currently I´m trying this with add_custom_command() and in general it works for a simpler pattern like
"xy-1" will be "abc1",
"xy-2" will be "abc2",
...,
"xy-123" will be "abc123",
I´m doing it with
COMMAND copy "${path_to_source_folder}xy-*.txt" "${path_to_destination_folder}abc*.txt"
In the working pattern the number of characters before the asterisk are the same for the source- and the destination-name.
But in the not working pattern, there are 3 characters in the source-name and four characters in the destination-name before the asterisk:
COMMAND copy "${path_to_source_folder}xy-*.txt" "${path_to_destination_folder}abcd*.txt"
This not working. There is no error coming from cmake, but it will not copy all files (only the first 99) and the names are not created properly.
A quick fix would be to list all (400+) files explicitly, but I´d like to avoid this ;-)
How to do this with add_custom_command() or if this is not possible, how to do it in another way?
Many thanks for your help!
Cheers Daniel
Upate:
Thanks for the hints in the comments! I´m running on Windows 10 and using powershell for running cmake.

OpenCover: Unable to run coverage for more than 2 assemblies

I am trying to use OpenCover With XUnit and MSBuild for our project and it works fine with one or two assemblies. But when the number of assemblies goes more than 2 it throws the below error:
EXEC : error : unknown command line option: MyProj.UnitTest.dll
[C:\CMR\Source\trunk\Build\Script\CMR.msbuild]
Committing...
No results, this could be for a number of reasons. The most common reasons are:
1) missing PDBs for the assemblies that match the filter please review the output
file and refer to the Usage guide (Usage.rtf) about filters.
2) the profiler may not be registered correctly,
please refer to the Usage guide and the -register switch.
Thought the problem would be with the 3rd assembly i added, so ran it individually again it worked fine. Below is the script I used:
<Exec Command='$(OpenCoverPath)\OpenCover.Console.exe "-target: $(XUnitPath)\xunit.console.exe" "-targetargs:C:\MyPath\UnitTest1.dll C:\MyPath\UnitTest2.dll C:\MyPath\UnitTest3.dll /noshadow" "-output:c:\OpenCoverReport\coverage.xml"'/>
And this is my assumption, for the purpose of posting here i had put paths of dll as C:\MyPath\UnitTest.dll but indeed the path is so huge and there are multiple assemblies with huge path. Does it has anything to do with this error?
try the -targetdir option of OpenCover
e.g.
<Exec Command='$(OpenCoverPath)\OpenCover.Console.exe -targetdir:"C:\MyPath" "-target: $(XUnitPath)\xunit.console.exe" "-targetargs:UnitTest1.dll UnitTest2.dll UnitTest3.dll /noshadow" "-output:c:\OpenCoverReport\coverage.xml" '/>

msbuild -p:outputdir=c:\mydir being ignored

I'm running msbuild from the command line with the following:
msbuild mysolution.sln -p:outputdir=c:\mydir
When I run this, the outputdir is being ignored and the default specified in the csproj file is being used.
The MSDN doc for this tool says that I should be able to override the build directory using this parameter. What am I doing wrong?
You should use OutputPath and more important you should use the right syntax :
msbuild mysolution.sln /p:OutputPath=c:\mydir
Note that OutputPath is preferred over OutDir. The documentation used to be wrong about this, but I see that they've finally fixed it.
Beyond that, it's difficult to say exactly what the problem is, since you didn't show the exact path that you're passing as a parameter. There are two possible problems that I can imagine:
The OutputPath option specifies the path to the output directory relative to the project directory. That means you can't set it to a global path like C:\mydir. I assume it is unable to find the path you specified, and so it defaults to the one specified in your project file.
If the path that you're actually specifying as a parameter contains spaces, the command is likely to fail. I believe you need to wrap the path in quotes and append an extra backslash to the end of the path string.
I believe you should be using OutputPath.