Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,26 @@ if(NOT DEFINED CMAKE_CXX_STANDARD OR CMAKE_CXX_STANDARD LESS 20)
set(CMAKE_CXX_STANDARD 20)
endif()
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.15)
if(APPLE)
# Determine target architecture for deployment target selection
# Priority: explicit CMAKE_OSX_ARCHITECTURES > CMAKE_SYSTEM_PROCESSOR > host processor
if(CMAKE_OSX_ARCHITECTURES)
set(_target_arch "${CMAKE_OSX_ARCHITECTURES}")
elseif(CMAKE_SYSTEM_PROCESSOR)
set(_target_arch "${CMAKE_SYSTEM_PROCESSOR}")
else()
set(_target_arch "${CMAKE_HOST_SYSTEM_PROCESSOR}")
endif()

# macOS 11.0 is the minimum for ARM64 (Apple Silicon was introduced with Big Sur)
# macOS 10.15 remains the target for Intel builds
if(_target_arch STREQUAL "arm64")
set(CMAKE_OSX_DEPLOYMENT_TARGET 11.0)
else()
set(CMAKE_OSX_DEPLOYMENT_TARGET 10.15)
endif()
Comment on lines +40 to +57
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

CMake CMAKE_OSX_ARCHITECTURES multi-architecture list semicolon separated

💡 Result:

CMAKE_OSX_ARCHITECTURES takes a CMake list, and CMake lists are semicolon-separated strings. So a multi-arch (“universal”) build is written like:

set(CMAKE_OSX_ARCHITECTURES "x86_64;arm64")

or per-target:

set_property(TARGET myapp PROPERTY OSX_ARCHITECTURES "x86_64;arm64")

Important details:

  • Set it before the first project() / enable_language() because it can affect toolchain configuration. It’s also intended to be set as a CACHE entry. [1]
  • On the command line, quote (or otherwise escape) the semicolon so your shell doesn’t treat it as a command separator:
cmake -S . -B build -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64"

CMake’s own behavior here follows the general rule: many CMake variables/properties accept semicolon-separated lists. [2]

Sources:
[1] CMake docs: CMAKE_OSX_ARCHITECTURES variable (latest) https://cmake.org/cmake/help/latest/variable/CMAKE_OSX_ARCHITECTURES.html
[2] CMake docs: Lists are semicolon-delimited / list handling https://cmake.org/cmake/help/v3.26/manual/cmake-language.7.html


🌐 Web query:

CMake STREQUAL behavior with lists and list(FIND) for detecting element membership

💡 Result:

What STREQUAL does with “lists”

In CMake, a “list” is just a single string whose elements are separated by semicolons (;). So STREQUAL is always a plain string equality test—it does not test element membership. If you compare a list variable, you’re comparing its full semicolon-joined representation (e.g., a;b;c). [1], [2]

set(L a b c)          # L is the string "a;b;c" [1]

if("${L}" STREQUAL "a;b;c")
  message("equal")
endif()

Why quoting matters (lists can “explode” into multiple arguments)

If you expand a list unquoted in a command call, CMake splits it on semicolons into multiple arguments (“list expansion”). Quoted arguments preserve semicolons as part of the single argument. [2]

So this is dangerous:

# BAD: ${L} becomes a;b;c, which is split into multiple arguments
if(${L} STREQUAL "a;b;c")
  ...
endif()

Prefer quoting expansions in comparisons:

if("${L}" STREQUAL "a;b;c")
  ...
endif()

Correct way to test whether a list contains an element: list(FIND)

list(FIND <list> <value> <outVar>) returns the index of an element equal to <value>, or -1 if not found. [1]

set(L a b c)

list(FIND L "b" idx)
if(idx GREATER -1)
  message("L contains b")
endif()

list(FIND L "x" idx)
if(idx EQUAL -1)
  message("L does not contain x")
endif()

Notes:

  • list(FIND ...) checks exact element equality (not substring / pattern matching). [1]
  • Use quotes around the searched value if it might contain spaces.

Sources: CMake list() documentation (list definition; list(FIND) return value) [1]; CMake language rules for unquoted argument splitting on semicolons vs quoted preservation [2]; if() comparison operator context (STREQUAL is a string comparison operator) [3].

[1] https://cmake.org/cmake/help/latest/command/list.html
[2] https://cmake.org/cmake/help/v3.26/manual/cmake-language.7.html
[3] https://cmake.org/cmake/help/latest/command/if.html


Fix multi-arch deployment target detection.

CMAKE_OSX_ARCHITECTURES is a semicolon-separated CMake list (e.g., arm64;x86_64 for universal builds). Using STREQUAL "arm64" will fail on such lists, incorrectly applying the Intel 10.15 target even when building for ARM64. Use list(FIND) to detect membership instead.

Suggested fix
-    if(_target_arch STREQUAL "arm64")
+    set(_arm64_idx -1)
+    list(FIND _target_arch "arm64" _arm64_idx)
+    if(_arm64_idx GREATER -1)
         set(CMAKE_OSX_DEPLOYMENT_TARGET 11.0)
     else()
         set(CMAKE_OSX_DEPLOYMENT_TARGET 10.15)
     endif()
🤖 Prompt for AI Agents
In `@CMakeLists.txt` around lines 40 - 57, The current check treats
CMAKE_OSX_ARCHITECTURES as a single string and compares _target_arch STREQUAL
"arm64", which fails for semicolon-separated multi-arch lists; change the logic
that determines the architecture to test membership (use list(FIND) on
CMAKE_OSX_ARCHITECTURES for "arm64") and base the CMAKE_OSX_DEPLOYMENT_TARGET on
that membership check (if "arm64" found -> set 11.0, else -> set 10.15), keeping
the existing fallback behavior that uses CMAKE_SYSTEM_PROCESSOR or
CMAKE_HOST_SYSTEM_PROCESSOR when CMAKE_OSX_ARCHITECTURES is not set.

unset(_target_arch)
endif()


include(pkg-utils)
Expand Down
Loading