Specifying system-specific environment variables

Hi,

This looks like a very basic question, but I was unable to find a good solution searching this site and others, or asking ChatGPT or Bard. So …

I have a QMake-based project for Linux and Windows that I’m trying to move to CMake. While Linux is OK, Windows (Visual Studio 2022) not really. In a sense it works, as I can build; but it isn’t “right”. Inside CMakeLists.txt I need several environment variables pointing to the location of libraries and tools. All is fine if I hardcode them or ask the user to pass them, but I want neither of these. To me, they should be in an external file, set up once and never mentioned again until the path of those tools changes. For this I found 3 potential solutions, but I couldn’t make any work:

  1. Use CMakeUserPresets.json. The thing is, I don’t know what to put there. I was hoping that I can put the windows-base preset (I’m adapting a project VS generated) with just the environment entry, while CMakePresets.json would also have the windows-base preset, but will have the other entries and the fields would get merged. Alas, what I get is a “duplicate presets” error.
  2. Use include in CMakePresets.json. This is pretty similar to CMakeUserPresets.json, in that I get a “duplicate presets” error.
  3. Use some other custom file and tell CMakePresets.json to load data from it. This is something ChatGPT came up with, recommending “$<1:$LOADS:my_environment.json>”. I can’t figure out if this is complete nonsense or it needs a little tweak, but CMake only seems to treat it as a literal string.

I already have a .cmd file that computes the values that I need, I’m just not sure what to do with them, given that I want to be able to both build from the CLI and make changes in Visual Studio, including changing CMakeLists.txt. Something that would work is to modify CMakePresets.json in that .cmd, but I wonder what is the right way to do this.

Thanks

1 Like

Are you trying to find dependencies? If so, find_package is the way to wrap up the search process (which should ideally be seamless for default setups). Other than that, presets sound fine…but I don’t know presets that well.

The LLMs are hallucinating here; there is no LOADS generator expression (and is completely wrong anyways as you likely need your logic during configure and genexes are strictly post-configure information.

Yes, I’m trying to find dependencies. Here are github links to the actual project: If the environment variables are not defined, the find_package() calls will fail.

(Well, technically I check if they are defined above, and exit if they are not defined, but the find_package() calls fail if I remove these checks.)

It’s just that I don’t want to commit the environment settings, which are specific to my machine. On Linux things just work, but in Windows the libraries are not found even though I installed them to their default locations.

So my question is if there is a way to have the environment variables in an external file, while keeping the "windows-base" preset where it is, in CMakePresets.json. Or, given that I know next to nothing about CMake, what is a better way to handle dependencies? Perhaps if I just installed Boost or Qt somewhere else, or if I searched for Boost or Qt in a different way, CMake would find them without needing any environment variable or CLI param, as it finds them in Linux?

I’m not sure that presets are best for this, but I’m also not very familiar with preset patterns.

I would solve this by documenting to add any relevant prefixes to CMAKE_PREFIX_PATH which is a ;-separated list (as a variable) or a path-list environment variable (;-separated on Windows and : elsewhere). You can then do:

cmake "-DCMAKE_PREFIX_PATH=c:/prefix/for/qt;c:/prefix/for/boost" /path/to/src

If you want, you can do this in your CMake code:

list(APPEND CMAKE_PREFIX_PATH
  $ENV{MYPROJ_QT_PREFIX}
  $ENV{MYPROJ_BOOST_PREFIX}
)

before the find_package calls and document the specific envvars instead of the more “general” way.

Thanks, Ben.

My understanding is that starting with Visual Studio 2019, you are supposed to just open CMakeLists.txt. There is no invoking cmake directly, as far as I can tell. The old way of generating a Visual Studio .sln still works, but, well, it is old, and doesn’t seem to bring a real advantage.

So I guess I’ll leave it at telling the users to adjust CMakePresets.json, unless I learn of something better.

There are still some things that the Visual Studio generator supports that the Ninja generator doesn’t, but if you don’t need them, yes, just using the native-provided CMake integration is probably sufficient.