#
# Portability CMake support by Parra Studios
# Cross-platform and architecture detection utility.
#
# Copyright (C) 2016 - 2026 Vicente Eduardo Ferrer Garcia <vic798@gmail.com>
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
if(PORTABILITY_FOUND)
return()
endif()
set(PORTABILITY_FOUND YES)
#
# Check the OS type
#
# Check Linux
string(REGEX MATCH "Linux" PROJECT_OS_LINUX ${CMAKE_SYSTEM_NAME})
if(PROJECT_OS_LINUX)
set(PROJECT_OS_LINUX TRUE BOOL INTERNAL)
set(PROJECT_OS_NAME "Linux")
set(PROJECT_OS_FAMILY unix)
endif()
# Check BSD
string(REGEX MATCH "BSD" PROJECT_OS_BSD ${CMAKE_SYSTEM_NAME})
if(PROJECT_OS_BSD)
set(PROJECT_OS_BSD TRUE BOOL INTERNAL)
set(PROJECT_OS_NAME "BSD")
set(PROJECT_OS_FAMILY unix)
endif()
# Check Solaris
string(REGEX MATCH "SunOS" PROJECT_OS_SOLARIS ${CMAKE_SYSTEM_NAME})
if(PROJECT_OS_SOLARIS)
set(PROJECT_OS_SOLARIS TRUE BOOL INTERNAL)
set(PROJECT_OS_NAME "Solaris")
set(PROJECT_OS_FAMILY unix)
endif()
# Check HP-UX
string(REGEX MATCH "HP-UX" PROJECT_OS_HPUX ${CMAKE_SYSTEM_NAME})
if(PROJECT_OS_HPUX)
set(PROJECT_OS_HPUX TRUE BOOL INTERNAL)
set(PROJECT_OS_NAME "HP-UX")
set(PROJECT_OS_FAMILY hpux)
endif()
# Check Android
if(ANDROID)
set(PROJECT_OS_ANDROID TRUE BOOL INTERNAL)
set(PROJECT_OS_NAME "Android")
set(PROJECT_OS_FAMILY unix)
endif()
# Check Haiku
string(REGEX MATCH "Haiku" PROJECT_OS_HAIKU ${CMAKE_SYSTEM_NAME})
if(PROJECT_OS_HAIKU)
set(HAIKU 1)
set(PROJECT_OS_HAIKU TRUE BOOL INTERNAL)
set(PROJECT_OS_NAME "Haiku")
set(PROJECT_OS_FAMILY beos)
add_compile_definitions(__HAIKU__)
endif()
# Check Windows
if(WIN32)
set(PROJECT_OS_WIN TRUE BOOL INTERNAL)
set(PROJECT_OS_NAME "Windows")
set(PROJECT_OS_FAMILY win32)
endif()
# Check MinGW
if(MINGW)
set(PROJECT_OS_MINGW TRUE BOOL INTERNAL)
set(PROJECT_OS_NAME "MinGW")
set(PROJECT_OS_FAMILY win32)
endif()
# Check Apple OS
if(APPLE)
# Check if it's OS X or another MacOS
string(REGEX MATCH "Darwin" PROJECT_OS_OSX ${CMAKE_SYSTEM_NAME})
if(NOT PROJECT_OS_OSX)
set(PROJECT_OS_MACOS TRUE BOOL INTERNAL)
set(PROJECT_OS_NAME "Apple MacOS")
else()
set(PROJECT_OS_MACOSX TRUE BOOL INTERNAL)
set(PROJECT_OS_NAME "Apple MacOS X")
endif()
set(PROJECT_OS_FAMILY macos)
# Retrieve MacOs version from sv_vers
exec_program(sw_vers OUTPUT_VARIABLE SW_VERS_OUTPUT)
string(REPLACE "\n" ";" SW_VERS_OUTPUT "${SW_VERS_OUTPUT}")
string(REPLACE ":" ";" SW_VERS_OUTPUT "${SW_VERS_OUTPUT}")
list(GET SW_VERS_OUTPUT 3 PROJECT_OS_VERSION)
string(STRIP "${PROJECT_OS_VERSION}" PROJECT_OS_VERSION)
endif()
# Check QNX
if(QNXNTO)
set(PROJECT_OS_QNX TRUE BOOL INTERNAL)
set(PROJECT_OS_NAME "QNX")
set(PROJECT_OS_FAMILY qnx)
endif()
# Check UNIX
if(NOT PROJECT_OS_NAME AND UNIX)
set(PROJECT_OS_UNIX TRUE BOOL INTERNAL)
set(PROJECT_OS_NAME "UNIX")
set(PROJECT_OS_FAMILY unix)
endif()
message(STATUS "Target Operative System: ${PROJECT_OS_NAME}")
message(STATUS "Target OS Family: ${PROJECT_OS_FAMILY}")
#
# Check the Architecture type
#
set(PROJECT_ARCH_NAME ${CMAKE_SYSTEM_PROCESSOR})
# 32 or 64 bit Linux
if(PROJECT_OS_LINUX)
if (${PROJECT_ARCH_NAME} MATCHES "^(x86|i[3-6]86|x86_64)$" AND "${CMAKE_SIZEOF_VOID_P}" STREQUAL "4")
set(PROJECT_ARCH_32BIT TRUE BOOL INTERNAL)
set(PROJECT_ARCH_X86 TRUE BOOL INTERNAL)
elseif(${PROJECT_ARCH_NAME} MATCHES "(x86_64)|(amd64)|(AMD64)")
set(PROJECT_ARCH_64BIT TRUE BOOL INTERNAL)
set(PROJECT_ARCH_AMD64 TRUE BOOL INTERNAL)
elseif(${PROJECT_ARCH_NAME} STREQUAL "aarch64")
set(PROJECT_ARCH_64BIT TRUE BOOL INTERNAL)
set(PROJECT_ARCH_AARCH64 TRUE BOOL INTERNAL)
elseif(${PROJECT_ARCH_NAME} STREQUAL "ppc64")
set(PROJECT_ARCH_64BIT TRUE BOOL INTERNAL)
elseif(${PROJECT_ARCH_NAME} STREQUAL "s390x")
set(PROJECT_ARCH_64BIT TRUE BOOL INTERNAL)
endif()
# Verify the architecture is correct
if(PROJECT_ARCH_32BIT)
if("${CMAKE_SIZEOF_VOID_P}" EQUAL "4")
message(STATUS "Linux ${PROJECT_ARCH_NAME} 32bit detected")
else()
message(WARNING "Linux ${PROJECT_ARCH_NAME} 32bit does not mach size of a pointer: ${CMAKE_SIZEOF_VOID_P}")
endif()
elseif(PROJECT_ARCH_64BIT)
if("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
message(STATUS "Linux ${PROJECT_ARCH_NAME} 64bit detected")
else()
message(WARNING "Linux ${PROJECT_ARCH_NAME} 64bit does not mach size of a pointer: ${CMAKE_SIZEOF_VOID_P}")
endif()
else()
message(STATUS "Linux ${PROJECT_ARCH_NAME} detected")
endif()
endif()
# Detect architecture based on pointer size
if(NOT PROJECT_ARCH_32BIT AND NOT PROJECT_ARCH_64BIT)
if("${CMAKE_SIZEOF_VOID_P}" EQUAL "4")
message(STATUS "32bit architecture ${PROJECT_ARCH_NAME} detected")
set(PROJECT_ARCH_32BIT TRUE BOOL INTERNAL)
if(PROJECT_OS_WIN)
set(WINXBITS Win32)
endif()
elseif("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
message(STATUS "64bit architecture ${PROJECT_ARCH_NAME} detected")
set(PROJECT_ARCH_64BIT TRUE BOOL INTERNAL)
if(PROJECT_OS_WIN)
set(WINXBITS Win64)
endif()
else()
message(WARNING "Architecture detection error, invalid size of void pointer: ${CMAKE_SIZEOF_VOID_P}")
endif()
endif()
#
# Define the library path environment variable name
#
if(PROJECT_OS_FAMILY STREQUAL "unix")
set(PROJECT_LIBRARY_PATH_NAME "LD_LIBRARY_PATH")
elseif(PROJECT_OS_FAMILY STREQUAL "hpux")
set(PROJECT_LIBRARY_PATH_NAME "SHLIB_PATH")
elseif(PROJECT_OS_HAIKU)
set(PROJECT_LIBRARY_PATH_NAME "LIBRARY_PATH")
elseif(PROJECT_OS_WIN OR PROJECT_OS_MINGW)
set(PROJECT_LIBRARY_PATH_NAME "PATH")
elseif(PROJECT_OS_FAMILY STREQUAL "macos")
set(PROJECT_LIBRARY_PATH_NAME "DYLD_LIBRARY_PATH")
else()
message(FATAL_ERROR "Unsupported Platform for PROJECT_LIBRARY_PATH_NAME in Portability")
endif()
#
# Define a macro for getting the library path with previous contents from environment variable
#
macro(PROJECT_LIBRARY_PATH variable path)
set(LIBRARY_PATH_ENV_VAR "$ENV{${PROJECT_LIBRARY_PATH_NAME}}")
if("${LIBRARY_PATH_ENV_VAR}" STREQUAL "")
set(${variable} "${path}")
else()
if(PROJECT_OS_WIN OR PROJECT_OS_MINGW)
set(${variable} "${path};${LIBRARY_PATH_ENV_VAR}")
else()
set(${variable} "${path}:${LIBRARY_PATH_ENV_VAR}")
endif()
endif()
endmacro()