Visual Studio has macros like $(TargetDirectory), $(OutputPath) etc.
In my source code, I want to specify a relative path for the loading of a file from a folder a few levels below the TargetDirectory.
Currently I'm doing this: mLayer = mEngine->AddLayer("D:\\Projects\\abc.osg"); and I want it to be something like mLayer = mEngine->AddLayer(($TargetDirectory)+"..\\..\\abc.osg");
It's just a temporary requirement, so that I can give my code to a person for a small demo, and his TargetDirectory is differently aligned wrt my directories. Is there any way to make use of the Visual Studio macros in source code? (at least I know that System environment variables can be accessed)
Go to Project Properties -> Configuration Properties -> C/C++ -> Preprocessor -> Preprocessor Definitions and add the following:
TARGET_DIRECTORY=LR"($(TargetDir))"
This defines a wide string literal named TARGET_DIRECTORY that contains the contents of the $(TargetDir) macro. The important thing here is that this creates a C++ raw string that does not treat backslashes as escape characters. Paths contain backslashes. Using a regular string literal would be incorrect and would even give you compiler errors in some cases.
Important!
If you use a macro that may contain a closing parenthesis followed by double quotation marks )" you must use an additional delimiter, that cannot occur in the macro value, for example:
TARGET_DIRECTORY=LR"|($(TargetDir))|"
In the case of windows file system paths this is not necessary because paths cannot contain double quotation marks.
You cannot do this automatically, but you can pass specific MSBuild properties to the preprocessor:
<ItemDefinitionGroup>
<ClCompile>
<PreprocessorDefinitions>TARGET_DIRECTORY="$(TargetDirectory)"</PreprocessorDefinitions>
</ClCompile>
</ItemDefinitionGroup>
This can be configured in the IDE by going to the Project Property Pages dialog, browsing to Configuration Properties -> C/C++ -> Preprocessor Definitions, and adding
TARGET_DIRECTORY="$(TargetDirectory)"
Note that your use of + for string literal concatenation is incorrect: string literals (and C Strings in general) cannot be concatenated using +. Rather, string literals can be concatenated simply by placing them adjacent to each other. For example,
TARGET_DIRECTORY "..\\..\\abc.osg"
Inside Properties -> Configuration Properties -> C/C++ -> Preprocessor -> Preprocessor you can add your directive.
PROJECT_DIR=R"($(ProjectDir))"
In code you can use it like.
std::string com = "powershell groovy "PROJECT_DIR"generate_report.groovy " + EXE_DIR;
EXE_DIR is a string in our case.
I'd suggest making these relative to the application's working directory, or something. Perhaps check out the GetCurrentDirectory function, at http://msdn.microsoft.com/en-us/library/aa364934%28v=vs.85%29.aspx.
Not that I know of but I have an alternative.
Deploy your file as a post build step. In this step you can consume the $(OutDir) macro which represents your binaries drop folder. This should help you place this file at a relative position from your app and use that relative position within your code.
This will also be a lasting solution rather than something done temporarily.
use TARGET_DIRECTORY=""$(TargetDir)"" instead of TARGET_DIRECTORY="$(TargetDir)" for string macro. (Note double quotes)
Worked for me in VS2005.
Related
Can Somebody explain me on short (just as idea) what the following fragment suggests?
- I'm new in C language so I don't understand the meaning of #...# sign:
#SET_MAKE#
VPATH = #srcdir#
pkgdatadir = $(datadir)/#PACKAGE#
pkgincludedir = $(includedir)/#PACKAGE#
pkglibdir = $(libdir)/#PACKAGE#
pkglibexecdir = $(libexecdir)/#PACKAGE#
or:
build_triplet = #build#
host_triplet = #host#
If is needed to put more code, let me know.
Thanks in advance.
The system of using names enclosed in # is used by autoconf to mark strings that should be replaced by the configure script.
These appear to be build-system variables of some sort, as the # symbol is not (I believe) used in C at all. Considering the names, this seems even more likely. The package and source directory will be inserted in the corresponding places.
Perhaps more interesting are the $(var)s, which are used often in Visual Studio project files (but not source, and a VS proj is a make file of sorts itself).
My guess is you have two make/build system variable types being used here. Whether they're from two system, I do not know. As Brian Roach pointed out in a comment, at least GNU autoconf is involved here.
What file did this come from, and what other text surrounds it? That may shed more light, if a well known name is used. It is possible this isn't a code file at all, and just a make file; or it could be a code file with build system variables in (for at-build replace).
This is not C at all, looks more like a makefile of some sort. Take a look at the filename where you found this, I doubt it ends in .c.
I would like to know if there is a possibility to get the list of project's include directories when building files with custom build step.
Imagine following situation: my project consists of A.cpp, B.cpp and C.blah. In project properties under the field "C/C++" -> "General" -> "Additional Include Directories" I have specified a list of includes directories to be used for A.cpp and B.cpp. Now for C.blah I do specify a custom build tool and write into "Command Line" -> "mytool.exe C.blah -I*Direcotries?* -o C.obj". How can I now get the list of include directories specified for the C/C++ in this step? When I click on "Macros" there is no such macro giving me the full list of includes.
Is anybody aware of a possibility to achieve this goal?
I think I found an answer, however incomplete.
One can specify in the property sheets something like this:
<PropertyGroup>
<ProjectIncludeDir>#(ClCompile->'%(AdditionalIncludeDirectories)')</ProjectIncludeDir>
</PropertyGroup>
This will make the macro $(ProjectIncludeDir) available to the custom build steps too containing the list of include directories.
The problem with this approach that string operations are not possible on this macro anymore. For example consider following:
<ProjectIncludeDirDot>$(ProjectIncludeDir.Replace(';',','))</ProjectIncludeDirDot>
This results for the macro $(ProjectIncludeDirDot) in #(ClCompile->'%(AdditionalIncludeDirectories)'). It seems that transforms are get evaluated after the macro evaluation, which breaks that replacement. If somebody knows for a better solution, please...
When the list of arguments to a method grows to the point where they do not fit comfortably on one line, I like to format code such that each argument is on a separate line (following the StyleCop suggestion), like this:
public void MyMethod(
int someArgument,
double someOtherArgument,
int someMoreArguments)
The problem I run into is that this formatting is "fragile" and does not get automatically reformatted when using Ctrl + K + D. For instance, if I happen to insert some spaces in front of one of the arguments, it doesn't get removed, and I end up doing some tedious manual reformatting.
If I copy a method (say, to provide an overloaded signature), the argument indentation in the copy gets totally messy.
I have a similar issue with LINQ statements, which I also like to format on multiple lines, like:
myEnumerable.
.Where(this and that)
.Where(this and that)
.FirstOrDefault();
I realize this is complete obsessive-compulsive formatting, and a very minor issue, but is there a way to make Visual Studio 2010 automatically reindent multi-line arguments following that pattern when it gets misaligned?
For anyone searching this problem for later versions, in Visual Studio 2017 I found an option to do this (I am not sure if it is available in other versions).
Under menu Tools → Options → Text editor → C/C++ → Formatting → Indentation → "Within parentheses, align new lines when I type them".
Choose the option "Align contents to opening parentheses".
You may want to look at ReSharper from JetBrains. It has all sorts of rules that can be applied to formatting code that is much better that the built-in Visual Studio stuff.
This particular option is located at:
ReSharper → menu Options → C# → Formatting Style → Line Breaks and Wrapping → Wrap long lines.
I don't know if it does exactly what you want, but it does wrap long lines.
It's more often obvious what a build command macro like $(SolutionDir) will evaluate to, but when building complex strings of these macros, it would be nice to be able to quickly evaluate the resulting real string. Is there any way of doing this except building a custom tool that takes a string of macros as input and outputs the evaluated string?
Just add a pre-build event and use "echo" to display the string in the Output window
echo $(SolutionDir)
I can't seem to find any useful documentation from Microsoft about how one would use the Delimiter and InheritsFromParent attributes in the UserMacro element when defining user Macros in .vsprops property sheet files for Visual Studio.
Here's sample usage:
<UserMacro Name="INCLUDEPATH" Value="$(VCROOT)\Inc"
InheritsFromParent="TRUE" Delimiter=";"/>
From the above example, I'm guessing that "inherit" really means "a) if definition is non-empty then append delimiter, and b) append new definition" where as the non-inherit behavior would be to simply replace any current macro definition. Does anyone know for sure? Even better, does anyone have any suggested source of alternative documentation for Visual Studio .vsprops files and macros?
NOTE: this is not the same as the InheritedPropertySheets attribute of the VisualStudioPropertySheet element, for example:
<VisualStudioPropertySheet ... InheritedPropertySheets=".\my.vsprops">
In this case "inherit" basically means "include".
[Answering my own question]
InheritsFromParent means prepend. To verify this, I did an experiment that reveals how User Macros work in Visual Studio 2008. Here's the setup:
Project p.vcproj includes the property sheet file d.vsprops ('d' for derived) using the InheritedPropertySheets tag.
d.vsprops includes the property sheet file b.vsprops ('b' for base.)
p.vcproj also defines a Pre-Build Event which dumps the environment.
Both .vsprops files contain User Macro definitions.
b.vsprops
...
<UserMacro Name="NOENV" Value="B"/>
<UserMacro Name="OVERRIDE" Value="B" PerformEnvironmentSet="true"/>
<UserMacro Name="PREPEND" Value="B" PerformEnvironmentSet="true"/>
...
d.vsprops
...
<VisualStudioPropertySheet ... InheritedPropertySheets=".\b.vsprops">
<UserMacro Name="ENV" Value="$(NOENV)" PerformEnvironmentSet="true"/>
<UserMacro Name="OVERRIDE" Value="D" PerformEnvironmentSet="true"/>
<UserMacro Name="PREPEND" Value="D" InheritsFromParent="true"
Delimiter="+" PerformEnvironmentSet="true"/>
...
p.vcproj
...
<Configuration ... InheritedPropertySheets=".\d.vsprops">
<Tool Name="VCPreBuildEventTool" CommandLine="set | sort"/>
...
build output
...
ENV=B
OVERRIDE=D
PREPEND=D+B
...
From these results we can conclude the following:
PerformEnvironmentSet="true" is necessary for User Macros to be defined in the environment used for build events. Proof: NOENV not shown in build output.
User Macros are always inherited from included property sheets regardless of PerformEnvironmentSet or InheritsFromParent. Proof: in b.vsprops, NOENV is not set in the environment and in d.vsprops it is used without need of InheritsFromParent.
Simple redefinition of a User Macro overrides any previous definition. Proof: OVERRIDE is set to D although it was earlier defined as B.
Redefinition of a User Macro with InheritsFromParent="true" prepends the new definition to any previous definition, separated by a specified Delimiter. Proof: PREPEND is set to D+B (not D or B+D.)
Here are some additional resources I found for explanation of Visual Studio .vsprops files and related topics, it's from a few years back but it is still helpful:
understanding the VC project system part I: files and tools
understanding the VC project system part II: configurations and the project property pages dialog
understanding the VC project system part III: macros, environment variables and sharing
understanding the VC project system part IV: properties and property inheritance
understanding the VC project system part V: building, tools and dependencies
understanding the VC project system part VI: custom build steps and build events
understanding the VC project system part VII: "makefile" projects and (re-)using environments
There's documentation on the UI version of this here.
A lot of the XML files seem somewhat undocumented, often just giving a schema file. Your guess as to how they function is pretty much right.
It is not the whole story.
Delimiters are not inherited. Only
the list of items they delimit are inherited: The same user macros can have different delimiters in different property sheets but only the last encountered delimiter is used. (I write "last encountered" because at project level, we cannot specify a delimiter and what gets used there is the last property sheet that specified inheritance for that macro)
Delimiters works only if made of a
single character. A delimiter longer
than one character may have its
first and/or last character stripped
in some cases, in a mistaken attempt
to "join" the list of values.
$(Inherit) appears to work inside
user macros. Like for aggregate
properties, it works as a placeholder for
the parent's values, and it can appear multiple times. When no $(Inherit) is found, it is implied at the beginning if the inheritance flag is set.
$(NoInherit) also appears to work in user's macros(makes VC behaves as if the checkbox was unticked).
User macros (and some built-ins) appears
to work when used for constructing a property sheet's path (VC's own project converter uses that feature). The value
taken by user's macros in this situation is not
always intuitive, though, especially if it gets redefined in other included property sheets.
In general, what gets "inherited" or concatenated are formulae and not values (ie. you cannot use a user macro to take a snapshot the local value of (say) $(IntDir) in a property sheet and hope to "bubble up" that value through inheritance, because what gets inherited is actually the formula "$(IntDir)", whose value will eventually be resolved at the project/config/file level).
A property sheet already loaded is ignored (seem to avoid that the same property sheet has its user macros aggregated twice)
Both "/" and "\" appear to work in
property sheet paths (and in most
places where VS expects a path).
A property sheet path starting with
"/" (after macros have been resolved) is assumed to be in "./", where '.' is the location of the
calling sheet/project). Same if the path does not start with "./", "../" or "drive:/" (dunno about UNC).