From 905d5667e8b49a931078a1bcea26deffe703453b Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Mon, 23 Mar 2020 13:16:39 +0100 Subject: FindRuby: Add support for RVM installations --- Modules/FindRuby.cmake | 98 ++++++++++++++++++++++++++++++++++-- Tests/FindRuby/CMakeLists.txt | 13 +++++ Tests/FindRuby/Rvm/CMakeLists.txt | 75 +++++++++++++++++++++++++++ Tests/FindRuby/Rvm/RvmDefault.cmake | 17 +++++++ Tests/FindRuby/Rvm/RvmOnly.cmake | 41 +++++++++++++++ Tests/FindRuby/Rvm/RvmStandard.cmake | 9 ++++ 6 files changed, 248 insertions(+), 5 deletions(-) create mode 100644 Tests/FindRuby/Rvm/CMakeLists.txt create mode 100644 Tests/FindRuby/Rvm/RvmDefault.cmake create mode 100644 Tests/FindRuby/Rvm/RvmOnly.cmake create mode 100644 Tests/FindRuby/Rvm/RvmStandard.cmake diff --git a/Modules/FindRuby.cmake b/Modules/FindRuby.cmake index 699d2b6..1bdee60 100644 --- a/Modules/FindRuby.cmake +++ b/Modules/FindRuby.cmake @@ -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,8 +146,32 @@ if(NOT Ruby_FIND_VERSION_EXACT) list(REMOVE_DUPLICATES _Ruby_POSSIBLE_EXECUTABLE_NAMES) endif() +# 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() + 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) @@ -164,11 +213,48 @@ function (_RUBY_VALIDATE_INTERPRETER) endfunction() -find_program (Ruby_EXECUTABLE - NAMES ${_Ruby_POSSIBLE_EXECUTABLE_NAMES} - NAMES_PER_DIR - ) -_RUBY_VALIDATE_INTERPRETER (${Ruby_FIND_VERSION}) +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) @@ -306,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 diff --git a/Tests/FindRuby/CMakeLists.txt b/Tests/FindRuby/CMakeLists.txt index aaab839..3f4807c 100644 --- a/Tests/FindRuby/CMakeLists.txt +++ b/Tests/FindRuby/CMakeLists.txt @@ -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 $ + --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 $ + ) + endif() endif() diff --git a/Tests/FindRuby/Rvm/CMakeLists.txt b/Tests/FindRuby/Rvm/CMakeLists.txt new file mode 100644 index 0000000..545fc94 --- /dev/null +++ b/Tests/FindRuby/Rvm/CMakeLists.txt @@ -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") diff --git a/Tests/FindRuby/Rvm/RvmDefault.cmake b/Tests/FindRuby/Rvm/RvmDefault.cmake new file mode 100644 index 0000000..a66b911 --- /dev/null +++ b/Tests/FindRuby/Rvm/RvmDefault.cmake @@ -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() diff --git a/Tests/FindRuby/Rvm/RvmOnly.cmake b/Tests/FindRuby/Rvm/RvmOnly.cmake new file mode 100644 index 0000000..3851a7c --- /dev/null +++ b/Tests/FindRuby/Rvm/RvmOnly.cmake @@ -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() diff --git a/Tests/FindRuby/Rvm/RvmStandard.cmake b/Tests/FindRuby/Rvm/RvmStandard.cmake new file mode 100644 index 0000000..26befdb7 --- /dev/null +++ b/Tests/FindRuby/Rvm/RvmStandard.cmake @@ -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() -- cgit v0.12