Skip to content

Commit

Permalink
Add iOS, tvOS, and watchOS support (#528)
Browse files Browse the repository at this point in the history
* Add iOS, tvOS, and watchOS support

* Fix spelling error

* Shorten if statement and omit macOS

* Put Darwin back, otherwise, os.version isn't set for macOS

* Refactor OS_SDK setting

* Add warning about multiple architectures in CMAKE_OSX_ARCHITECTURES
  • Loading branch information
ssrobins authored Jul 27, 2023
1 parent 3c2e6fd commit 57a4cb7
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 8 deletions.
57 changes: 49 additions & 8 deletions conan_provider.cmake
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
set(CONAN_MINIMUM_VERSION 2.0.5)


function(detect_os OS OS_API_LEVEL OS_VERSION OS_SUBSYSTEM)
function(detect_os OS OS_API_LEVEL OS_SDK OS_SUBSYSTEM OS_VERSION)
# it could be cross compilation
message(STATUS "CMake-Conan: cmake_system_name=${CMAKE_SYSTEM_NAME}")
if(CMAKE_SYSTEM_NAME AND NOT CMAKE_SYSTEM_NAME STREQUAL "Generic")
if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin")
set(${OS} Macos PARENT_SCOPE)
message(STATUS "CMake-Conan: cmake_osx_deployment_target=${CMAKE_OSX_DEPLOYMENT_TARGET}")
set(${OS_VERSION} ${CMAKE_OSX_DEPLOYMENT_TARGET} PARENT_SCOPE)
elseif(${CMAKE_SYSTEM_NAME} STREQUAL "QNX")
set(${OS} Neutrino PARENT_SCOPE)
elseif(${CMAKE_SYSTEM_NAME} STREQUAL "CYGWIN")
Expand All @@ -25,18 +23,58 @@ function(detect_os OS OS_API_LEVEL OS_VERSION OS_SUBSYSTEM)
message(STATUS "CMake-Conan: android_platform=${ANDROID_PLATFORM}")
set(${OS_API_LEVEL} ${_OS_API_LEVEL} PARENT_SCOPE)
endif()
if(CMAKE_SYSTEM_NAME MATCHES "Darwin|iOS|tvOS|watchOS")
# CMAKE_OSX_SYSROOT contains the full path to the SDK for MakeFile/Ninja
# generators, but just has the original input string for Xcode.
if(NOT IS_DIRECTORY ${CMAKE_OSX_SYSROOT})
set(_OS_SDK ${CMAKE_OSX_SYSROOT})
else()
if(CMAKE_OSX_SYSROOT MATCHES Simulator)
set(apple_platform_suffix simulator)
else()
set(apple_platform_suffix os)
endif()
if(CMAKE_OSX_SYSROOT MATCHES AppleTV)
set(_OS_SDK "appletv${apple_platform_suffix}")
elseif(CMAKE_OSX_SYSROOT MATCHES iPhone)
set(_OS_SDK "iphone${apple_platform_suffix}")
elseif(CMAKE_OSX_SYSROOT MATCHES Watch)
set(_OS_SDK "watch${apple_platform_suffix}")
endif()
endif()
if(DEFINED _OS_SDK)
message(STATUS "CMake-Conan: cmake_osx_sysroot=${CMAKE_OSX_SYSROOT}")
set(${OS_SDK} ${_OS_SDK} PARENT_SCOPE)
endif()
if(DEFINED CMAKE_OSX_DEPLOYMENT_TARGET)
message(STATUS "CMake-Conan: cmake_osx_deployment_target=${CMAKE_OSX_DEPLOYMENT_TARGET}")
set(${OS_VERSION} ${CMAKE_OSX_DEPLOYMENT_TARGET} PARENT_SCOPE)
endif()
endif()
endif()
endfunction()


function(detect_arch ARCH)
if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|ARM64|arm64")
# CMAKE_OSX_ARCHITECTURES can contain multiple architectures, but Conan only supports one.
# Therefore this code only finds one. If the recipes support multiple architectures, the
# build will work. Otherwise, there will be a linker error for the missing architecture(s).
if(DEFINED CMAKE_OSX_ARCHITECTURES)
string(REPLACE " " ";" apple_arch_list "${CMAKE_OSX_ARCHITECTURES}")
list(LENGTH apple_arch_list apple_arch_count)
if(apple_arch_count GREATER 1)
message(WARNING "CMake-Conan: Multiple architectures detected, this will only work if Conan recipe(s) produce fat binaries.")
endif()
endif()
if(CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64|ARM64|arm64" OR CMAKE_OSX_ARCHITECTURES MATCHES arm64)
set(_ARCH armv8)
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "armv7-a|armv7l")
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "armv7-a|armv7l" OR CMAKE_OSX_ARCHITECTURES MATCHES armv7)
set(_ARCH armv7)
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "i686")
elseif(CMAKE_OSX_ARCHITECTURES MATCHES armv7s)
set(_ARCH armv7s)
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "i686" OR CMAKE_OSX_ARCHITECTURES MATCHES i386)
set(_ARCH x86)
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "AMD64|amd64|x86_64")
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "AMD64|amd64|x86_64" OR CMAKE_OSX_ARCHITECTURES MATCHES x86_64)
set(_ARCH x86_64)
endif()
message(STATUS "CMake-Conan: cmake_system_processor=${_ARCH}")
Expand Down Expand Up @@ -109,7 +147,7 @@ endfunction()


function(detect_host_profile output_file)
detect_os(MYOS MYOS_API_LEVEL MYOS_VERSION MYOS_SUBSYSTEM)
detect_os(MYOS MYOS_API_LEVEL MYOS_SDK MYOS_SUBSYSTEM MYOS_VERSION)
detect_arch(MYARCH)
detect_compiler(MYCOMPILER MYCOMPILER_VERSION)
detect_cxx_standard(MYCXX_STANDARD)
Expand All @@ -131,6 +169,9 @@ function(detect_host_profile output_file)
if(MYOS_VERSION)
string(APPEND PROFILE os.version=${MYOS_VERSION} "\n")
endif()
if(MYOS_SDK)
string(APPEND PROFILE os.sdk=${MYOS_SDK} "\n")
endif()
if(MYOS_SUBSYSTEM)
string(APPEND PROFILE os.subsystem=${MYOS_SUBSYSTEM} "\n")
endif()
Expand Down
73 changes: 73 additions & 0 deletions tests/test_smoke.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ def test_add_subdirectory(self, capfd, chdir_build):
out, _ = capfd.readouterr()
assert "subdir/0.1: Hello World Release!" in out


class TestOsVersion:
@darwin
def test_os_version(self, capfd, chdir_build):
Expand Down Expand Up @@ -259,3 +260,75 @@ def test_android_x86(self, capfd, chdir_build):
assert "os=Android" in out
assert "os.api_level=19" in out
assert "tools.android:ndk_path=" in out


class TestiOS:
@darwin
def test_ios(self, capfd, chdir_build):
run("cmake .. --fresh -DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=conan_provider.cmake -DCMAKE_BUILD_TYPE=Release "
"-DCMAKE_OSX_ARCHITECTURES=arm64 -DCMAKE_SYSTEM_NAME=iOS "
"-DCMAKE_OSX_SYSROOT=iphoneos -DCMAKE_OSX_DEPLOYMENT_TARGET=11.0")
out, _ = capfd.readouterr()
assert "arch=armv8" in out
assert "os=iOS" in out
assert "os.sdk=iphoneos" in out
assert "os.version=11.0" in out

@darwin
def test_ios_simulator(self, capfd, chdir_build):
run("cmake .. --fresh -DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=conan_provider.cmake -G Xcode "
"-DCMAKE_OSX_ARCHITECTURES=x86_64 -DCMAKE_SYSTEM_NAME=iOS "
"-DCMAKE_OSX_SYSROOT=iphonesimulator -DCMAKE_OSX_DEPLOYMENT_TARGET=11.0")
out, _ = capfd.readouterr()
assert "arch=x86_64" in out
assert "os=iOS" in out
assert "os.sdk=iphonesimulator" in out
assert "os.version=11.0" in out


class TestTvOS:
@darwin
def test_tvos(self, capfd, chdir_build):
run("cmake .. --fresh -DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=conan_provider.cmake -G Xcode "
"-DCMAKE_OSX_ARCHITECTURES=arm64 -DCMAKE_SYSTEM_NAME=tvOS "
"-DCMAKE_OSX_SYSROOT=appletvos -DCMAKE_OSX_DEPLOYMENT_TARGET=15.0")
out, _ = capfd.readouterr()
assert "arch=armv8" in out
assert "os=tvOS" in out
assert "os.sdk=appletvos" in out
assert "os.version=15.0" in out

@darwin
def test_tvos_simulator(self, capfd, chdir_build):
run("cmake .. --fresh -DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=conan_provider.cmake -DCMAKE_BUILD_TYPE=Release "
"-DCMAKE_OSX_ARCHITECTURES=arm64 -DCMAKE_SYSTEM_NAME=tvOS "
"-DCMAKE_OSX_SYSROOT=appletvsimulator -DCMAKE_OSX_DEPLOYMENT_TARGET=15.0")
out, _ = capfd.readouterr()
assert "arch=armv8" in out
assert "os=tvOS" in out
assert "os.sdk=appletvsimulator" in out
assert "os.version=15.0" in out


class TestWatchOS:
@darwin
def test_watchos(self, capfd, chdir_build):
run("cmake .. --fresh -DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=conan_provider.cmake -DCMAKE_BUILD_TYPE=Release -G Ninja "
"-DCMAKE_OSX_ARCHITECTURES=arm64 -DCMAKE_SYSTEM_NAME=watchOS "
"-DCMAKE_OSX_SYSROOT=watchos -DCMAKE_OSX_DEPLOYMENT_TARGET=7.0")
out, _ = capfd.readouterr()
assert "arch=armv8" in out
assert "os=watchOS" in out
assert "os.sdk=watchos" in out
assert "os.version=7.0" in out

@darwin
def test_watchos_simulator(self, capfd, chdir_build):
run("cmake .. --fresh -DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=conan_provider.cmake -G Xcode "
"-DCMAKE_OSX_ARCHITECTURES=x86_64 -DCMAKE_SYSTEM_NAME=watchOS "
"-DCMAKE_OSX_SYSROOT=watchsimulator -DCMAKE_OSX_DEPLOYMENT_TARGET=7.0")
out, _ = capfd.readouterr()
assert "arch=x86_64" in out
assert "os=watchOS" in out
assert "os.sdk=watchsimulator" in out
assert "os.version=7.0" in out

0 comments on commit 57a4cb7

Please sign in to comment.