236 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			CMake
		
	
	
	
	
	
			
		
		
	
	
			236 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			CMake
		
	
	
	
	
	
| # Mason CMake
 | |
| 
 | |
| include(CMakeParseArguments)
 | |
| 
 | |
| function(mason_detect_platform)
 | |
|     # Determine platform
 | |
|     if(NOT MASON_PLATFORM)
 | |
|         # we call uname -s manually here since
 | |
|         # CMAKE_HOST_SYSTEM_NAME will not be defined before the project() call
 | |
|         execute_process(
 | |
|             COMMAND uname -s
 | |
|             OUTPUT_VARIABLE UNAME
 | |
|             OUTPUT_STRIP_TRAILING_WHITESPACE)
 | |
| 
 | |
|         if (UNAME STREQUAL "Darwin")
 | |
|             set(MASON_PLATFORM "osx" PARENT_SCOPE)
 | |
|         else()
 | |
|             set(MASON_PLATFORM "linux" PARENT_SCOPE)
 | |
|         endif()
 | |
|     endif()
 | |
| 
 | |
|     # Determine platform version string
 | |
|     if(NOT MASON_PLATFORM_VERSION)
 | |
|         # Android Studio only passes ANDROID_ABI, but we need to adjust that to the Mason
 | |
|         if(MASON_PLATFORM STREQUAL "android" AND NOT MASON_PLATFORM_VERSION)
 | |
|             if (ANDROID_ABI STREQUAL "armeabi")
 | |
|                 set(MASON_PLATFORM_VERSION "arm-v5-9" PARENT_SCOPE)
 | |
|             elseif (ANDROID_ABI STREQUAL "armeabi-v7a")
 | |
|                 set(MASON_PLATFORM_VERSION "arm-v7-9" PARENT_SCOPE)
 | |
|             elseif (ANDROID_ABI STREQUAL "arm64-v8a")
 | |
|                 set(MASON_PLATFORM_VERSION "arm-v8-21" PARENT_SCOPE)
 | |
|             elseif (ANDROID_ABI STREQUAL "x86")
 | |
|                 set(MASON_PLATFORM_VERSION "x86-9" PARENT_SCOPE)
 | |
|             elseif (ANDROID_ABI STREQUAL "x86_64")
 | |
|                 set(MASON_PLATFORM_VERSION "x86-64-21" PARENT_SCOPE)
 | |
|             elseif (ANDROID_ABI STREQUAL "mips")
 | |
|                 set(MASON_PLATFORM_VERSION "mips-9" PARENT_SCOPE)
 | |
|             elseif (ANDROID_ABI STREQUAL "mips64")
 | |
|                 set(MASON_PLATFORM_VERSION "mips-64-9" PARENT_SCOPE)
 | |
|             else()
 | |
|                 message(FATAL_ERROR "Unknown ANDROID_ABI '${ANDROID_ABI}'.")
 | |
|             endif()
 | |
|         elseif(MASON_PLATFORM STREQUAL "ios")
 | |
|             set(MASON_PLATFORM_VERSION "8.0" PARENT_SCOPE)
 | |
|         else()
 | |
|             execute_process(
 | |
|                 COMMAND uname -m
 | |
|                 OUTPUT_VARIABLE MASON_PLATFORM_VERSION
 | |
|                 OUTPUT_STRIP_TRAILING_WHITESPACE)
 | |
|             set(MASON_PLATFORM_VERSION "${MASON_PLATFORM_VERSION}" PARENT_SCOPE)
 | |
|         endif()
 | |
|     endif()
 | |
| endfunction()
 | |
| 
 | |
| function(mason_use _PACKAGE)
 | |
|     if(NOT _PACKAGE)
 | |
|         message(FATAL_ERROR "[Mason] No package name given")
 | |
|     endif()
 | |
| 
 | |
|     cmake_parse_arguments("" "HEADER_ONLY" "VERSION" "" ${ARGN})
 | |
| 
 | |
|     if(_UNPARSED_ARGUMENTS)
 | |
|         message(FATAL_ERROR "[Mason] mason_use() called with unrecognized arguments: ${_UNPARSED_ARGUMENTS}")
 | |
|     endif()
 | |
| 
 | |
|     if(NOT _VERSION)
 | |
|         message(FATAL_ERROR "[Mason] Specifying a version is required")
 | |
|     endif()
 | |
| 
 | |
|     if(MASON_PACKAGE_${_PACKAGE}_INVOCATION STREQUAL "${MASON_INVOCATION}")
 | |
|         # Check that the previous invocation of mason_use didn't select another version of this package
 | |
|         if(NOT MASON_PACKAGE_${_PACKAGE}_VERSION STREQUAL ${_VERSION})
 | |
|             message(FATAL_ERROR "[Mason] Already using ${_PACKAGE} ${MASON_PACKAGE_${_PACKAGE}_VERSION}. Cannot select version ${_VERSION}.")
 | |
|         endif()
 | |
|     else()
 | |
|         if(_HEADER_ONLY)
 | |
|             set(_PLATFORM_ID "headers")
 | |
|         else()
 | |
|             set(_PLATFORM_ID "${MASON_PLATFORM}-${MASON_PLATFORM_VERSION}")
 | |
|         endif()
 | |
| 
 | |
|         set(_SLUG "${_PLATFORM_ID}/${_PACKAGE}/${_VERSION}")
 | |
|         set(_INSTALL_PATH "${MASON_PACKAGE_DIR}/${_SLUG}")
 | |
|         file(RELATIVE_PATH _INSTALL_PATH_RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${_INSTALL_PATH}")
 | |
| 
 | |
|         if(NOT EXISTS "${_INSTALL_PATH}")
 | |
|             set(_CACHE_PATH "${MASON_PACKAGE_DIR}/.binaries/${_SLUG}.tar.gz")
 | |
|             if (NOT EXISTS "${_CACHE_PATH}")
 | |
|                 # Download the package
 | |
|                 set(_URL "${MASON_REPOSITORY}/${_SLUG}.tar.gz")
 | |
|                 message("[Mason] Downloading package ${_URL}...")
 | |
| 
 | |
|                 set(_FAILED)
 | |
|                 set(_ERROR)
 | |
|                 # Note: some CMake versions are compiled without SSL support
 | |
|                 get_filename_component(_CACHE_DIR "${_CACHE_PATH}" DIRECTORY)
 | |
|                 file(MAKE_DIRECTORY "${_CACHE_DIR}")
 | |
|                 execute_process(
 | |
|                     COMMAND curl --retry 3 -s -f -S -L "${_URL}" -o "${_CACHE_PATH}.tmp"
 | |
|                     RESULT_VARIABLE _FAILED
 | |
|                     ERROR_VARIABLE _ERROR)
 | |
|                 if(_FAILED)
 | |
|                     message(FATAL_ERROR "[Mason] Failed to download ${_URL}: ${_ERROR}")
 | |
|                 else()
 | |
|                     # We downloaded to a temporary file to prevent half-finished downloads
 | |
|                     file(RENAME "${_CACHE_PATH}.tmp" "${_CACHE_PATH}")
 | |
|                 endif()
 | |
|             endif()
 | |
| 
 | |
|             # Unpack the package
 | |
|             message("[Mason] Unpacking package to ${_INSTALL_PATH_RELATIVE}...")
 | |
|             file(MAKE_DIRECTORY "${_INSTALL_PATH}")
 | |
|             execute_process(
 | |
|                 COMMAND ${CMAKE_COMMAND} -E tar xzf "${_CACHE_PATH}"
 | |
|                 WORKING_DIRECTORY "${_INSTALL_PATH}")
 | |
|         endif()
 | |
| 
 | |
|         # Error out if there is no config file.
 | |
|         if(NOT EXISTS "${_INSTALL_PATH}/mason.ini")
 | |
|             message(FATAL_ERROR "[Mason] Could not find mason.ini for package ${_PACKAGE} ${_VERSION}")
 | |
|         endif()
 | |
| 
 | |
|         set(MASON_PACKAGE_${_PACKAGE}_PREFIX "${_INSTALL_PATH}" CACHE STRING "${_PACKAGE} ${_INSTALL_PATH}" FORCE)
 | |
|         mark_as_advanced(MASON_PACKAGE_${_PACKAGE}_PREFIX)
 | |
| 
 | |
|         # Load the configuration from the ini file
 | |
|         file(STRINGS "${_INSTALL_PATH}/mason.ini" _CONFIG_FILE)
 | |
|         foreach(_LINE IN LISTS _CONFIG_FILE)
 | |
|             string(REGEX MATCH "^([a-z_]+) *= *" _KEY "${_LINE}")
 | |
|             if (_KEY)
 | |
|                 string(LENGTH "${_KEY}" _KEY_LENGTH)
 | |
|                 string(SUBSTRING "${_LINE}" ${_KEY_LENGTH} -1 _VALUE)
 | |
|                 string(REGEX REPLACE ";.*$" "" _VALUE "${_VALUE}") # Trim trailing commas
 | |
|                 string(REPLACE "{prefix}" "${_INSTALL_PATH}" _VALUE "${_VALUE}")
 | |
|                 string(STRIP "${_VALUE}" _VALUE)
 | |
|                 string(REPLACE "=" "" _KEY "${_KEY}")
 | |
|                 string(STRIP "${_KEY}" _KEY)
 | |
|                 string(TOUPPER "${_KEY}" _KEY)
 | |
|                 if(_KEY STREQUAL "INCLUDE_DIRS" OR _KEY STREQUAL "STATIC_LIBS" )
 | |
|                     separate_arguments(_VALUE)
 | |
|                 endif()
 | |
|                 set(MASON_PACKAGE_${_PACKAGE}_${_KEY} "${_VALUE}" CACHE STRING "${_PACKAGE} ${_KEY}" FORCE)
 | |
|                 mark_as_advanced(MASON_PACKAGE_${_PACKAGE}_${_KEY})
 | |
|             endif()
 | |
|         endforeach()
 | |
| 
 | |
|         # Compare version in the package to catch errors early on
 | |
|         if(NOT _VERSION STREQUAL MASON_PACKAGE_${_PACKAGE}_VERSION)
 | |
|             message(FATAL_ERROR "[Mason] Package at ${_INSTALL_PATH_RELATIVE} has version '${MASON_PACKAGE_${_PACKAGE}_VERSION}', but required '${_VERSION}'")
 | |
|         endif()
 | |
| 
 | |
|         if(NOT _PACKAGE STREQUAL MASON_PACKAGE_${_PACKAGE}_NAME)
 | |
|             message(FATAL_ERROR "[Mason] Package at ${_INSTALL_PATH_RELATIVE} has name '${MASON_PACKAGE_${_PACKAGE}_NAME}', but required '${_NAME}'")
 | |
|         endif()
 | |
| 
 | |
|         if(NOT _HEADER_ONLY)
 | |
|             if(NOT MASON_PLATFORM STREQUAL MASON_PACKAGE_${_PACKAGE}_PLATFORM)
 | |
|                 message(FATAL_ERROR "[Mason] Package at ${_INSTALL_PATH_RELATIVE} has platform '${MASON_PACKAGE_${_PACKAGE}_PLATFORM}', but required '${MASON_PLATFORM}'")
 | |
|             endif()
 | |
| 
 | |
|             if(NOT MASON_PLATFORM_VERSION STREQUAL MASON_PACKAGE_${_PACKAGE}_PLATFORM_VERSION)
 | |
|                 message(FATAL_ERROR "[Mason] Package at ${_INSTALL_PATH_RELATIVE} has platform version '${MASON_PACKAGE_${_PACKAGE}_PLATFORM_VERSION}', but required '${MASON_PLATFORM_VERSION}'")
 | |
|             endif()
 | |
|         endif()
 | |
| 
 | |
|         # Concatenate the static libs and libraries
 | |
|         set(_LIBRARIES)
 | |
|         list(APPEND _LIBRARIES ${MASON_PACKAGE_${_PACKAGE}_STATIC_LIBS} ${MASON_PACKAGE_${_PACKAGE}_LDFLAGS})
 | |
|         set(MASON_PACKAGE_${_PACKAGE}_LIBRARIES "${_LIBRARIES}" CACHE STRING "${_PACKAGE} _LIBRARIES" FORCE)
 | |
|         mark_as_advanced(MASON_PACKAGE_${_PACKAGE}_LIBRARIES)
 | |
| 
 | |
|         if(NOT _HEADER_ONLY)
 | |
|             string(REGEX MATCHALL "(^| +)-L *([^ ]+)" MASON_PACKAGE_${_PACKAGE}_LIBRARY_DIRS "${MASON_PACKAGE_${_PACKAGE}_LDFLAGS}")
 | |
|             string(REGEX REPLACE "(^| +)-L *" "\\1" MASON_PACKAGE_${_PACKAGE}_LIBRARY_DIRS "${MASON_PACKAGE_${_PACKAGE}_LIBRARY_DIRS}")
 | |
|             set(MASON_PACKAGE_${_PACKAGE}_LIBRARY_DIRS "${MASON_PACKAGE_${_PACKAGE}_LIBRARY_DIRS}" CACHE STRING "${_PACKAGE} ${MASON_PACKAGE_${_PACKAGE}_LIBRARY_DIRS}" FORCE)
 | |
|             mark_as_advanced(MASON_PACKAGE_${_PACKAGE}_LIBRARY_DIRS)
 | |
|         endif()
 | |
| 
 | |
|         # Store invocation ID to prevent different versions of the same package in one invocation
 | |
|         set(MASON_PACKAGE_${_PACKAGE}_INVOCATION "${MASON_INVOCATION}" CACHE INTERNAL "${_PACKAGE} invocation ID" FORCE)
 | |
|     endif()
 | |
| endfunction()
 | |
| 
 | |
| macro(target_add_mason_package _TARGET _VISIBILITY _PACKAGE)
 | |
|     if (NOT MASON_PACKAGE_${_PACKAGE}_INVOCATION)
 | |
|         message(FATAL_ERROR "[Mason] Package ${_PACKAGE} has not been initialized yet")
 | |
|     endif()
 | |
| 
 | |
|     target_include_directories(${_TARGET} ${_VISIBILITY} "${MASON_PACKAGE_${_PACKAGE}_INCLUDE_DIRS}")
 | |
|     target_compile_definitions(${_TARGET} ${_VISIBILITY} "${MASON_PACKAGE_${_PACKAGE}_DEFINITIONS}")
 | |
|     target_compile_options(${_TARGET} ${_VISIBILITY} "${MASON_PACKAGE_${_PACKAGE}_OPTIONS}")
 | |
|     target_link_libraries(${_TARGET} ${_VISIBILITY} "${MASON_PACKAGE_${_PACKAGE}_LIBRARIES}")
 | |
| endmacro()
 | |
| 
 | |
| # Setup
 | |
| 
 | |
| string(RANDOM LENGTH 16 MASON_INVOCATION)
 | |
| 
 | |
| # Read environment variables if CMake is run in command mode
 | |
| if (CMAKE_ARGC)
 | |
|     set(MASON_PLATFORM "$ENV{MASON_PLATFORM}")
 | |
|     set(MASON_PLATFORM_VERSION "$ENV{MASON_PLATFORM_VERSION}")
 | |
|     set(MASON_PACKAGE_DIR "$ENV{MASON_PACKAGE_DIR}")
 | |
|     set(MASON_REPOSITORY "$ENV{MASON_REPOSITORY}")
 | |
| endif()
 | |
| 
 | |
| # Directory where Mason packages are located; typically ends with mason_packages
 | |
| if (NOT MASON_PACKAGE_DIR)
 | |
|     set(MASON_PACKAGE_DIR "${CMAKE_SOURCE_DIR}/mason_packages")
 | |
| endif()
 | |
| 
 | |
| # URL prefix of where packages are located.
 | |
| if (NOT MASON_REPOSITORY)
 | |
|     set(MASON_REPOSITORY "https://mason-binaries.s3.amazonaws.com")
 | |
| endif()
 | |
| 
 | |
| mason_detect_platform()
 | |
| 
 | |
| # Execute commands if CMake is run in command mode
 | |
| if (CMAKE_ARGC)
 | |
|     # Collect remaining arguments for passing to mason_use
 | |
|     set(_MASON_ARGS)
 | |
|     foreach(I RANGE 4 ${CMAKE_ARGC})
 | |
|         list(APPEND _MASON_ARGS "${CMAKE_ARGV${I}}")
 | |
|     endforeach()
 | |
| 
 | |
|     # Install the package
 | |
|     mason_use(${_MASON_ARGS})
 | |
| 
 | |
|     # Optionally print variables
 | |
|     if(DEFINED MASON_PACKAGE_${CMAKE_ARGV4}_${CMAKE_ARGV3})
 | |
|         # CMake can't write to stdout with message()
 | |
|         execute_process(COMMAND ${CMAKE_COMMAND} -E echo "${MASON_PACKAGE_${CMAKE_ARGV4}_${CMAKE_ARGV3}}")
 | |
|     endif()
 | |
| endif()
 |