I have a project that is to be compiled for Linux and Windows. Compilation for the former is done in a Linux environment, and compilation for the latter is done in w64devkit, i.e. I don't need to consider cross-compiling from a single host.
For the Windows build, all compiled files need the -isystem $(VCPKG_DIR)/installed/x64-windows/include compile flag, and the -L $(VCPKG_DIR)/installed/x64-windows/lib linker flag, where $(VCPKG_DIR) refers to the base location where vcpkg is installed.
(For simplicity, the rest of this question focuses on the include path)
This seemed like a good application for CMake presets, something along the lines of:
{
"version": 1,
"cmakeMinimumRequired": {
"major": 3,
"minor": 19,
"patch": 0
},
"configurePresets": [
{
"name": "linux",
"displayName": "Build for Linux",
"description": "Linux build using make generator",
"generator": "Unix Makefiles",
"binaryDir": "${sourceDir}/build"
},
{
"name": "win64",
"displayName": "Build for Windows",
"description": "Windows build using make generator",
"generator": "Unix Makefiles",
"binaryDir": "${sourceDir}/build",
"CMAKE_C_FLAGS": "${VCPKG_DIR}/installed/x64-windows/include"
}
]
}
But from this answer, I learned that the only way we should set include paths are via target_include_directories() (or target_sources()).
This makes sense, but my concern is that in my project, I have many directories (that are peers of each other), each of which has CMakeLists.txt. It seems, then, that I would need to add a target_include_directories() line in each of those CMakeLists.txt files, e.g.
target_include_directories(submodule SYSTEM ${VCPKG_DIR}/installed/x64-windows/include)
I.e. my concern is the repetition of this line across multiple CMakeLists.txt files. This seems like a good candidate for consolidation at one location, something to the effect "if building for Windows, always add -I ${VCPKG_DIR}/installed/x64-windows/include", which seems kind of like the intent of CMake Presets.
But if this is not achievable, or not best practice, with CMake Presets, then how can I make adding that include path in each CMakeLists.txt file conditional on the build target? Would I have to do something like:
if(WIN64)
target_include_directories(my_executable SYSTEM "${VCPKG_DIR}/installed/x64-windows/include")
endif()
?
My question is: what is the most consolidated (least repetitive) way, or the idiomatically-correct way of conditionalizing an include-path across many CMakeLists.txt that is conditional on the build target? Put another way: if my logic is "when building for win64, always include ${VCPKG_DIR}/installed/x64-windows/include as a system include path," what is the best (or idiomatically correct) way to implement that in CMake?
Here's a minimal example for you. I did it on Linux, but the steps should be identical on Windows. I assume CMake is up to date and you have Ninja installed.
First we install vcpkg and libuv. This took about 5 minutes on my laptop.
Now we create an example project:
Now here's the contents of
CMakeLists.txt:And this is
main.cpp. Just enough to test that we can find the header.Now to build this:
In the output here I can very clearly see
-isystem .../vcpkg/installed/x64-linux/include.This works because linking to targets (i.e. either
libuv::uvorlibuv::uv_a) automatically triggers propagation of the library's public include path(s) (i.e.vcpkg/installed/x64-linux/include) to your target. Because this target was imported viafind_package, CMake knows to use-isystemrather than-I. It also uses the full path to the static library rather than risking name resolution issues with-L. This is the better behavior anyway.This fragment is a bit of a hack:
CMake lacks a standardized way of selecting between static and shared libraries, so every project seems to do their own thing. Libuv happens to name their shared library
libuv::uvand their static librarylibuv::uv_a. Vcpkg will only ever have one available, though.The above expression will resolve to
libuv::uv_aif it exists and tolibuv::uvotherwise.I strongly suggest you read the documentation on using third-party libraries in CMake: https://cmake.org/cmake/help/latest/guide/using-dependencies/index.html
I would also peruse this documentation, especially the part on transitive usage requirements: https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html