If we configure using the following CMakeLists.txt:
cmake_minimum_required(VERSION 3.25)enable_language(CUDA)# Note: if we move the projct command here, all is fineinclude(FindCUDA/select_compute_arch)CUDA_DETECT_INSTALLED_GPUS(INSTALLED_GPU_CCS_1)project(foo CUDA)
We get:
CMake Error at /path/to/cmake/3.28.1/share/cmake-3.28/Modules/FindCUDA/select_compute_arch.cmake:120 (file): file failed to open for writing (Permission denied): /detect_cuda_compute_capabilities.cuCall Stack (most recent call first): CMakeLists.txt:5 (CUDA_DETECT_INSTALLED_GPUS)
and some additional errors. Now, the problematic file is defined as:
which sort-of assumes ${PROJECT_BINARY_DIR} is not empty. Yet - it is empty before a project has been defined. edit: Since, apparently, enabling languages before a project is defined is unsupported, then the enable_language(CUDA) command should be failing immediately, with the error saying that it can't be invoked with no project defined; the half-hearted effort doomed to fail is confusing to users.
Edited
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information
Child items 0
Show closed items
No child items are currently assigned. Use child items to break down this issue into smaller parts.
Linked items 0
Link issues together to show that they're related.
Learn more.
I'm pretty sure calling enable_languages() before the first project() call is unsupported. The toolchain file won't be loaded before the first project() call, so in general the information enable_languages() needs isn't available yet. Even if you're not using a toolchain file, none of the platform-level details will be set until the first project() call either, so again, enable_language() doesn't have everything it needs.
I'm pretty sure calling enable_languages() before the first project() call is unsupported.
What if you're in a CMake module (or any file other than the CMakeLists.txt)? You don't know whether you've been included before or after a project was defined. Or are you also saying that modules should not be included before a project exists?
Also, enabling a language does seem to do the searching-for-stuff which determines the CUDA architectures - and that happens independently of whether or not you've defined a project, IIANM.
It's up to the project that includes a module to know whether that module is safe to include before the first project() call. Some modules will be safe to do that (e.g. FetchContent is often included and used before the first project() call), other modules will need things that are only available after project() has been called.
As a module author, it's not usually up to you to know the context in which you are included unless you document such behavior. Normally, you would document your restrictions (unless they can reasonably be assumed as something the consumer should already know).
Also, enabling a language does seem to do the searching-for-stuff which determines the CUDA architectures...
That doesn't change the points I raised previously. Just because something appears to work, or that it happens to work for some cases, that doesn't mean it's safe to do in general or that it will continue to be safe. The fact remains that you need platform details to be set first, and language details can be set by a toolchain file, so it is therefore not safe in general to call enable_language() before project(), regardless of what you see if you do it anyway.
@robertmaynard : Hmm. CMAKE_PROJECT_INCLUDE_BEFORE will do what I need it to. It makes my CMake code slightly more convoluted, but I guess I can live with that.
But then - if it's not supported, why is it at all allowed? i.e. why doesn't it just fail with an error saying you can't enable languages without a project?
You would have the same problem with CMAKE_PROJECT_INCLUDE_BEFORE. That injects code before the toolchain file is loaded. You would need to use CMAKE_PROJECT_INCLUDE instead, which injects after the toolchain file is loaded. See https://cmake.org/cmake/help/latest/command/project.html#code-injection for details of the order things are processed.
@craig.scott : So, I would need to create an "artificial" CMake file just for enabling a language, and add to the list (?) of files in CMAKE_PROJECT_INCLUDE. I don't know, that doesn't sound right for a language-enablement. But, you know what? I'll open a different bug about that instead.
As far as this bug is concerned - if enabling languages before a project definition is unsupported, then I should get an error message saying just that.
That change should have a policy. In the NEW behavior it will error, and if the policy is not set it will warn. Either way projects violating this rule will get some kind of diagnostic.
@brad.king Would it be acceptable for that proposed policy to also ensure that enable_language() only enables a previously not-enabled language if it is being called in the top level scope? We don't explicitly say that languages should not be enabled in subdirectories, but there's code in some places that don't properly support that. I don't recall where we discussed that before, but I know we concluded that languages should really only be enabled in the top level scope. If we can include this in the proposed policy, then the policy becomes one of "only allow enable_language() to be called at a place where it is actually supported". I think that's a better outcome than one that only tackles half the set of requirements.
@brad.king Well, right now, it's a confusing error. I don't mind whether it's a warning or an error, as long as it says what I did wrong. So, with policy, without a policy - fine by me.
Would it be acceptable for that proposed policy to also ensure that enable_language() only enables a previously not-enabled language if it is being called in the top level scope?
I don't see why that choice should be mixed up with warning-vs-error on enabling before a project is defined.
Both cases are an unsupported use of enable_language(). One is before the first project() call, the other is from a lower directory scope. There's little value having separate policies for catching these as errors, they are closely enough related that a single policy that turns them into an error seems better here. Neither currently issues a warning (the warning/error you do see in your case is a side-effect, not a warning about the underlying problem), but both would start to warn with the proposed policy set to OLD or unset. They would both become an error if the policy was set to NEW.
I think the actual rule about enabling languages might be that enable_language need to be called in a common ancestor directory to all directories that use the language. Often that is the top, but it is possible to construct cases where it is not. In any case, I think it's too subtle to enforce with a blanket policy.
Let's focus on the ordering w.r.t. the top-most project().
Would it be acceptable for that proposed policy to also ensure that enable_language() only enables a previously not-enabled language if it is being called in the top level scope?
You can enable a language in a nested directory before the parent, as long as the parent does enable the language before the end of execution. So a subdirectory can enable a language, set a global variable and the parent uses that variable to 're-enable' the language.
I think the actual rule about enabling languages might be that enable_language need to be called in a common ancestor directory to all directories that use the language. Often that is the top, but it is possible to construct cases where it is not. In any case, I think it's too subtle to enforce with a blanket policy.
Looking at the implementation of cmGlobalGenerator::EnableLanguage(), there are parts in there that do very much assume enable_language() is being called in the top-most CMakeLists.txt file. Some of that logic was added by me for the CMAKE_PROJECT_TOP_LEVEL_INCLUDES support added in CMake 3.24, but logic that existed before that appears to have also tacitly been assuming that enable_language() was called in a top level CMakeLists.txt too. I say that because it sets variables that should really be set by the very top level CMakeLists.txt, like CMAKE_SYSTEM_NAME. @brad.king's comment that the enable_language() call is required to be in the highest ancestor directory of all directories that use the language is insufficient, it would have to be the highest ancestor of all directories that use any language because of some of these variables that get set. Such languages could have been enabled by a previous call to enable_language(), and we don't track the scope from which a language was first enabled (at least, not that I can see).
I do think we should remove this grey area from CMake. We can add a policy that requires enable_language() to be called from the top level if it is enabling a non-yet enabled language. This still allows enable_language() to be called in lower directory scopes with an already-enabled language, which would be a no-op (this is already the current behavior, we just need to continue to allow that). This is essential for FetchContent and similar techniques which pull subprojects into a parent build directly. I now agree that we should make this a separate policy from one that enforces that enable_language() cannot be called before the first project() call (the main focus of this issue). We should probably split out this discussion of calling enable_language() from non-top scopes to its own dedicated issue.
Actually, I now see that the variables expected to be set/handled at the top level will always be set at the top level. The top level project() call will always set at least one language, possibly a language called NONE which is treated specially. Thus, as long as enable_language() is not being called before the first project(), the variables will be set and the concerns in my previous comment above are unfounded.
It's more that there may be projects that are relying on being able to call enable_language() only in subdirectories. Since posting my earlier comments, I can now think of some legitimate use cases for that, and since it has been supported for a long time, it's probably unlikely we can or should now prohibit it.
Eyal Rozenbergchanged title from The CUDA_DETECT_INSTALLED_GPUS assumes a project is defined to Fail if enable_language() invoked before a project is defined
changed title from The CUDA_DETECT_INSTALLED_GPUS assumes a project is defined to Fail if enable_language() invoked before a project is defined
Eyal Rozenbergchanged title from Fail if enable_language() invoked before a project is defined to Fail better if enable_language() invoked before a project is defined
changed title from Fail if enable_language() invoked before a project is defined to Fail better if enable_language() invoked before a project is defined
I'll add the policy that enforces calling project() before enable_language(). I have work for this locally, but I'll wait until !9347 (merged) is merged, since it is adding a new policy too (CMP0164). I'll take the CMP0165 slot once that is merged.