Skip to content

Commit

Permalink
Support commands with executable targets
Browse files Browse the repository at this point in the history
Adds get_executable_path()
This CMake function checks if its argument is an executable target, and
if so returns the appropriate property as a value or generator
expression
This allows commands to be given executable targets in addtion to paths.

Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>
  • Loading branch information
sloretz committed Jul 29, 2021
1 parent 84e1cea commit 8534ffd
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 4 deletions.
1 change: 1 addition & 0 deletions ament_cmake_core/cmake/core/all.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ foreach(filename
"ament_package_xml"
"ament_register_extension"
"assert_file_exists"
"get_executable_path"
"list_append_unique"
"normalize_path"
"python"
Expand Down
81 changes: 81 additions & 0 deletions ament_cmake_core/cmake/core/get_executable_path.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# Copyright 2021 Open Source Robotics Foundation, Inc.
#
# 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.

#
# Get the path to an executable at build or configure time.
#
# The argument target_or_path may either be a path to an executable (such as
# PYTHON_EXECUTABLE), or an executable target (such as Python3::Interpreter).
# If the argument is an executable target then its location will be returned.
# otherwise the original argument will be returned unmodified.
#
# Use CONFIGURE when an executable is to be run at configure time, such as when
# using execute_process().
# The returned value will be the path to the process.
# Use BUILD when an executable is to be run at build or test time, such as
# when using add_custom_command() or add_test().
# The returned value will be either a path or a generator expression that
# evaluates to the path of an executable target.
#
# :param var: the output variable name
# :type var: string
# :param target_or_path: imported executable target or a path to an executable
# :param target_or_path: string
#
# @public
#
function(get_executable_path var target_or_path)
cmake_parse_arguments(ARG "BUILD;CONFIGURE" "" "" ${ARGN})
if(ARG_UNPARSED_ARGUMENTS)
message(FATAL_ERROR "get_executable() called with unused arguments: "
"${ARG_UNPARSED_ARGUMENTS}")
endif()
if(NOT ARG_BUILD AND NOT ARG_CONFIGURE)
message(FATAL_ERROR "get_executable_path() must have BUILD or CONFIGURE set"
"${ARG_UNPARSED_ARGUMENTS}")
endif()

# If it isn't a target, return whatever was given unmodified
set(output_var "${target_or_path}")

if(TARGET ${target_or_path})
# There is a target with this name
get_target_property(type "${target_or_path}" TYPE)
get_target_property(imported "${target_or_path}" IMPORTED)
if ("${type}" STREQUAL "EXECUTABLE")
# The target is an executable, grab its LOCATION property
if(ARG_BUILD)
if(imported)
# Return a generator expression to get the LOCATION property
set(output_var "$<TARGET_PROPERTY:${target_or_path},LOCATION>")
else()
# Return a generator expression to get the output location
set(output_var "$<TARGET_FILE:${target_or_path}>")
endif()
else()
if(imported)
# Return the content of the property directly
get_target_property(output_var "${target_or_path}" LOCATION)
else()
message(WARNING
"There exists a non-imported executable target named"
" '${target_or_path}', but those cannot be used at configure time."
" Assuming it's a path instead.")
endif()
endif()
endif()
endif()

set("${var}" "${output_var}" PARENT_SCOPE)
endfunction()
4 changes: 3 additions & 1 deletion ament_cmake_nose/cmake/ament_add_nose_test.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ function(_ament_add_nose_test testname path)
set(ARG_PYTHON_EXECUTABLE "${PYTHON_EXECUTABLE}")
endif()

get_executable_path(python_interpreter "${ARG_PYTHON_EXECUTABLE}" BUILD)

set(result_file "${AMENT_TEST_RESULTS_DIR}/${PROJECT_NAME}/${testname}.xunit.xml")
# Invoke ${NOSETESTS} explicitly with the ${PYTHON_EXECUTABLE} because on
# some systems, like OS X, the ${NOSETESTS} binary may have a #! which points
Expand All @@ -86,7 +88,7 @@ function(_ament_add_nose_test testname path)
# ${NOSETESTS} executable references.
# See: https://github.com/ament/ament_cmake/pull/70
set(cmd
"${ARG_PYTHON_EXECUTABLE}"
"${python_interpreter}"
"-u" # unbuffered stdout and stderr
"${NOSETESTS}" "${path}"
"--nocapture" # stdout will be printed immediately
Expand Down
4 changes: 3 additions & 1 deletion ament_cmake_pytest/cmake/ament_add_pytest_test.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ function(ament_add_pytest_test testname path)
set(ARG_PYTHON_EXECUTABLE "${PYTHON_EXECUTABLE}")
endif()

get_executable_path(python_interpreter "${ARG_PYTHON_EXECUTABLE}" BUILD)

# ensure pytest is available
ament_has_pytest(has_pytest QUIET PYTHON_EXECUTABLE "${ARG_PYTHON_EXECUTABLE}")
if(NOT has_pytest)
Expand All @@ -83,7 +85,7 @@ function(ament_add_pytest_test testname path)

set(result_file "${AMENT_TEST_RESULTS_DIR}/${PROJECT_NAME}/${testname}.xunit.xml")
set(cmd
"${ARG_PYTHON_EXECUTABLE}"
"${python_interpreter}"
"-u" # unbuffered stdout and stderr
"-m" "pytest"
"${path}"
Expand Down
4 changes: 3 additions & 1 deletion ament_cmake_pytest/cmake/ament_get_pytest_cov_version.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,10 @@ function(ament_get_pytest_cov_version var)
set(ARG_PYTHON_EXECUTABLE "${PYTHON_EXECUTABLE}")
endif()

get_executable_path(python_interpreter "${ARG_PYTHON_EXECUTABLE}" CONFIGURE)

# Newer versions of pytest require providing '--version' twice to include plugin versions
set(cmd "${ARG_PYTHON_EXECUTABLE}" "-m" "pytest" "--version" "--version")
set(cmd "${python_interpreter}" "-m" "pytest" "--version" "--version")
execute_process(
COMMAND ${cmd}
RESULT_VARIABLE res
Expand Down
4 changes: 3 additions & 1 deletion ament_cmake_pytest/cmake/ament_has_pytest.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ function(ament_has_pytest var)
set(ARG_PYTHON_EXECUTABLE "${PYTHON_EXECUTABLE}")
endif()

set(cmd "${ARG_PYTHON_EXECUTABLE}" "-m" "pytest" "--version")
get_executable_path(python_interpreter "${ARG_PYTHON_EXECUTABLE}" CONFIGURE)

set(cmd "${python_interpreter}" "-m" "pytest" "--version")
execute_process(
COMMAND ${cmd}
RESULT_VARIABLE res
Expand Down

0 comments on commit 8534ffd

Please sign in to comment.