Is there a way to define the project file path in a solution using a user macro/environment variable? I can't seem to do that.
Kind of like an environment variable is used to define the additional include directories in a C++ project, except I want to do the same for the location of a project file in a solution.
I've tried editing the solution in a text editor to change the path to start with %MyMacroName% or $(MyMacroName) but neither of them seems to parse just right. The project files can't be located when the solution is opened.
In .sln file use syntax "%ENV_VAR%rest_of_the_path\test.csproj"
In .csproj file use syntax "$(ENV_VAR)rest_of_the_path\test.dll"
That works for me, ENV_VAR is custom environment variable defined for operating system like ENV_VAR = "C:\MyPath\"
MSBuild allows you use to environment variables,
http://msdn.microsoft.com/en-US/library/ms171459(v=VS.80).aspx
So that you should be able to define environment variables as you wish, and then modify vCxproj files to make use of them.
I am not sure if that tip works for sln files, as sln files are not MSBuild scripts.
From Microsoft Docs .vcxproj and .props file structure:
We recommend you only create and modify .vcxproj projects in the IDE, and avoid manual editing as much as possible. In most cases, you never need to manually edit the project file. Whenever possible you should use the Visual Studio property pages to modify project settings.
If you need customizations that aren't possible in the IDE, we recommend you add custom props or targets.
In props file, use syntax <ENV_VAR>your_local_path</ENV_VAR>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros">
<ENV_VAR>your_local_path</ENV_VAR>
Related
Using VS 2017.
I just spent quite a bit of time wondering why relative paths don't work when running my application in a debug session from within VS (works fine when started from CMD). Apparently the default working directory is pointing at ${ProjectDir} instead of ${OutDir}.
I would like to change the default path but since I lack VS knowledge I am unable to find it in the settings of the IDE.
UPDATE: To avoid confusion: I know about the setting inside the solution/project properties (Debugging section). I am looking for something that sets the directory whenever a new project is created or imported.
May be it is a little late to answer this question, but ...
Also I'm using VS2013 (for business reasons) but I think for VS2017 it should work in a similar way.
My solution:
put something like the following in your .vcxproj file and leave the VS-Gui property dialog as is (or turn it back to inherit-or-standard)
<PropertyGroup>
<my_workdir>$(SolutionDir)..\runtime\$(PlatformTarget)-$(Configuration)\</my_workdir>
<LocalDebuggerWorkingdirectory>$(my_workdir)</LocalDebuggerWorkingDirectory>
</PropertyGroup>
After reloading the solution you should see your settings $(my_workdir) in the property-dialog.
Depending on the current build config it expands to ..\runtime\x64-Debug or so, but this is a matter of taste.
I prefer to use paths relative to the solution directory where ever possible.
If you want this as a standard behaviour...
have a look in your .vcxproj file (usually generated via VS->AddNewProject).
You should find there something like this:
<ImportGroup>
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props"
Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')"
Label="LocalAppDataPlatform" />
. . .
The $(UserRootDir) macro expands to %HOME%\AppData\Local\MicroSoft\MSBuild\v4.0 or so.
You can (create &) edit the *.user.props files there.
In your case you would put the <LocalDebuggerWorkingDirectory>.. definition in these files -- and that's it.
For my self I do not use this method.
I use a ./props/global_definitions.props file in the $(SolutionDirectory) which I import (using a text editor) into my .vcxproj files.
I wanted to use two configurations in my Visual Studio 2019 C++ project, lets say I wanted to rename Debug to Debug-A and add a new configuration called Debug-B based on Debug-A.
Debug-A and Debug-B differ only by one define symbol, lets say one has SYMBOL_A and another has SYMBOL_B.
Currently, I don't care about Release and anything other than x64.
It works corretly until I add a NuGet package (for example fmt). Then, when I try to compile, I get undefined symbol linker errors. Just like fmtd.lib was not included, if I include it manually (or change the project configuration name to Debug), the issue is gone.
I know the reason why NuGet includes it if my project configuration is named Debug. Look at the nuget package targets file (packages/fmt.7.0.1/build/fmt.targets) - lib files are hardcoded to $(Configuration) being either Debug or Release.
As far as I know, all NuGet C++ packages are built this way.
<?xml version="1.0" encoding="utf-8"?>
<Project ToolVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<!-- ... -->
<ItemDefinitionGroup Condition="'$(Configuration)'=='Debug'">
<Link>
<AdditionalDependencies>fmtd.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<Lib>
<AdditionalDependencies>fmtd.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Lib>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)'=='Release'">
<Link>
<AdditionalDependencies>fmt.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
<Lib>
<AdditionalDependencies>fmt.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Lib>
</ItemDefinitionGroup>
<!-- ... -->
</Project>
I know I can manually link the libs, but fmt was just an example, I use a lot of packages and manually linking will become an issue quite fast.
Is there any way to use the quick selection of preprocessor symbols provided by active solution configuration (the toolbar dropdown) and still be able to use NuGet properly? For example parsing the nuget files with fake $(Configuration) variable. Using $(Platform) (x86, x64 etc.) is impossible, library include path is depending on it's hardcoded value too.
Sample project with this bug.
If, as you mentioned, the NuGet Packages’ lib files are hardcoded, then we may need to find solutions from other sides, for example .vcxproj file or MSBuild.
I didn’t find any directly properties/parameters/ways which meet your requirements. But, is it possible to keep the Debug name, I mean, leave it named Debug not Debug-A or Debug-B, and then switch to use different Configurations by using other methods. Imagine there is a Debug configuration file(DebugB)(maybe DebugB related things are set in this file) excluded in the project and the project currently use another Debug configuration(DebugA), and during the build, the project will exactly use DebugA configuration. To switch, do something, or add a code line in .vcxproj file to include the file which contains DebugB configuration, and then let the DebugB configuration cover the DebugA configuration.
So, for covering the properties/items of .vcproj file. Perhaps customize build works.
Hope above could give you a little help.
Case:
When I build from MSBuild (with VS Build Tools 2017) I don't get any value for $(ExtensionTasksPath) variable
from main msbuild file, when I build with integrated VS MSBuild value is passed from main file to MSBuild.ExtensionPack.tasks, is that expected behavior and why does it happen? I don't use any properties for the sake of testing that particular case.
Is that expected behavior and why does it happen?
I think it's not we expect.As I test on a VM, the msbuild from VS Build Tools2017 get the same value as what we can get in msbuild from VS IDE.
For the reason of this behavior I have some suggestions to help trouble
shooting:
1.First of all, make sure both two scenarios builds successfully.
2.As you mentioned above, you runs them in separate VMs, make sure the two file under test are the same and entire solution folder.(The package folder under solution directory makes sense)
3.Check in the .xxproj file, check if exists <Import Project="..\packages\MSBuild.Extension.Pack.1.9.1\build\net40\MSBuild.Extension.Pack.targets" ...>
I've found the $(ExtensionTasksPath) property is defined in MSBuild.Extension.Pack.targets file, and this file is imported into .xxproj file by <Import> tag.
Have a look at pics below from my sample project which install MSBuild.Extension.Pack by nuget:
After my project install the extension bu nuget, there is an Import sentence in csproj file, open it we can find:
The value of $(ExtensionTasksPath) in defined here. So i guess you may have sth missing with the targets file or the import sentense or have sth corrupt this property.
In summary:
1.keep the entire solution folder could be the best suggestion.
2.And if it not works, add a script below to your .xxproj file can work:
<PropertyGroup>
<ExtensionTasksPath> Absolute path of your MSBuild.ExtensionPack.dll</ExtensionTasksPath>
</PropertyGroup>
It will overwrite values from tag and no matter where you put the assembly, just add the absolute path can work.
It my answer is helpful, please give me a feedback. And any update please feel free to contact me.
I am maintaining a large codebase and some vcproj files are used in different solutions. Due to some horrendous configuration and dependencies it seems the best way to handle some build issues is to #ifdef the code but in order to do that I need to set a preprocessor definition at the solution file level and not at the vcproj level.
Is that possible?
How to do it?
I believe what you may want to do is create a project property sheet with the VS Project Manager that all the projects could inherit from. This would allow you to set any common project settings, including preprocessor macros, in a single location and inherit them as you need.
Select all the projects in your solution. Project + Properties, C/C++, Preprocessor, Preprocessor Definitions. Add
/DSOLUTION=$(SolutionName)
You can now test the SOLUTION macro value in your source code.
I finally find somethings that suits me
in my "C:\Users\\AppData\Local\Microsoft\MSBuild\v4.0"
I change it a little bit for:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(SolutionDir)\$(SolutionName).props" Condition="Exists('$(SolutionDir)\$(SolutionName).props')"/>
</Project>
So now, if a "mysolution.props" lays beside of "mysolution.sln" then I get a property sheet for the entire solution without changing anything inside my projects. It becomes a new features for my Visual Environement
2008 sln's are really dumb, they only have lists of projects/files to put in the solution explorer and project dependencies, so I don't think that's an option.
My gut instinct is to do something with relative paths. For example, in your stdafx.h's you could #include "....\project_configuration.h", then for building sln a, you'd check things out to one dir, and sln b another. Each would have its separate project_configuration.h.
I believe you could do something similar with vsprops files, which are essentially #includes for vcproj files, though I've found them a bit annoying to maintain over time.
Another approch:
Edit your vcxproj (or your vcxproj.user) with something like this
<PreprocessorDefinitions Condition="'$(SolutionName)'=='NameOfYourSolution'">
YOUR_DEFINITION;%(PreprocessorDefinitions)
</PreprocessorDefinitions>
it's not perfect as it depends on your sln filename.
It would be great if we use a $(SolutionConfiguration) variable instead.
Unfortunatly, I only see variable for project configuration: $(Configuration).
In any case, it does the trick...
Well, I also looked at
Define a preprocessor value from command line using MSBuild
and
msbuild, defining Conditional Compilation Symbols
and those might work as well, however our build system is pretty brittle right now and I am not in a position to change it all.
The solution I came up with was to clone the build configuration for the project in a solution and give it a different name. Then I added a macros/preprocessor definition to that new configuration.
It appears to work as desired. So one solution uses the old "release" configuration and the other solution uses a clone "ReleaseSpecial" (not the name I really used) configuration with different preprocessor defs.
Not ideal, but it works.
It would be nice if the propoerties were easier to deal with or SLN files could pass in preprocessor defs.
In Visual Studio 2010 we have MSBuild for C++ project. Also we can add additional custom properties files "*.props" to projects, which are just MSBuild scripts.
Is it possible in imported "some.props" file know its directory?
for example there is "project.vcxproj" file and "common.props" file.
I would like to write something:
<IncludeDir>$( [and something for common.props file directory here] )\include</IncludeDir>
What should I write there?
%programfiles%\msbuild, which is accessible with $(MSBuildExtensionsPath), is the recommended place to put .props and .targets files that you would install and leave static. For example, many Microsoft teams that ship build process put their .targets files there.
If you plan to check-in those .props files for your team to use, or modify them, or maybe have different ones for different sets of source code, it's not such a good location; it isn't next to your source code and it requires admin rights to modify. In such cases, I recommend you put the files near your source code, perhaps at the root of a tree or subtree that includes all the projects for which it is relevant.
If you can put them under %Program Files%/MSBuild/ then you can use the MSBuildExtensionsPath property. This resolves to %Program Files%\MSBuild. If you cannot put the files there then another option would be to create an environment variable. In MSBuild you can access env variables just like properties. For example you can do <Message Text="Path :$(Path)"/> to print out the current path.