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.
Comments