Discussion:
[CMake] How to find vcvarsall.bat (e.g. at "C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC")? CMAKE_LINKER?
Niels Dekker - address until 2018
2014-05-08 20:44:22 UTC
Permalink
We need to find a file named "vcvarsall.bat", located in the
installation directory of Visual C++, which may have one of the
following path names, for example:

"C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\"
"M:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\"
"C:\Program Files\Microsoft Visual Studio 9.0\VC\"
etc.

How can we retrieve this directory path name within our CMakeLists.txt?
There's no standard CMake variable like ${CMAKE_COMPILER_DIR}, right?

Looking at a CMakeCache.txt file generated for Visual C++ 12 (2013) by
CMake 2.8.12.2, I saw exactly one variable that would help us:

CMAKE_LINKER:FILEPATH=C:/Program Files (x86)/Microsoft Visual Studio
12.0/VC/bin/link.exe
David Cole
2014-05-08 21:09:05 UTC
Permalink
How about:

if(EXISTS "$ENV{VS110COMNTOOLS}../../VC")
get_filename_component(VC11_DIR "$ENV{VS110COMNTOOLS}../../VC"
ABSOLUTE)
endif()
if(EXISTS "$ENV{VS120COMNTOOLS}../../VC")
get_filename_component(VC12_DIR "$ENV{VS120COMNTOOLS}../../VC"
ABSOLUTE)
endif()
message(STATUS "VC11_DIR='${VC11_DIR}'")
message(STATUS "VC12_DIR='${VC12_DIR}'")


HTH,
David C.
Niels Dekker - address until 2018
2014-05-08 21:55:07 UTC
Permalink
Thanks for your suggestions, J Decker and David. I find both approaches
(using registry entry paths as hints to find_program or using
$ENV{VS110COMNTOOLS}) quite interesting. However, I'd rather not have to
write such code for each compiler version separately, in my CMakeLists.
Also I have the impression that CMake already "knows" the directory path
name of the selected compiler (current generator), so it would be
helpful if CMake could tell me so directly.

We currently find vcvarsall.bat as follows:

get_filename_component(MY_LINKER_DIR ${CMAKE_LINKER} DIRECTORY)
find_file(MY_VCVARSALL_BAT vcvarsall.bat
"${MY_LINKER_DIR}/.." "${MY_LINKER_DIR}/../..")

This appears to work fine for any Visual C++ version I have tested so
far, including both 32 and 64 bits. However, it assumes that CMake
generates this CMAKE_LINKER variable. Is it okay to make that assumption?

Kind regards, Niels
Post by David Cole
if(EXISTS "$ENV{VS110COMNTOOLS}../../VC")
get_filename_component(VC11_DIR "$ENV{VS110COMNTOOLS}../../VC"
ABSOLUTE)
endif()
if(EXISTS "$ENV{VS120COMNTOOLS}../../VC")
get_filename_component(VC12_DIR "$ENV{VS120COMNTOOLS}../../VC"
ABSOLUTE)
endif()
message(STATUS "VC11_DIR='${VC11_DIR}'")
message(STATUS "VC12_DIR='${VC12_DIR}'")
David Cole
2014-05-09 01:32:29 UTC
Permalink
In CMakeCache.txt, for a Visual Studio based build where C and/or C++
has been enabled:

//CXX compiler
CMAKE_CXX_COMPILER:FILEPATH=C:/Program Files (x86)/Microsoft Visual
Studio 11.0/VC/bin/cl.exe

//C compiler
CMAKE_C_COMPILER:FILEPATH=C:/Program Files (x86)/Microsoft Visual
Studio 11.0/VC/bin/cl.exe

Those are as rock solid a basis as you'll get for a "typical" visual
studio build. I think it would be wiser to depend on those than on the
CMAKE_LINKER variable.

Microsoft has a habit of assuming things like this are internal
implementation details, though, and they often move things around from
version to version.

So nothing is guaranteed.

But I would think the compiler variables would be better suited if you
don't want to rely on ENV or registry... I would point out however,
that you don't need to rely on any cmake vars or any cmake commands
having been run if you go with ENV or registry.


HTH,
David C.
Niels Dekker - address until 2018
2014-05-09 09:29:07 UTC
Permalink
Thanks for suggesting CMAKE_CXX_COMPILER, David. Cool! Indeed, the
following appears to work fine, as I tested with CMake 2.8.12.2 (for
both Visual C++ 2008 and Visual C++ 2013):

get_filename_component(MY_COMPILER_DIR
${CMAKE_CXX_COMPILER} DIRECTORY)
find_file(MY_VCVARSALL_BAT vcvarsall.bat
"${MY_COMPILER_DIR}/.." "${MY_COMPILER_DIR}/../..")

Does CMAKE_CXX_COMPILER always provide the full path name of the
compiler, when we use the current version of CMake (2.8.12.2)? In the
past it did not, apparently, as a CMakeCache.txt file generated by CMake
2.8.8 simply had "cl" as compiler file path:

//C++ compiler
CMAKE_CXX_COMPILER:FILEPATH=cl

I cannot find the CMAKE_CXX_COMPILER variable in the CMakeCache.txt
files I generated by CMake 2.8.12.2. Is there an option to get such
CMake variables into CMakeCache.txt?

Kind regards, Niels
Post by David Cole
In CMakeCache.txt, for a Visual Studio based build where C and/or C++
//CXX compiler
CMAKE_CXX_COMPILER:FILEPATH=C:/Program Files (x86)/Microsoft Visual
Studio 11.0/VC/bin/cl.exe
//C compiler
CMAKE_C_COMPILER:FILEPATH=C:/Program Files (x86)/Microsoft Visual Studio
11.0/VC/bin/cl.exe
Those are as rock solid a basis as you'll get for a "typical" visual
studio build. I think it would be wiser to depend on those than on the
CMAKE_LINKER variable.
Microsoft has a habit of assuming things like this are internal
implementation details, though, and they often move things around from
version to version.
So nothing is guaranteed.
But I would think the compiler variables would be better suited if you
don't want to rely on ENV or registry... I would point out however, that
you don't need to rely on any cmake vars or any cmake commands having
been run if you go with ENV or registry.
Iulian-Nicu Şerbănoiu
2014-05-10 20:31:41 UTC
Permalink
Isn't it better to use vsvars32.bat? (or vsvars64.bat? - don't have a 64
bit windows)

Here is the batch script for VS 2013, 2012, 2010 (priority in this specific
order)

~~~~~~~~~

IF EXIST "%VS120COMNTOOLS%" CALL "%VS120COMNTOOLS%vsvars32.bat" && SET
GENERATOR="Visual Studio 12" && GOTO BUILDIF EXIST "%VS110COMNTOOLS%"
CALL "%VS110COMNTOOLS%vsvars32.bat" && SET GENERATOR="Visual Studio
11" && GOTO BUILDIF EXIST "%VS100COMNTOOLS%" CALL
"%VS100COMNTOOLS%vsvars32.bat" && SET GENERATOR="Visual Studio 10" &&
GOTO BUILD


:BUILD

cmake -G %GENERATOR% ....
msbuild ....
~~~~~~~~~~~

Here is the source for the script:
https://bitbucket.org/undergraver/codetrainer/src/b606752e18f10fefd6b84eb22ac3b7c1e674e729/scripts/windows/build.bat?at=default

Best regards,
Iulian
Post by David Cole
if(EXISTS "$ENV{VS110COMNTOOLS}../../VC")
get_filename_component(VC11_DIR "$ENV{VS110COMNTOOLS}../../VC"
ABSOLUTE)
endif()
if(EXISTS "$ENV{VS120COMNTOOLS}../../VC")
get_filename_component(VC12_DIR "$ENV{VS120COMNTOOLS}../../VC"
ABSOLUTE)
endif()
message(STATUS "VC11_DIR='${VC11_DIR}'")
message(STATUS "VC12_DIR='${VC12_DIR}'")
HTH,
David C.
--
Powered by www.kitware.com
http://www.cmake.org/Wiki/CMake_FAQ
Kitware offers various services to support the CMake community. For more
CMake Support: http://cmake.org/cmake/help/support.html
CMake Consulting: http://cmake.org/cmake/help/consulting.html
CMake Training Courses: http://cmake.org/cmake/help/training.html
Visit other Kitware open-source projects at http://www.kitware.com/
opensource/opensource.html
http://www.cmake.org/mailman/listinfo/cmake
Niels Dekker - address until 2018
2014-05-11 09:03:27 UTC
Permalink
Post by Iulian-Nicu Şerbănoiu
Isn't it better to use vsvars32.bat? (or vsvars64.bat? - don't have
a 64 bit windows)
vcvarsall.bat supports both 32-bits and 64-bits, as it may calls either
vcvars32.bat or vcvars64.bat (depending on its optional argument, see
http://msdn.microsoft.com/en-us/library/x4d2c09s.aspx). But indeed, if
you only have 32-bits Windows, you might as well call vcvars32.bat directly.
Post by Iulian-Nicu Şerbănoiu
Here is the batch script for VS 2013, 2012, 2010 (priority in this
specific order)
~~~~~~~~~
IF EXIST "%VS120COMNTOOLS%" CALL "%VS120COMNTOOLS%vsvars32.bat" &&SET GENERATOR="Visual Studio 12" &&GOTO BUILD
IF EXIST "%VS110COMNTOOLS%" CALL "%VS110COMNTOOLS%vsvars32.bat" &&SET GENERATOR="Visual Studio 11" &&GOTO BUILD
IF EXIST "%VS100COMNTOOLS%" CALL "%VS100COMNTOOLS%vsvars32.bat" &&SET GENERATOR="Visual Studio 10" &&GOTO BUILD
Thank, Iulian. But my original question was about finding vcvarsall.bat
from within CMakeLists.txt, and whether it is okay to use CMAKE_LINKER,
given the fact that CMAKE_LINKER is undocumented. David Cole suggested
me to use CMAKE_CXX_COMPILER instead, which appears to work fine:

get_filename_component(MY_COMPILER_DIR
${CMAKE_CXX_COMPILER} DIRECTORY)
find_file(MY_VCVARSALL_BAT vcvarsall.bat
"${MY_COMPILER_DIR}/.." "${MY_COMPILER_DIR}/../..")

Result: MY_VCVARSALL_BAT = C:/Program Files (x86)/Microsoft Visual
Studio 12.0/VC/vcvarsall.bat :-)

Kind regards, Niels
David Cole
2014-05-09 09:53:32 UTC
Permalink
Post by Niels Dekker - address until 2018
Does CMAKE_CXX_COMPILER always provide the full path name of the
compiler, when we use the current version of CMake (2.8.12.2)? In the
past it did not, apparently, as a CMakeCache.txt file generated by
CMake 2.8.8 simply had "cl" as compiler file path
I think now it does, but I'm not 100% certain if it's guaranteed to be
true. Or, if guaranteed, what version of CMake it started being that
way. Maybe Brad will chime in and confirm or deny, and mention the
version if he knows it...

The thing I do know is that since the compiler ID stuff was refactored
and re-architected, there is a directory in your build tree named
"CMakeFiles/${CMAKE_VERSION}" and it contains the file
"CMakeCXXCompiler.cmake" (among others) with all of the information
about the enabled C++ compiler in it. This file is loaded by CMake even
if that information does not appear in your CMakeCache.txt, so the
variable CMAKE_CXX_COMPILER should have a consistent value from run to
run, even if it's not stored in the cache file directly.

Be aware that this file will be re-generated by the next version of
CMake if you upgrade CMake and run it in a pre-existing build
directory, it will create all of its own support files like those in
its very own version-named directory, and the ones from the older
version of CMake are ignored. For this, and many other reasons, it is
always best to start with a clean build tree when switching versions of
CMake.


HTH,
David C.
David Cole
2014-05-09 09:58:09 UTC
Permalink
Also, one more comment on your technique:

If you use get_filename_component in conjunction with paths that
contain ".." or Windows-style component separators ("\"), you can
always clean up the resulting string with the "ABSOLUTE" argument to
get_filename_component. It will collapse any "/../" or "/./" bits of
the path, and convert all the "\" to ?
"/" in the resulting variable.

It's just easier to read the values (as a person) if you don't have to
think about any ".." resolution mentally when looking at cache entries
and variable values. So.... as input to find_*, I would recommend using
only ABSOLUTE paths as the hints and paths for such calls.


HTH,
David C.
Niels Dekker - address until 2018
2014-05-09 20:03:45 UTC
Permalink
If you use get_filename_component in conjunction with paths that contain
".." or Windows-style component separators ("\"), you can always clean
up the resulting string with the "ABSOLUTE" argument to
get_filename_component. It will collapse any "/../" or "/./" bits of the
path, and convert all the "\" to "/" in the resulting variable.
It's just easier to read the values (as a person) if you don't have to
think about any ".." resolution mentally when looking at cache entries
and variable values. So.... as input to find_*, I would recommend using
only ABSOLUTE paths as the hints and paths for such calls.
Thanks David, but my cache entry for MY_VCVARSALL_BAT looks fine
already, having done the following:

get_filename_component(MY_COMPILER_DIR
${CMAKE_CXX_COMPILER} DIRECTORY)
find_file(MY_VCVARSALL_BAT vcvarsall.bat
${MY_COMPILER_DIR}/.." "${MY_COMPILER_DIR}/../..")
//Path to a file.
MY_VCVARSALL_BAT:FILEPATH=C:/Program Files (x86)/Microsoft Visual Studio 12.0/VC/vcvarsall.bat
So any ".." has been resolved automatically by find_file, even without
explicitly specifying "ABSOLUTE" :-)

Was your idea to add the following line?

get_filename_component(MY_VCVARSALL_BAT ${MY_VCVARSALL_BAT} ABSOLUTE)

Again, it does not seem to make a difference in this case. Right?

Kind regards, Niels
David Cole
2014-05-12 13:09:36 UTC
Permalink
Post by Niels Dekker - address until 2018
Thanks David, but my cache entry for MY_VCVARSALL_BAT looks fine
already
...
So any ".." has been resolved automatically by find_file, even
without explicitly specifying "ABSOLUTE" :-)
...it does not seem to make a difference in this case. Right?
Right. Then you are good to go. I have not relied on "find_*" in
relation to using these in my scripts, and typically just construct a
cache var from using get_filename_component. If you actually do find
the file, then you end up with either a full path, or a NOTFOUND, so,
of course, you are all set in your situation. Sorry for the noise.

D

Loading...