Recently I had to reinstall Windows to debug a hardware issue. I decided to try to make the most of this by trying to build my game on Windows.
Installing vcpkg
First, you need to clone vcpkg. I installed the git bash program from the git website
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.bat
Next, you need to decide whether to install 32-bit (x86) or 64-bit (x64) dependencies, or both, then run one or both of the following commands:
VCPKG_DEFAULT_TRIPLET=x86-windows ./vcpkg.exe install DEPS
VCPKG_DEFAULT_TRIPLET=x64-windows ./vcpkg.exe install DEPS
where DEPS
is a space-deliminated list of package names.
You can search for packages like so:
./vcpkg.exe search query
If you’re unable to find a dependency, you may have to write your own “port” file to add it to vcpkg.
Finally, to let Visual Studio know about the dependencies, run this:
./vcpkg.exe integrate install
Building
Toolchain
Import your program into Visual Studio as a cmake project. When generating the CMake cache, you’ll probably receive “not found” errors.
Right click on CMakeLists.txt and select “Open CMake Settings”. A file called CMakeSettings.json should appear, with content like the following:
{
"configurations": [
{
"name": "x64-Release",
"generator": "Ninja",
"configurationType": "RelWithDebInfo",
"inheritEnvironments": [
"msvc_x64_x64"
],
"buildRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\build\\${name}",
"installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}",
"cmakeCommandArgs": "",
"buildCommandArgs": "-v",
"ctestCommandArgs": ""
}
]
}
Add the vcpkg toolchain file to cmakeCommandArgs
"cmakeCommandArgs": "-DCMAKE_TOOLCHAIN_FILE=\"C:\\Users\\ruben\\vcpkg\\scripts\\buildsystems\\vcpkg.cmake\""
Clear the CMake cache by doing CMake > Delete Cache Folders > CMakeLists.txt, then click the Generate button on the CMake changes detected banner.
This should be enough to get Visual Studio to find the dependencies, but I found that this wouldn’t work when you have custom CMake find files which probably don’t support the toolchain.
Explicit dependency paths
I’ve yet to find out how to modify the find modules to use vcpkg’s toolchain cleanly, but in the meantime I set the directories manually by adding CMake flags and environment variables.
You should prefer more general settings to individual include/lib settings.
For example, findX.cmake files may allow you to specify a single environment
variable to the install root instead of separate X_INCLUDE_DIR
and X_LIBRARY
CMake variables. This is shown below, with ENETDIR
and SFML_ROOT
.
Don’t be too afraid to modify any embedded find scripts to support environment
variables.
{
"environments": [
{
"ENETDIR": "C:\\Users\\ruben\\vcpkg\\installed\\x64-windows",
"SFML_ROOT": "C:\\Users\\ruben\\vcpkg\\installed\\x64-windows",
"SFGUI_ROOT": "C:\\Users\\ruben\\vcpkg\\installed\\x64-windows",
"THOR_ROOT": "C:\\Users\\ruben\\vcpkg\\installed\\x64-windows",
"LUA_ROOT": "C:\\Users\\ruben\\vcpkg\\installed\\x64-windows"
}
],
"configurations": [
{
"cmakeCommandArgs": "-DCMAKE_TOOLCHAIN_FILE=\"C:\\Users\\ruben\\vcpkg\\scripts\\buildsystems\\vcpkg.cmake\""
}
]
}
Note that you may need to clear the CMake cache and regenerate for changes to take affect.
Common mistakes
Console program vs Windows program
By default, MSVC will compile your program as a console program. This mode results in Windows allocating and showing a console for you when starting the program up. This console will require a redraw on every std::cerr or std::cout print, resulting in massive performance issues.
If you program shows a graphical window, then you should change it to a Windows program.
There are three methods to do this.
-
The first option is to set the executable type to WIN32 in CMake:
if(WIN32) add_executable(${EXECUTABLE_NAME} WIN32 ${SRC}) else() add_executable(${EXECUTABLE_NAME} ${SRC}) endif()
-
Second, by setting linker flags using CMake:
if(WIN32) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup") endif()
-
The final option is to set the linker flags using a pragma directive:
#ifdef _WIN32 #pragma comment(linker, "/SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup") #endif
The ENTRY parameter allows you to use the standard main()
entrypoint instead
of the non-standard WinMain()
.
You may need to clear and regenerate the CMake cache.
Profit!
Hopefully that should be enough to get it work. Please contact me if you know of any ways to make this cleaner or more robust.