Merge topic 'FindRuby-rvm'

905d5667e8 FindRuby: Add support for RVM installations
e6699b9b59 FindRuby: Validate Ruby_EXECUTABLE before accepting it

Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !4386
This commit is contained in:
Brad King 2020-03-25 12:16:26 +00:00 committed by Kitware Robot
commit 79415fa6d3
6 changed files with 290 additions and 7 deletions

View File

@ -22,6 +22,9 @@ standard syntax, e.g.
It also determines what the name of the library is.
Virtual environments such as RVM are handled as well, by passing
the argument ``Ruby_FIND_VIRTUALENV``
Result Variables
^^^^^^^^^^^^^^^^
@ -49,6 +52,28 @@ Also:
``Ruby_INCLUDE_PATH``
same as Ruby_INCLUDE_DIRS, only provided for compatibility reasons, don't use it
Hints
^^^^^
``Ruby_ROOT_DIR``
Define the root directory of a Ruby installation.
``Ruby_FIND_VIRTUALENV``
This variable defines the handling of virtual environments managed by
``rvm``. It is meaningful only when a virtual environment
is active (i.e. the ``rvm`` script has been evaluated or at least the
``MY_RUBY_HOME`` environment variable is set).
The ``Ruby_FIND_VIRTUALENV`` variable can be set to empty or
one of the following:
* ``FIRST``: The virtual environment is used before any other standard
paths to look-up for the interpreter. This is the default.
* ``ONLY``: Only the virtual environment is used to look-up for the
interpreter.
* ``STANDARD``: The virtual environment is not used to look-up for the
interpreter (assuming it isn't still in the PATH...)
#]=======================================================================]
# Backwards compatibility
@ -121,14 +146,115 @@ if(NOT Ruby_FIND_VERSION_EXACT)
list(REMOVE_DUPLICATES _Ruby_POSSIBLE_EXECUTABLE_NAMES)
endif()
if(_Ruby_DEBUG_OUTPUT)
message("_Ruby_POSSIBLE_EXECUTABLE_NAMES=${_Ruby_POSSIBLE_EXECUTABLE_NAMES}")
# virtual environments handling (eg RVM)
if (DEFINED ENV{MY_RUBY_HOME})
if(_Ruby_DEBUG_OUTPUT)
message("My ruby home is defined: $ENV{MY_RUBY_HOME}")
endif()
if (DEFINED Ruby_FIND_VIRTUALENV)
if (NOT Ruby_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY|STANDARD)$")
message (AUTHOR_WARNING "FindRuby: ${Ruby_FIND_VIRTUALENV}: invalid value for 'Ruby_FIND_VIRTUALENV'. 'FIRST', 'ONLY' or 'STANDARD' expected. 'FIRST' will be used instead.")
set (_Ruby_FIND_VIRTUALENV "FIRST")
else()
set (_Ruby_FIND_VIRTUALENV ${Ruby_FIND_VIRTUALENV})
endif()
else()
set (_Ruby_FIND_VIRTUALENV FIRST)
endif()
else()
if (DEFINED Ruby_FIND_VIRTUALENV)
message("Environment variable MY_RUBY_HOME isn't set, defaulting back to Ruby_FIND_VIRTUALENV=STANDARD")
endif()
set (_Ruby_FIND_VIRTUALENV STANDARD)
endif()
find_program (Ruby_EXECUTABLE
NAMES ${_Ruby_POSSIBLE_EXECUTABLE_NAMES}
NAMES_PER_DIR
)
if(_Ruby_DEBUG_OUTPUT)
message("_Ruby_POSSIBLE_EXECUTABLE_NAMES=${_Ruby_POSSIBLE_EXECUTABLE_NAMES}")
message("_Ruby_FIND_VIRTUALENV=${_Ruby_FIND_VIRTUALENV}")
endif()
function (_RUBY_VALIDATE_INTERPRETER)
if (NOT Ruby_EXECUTABLE)
return()
endif()
cmake_parse_arguments (PARSE_ARGV 0 _RVI "EXACT;CHECK_EXISTS" "" "")
if (_RVI_UNPARSED_ARGUMENTS)
set (expected_version ${_RVI_UNPARSED_ARGUMENTS})
else()
unset (expected_version)
endif()
if (_RVI_CHECK_EXISTS AND NOT EXISTS "${Ruby_EXECUTABLE}")
# interpreter does not exist anymore
set (_Ruby_Interpreter_REASON_FAILURE "Cannot find the interpreter \"${Ruby_EXECUTABLE}\"")
set_property (CACHE Ruby_EXECUTABLE PROPERTY VALUE "Ruby_EXECUTABLE-NOTFOUND")
return()
endif()
# Check the version it returns
# executable found must have a specific version
execute_process (COMMAND "${Ruby_EXECUTABLE}" -e "puts RUBY_VERSION"
RESULT_VARIABLE result
OUTPUT_VARIABLE version
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
if (result OR (_RVI_EXACT AND NOT version VERSION_EQUAL expected_version) OR (version VERSION_LESS expected_version))
# interpreter not usable or has wrong major version
if (result)
set (_Ruby_Interpreter_REASON_FAILURE "Cannot use the interpreter \"${Ruby_EXECUTABLE}\"")
else()
set (_Ruby_Interpreter_REASON_FAILURE "Wrong major version for the interpreter \"${Ruby_EXECUTABLE}\"")
endif()
set_property (CACHE Ruby_EXECUTABLE PROPERTY VALUE "Ruby_EXECUTABLE-NOTFOUND")
return()
endif()
endfunction()
while(1)
# Virtual environments handling
if(_Ruby_FIND_VIRTUALENV MATCHES "^(FIRST|ONLY)$")
if(_Ruby_DEBUG_OUTPUT)
message("Inside Matches")
endif()
find_program (Ruby_EXECUTABLE
NAMES ${_Ruby_POSSIBLE_EXECUTABLE_NAMES}
NAMES_PER_DIR
PATHS ENV MY_RUBY_HOME
PATH_SUFFIXES bin Scripts
NO_CMAKE_PATH
NO_CMAKE_ENVIRONMENT_PATH
NO_SYSTEM_ENVIRONMENT_PATH
NO_CMAKE_SYSTEM_PATH)
if(_Ruby_DEBUG_OUTPUT)
message("Ruby_EXECUTABLE=${Ruby_EXECUTABLE}")
endif()
_RUBY_VALIDATE_INTERPRETER (${Ruby_FIND_VERSION}})
if(Ruby_EXECUTABLE)
break()
endif()
if(NOT _Ruby_FIND_VIRTUALENV STREQUAL "ONLY")
break()
endif()
elseif(_Ruby_DEBUG_OUTPUT)
message("_Ruby_FIND_VIRTUALENV doesn't match: ${_Ruby_FIND_VIRTUALENV}")
endif()
# try using standard paths
find_program (Ruby_EXECUTABLE
NAMES ${_Ruby_POSSIBLE_EXECUTABLE_NAMES}
NAMES_PER_DIR)
_RUBY_VALIDATE_INTERPRETER (${Ruby_FIND_VERSION})
if (Ruby_EXECUTABLE)
break()
endif()
break()
endwhile()
if(Ruby_EXECUTABLE AND NOT Ruby_VERSION_MAJOR)
function(_RUBY_CONFIG_VAR RBVAR OUTVAR)
@ -266,6 +392,8 @@ if(Ruby_VERSION_MAJOR)
set(_Ruby_NODOT_VERSION "${Ruby_VERSION_MAJOR}${Ruby_VERSION_MINOR}${Ruby_VERSION_PATCH}")
endif()
# FIXME: Currently we require both the interpreter and development components to be found
# in order to use either. See issue #20474.
find_path(Ruby_INCLUDE_DIR
NAMES ruby.h
HINTS

View File

@ -24,7 +24,7 @@ if(CMake_TEST_FindRuby)
--test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
)
set_tests_properties(FindRuby.Fail PROPERTIES
PASS_REGULAR_EXPRESSION "Could NOT find Ruby: Found unsuitable version \".*\", but required is.*least \"[0-9]+\\.[0-9]+\\.[0-9]+\" \\(found .*\\)")
PASS_REGULAR_EXPRESSION "Could NOT find Ruby.*(Required is at least version \"[0-9]+\\.[0-9]+\\.[0-9]+\")")
# Looks for 1.9.9 EXACTLY, which unlike the "FindRuby" test above will fail on every machine
# since this version doesn't exist (ruby goes from 1.9.3 to 2.0.0)
@ -41,4 +41,17 @@ if(CMake_TEST_FindRuby)
set_tests_properties(FindRuby.FailExact PROPERTIES
PASS_REGULAR_EXPRESSION "Could NOT find Ruby: Found unsuitable version \".*\", but required is.*exact version \"[0-9]+\\.[0-9]+\\.[0-9]+\" \\(found .*\\)")
# RVM specific test
if(CMake_TEST_FindRuby_RVM)
add_test(NAME FindRuby.Rvm COMMAND
${CMAKE_CTEST_COMMAND} -C $<CONFIGURATION>
--build-and-test
"${CMake_SOURCE_DIR}/Tests/FindRuby/Rvm"
"${CMake_BINARY_DIR}/Tests/FindRuby/Rvm"
${build_generator_args}
--build-project TestRVM
--build-options ${build_options}
--test-command ${CMAKE_CTEST_COMMAND} -V -C $<CONFIGURATION>
)
endif()
endif()

View File

@ -0,0 +1,75 @@
cmake_minimum_required(VERSION 3.17)
project(TestRVM LANGUAGES NONE)
include(CTest)
# To run this test, you need to have at least one RVM ruby installed
# and to ensure that the env variable 'MY_RUBY_HOME' is set to a valid RVM ruby when you run the test
# (which is the case if you have done `rvm use x.y.z`, but could be manually set too)
# Properly using rvm would require sourcing a shell script, eg `source "$HOME/.rvm/scripts/rvm"`
# Instead, I'll just rely on the env variable MY_RUBY_HOME
set(MY_RUBY_HOME "$ENV{MY_RUBY_HOME}")
if(NOT MY_RUBY_HOME)
message(FATAL_ERROR "Env variable MY_RUBY_HOME should be set to a valid RVM ruby location, or you should call `rvm use x.y.z` before")
endif()
execute_process (COMMAND "${MY_RUBY_HOME}/bin/ruby" -e "puts RUBY_VERSION"
RESULT_VARIABLE result
OUTPUT_VARIABLE RVM_RUBY_VERSION
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
if (result)
message (FATAL_ERROR "Unable to detect RVM ruby version from `${MY_RUBY_HOME}/bin/ruby`: ${RVM_RUBY_VERSION}")
endif()
execute_process(COMMAND "${CMAKE_COMMAND}" -E env --unset=MY_RUBY_HOME --unset=PATH
"which" "ruby"
RESULT_VARIABLE result
OUTPUT_VARIABLE SYSTEM_RUBY
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
if (SYSTEM_RUBY MATCHES "^${MY_RUBY_HOME}/.+")
message(FATAL_ERROR "Unable to find system ruby, found ${SYSTEM_RUBY} which is part of MY_RUBY_HOME=${MY_RUBY_HOME}")
endif()
# Check version of the system ruby executable.
execute_process (COMMAND "${SYSTEM_RUBY}" -e "puts RUBY_VERSION"
RESULT_VARIABLE result
OUTPUT_VARIABLE SYSTEM_RUBY_VERSION
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
if (result)
message (FATAL_ERROR "Unable to detect system ruby version from '${SYSTEM_RUBY}': ${SYSTEM_RUBY_VERSION}")
endif()
if(SYSTEM_RUBY_VERSION VERSION_EQUAL RVM_RUBY_VERSION)
message(FATAL_ERROR "Your RVM Ruby Version and your System ruby version are the same (${RVM_RUBY_VERSION}).")
endif()
message("Found System Ruby (${SYSTEM_RUBY_VERSION}): ${SYSTEM_RUBY}")
message("Found RVM Ruby (${RVM_RUBY_VERSION}): ${MY_RUBY_HOME}/bin/ruby")
add_test(NAME FindRuby.RvmDefault
COMMAND "${CMAKE_COMMAND}" -E env "MY_RUBY_HOME=${MY_RUBY_HOME}"
"${CMAKE_COMMAND}" "-DRUBY_HOME=${MY_RUBY_HOME}"
-P "${CMAKE_CURRENT_LIST_DIR}/RvmDefault.cmake")
add_test(NAME FindRuby.RvmOnly
COMMAND "${CMAKE_COMMAND}" -E env --unset=PATH
"MY_RUBY_HOME=${MY_RUBY_HOME}"
"${CMAKE_COMMAND}" "-DRUBY_HOME=${MY_RUBY_HOME}"
"-DRVM_RUBY_VERSION=${RVM_RUBY_VERSION}" "-DSYSTEM_RUBY_VERSION=${SYSTEM_RUBY_VERSION}"
-P "${CMAKE_CURRENT_LIST_DIR}/RvmOnly.cmake")
add_test(NAME FindRuby.UnsetRvmOnly
COMMAND "${CMAKE_COMMAND}" -E env --unset=MY_RUBY_HOME "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin"
"${CMAKE_COMMAND}" "-DRVM_RUBY_VERSION=${RVM_RUBY_VERSION}" "-DSYSTEM_RUBY_VERSION=${SYSTEM_RUBY_VERSION}"
-P "${CMAKE_CURRENT_LIST_DIR}/RvmOnly.cmake")
add_test(NAME FindRuby.RvmStandard
COMMAND "${CMAKE_COMMAND}" -E env "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin"
"MY_RUBY_HOME=${MY_RUBY_HOME}"
"${CMAKE_COMMAND}" "-DRUBY_HOME=${MY_RUBY_HOME}"
-P "${CMAKE_CURRENT_LIST_DIR}/RvmStandard.cmake")

View File

@ -0,0 +1,17 @@
set(CMAKE_FIND_LIBRARY_PREFIXES "")
set(CMAKE_FIND_LIBRARY_SUFFIXES "")
find_package (Ruby 2.1.1 REQUIRED)
if (NOT RUBY_EXECUTABLE MATCHES "^${RUBY_HOME}/.+")
message (FATAL_ERROR "Failed to use RVM environment: ${RUBY_EXECUTABLE}, ${RUBY_HOME}")
endif()
find_package (Ruby 2.1 REQUIRED)
if (NOT RUBY_EXECUTABLE MATCHES "^${RUBY_HOME}/.+")
message (FATAL_ERROR "Failed to use RVM environment: ${RUBY_EXECUTABLE}, ${RUBY_HOME}")
endif()
find_package (Ruby REQUIRED)
if (NOT RUBY_EXECUTABLE MATCHES "^${RUBY_HOME}/.+")
message (FATAL_ERROR "Failed to use RVM environment: ${RUBY_EXECUTABLE}, ${RUBY_HOME}")
endif()

View File

@ -0,0 +1,41 @@
set(CMAKE_FIND_LIBRARY_PREFIXES "")
set(CMAKE_FIND_LIBRARY_SUFFIXES "")
set(Ruby_FIND_VIRTUALENV ONLY)
# Test: FindRuby.RvmOnly
if (RUBY_HOME)
# => Trying to find exactly system ruby using ONLY virtual environment should fail
find_package (Ruby ${SYSTEM_RUBY_VERSION} EXACT QUIET)
if(Ruby_FOUND)
message (FATAL_ERROR "Ruby unexpectedly found.")
endif()
# And should work to find the rvm version
find_package (Ruby ${RVM_RUBY_VERSION} EXACT QUIET)
if(Ruby_FOUND)
message (FATAL_ERROR "Ruby unexpectedly found.")
endif()
endif()
# Test: FindRuby.UnsetRvmOnly
if (NOT RUBY_HOME)
# If ENV{MY_RUBY_HOME} isn't defined, it should default back to "STANDARD"
# At which point:
# It shouldn't find the RVM ruby
find_package (Ruby ${RVM_RUBY_VERSION} EXACT QUIET)
if(Ruby_FOUND)
message(FATAL_ERROR "Found RVM ruby when expecting system")
endif()
# it should find the system ruby
find_package (Ruby ${SYSTEM_RUBY_VERSION} EXACT QUIET)
if(NOT Ruby_FOUND)
message (FATAL_ERROR "Ruby not found.")
endif()
if (Ruby_FOUND MATCHES "^${RUBY_HOME}/.+")
message(FATAL_ERROR "Failed to find system ruby")
endif()
endif()

View File

@ -0,0 +1,9 @@
set(CMAKE_FIND_LIBRARY_PREFIXES "")
set(CMAKE_FIND_LIBRARY_SUFFIXES "")
set (Ruby_FIND_VIRTUALENV STANDARD)
find_package (Ruby REQUIRED)
if (RUBY_EXECUTABLE MATCHES "^${RUBY_HOME}/.+")
message (FATAL_ERROR "RVM ruby unexpectedly found at ${RUBY_EXECUTABLE}, matches ${RUBY_HOME}")
endif()