Referencing Visual studio variables from cmake - visual-studio

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)

Related

Setup Library Project for Variable definitions

I'm currently trying to make a library with several variable definitions I can use in different Setup Projects but without success.
I have several huge *.wxs files which are build into a library where the File/#Source should depend on project settings. The reason for that is our internal directory structur which looks like any\path\Redistributables\In-Test\X64\productA or any\path\Redistributables\RC\X86\productA so the last 2 parts of my path should change e.g. on x64 and x86 build.
Now I have several Setup Projects too which uses the same path but working in another subdirectory e.g Redistributables\In-Test\X64\AnyOtherProductB.
I dont want to pass preprocessor variables with the same values to each project because the path could change later and I would have to edit too many project settings then.
So my question:
Is it possible to build something like a "Variable/property Container" with public variables/properties so I could just reference that library to use the variables defined in it for my <component><file source...>?
I've tried to achieve that with prepocessor variables before $(var.sourcedir)$(var.compilemode)$(var.platform) with no luck. These 3 are the parts I need to define once to use them in nearly all projects.
Small edit here, I do this a lot where I read the question quickly and make an answer then reread the question and think my answer doesn't quite fit the question but in this case I hope it is still helpful and maybe one of the other resources referenced here will help as well.
Ah I did something like this and banged my head against the wall for a while trying to figure it out.
The problem is you can't use variables like $(var.sourceDir) in the wixlib and then change it later on when you use the lib in a project. What happens is the compiler replaces $(var.sourceDir) in your wixlib with the actual value of this variable when you build it. You can verify this by opening up your obj file and looking for a component or something that uses this directory and see that it has the value of the sourceDir variable not $(var.sourceDir).
To solve the issue we are going to use bind/wix variables (not sure of the terminology) which get evaluated at linking time.
This was the "how to" that I eventually got to which helped me a lot
So, update your variables to something like this !(bindpath.SourceDir)
<Fragment>
<util:RegistrySearchRef Id="MSVCPPRedist_x64_12"/>
<PackageGroup Id="MSVCPPRedist_x64_12">
<ExePackage
Id="MSVCPPRedist_x64_12_0_21005"
Cache="no"
Description="Visual C++ 2013 Redistributable needed for [WixBundleName]"
DetectCondition="MSVCPPRedist_x64_12 OR NOT VersionNT64"
DisplayName="Prerequisite - Visual C++ 2013 Redistributable (x64)"
InstallCommand="/install /quiet /norestart /log vc12log.txt"
PerMachine="yes"
Permanent="yes"
SourceFile="!(bindpath.PrerequisitesDir)VC++\vcredist_x64_12.exe"
UninstallCommand="/uninstall"
Vital="yes"/>
</PackageGroup>
</Fragment>
And then in some props file or project file on the build machine you can include something like this:
<LinkerAdditionalOptions>-b "PrerequisitesDir=$(PrerequisitesDir)\"</LinkerAdditionalOptions>
Where the $(PrerequisitesDir) property was set based on a relative path in a msbuild file on the build machine like so (or use absolute path is also fine):
<!-- Directories -->
<PrerequisitesDir>$(MSBuildThisFileDirectory)..\..\..\Installers\Prerequisites\</PrerequisitesDir>
Now when you build the linker phase will use the build time defined bindPath to find the source files.
In regards to the platform and configuration vars, I think you can use WixVariables referenced as !(wix.VariableName) but I'm not sure off the top of my head and without more experimenting myself. You can take a look at this answer here to help get more acquainted with the different types of variables. If WixVariables don't work you can just build several flavours of yoru wixlib and reference the appropriate one in your wixproj themselves by using the MSBuild properties $(configuration), ect.. in the hintpath of the wixlib file.

How do you reference the solution folder in .targets?

I have a custom tool that I run on certain file types using the .targets mechanism in Visual Studio 2015.
Projects exist at many levels, and I want to reference this tool when the code is pulled to ANY drive/folder, including the TFS CI agent.
I tried using a relative path, but because the files are at different levels, it doesn't work for all projects.
I tried using a registry setting and environment variable, but that doesn't bode well for the CI machine which might build in a different folder each time.
Is it possible to get the solution folder of which the project/file is in, then I can use a relative path to the tool directory?
All I can find is these properties, which do not seem to help:
General MSBuild properties:
https://msdn.microsoft.com/en-us/library/bb629394.aspx
https://msdn.microsoft.com/en-us/library/ms164309.aspx
Registry and environment variables:
https://msdn.microsoft.com/en-us/library/ms171458.aspx
You can use all the standard tokens within .targets.
Just use
$(SolutionDir)
See https://msdn.microsoft.com/en-us/library/c02as0cs.aspx
Self-service answer: use visual studio's property editing for a vcxproj in preprocessor macros or include paths or such to look at a bunch of available variables. You can usually find what you need in there, by name, or by example, including the one you need here. Better than any documentation.

Visual Studio msbuild

I have a question regarding the commandline options of msbuild. I am
currently using msbuild to build projects using the existing solution
files. These solution files have references to external dll which have
different paths on each machine. I am currently writing a build script
and passing the specific path to the project file via the /p: switch of
msbuild.
My current build line is:
msbuild test.sln /p:ReferencePath="c:\abc" /p:ReferencePath="c:\rca"
What i have noticed that Reference Path now contains only c:\rca and
not c:\abc. this is causing problems for me since, the external dlls
lie in two different directorys. I am allowed to keep multiple
reference paths via visual studio, but not via the commandline.
Is there any known way by which i can do this
I believe you can use this /p:ReferencePath="c:\abc;c:\rca"
At least that is what that link is hinting at, they are using %3B to encode the ";" within the build file.
Although the correct syntax for providing more the one reference path is listed above, I would suggest solving the root cause which in my opinion is the different locations of your referenced assembly. I would suggest you put all thirdparty dependencies, apart from the framework assemblies in your source code repository for the following reasons:
Relatitve paths are consistent across computers
The source code is always in sink with the correct version of your thirdparty assembly (if you for instance need to build an old version of your software 2 years from now).
Upgrading your thirdparty assembly is as easy as upgrading on one machine and then committing your changes to the repository. (In a previous project we even went as far as checking in the entire java runtime environment and were quite happy with the given setup.)
Try seperating your pathes with a semi-colon (;)
Like this:
c:\abc;c:\rca
You may be better off by synchronizing your libraries across machines. I have found that Visual Studio makes this easy. Simply add a solution folder, and add your libraries there. Then, in each project, reference the libraries from this common place. This way, each developer has them in the same place.
This will remove one of variables you have when trying to script out builds.
The command line options for setting the reference path will work just fine (assuming you escape the semi colon, it seems both %3B and ; will work). However, when the argument was passed in from nant (and I needed multiple paths), creating a 'Visual Studio Project User Options file' seemed to work better.
I just emit (echo) a file to the file system with the following format:
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ReferencePath>
C:\abc;c:\rca
</ReferencePath>
</PropertyGroup>
I give the *.user file an appropriate name (given a project file MyProject.csproj, my user file would be MyProject.csproj.user)

MSBuild directory structure limit workarounds

Does anyone have a method to overcome the 260 character limit of the MSBuild tool for building Visual Studio projects and solutions from the command line? I'm trying to get the build automated using CruiseControl (CruiseControl.NET isn't an option, so I'm trying to tie it into normal ant scripts) and I keep on running into problems with the length of the paths. To clarify, the problem is in the length of paths of projects referenced in the solution file, as the tool doesn't collapse paths down properly :(
I've also tried using DevEnv which sometimes works and sometimes throws an exception, which isn't good for an automated build on a separate machine. So please don't suggest using this as a replacement.
And to top it all, the project builds fine when using Visual Studio through the normal IDE.
It seems that it is limitation of the MSBuild. We had the same problem, and in the end, we had to get paths shortened, because did not find any other solution that worked properly.
The SUBST command stills seems to exist so remapping the root of your build folder to a drive letter may save some characters if Judah Himango's solution is no good.
I solved similar issue by adjusting CSPROJ-file:
<BaseIntermediateOutputPath>$([System.IO.Path]::GetFullPath('$(MSBuildProjectDirectory)\..\..\..\Intermediate\$(AssemblyName)_$(ProjectGuid)\'))</BaseIntermediateOutputPath>
As the result during compilation CSC.EXE receives full path instead of relative one.
Thanks to harrydev for clue on how CSC.EXE operates with the paths.
There are two kinds of long path problems relevant to build. One is paths that aren't really too long, but have lots of "..\" in them. Typically, these are references' HintPath values. MSBuild should normalize these paths down to below the max limit, so that they work.
The other kind of path is just plain too long. Sorry, but these just won't work. After looking at it a fair bit, the problem is that there just isn't sufficient API support for long paths. The BCL team (see their blog) had similar problems. Only some of the Win32 API's support the \?\ format. Arbitrary build tools, and probably 98% of apps out there, don't; and worse would probably behave badly (think of all the buffers sized for MAX_PATH).
We came to the conclusion that until there's a big ecosystem effort to make long paths work, or Windows comes up with some ingenious way to make them work anyway (like the short paths mangling?) long paths just aren't possible for MSBuild to support. Workarounds include subst, as you found; but if your tree just is simply too deep, your only options are to build it in fragments, or to shorten the folder names. Sorry.
Dan/MSBuild
I found the problem to be that when the C# compiler (csc.exe) is called it uses the projects directory path PROJECTDIRECTORY together with the output path OUTPUTPATH by simply appending them as:
PROJECTDIRECTORY+OUTPUTPATH
However, if the OUTPUTPATH is relative i.e. "..\..\Build\ProjectName\AnyCPU_Debug_Bin\" and the project directory is pretty long then the total length is longer than 259 characters since the path will be:
PROJECTPATH+"..\..\Build\ProjectName\AnyCPU_Debug_Bin\"
instead of an absolute path.
If csc.exe would make an absolute path before calling Win32 functions this would work. Since in our case the absolute path length is less than 160 characters.
For some reason the call to csc.exe from visual studio is then different from MSBuild than it is from visual studio. Do not know why.
In any case, the problem can be resolved by changing either or both PROJECTDIRECTORY and/or OUTPUTPATH paths.
Have you tried DOS paths? Or the \\?\ prefix? The .NET BCL team blog has more info.
If the path length is 260, then there is warning resolving reference, for 259 or 261 of this error does not occur. I think there is msbuild bug.
I know there is already an accepted answer, but I had a different problem while using msbuild that gave me the same error output, and led me on a circular wild-goose chase. So, for future googlers, here goes:
We have a batch file that calls msbuild, but as the build machine can build for multiple versions of Visual Studio, each batch file calls vcvarsall.bat before it runs msbuild. This has the nasty side effect of stuffing the path completely full of the same thing over and over again. When it fills up, you get the error shown in the question above: The input line is too long. A simple Google search could make you think your paths are suddenly too long for msbuild.
In my case, it was as simple as killing the session of cmd.exe and restarting, as this reverted the environment variables to their native state.

Using Visual Studio 2008 to Assemble, Link, Debug, and Execute MASM 6.11 Assembly Code

I would like to use Visual Studio 2008 to the greatest extent possible while effectively compiling/linking/building/etc code as if all these build processes were being done by the tools provided with MASM 6.11. The exact version of MASM does not matter, so long as it's within the 6.x range, as that is what my college is using to teach 16-bit assembly.
I have done some research on the subject and have come to the conclusion that there are several options:
Reconfigure VS to call the MASM 6.11 executables with the same flags, etc as MASM 6.11 would natively do.
Create intermediary batch file(s) to be called by VS to then invoke the proper commands for MASM's linker, etc.
Reconfigure VS's built-in build tools/rules (assembler, linker, etc) to provide an environment identical to the one used by MASM 6.11.
Option (2) was brought up when I realized that the options available in VS's "External Tools" interface may be insufficient to correctly invoke MASM's build tools, thus a batch file to interpret VS's strict method of passing arguments might be helpful, as a lot of my learning about how to get this working involved my manually calling ML.exe, LINK.exe, etc from the command prompt.
Below are several links that may prove useful in answering my question. Please keep in mind that I have read them all and none are the actual solution. I can only hope my specifying MASM 6.11 doesn't prevent anyone from contributing a perhaps more generalized answer.
Similar method used to Option (2), but users on the thread are not contactable:
http://www.codeguru.com/forum/archive/index.php/t-284051.html
(also, I have my doubts about the necessity of an intermediary batch file)
Out of date explanation to my question:
http://www.cs.fiu.edu/~downeyt/cop3402/masmaul.html
Probably the closest thing I've come to a definitive solution, but refers to a suite of tools from something besides MASM, also uses a batch file:
http://www.kipirvine.com/asm/gettingStarted/index.htm#16-bit
I apologize if my terminology for the tools used in each step of the code -> exe process is off, but since I'm trying to reproduce the entirety of steps in between completion of writing the code and generating an executable, I don't think it matters much.
There is a MASM rules file located at (32-bit system remove (x86)):
C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\VCProjectDefaults\masm.rules
Copy that file to your project directory, and add it to the Custom Build Rules for your project. Then "Modify Rule File...", select the MASM build rule and "Modify Build Rule...".
Add a property:
User property type: String
Default value: *.inc
Description: Add additional MASM file dependencies.
Display name: Additional Dependencies
Is read only: False
Name: AdditionalDependencies
Property page name: General
Switch: [value]
Set the Additional Dependencies value to [AdditionalDependencies]. The build should now automatically detect changes to *.inc, and you can edit the properties for an individual asm file to specify others.
You can create a makefile project. In Visual Studio, under File / New / Project, choose Visual C++ / Makefile project.
This allows you to run an arbitrary command to build your project. It doesn't have to be C/C++. It doesn't even have to be a traditional NMake makefile. I've used it to compile a driver using a batch file, and using a NAnt script.
It should be fairly easy to get it to run the MASM 6.x toolchain.
I would suggest to define Custom Build rules depending on file extension.
(Visual Studio 2008, at least in Professinal Edition, can generate .rules files, which can be distributed). There you can define custom build tools for asm files. By using this approach, you should be able to leave the linker step as is.
Way back, we used MASM32 link text as IDE to help students learn assembly. You could check their batchfiles what they do to assemble and link.
instead of batch files, why not use the a custom build step defined on the file?
If you are going to use Visual Studio, couldn't you give them a skeleton project in C/C++ with the entry point for a console app calling a function that has en empty inline assembly block, and let them fill their results in it?
Why don't you use Irvine's guide? Irvine's library is nice and if you want, you can ignore it and work with Windows procs directly. I've searching for a guide like this, Irvine's was the best solution.

Resources