mirror of
https://gitlab.kitware.com/cmake/cmake.git
synced 2026-10-04 04:03:22 +03:00
cmGeneratorTarget: Add OBJC/OBJCXX support to header set verification
Extend header set verification to support Objective-C and Objective-C++.
The supported-language table grows to {"C", "CXX", "OBJC", "OBJCXX"}
and the lattice join is updated so OBJCXX is chosen when both CXX and
OBJC sources are present. GenerateStubForLanguage emits .m/.mm stubs
and the relevant OBJC/OBJCXX standard properties are copied to the
verification target.
Add OBJC/OBJCXX test cases conditioned on CMake_TEST_OBJC, isolated in
dedicated project files to avoid affecting language inference for
unrelated targets. Update property documentation and add a release note.
This commit is contained in:
1 parent
f974ef0f75
commit
da42e4ed20
12 files changed
+115
-23
No files matched your search
@@ -3,6 +3,10 @@ VERIFY_INTERFACE_HEADER_SETS
|
||||
|
||||
.. versionadded:: 3.24
|
||||
|
||||
.. versionchanged:: 4.4
|
||||
``OBJC`` and ``OBJCXX`` languages are now supported in addition to ``C``
|
||||
and ``CXX``.
|
||||
|
||||
Used to verify that all headers in a target's ``PUBLIC`` and ``INTERFACE``
|
||||
header sets can be included on their own.
|
||||
|
||||
|
||||
@@ -3,6 +3,10 @@ VERIFY_PRIVATE_HEADER_SETS
|
||||
|
||||
.. versionadded:: 4.3
|
||||
|
||||
.. versionchanged:: 4.4
|
||||
``OBJC`` and ``OBJCXX`` languages are now supported in addition to ``C``
|
||||
and ``CXX``.
|
||||
|
||||
Used to verify that all headers in a target's ``PUBLIC`` and ``PRIVATE``
|
||||
header sets can be included on their own.
|
||||
|
||||
|
||||
@@ -6,11 +6,16 @@ properties set to true, and its :prop_tgt:`AUTOMOC`, :prop_tgt:`AUTORCC`,
|
||||
|
||||
If the header's :prop_sf:`LANGUAGE` property is set, the value of that property
|
||||
is used to determine the language with which to compile the header file.
|
||||
Otherwise, if the target has any C++ sources, the header is compiled as C++.
|
||||
Otherwise, if the target has any C sources, the header is compiled as C.
|
||||
Otherwise, if C++ is enabled globally, the header is compiled as C++.
|
||||
Otherwise, if C is enabled globally, the header is compiled as C. Otherwise,
|
||||
the header file is not compiled.
|
||||
The supported languages are ``C``, ``CXX``, ``OBJC``, and ``OBJCXX``.
|
||||
If the language is not one of those four, the header file is not compiled.
|
||||
|
||||
Otherwise, the language is inferred from the target's sources using the
|
||||
following precedence: ``OBJCXX`` takes priority over all others; if both
|
||||
``CXX`` and ``OBJC`` sources are present, the header is compiled as
|
||||
``OBJCXX``; otherwise ``CXX`` takes precedence over ``OBJC``, and ``OBJC``
|
||||
takes precedence over ``C``. If no matching sources are found, the same
|
||||
precedence is applied to the globally enabled languages. If no supported
|
||||
language is found, the header file is not compiled.
|
||||
|
||||
If the header's :prop_sf:`SKIP_LINTING` property is set to true, the file is
|
||||
not compiled.
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
verify-header-sets-objc
|
||||
-----------------------
|
||||
|
||||
* The :prop_tgt:`VERIFY_INTERFACE_HEADER_SETS` and
|
||||
:prop_tgt:`VERIFY_PRIVATE_HEADER_SETS` target properties now support
|
||||
``OBJC`` and ``OBJCXX`` languages in addition to ``C`` and ``CXX``.
|
||||
@@ -5907,19 +5907,21 @@ bool cmGeneratorTarget::AddHeaderSetVerification()
|
||||
// the same things so we pick up the same transitive
|
||||
// properties. For the <LANG>_... properties, we don't care if
|
||||
// we set them for languages this target won't eventually use.
|
||||
// The verify header sets feature currently only supports the
|
||||
// C and C++ languages, so we just always set those here for
|
||||
// simplicity rather than working out all languages the target
|
||||
// has to compile for.
|
||||
static std::vector<std::string> propertiesToCopy = {
|
||||
"COMPILE_DEFINITIONS", "COMPILE_FEATURES",
|
||||
"COMPILE_FLAGS", "COMPILE_OPTIONS",
|
||||
"DEFINE_SYMBOL", "INCLUDE_DIRECTORIES",
|
||||
"LINK_LIBRARIES", "C_STANDARD",
|
||||
"C_STANDARD_REQUIRED", "C_EXTENSIONS",
|
||||
"CXX_STANDARD", "CXX_STANDARD_REQUIRED",
|
||||
"CXX_EXTENSIONS"
|
||||
};
|
||||
// Copy language-standard properties for all supported
|
||||
// languages. We don't care if we set properties for languages
|
||||
// this target won't eventually use.
|
||||
static std::array<std::string, 19> const propertiesToCopy{ {
|
||||
"COMPILE_DEFINITIONS", "COMPILE_FEATURES",
|
||||
"COMPILE_FLAGS", "COMPILE_OPTIONS",
|
||||
"DEFINE_SYMBOL", "INCLUDE_DIRECTORIES",
|
||||
"LINK_LIBRARIES", "C_STANDARD",
|
||||
"C_STANDARD_REQUIRED", "C_EXTENSIONS",
|
||||
"CXX_STANDARD", "CXX_STANDARD_REQUIRED",
|
||||
"CXX_EXTENSIONS", "OBJC_STANDARD",
|
||||
"OBJC_STANDARD_REQUIRED", "OBJC_EXTENSIONS",
|
||||
"OBJCXX_STANDARD", "OBJCXX_STANDARD_REQUIRED",
|
||||
"OBJCXX_EXTENSIONS",
|
||||
} };
|
||||
for (std::string const& prop : propertiesToCopy) {
|
||||
cmValue propValue = this->Target->GetProperty(prop);
|
||||
if (propValue.IsSet()) {
|
||||
@@ -6018,9 +6020,11 @@ cm::optional<std::string> cmGeneratorTarget::ResolveHeaderLanguage(
|
||||
cmSourceFile& source,
|
||||
cm::optional<cm::optional<std::string>>& defaultLanguage) const
|
||||
{
|
||||
static std::array<cm::string_view, 2> const supportedLangs{ {
|
||||
static std::array<cm::string_view, 4> const supportedLangs{ {
|
||||
"C",
|
||||
"CXX",
|
||||
"OBJC",
|
||||
"OBJCXX",
|
||||
} };
|
||||
auto isSupported = [](cm::string_view lang) -> bool {
|
||||
return std::find(supportedLangs.begin(), supportedLangs.end(), lang) !=
|
||||
@@ -6039,7 +6043,11 @@ cm::optional<std::string> cmGeneratorTarget::ResolveHeaderLanguage(
|
||||
/*
|
||||
Compute and cache the default language for unlanguaged headers.
|
||||
The lattice join is run once per file set, not once per header.
|
||||
Lattice: CXX > C
|
||||
Lattice: OBJCXX
|
||||
/ \
|
||||
CXX OBJC
|
||||
\ /
|
||||
C
|
||||
*/
|
||||
if (!defaultLanguage) {
|
||||
std::set<std::string> langs;
|
||||
@@ -6060,8 +6068,12 @@ cm::optional<std::string> cmGeneratorTarget::ResolveHeaderLanguage(
|
||||
}
|
||||
|
||||
cm::optional<std::string> resolved;
|
||||
if (langs.count("CXX")) {
|
||||
if (langs.count("OBJCXX") || (langs.count("CXX") && langs.count("OBJC"))) {
|
||||
resolved = "OBJCXX"; // promote
|
||||
} else if (langs.count("CXX")) {
|
||||
resolved = "CXX";
|
||||
} else if (langs.count("OBJC")) {
|
||||
resolved = "OBJC";
|
||||
} else if (langs.count("C")) {
|
||||
resolved = "C";
|
||||
}
|
||||
@@ -6075,10 +6087,12 @@ cm::optional<std::string> cmGeneratorTarget::GenerateStubForLanguage(
|
||||
std::string const& language, std::string const& headerFilename,
|
||||
std::string const& verifyTargetName, cmSourceFile& source) const
|
||||
{
|
||||
static std::array<std::pair<cm::string_view, cm::string_view>, 2> const
|
||||
static std::array<std::pair<cm::string_view, cm::string_view>, 4> const
|
||||
langToExt = { {
|
||||
{ "C", ".c" },
|
||||
{ "CXX", ".cxx" },
|
||||
{ "OBJC", ".m" },
|
||||
{ "OBJCXX", ".mm" },
|
||||
} };
|
||||
|
||||
// NOLINTNEXTLINE(readability-qualified-auto)
|
||||
|
||||
@@ -1500,7 +1500,7 @@ add_RunCMake_test(CMakePresetsWorkflow
|
||||
-DCMake_TEST_JSON_SCHEMA=${CMake_TEST_JSON_SCHEMA}
|
||||
)
|
||||
|
||||
add_RunCMake_test(VerifyHeaderSets)
|
||||
add_RunCMake_test(VerifyHeaderSets -DCMake_TEST_OBJC=${CMake_TEST_OBJC})
|
||||
add_RunCMake_test(set_tests_properties)
|
||||
|
||||
add_RunCMake_test(CMakeListFileName)
|
||||
|
||||
@@ -46,6 +46,17 @@ run_cmake_build(VerifyInterfaceHeaderSets interface iface_lang_cxx)
|
||||
run_cmake_build(VerifyInterfaceHeaderSets interface list)
|
||||
run_cmake_build(VerifyInterfaceHeaderSets interface skip_linting)
|
||||
|
||||
if(CMake_TEST_OBJC)
|
||||
set(RunCMake_TEST_OPTIONS -DCMAKE_VERIFY_INTERFACE_HEADER_SETS=ON)
|
||||
if(NOT RunCMake_GENERATOR_IS_MULTI_CONFIG)
|
||||
list(APPEND RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Debug)
|
||||
endif()
|
||||
run_cmake(VerifyInterfaceHeaderSetsObjC)
|
||||
unset(RunCMake_TEST_OPTIONS)
|
||||
run_cmake_build(VerifyInterfaceHeaderSetsObjC interface lang_test_objc)
|
||||
run_cmake_build(VerifyInterfaceHeaderSetsObjC interface lang_test_objcxx)
|
||||
endif()
|
||||
|
||||
set(RunCMake_TEST_OPTIONS -DCMAKE_VERIFY_INTERFACE_HEADER_SETS=ON)
|
||||
run_cmake(AllVerifyInterfaceHeaderSets)
|
||||
unset(RunCMake_TEST_OPTIONS)
|
||||
@@ -94,6 +105,17 @@ run_cmake_build(VerifyPrivateHeaderSets private iface_lang_cxx)
|
||||
run_cmake_build(VerifyPrivateHeaderSets private list)
|
||||
run_cmake_build(VerifyPrivateHeaderSets private skip_linting)
|
||||
|
||||
if(CMake_TEST_OBJC)
|
||||
set(RunCMake_TEST_OPTIONS -DCMAKE_VERIFY_PRIVATE_HEADER_SETS=ON)
|
||||
if(NOT RunCMake_GENERATOR_IS_MULTI_CONFIG)
|
||||
list(APPEND RunCMake_TEST_OPTIONS -DCMAKE_BUILD_TYPE=Debug)
|
||||
endif()
|
||||
run_cmake(VerifyPrivateHeaderSetsObjC)
|
||||
unset(RunCMake_TEST_OPTIONS)
|
||||
run_cmake_build(VerifyPrivateHeaderSetsObjC private lang_test_objc)
|
||||
run_cmake_build(VerifyPrivateHeaderSetsObjC private lang_test_objcxx)
|
||||
endif()
|
||||
|
||||
set(RunCMake_TEST_OPTIONS -DCMAKE_VERIFY_PRIVATE_HEADER_SETS=ON)
|
||||
run_cmake(AllVerifyPrivateHeaderSets)
|
||||
unset(RunCMake_TEST_OPTIONS)
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
cmake_policy(SET CMP0209 NEW)
|
||||
|
||||
enable_language(C CXX OBJC OBJCXX)
|
||||
|
||||
add_library(lang_test_objc STATIC lib.m)
|
||||
target_sources(lang_test_objc INTERFACE FILE_SET HEADERS FILES lang_test.h)
|
||||
target_compile_definitions(lang_test_objc INTERFACE EXPECT_OBJC)
|
||||
|
||||
# OBJC + OBJCXX sources -> lattice promotes to OBJCXX for unlanguaged headers
|
||||
add_library(lang_test_objcxx STATIC lib.m lib.mm)
|
||||
target_sources(lang_test_objcxx INTERFACE FILE_SET HEADERS FILES lang_test.h)
|
||||
target_compile_definitions(lang_test_objcxx INTERFACE EXPECT_CXX EXPECT_OBJC)
|
||||
@@ -0,0 +1,12 @@
|
||||
cmake_policy(SET CMP0209 NEW)
|
||||
|
||||
enable_language(C CXX OBJC OBJCXX)
|
||||
|
||||
add_library(lang_test_objc STATIC lib.m)
|
||||
target_sources(lang_test_objc PRIVATE FILE_SET HEADERS FILES lang_test.h)
|
||||
target_compile_definitions(lang_test_objc PRIVATE EXPECT_OBJC)
|
||||
|
||||
# OBJC + OBJCXX sources -> lattice promotes to OBJCXX for unlanguaged headers
|
||||
add_library(lang_test_objcxx STATIC lib.m lib.mm)
|
||||
target_sources(lang_test_objcxx PRIVATE FILE_SET HEADERS FILES lang_test.h)
|
||||
target_compile_definitions(lang_test_objcxx PRIVATE EXPECT_CXX EXPECT_OBJC)
|
||||
@@ -5,4 +5,11 @@
|
||||
# error "__cplusplus not defined but EXPECT_CXX defined"
|
||||
#endif
|
||||
|
||||
#if defined(__OBJC__) && !defined(EXPECT_OBJC)
|
||||
# error "__OBJC__ defined but EXPECT_OBJC not defined"
|
||||
#endif
|
||||
#if !defined(__OBJC__) && defined(EXPECT_OBJC)
|
||||
# error "__OBJC__ not defined but EXPECT_OBJC defined"
|
||||
#endif
|
||||
|
||||
extern void lang_test_h(void);
|
||||
@@ -0,0 +1,3 @@
|
||||
void lang_test_h(void)
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
void lang_test_h_mm(void)
|
||||
{
|
||||
}
|
||||
Reference in new issue
Block a user