enable_language(): Fail if called before project()

Fixes: #25550
This commit is contained in:
Craig Scott 2024-03-30 14:48:50 +11:00
parent d166e7d740
commit 97464aa970
No known key found for this signature in database
GPG Key ID: 6FF37CBDCCADED9F
15 changed files with 101 additions and 8 deletions

View File

@ -9,15 +9,19 @@ Enable languages (CXX/C/OBJC/OBJCXX/Fortran/etc)
Enables support for the named languages in CMake. This is the same as
the :command:`project` command but does not create any of the extra
variables that are created by the project command.
variables that are created by the :command:`project` command.
.. include:: SUPPORTED_LANGUAGES.txt
This command must be called in file scope, not in a function call.
Furthermore, it must be called in the highest directory common to all
targets using the named language directly for compiling sources or
indirectly through link dependencies. It is simplest to enable all
needed languages in the top-level directory of a project.
The following restrictions apply to where ``enable_language()`` may be called:
* It must be called in file scope, not in a function call.
* It must not be called before the first call to :command:`project`.
See policy :policy:`CMP0165`.
* It must be called in the highest directory common to all targets
using the named language directly for compiling sources or
indirectly through link dependencies. It is simplest to enable all
needed languages in the top-level directory of a project.
The ``OPTIONAL`` keyword is a placeholder for future implementation and
does not currently work. Instead you can use the :module:`CheckLanguage`

View File

@ -57,6 +57,7 @@ Policies Introduced by CMake 3.30
.. toctree::
:maxdepth: 1
CMP0165: enable_language() must not be called before project(). </policy/CMP0165>
CMP0164: add_library() rejects SHARED libraries when not supported by the platform. </policy/CMP0164>
CMP0163: The GENERATED source file property is now visible in all directories. </policy/CMP0163>
CMP0162: Visual Studio generators add UseDebugLibraries indicators by default. </policy/CMP0162>

26
Help/policy/CMP0165.rst Normal file
View File

@ -0,0 +1,26 @@
CMP0165
-------
.. versionadded:: 3.30
:command:`enable_language` must not be called before :command:`project`.
In CMake 3.29 and below, if a project called :command:`enable_language`
before the first call to :command:`project`, the language would be enabled
but possibly using unset details that were expected to be set.
In CMake 3.30 and above, :command:`enable_language` prefers to reject this
case and stop with a fatal error instead if it detects that :command:`project`
has not yet been called. This policy provides compatibility for projects that
happened to work when :command:`enable_language` was called before
:command:`project` and have not been updated to call these commands in the
required order.
The ``OLD`` behavior for this policy is to allow :command:`enable_language`
to be called before :command:`project`. The ``NEW`` behavior for this policy
is to fail with a fatal error in such cases.
.. |INTRODUCED_IN_CMAKE_VERSION| replace:: 3.30
.. |WARNS_OR_DOES_NOT_WARN| replace:: warns
.. include:: STANDARD_ADVICE.txt
.. include:: DEPRECATED.txt

View File

@ -0,0 +1,6 @@
enable_language-before-project
------------------------------
* The :command:`enable_language` command now fails with an error
if it is called before the first :command:`project` call.
See policy :policy:`CMP0165`.

View File

@ -4,6 +4,9 @@
#include "cmExecutionStatus.h"
#include "cmMakefile.h"
#include "cmMessageType.h"
#include "cmPolicies.h"
#include "cmSystemTools.h"
bool cmEnableLanguageCommand(std::vector<std::string> const& args,
cmExecutionStatus& status)
@ -13,6 +16,27 @@ bool cmEnableLanguageCommand(std::vector<std::string> const& args,
return false;
}
cmMakefile& mf = status.GetMakefile();
if (!mf.IsNormalDefinitionSet("PROJECT_NAME")) {
switch (mf.GetPolicyStatus(cmPolicies::CMP0165)) {
case cmPolicies::WARN:
mf.IssueMessage(
MessageType::AUTHOR_WARNING,
"project() should be called prior to this enable_language() call.");
break;
case cmPolicies::OLD:
break;
case cmPolicies::NEW:
mf.IssueMessage(
MessageType::FATAL_ERROR,
"project() must be called prior to this enable_language() call.");
cmSystemTools::SetFatalErrorOccurred();
return false;
default:
break;
}
}
bool optional = false;
std::vector<std::string> languages;
for (std::string const& it : args) {
@ -23,6 +47,6 @@ bool cmEnableLanguageCommand(std::vector<std::string> const& args,
}
}
status.GetMakefile().EnableLanguage(languages, optional);
mf.EnableLanguage(languages, optional);
return true;
}

View File

@ -505,7 +505,10 @@ class cmMakefile;
SELECT(POLICY, CMP0164, \
"add_library() rejects SHARED libraries when not supported by the " \
"platform.", \
3, 30, 0, cmPolicies::WARN)
3, 30, 0, cmPolicies::WARN) \
SELECT(POLICY, CMP0165, \
"enable_language() must not be called before project().", 3, 30, 0, \
cmPolicies::WARN)
#define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
#define CM_FOR_EACH_POLICY_ID(POLICY) \

View File

@ -0,0 +1 @@
1

View File

@ -0,0 +1,4 @@
CMake Error at CMP0165-NEW\.cmake:[0-9]+ \(enable_language\):
project\(\) must be called prior to this enable_language\(\) call\.
Call Stack \(most recent call first\):
CMakeLists\.txt:[0-9]+ \(include\)

View File

@ -0,0 +1,2 @@
cmake_policy(SET CMP0165 NEW)
enable_language(C)

View File

@ -0,0 +1,2 @@
cmake_policy(SET CMP0165 OLD)
enable_language(C)

View File

@ -0,0 +1,5 @@
CMake Warning \(dev\) at CMP0165-WARN\.cmake:[0-9]+ \(enable_language\):
project\(\) should be called prior to this enable_language\(\) call\.
Call Stack \(most recent call first\):
CMakeLists\.txt:[0-9]+ \(include\)
This warning is for project developers\. Use -Wno-dev to suppress it\.

View File

@ -0,0 +1,2 @@
# Don't touch the policy, it should warn by default
enable_language(C)

View File

@ -0,0 +1,7 @@
cmake_minimum_required(VERSION 3.29)
# This is different to the usual RunCMake test pattern. We are specifically
# testing the scenario where enable_language() is called before project().
include(${RunCMake_TEST}.cmake)
project(${RunCMake_TEST} NONE)

View File

@ -0,0 +1,5 @@
include(RunCMake)
run_cmake(CMP0165-WARN)
run_cmake(CMP0165-OLD)
run_cmake(CMP0165-NEW)

View File

@ -174,6 +174,7 @@ add_RunCMake_test(CMP0156 -DCMAKE_C_COMPILER_ID=${CMAKE_C_COMPILER_ID}
-DCMAKE_C_COMPILER_VERSION=${CMAKE_C_COMPILER_VERSION})
add_RunCMake_test(CMP0160)
add_RunCMake_test(CMP0163)
add_RunCMake_test(CMP0165)
# The test for Policy 65 requires the use of the
# CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS variable, which both the VS and Xcode