Read user-defined project macros programmatically - visual-studio

How can I read one of VS project environment variables oder user-defined macros such as the ${SolutionPath} from source code in C++?
I just created a new user-defined macro where I want to store the current Version of my project. I want to use this value during build as well as to show it in the GUI. Do you have any better idea to have only one place to store the current version of my product?
It seems like defining additional preprocessor flags for each project using /D might by a solution, but I cannot get it to work to define a precompiler flag with a value.

You can add an additional compiler option using the following format
/D "VariableName=\"VariableValue\""
This will make the macro available in the project just as if you typed:
\#define VariableName VariableValue

Related

VisualStudio 2019 is it possible te set the build variables from CMAKE. And more generally how to set them up

I am keeping asking questions about VisualStudio but to be honest I do not understand a word from its documentation.
In the json files generated by the VS are placed build variables like ${workspaceRootFolderName}, ${workspaceRoot}, ${env.gccpath} etc etc but I do not know how to set it up.
If the the CMAKE project.
I have two questions:
Is it possible to set those variables from CMAKE files?
If not how can I set them up another way. At the moment project builds but VS generated launch files cannot evaluate the variables
There are target properties that can be used to set these kind of variables in a Visual Studio project. They all begin with VS_. I didn't see any that corresponded with these particular variables in this project.
The alternative seems to be to save them in a User props file and you can set property that incorporates that file into your project.
https://cmake.org/cmake/help/latest/prop_tgt/VS_USER_PROPS.html

Referencing Visual studio variables from cmake

I'm using cmake to generate a visual c++ project and I want to add a visual studio variable to my include path.
For normal variables with a hardcoded path I can simply do
include_directories(PathToFolderIWantToInclude)
However now I want to do the same thing with a variable visual studio already knows about. $(KIT_SHARED_IncludePath)
I tried simply doing
include_directories($(KIT_SHARED_IncludePath))
However that yields c:\path\to\my\project\$(KIT_SHARED_IncludePath). I also tried storing the value in a variable and using the variable instead however that didn't work either. How do I prevent cmake from prepending my current path onto the include path?
The problem is that CMake doesn't have a straight way to pass a relative path in the include_directories and have it not preppended with the value of CMAKE_CURRENT_SOURCE_DIR variable(setting which to nothing doesn't help either). But given the VS macros expand to the absolute paths we could try to circumvent cmake guards by providing a VS macro as follows:
include_directories("\\\\?\\$(KIT_SHARED_IncludePath)")
It will do the trick because it is an absolute path for sure and the correct path will be added as an additional include path to the compiler. Alas, in 2016 MS tool, which is MSVC compiler, doesn't know how to handle the very paths MS introduced many years ago. So this way of doing things is for the people who lives in a better time when MSVC knows how to handle the extended-length paths.
But we are not done yet. We have one more way to circumvent this contorversial CMake behavior: we can use generator expressions. The one we can use is at the top of the list:
include_directories($<1:$(KIT_SHARED_IncludePath)>)
That way CMake doesn't stand a chance and has to comply — the correct line gets added to the list of the additional includes. But it has a side effect: CMake starts complaining(gives a warning, not a error) about a relative path in the include_directories command which you can shut up with either the following command:
cmake_policy(SET CMP0021 OLD)
Or run cmake with the following parameter each time: -Wno-dev. But the latter one will disable all the warnings so I consider the first option preferable in the case.
UPD: Found even easier way to achieve the same. Just add the following line to your cmake file:
add_definitions(-I$(KIT_SHARED_IncludePath))
CMake doesn't support references to internal variables of build environment.
It actually want full information about the project at configuration stage (cmake call which produce .sln). Exception is only for features, accessible throgh using generator-expressions: they allow to defer some decisions to build step (building the project). But this functionality is very limited.
The best you can is to guess value of required include path. It normally looks like C:\Program Files (x86)\Windows Kits\10\Include\<KitVersion>\shared.
For example, you may use command find_path with appropriate hints. And use resulted variable with command include_directories.
Found something for UnitTests here ...CMake and Microsoft Unit Test Framework
This is expanded, use absolute paths, but works in my VS project build by CMake v3.22.1
target_include_directories(${target} PRIVATE "$ENV{VCInstallDir}UnitTest/include")
target_link_directories(${target} PRIVATE "$ENV{VCInstallDir}UnitTest/lib")
(sets C/C++ \ Additional Include Directories resp. Linker \ Additional Library Directories)

Method to make IncludeDirs available to external tool

I'm currently trying to make splint available as an external tool in Visual Studio 2010.
It has problems with finding all includes for the file, since it seems that the INCLUDE variable is only set at build time and I haven't found any other possibility to extract the include files in any way.
My question: Would there be any way to extract the IncludeDir field from the current file's project's Properties page, ideally with the VC++'s AdditionalIncludeDirectories?
Note also that AdditionalIncludeDirectories is per file, as it can be changed for individual source files as well as on the project level, and if it contains macros it can evaluate differently for each source file too!
I'm not familiar with driving the MSBuild objects via the API, but that's used by the IDE. Whether that way or by simply running MSBuild.exe, you need to get it to figure out all the properties, conditions, etc. and then tell you the result. If everything is well behaved, you could create a target that also uses the ClCompile item array and emits the %(AdditionalIncludeDirectories) metadata somehow such as writing it to a file or passing it to your other tool somehow. That's what's used to generate the /I parameters to CL, and you can get the same values.
If things are not well behaved in that necessary values are changed during the detailed build process, you would need to get the same prelims done just like the ClCompile target normally does, too. Or just override ClCompile with your own (last definition of a target is used) so it certainly is in the same context.
Either way, there are places where build script files can be automatically included into all projects, so you can add your stuff there or use a command argument (I think) to MSBuild to add another Include.
—John

Using a #define in build output name in Visual Studio

I'm using Visual Studio 2010 for a C/C++ project. As far as version numbers go I like to have a revision and build date; for example "Project 1.0 R2 Apr 21 2013". I display this at startup, so I can easily tell if someone is running an old version. Now I'd like to put things like this in the filename of the executable created by the build. For example, "Project10R2.exe".
I make use of the build macros as listed here. For display of the build date, I use the predefined macro as listed here. To clarify possible confusion, the build macros are usable from, say, the project properties and what they refer to as "predefined macros" are #define's. I know you can define custom custom build macros (see this) (and obviously any #define I desire).
Now what I want is to use one with the other. That is, I'd like to define a revision string in one place and have it appear both in the program output at startup (easy with a #define) and also in the build output filename (easy with a custom $ macro). I don't want to maintain two different constants.
Anyone know how to do this? It appears you cannot even put the build date in the filename (not safely, anyway, if you use the Windows %DATE% environment variable, you may end up with illegal characters.)
As you've said you can create a custom build macro and then in your project's Properties > C/C++ > Preprocessor > Preprocessor Definitions, you can add something like this: $(my_custom_build_macro);... but this would define the macro in every file.

Visual C++ 2010: Including boost in several projects in a solution?

I'm using the boost library in several projects in my Visual C++ 2010 solution. What I'm currently doing is modifying each project's properties by setting:
Properties->Configuration Properties->C/C++->General->Additional Include Directories to include the boost directory C:\boost\boost_1_47
Properties->Configuration Properties->Linker->General->Additional Library Directories to include the boost lib directory C:\boost\boost_1_47\lib
Now that I'm upgrading my boost version to 1.51 I realize I'm violating DRY by specifying this information more than once (i.e., once for each project). I want to define the boost info in a single place.
After researching it seems like Property Sheets are a good solution. I've read about property sheet inheritance but I don't see how that's useful because it seems that if you want to add a project-specific include directory then you will have to set the Additional Include Directories in the properties for that specific project which will then override the inherited property sheet which defines the boost include directory. If I am wrong about this please correct me.
So my next thought is to create a single property sheet called GlobalMacros.prop and define a user macro something like $(BoostDir) and then add this property sheet to each project. Then I can use the macro in each project's properties when I'm defining include directories and library directories. However, when creating a macro there is an option "set this macro as an environment variable in the build environment" and I am not sure what that does or if I should set it.
Overall I want to know what is the best way to reduce repeated configuration definitions for common settings?
I'm actually the developer that originally implemented property sheets in Visual C++ back in VS 2005 (although I'm not responsible for the mess that is the VC++ project properties dialog). Caveat: I stopped working on VC++ after 2005, so below may not be entirely accurate for your version.
In the Property Manager, you should be able to multiselect all of your project configurations in all projects and add a new property sheet. This will automatically inherit those project configurations from the same property sheet. In that property sheet, set the boost include and library directories directly or use a macro for BoostVersion and BoostDir and use those macros in the property sheet's properties.
Provided that the project configurations have "inherit from parent or project defaults" checked (this controls inserting $(Inherit) vs $(NoInherit) in 2005/2008 and %(<propertyname>) in 2010/2012) for those properties, you should see any project-specific properties set in the project configurations prepended, by default, to the values in the property sheet.
You can confirm this by going to a project and checking the compiler's "Command Line" tab to see if the switches are what you expect.
Edit: note that there are two types of properties in VC++: "single-value" and "multi-value". An example of a single-value property is the compiler's warning level. The value on the command line for a single-value property comes from the first place in the property inheritance chain that specifies it, starting with the project configuration, then the property sheets, then the built-in default in the project system. An example of a multi-value property is the compiler's include directories. Multi-value properties get concatenated with their parent property sheets unless $(NoInherit) is specified (2005/2008) or %(<propertyname>) is not specified (2010/2012). Thus, by default, you should see the boost paths showing up in your project settings provided they have intentionally not inherited the property from the property sheet.

Resources