From 9805ea599cb7ddf60fe25c37dfa2b16eb63feda8 Mon Sep 17 00:00:00 2001 From: Larry Meadows Date: Tue, 5 Nov 2024 21:45:54 -0800 Subject: [PATCH] Ability to select alternative compiler per file (#1086) [ROCm/rocprofiler-sdk commit: cc1498bb3b4b4071dac97d76f4c1a9eee7833168] --- projects/rocprofiler-sdk/.cmake-format.yaml | 9 ++ .../rocprofiler-sdk-custom-compilation.cmake | 90 +++++++++++++++ .../Templates/rocprofiler-sdk/config.cmake.in | 4 + .../cmake/rocprofiler_config_install.cmake | 10 ++ .../rocprofiler-sdk/source/CMakeLists.txt | 1 + .../source/sbin/CMakeLists.txt | 15 +++ .../sbin/rocprofiler-sdk-launch-compiler.sh | 106 ++++++++++++++++++ 7 files changed, 235 insertions(+) create mode 100644 projects/rocprofiler-sdk/cmake/Modules/rocprofiler-sdk-custom-compilation.cmake create mode 100644 projects/rocprofiler-sdk/source/sbin/CMakeLists.txt create mode 100755 projects/rocprofiler-sdk/source/sbin/rocprofiler-sdk-launch-compiler.sh diff --git a/projects/rocprofiler-sdk/.cmake-format.yaml b/projects/rocprofiler-sdk/.cmake-format.yaml index a4fd524309..4e40836786 100644 --- a/projects/rocprofiler-sdk/.cmake-format.yaml +++ b/projects/rocprofiler-sdk/.cmake-format.yaml @@ -253,6 +253,15 @@ parse: BINARY_DIR: '*' INSTALL_DIR: '*' COMPONENT: '*' + rocprofiler_sdk_custom_compilation: + flags: + - GLOBAL + - PROJECT + kwargs: + COMPILER: '*' + DIRECTORY: '*' + TARGET: '*' + SOURCE: '*' override_spec: {} vartags: [] proptags: [] diff --git a/projects/rocprofiler-sdk/cmake/Modules/rocprofiler-sdk-custom-compilation.cmake b/projects/rocprofiler-sdk/cmake/Modules/rocprofiler-sdk-custom-compilation.cmake new file mode 100644 index 0000000000..a403587241 --- /dev/null +++ b/projects/rocprofiler-sdk/cmake/Modules/rocprofiler-sdk-custom-compilation.cmake @@ -0,0 +1,90 @@ +# +# Custom compilation of source code +# + +include_guard(GLOBAL) + +# ----------------------------------------------------------------------------------------# +# this provides a function to easily select which files use alternative compiler: +# +# * GLOBAL --> all files +# * TARGET --> all files in a target +# * SOURCE --> specific source files +# * DIRECTORY --> all files in directory +# * PROJECT --> all files/targets in a project/subproject +# +function(rocprofiler_sdk_custom_compilation) + cmake_parse_arguments(COMP "GLOBAL;PROJECT" "COMPILER" "DIRECTORY;TARGET;SOURCE" + ${ARGN}) + + # find rocprofiler-sdk-launch-compiler + find_program( + ROCPROFILER_SDK_COMPILE_LAUNCHER + NAMES rocprofiler-sdk-launch-compiler + HINTS ${rocprofiler-sdk_ROOT_DIR} ${PROJECT_BINARY_DIR} ${CMAKE_BINARY_DIR} + PATHS ${rocprofiler-sdk_ROOT_DIR} ${PROJECT_BINARY_DIR} ${CMAKE_BINARY_DIR} + PATH_SUFFIXES sbin) + + if(NOT COMP_COMPILER) + message( + FATAL_ERROR + "rocprofiler_sdk_custom_compilation not provided COMPILER argument") + elseif(NOT EXISTS "${COMP_COMPILER}") + cmake_path(GET COMP_COMPILER FILENAME COMP_COMPILER_BASE) + find_program( + ROCPROFILER_SDK_COMPILER_${COMP_COMPILER_BASE} + NAMES ${COMP_COMPILER_BASE} + PATH_SUFFIXES bin REQUIRED) + set(COMP_COMPILER ROCPROFILER_SDK_COMPILER_${COMP_COMPILER_BASE}) + endif() + + if(NOT ROCPROFILER_SDK_COMPILE_LAUNCHER) + message( + FATAL_ERROR + "rocprofiler-sdk could not find 'rocprofiler-sdk-launch-compiler'. Please set '-DROCPROFILER_SDK_COMPILE_LAUNCHER=/path/to/launcher'" + ) + endif() + + if(COMP_GLOBAL) + # if global, don't bother setting others + set_property( + GLOBAL + PROPERTY + RULE_LAUNCH_COMPILE + "${ROCPROFILER_SDK_COMPILE_LAUNCHER} ${COMP_COMPILER} ${CMAKE_CXX_COMPILER}" + ) + set_property( + GLOBAL + PROPERTY + RULE_LAUNCH_LINK + "${ROCPROFILER_SDK_COMPILE_LAUNCHER} ${COMP_COMPILER} ${CMAKE_CXX_COMPILER}" + ) + else() + foreach(_TYPE PROJECT DIRECTORY TARGET SOURCE) + # make project/subproject scoping easy, e.g. + # rocprofiler_sdk_custom_compilation(PROJECT) after project(...) + if("${_TYPE}" STREQUAL "PROJECT" AND COMP_${_TYPE}) + list(APPEND COMP_DIRECTORY ${PROJECT_SOURCE_DIR}) + unset(COMP_${_TYPE}) + endif() + + # set the properties if defined + if(COMP_${_TYPE}) + foreach(_VAL ${COMP_${_TYPE}}) + set_property( + ${_TYPE} ${_VAL} + PROPERTY + RULE_LAUNCH_COMPILE + "${ROCPROFILER_SDK_COMPILE_LAUNCHER} ${COMP_COMPILER} ${CMAKE_CXX_COMPILER}" + ) + set_property( + ${_TYPE} ${_VAL} + PROPERTY + RULE_LAUNCH_LINK + "${ROCPROFILER_SDK_COMPILE_LAUNCHER} ${COMP_COMPILER} ${CMAKE_CXX_COMPILER}" + ) + endforeach() + endif() + endforeach() + endif() +endfunction() diff --git a/projects/rocprofiler-sdk/cmake/Templates/rocprofiler-sdk/config.cmake.in b/projects/rocprofiler-sdk/cmake/Templates/rocprofiler-sdk/config.cmake.in index c69e67741a..3b6703beda 100644 --- a/projects/rocprofiler-sdk/cmake/Templates/rocprofiler-sdk/config.cmake.in +++ b/projects/rocprofiler-sdk/cmake/Templates/rocprofiler-sdk/config.cmake.in @@ -146,3 +146,7 @@ find_package_handle_standard_args( REQUIRED_VARS @PACKAGE_NAME@_ROOT_DIR @PACKAGE_NAME@_INCLUDE_DIR @PACKAGE_NAME@_LIB_DIR @PACKAGE_NAME@_LIBRARIES @PACKAGE_NAME@_VERSION HANDLE_COMPONENTS HANDLE_VERSION_RANGE) + +if(EXISTS ${@PACKAGE_NAME@_CMAKE_DIR}/Modules) + list(APPEND CMAKE_MODULE_PATH ${@PACKAGE_NAME@_CMAKE_DIR}/Modules) +endif() diff --git a/projects/rocprofiler-sdk/cmake/rocprofiler_config_install.cmake b/projects/rocprofiler-sdk/cmake/rocprofiler_config_install.cmake index b776ee7b1c..46df9ad4fe 100644 --- a/projects/rocprofiler-sdk/cmake/rocprofiler_config_install.cmake +++ b/projects/rocprofiler-sdk/cmake/rocprofiler_config_install.cmake @@ -44,6 +44,11 @@ install( DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PACKAGE_NAME} COMPONENT development) +install( + FILES ${PROJECT_SOURCE_DIR}/cmake/Modules/rocprofiler-sdk-custom-compilation.cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PACKAGE_NAME}/Modules + COMPONENT development) + rocprofiler_install_env_setup_files( NAME ${PACKAGE_NAME} VERSION ${PROJECT_VERSION} @@ -88,6 +93,11 @@ configure_file( ${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}-sdk/${PROJECT_NAME}-sdk-config-nolink-target.cmake COPYONLY) +configure_file( + ${PROJECT_SOURCE_DIR}/cmake/Modules/rocprofiler-sdk-custom-compilation.cmake + ${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}/cmake/${PACKAGE_NAME}/Modules/rocprofiler-sdk-custom-compilation.cmake + COPYONLY) + install( FILES ${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR}/cmake/${PACKAGE_NAME}/${PACKAGE_NAME}-config.cmake diff --git a/projects/rocprofiler-sdk/source/CMakeLists.txt b/projects/rocprofiler-sdk/source/CMakeLists.txt index 4b945f28e7..f6abaab497 100644 --- a/projects/rocprofiler-sdk/source/CMakeLists.txt +++ b/projects/rocprofiler-sdk/source/CMakeLists.txt @@ -9,4 +9,5 @@ add_subdirectory(include) add_subdirectory(lib) add_subdirectory(libexec) add_subdirectory(bin) +add_subdirectory(sbin) add_subdirectory(docs) diff --git a/projects/rocprofiler-sdk/source/sbin/CMakeLists.txt b/projects/rocprofiler-sdk/source/sbin/CMakeLists.txt new file mode 100644 index 0000000000..1e214276d8 --- /dev/null +++ b/projects/rocprofiler-sdk/source/sbin/CMakeLists.txt @@ -0,0 +1,15 @@ +# +# +# + +configure_file( + rocprofiler-sdk-launch-compiler.sh + ${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_SBINDIR}/rocprofiler-sdk-launch-compiler + COPYONLY) + +install( + FILES ${PROJECT_BINARY_DIR}/${CMAKE_INSTALL_SBINDIR}/rocprofiler-sdk-launch-compiler + DESTINATION ${CMAKE_INSTALL_SBINDIR} + PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ + WORLD_EXECUTE + COMPONENT tools) diff --git a/projects/rocprofiler-sdk/source/sbin/rocprofiler-sdk-launch-compiler.sh b/projects/rocprofiler-sdk/source/sbin/rocprofiler-sdk-launch-compiler.sh new file mode 100755 index 0000000000..b8d5596991 --- /dev/null +++ b/projects/rocprofiler-sdk/source/sbin/rocprofiler-sdk-launch-compiler.sh @@ -0,0 +1,106 @@ +#!/bin/bash -e +# +# This script allows CMAKE_CXX_COMPILER to be a standard +# C++ compiler and rocprofiler-sdk sets RULE_LAUNCH_COMPILE and +# RULE_LAUNCH_LINK in CMake so that all compiler and link +# commands are prefixed with this script followed by the +# C++ compiler. Thus if $1 == $2 then we know the command +# was intended for the C++ compiler and we discard both +# $1 and $2 and redirect the command to linker. +# If $1 != $2 then we know that the command was not intended +# for the C++ compiler and we just discard $1 and launch +# the original command. Examples of when $2 will not equal +# $1 are 'ar', 'cmake', etc. during the linking phase +# + +# emit a message about the underlying command executed +: ${DEBUG:=0} +: ${ROCPROFILER_SDK_LAUNCH_COMPILER_DEBUG:=${DEBUG}} + +debug-message() +{ + if [ "${ROCPROFILER_SDK_LAUNCH_COMPILER_DEBUG}" -ne 0 ]; then + echo -e "##### $(basename ${BASH_SOURCE[0]}) executing: \"$@\"... #####" + fi +} + +# if rocprofiler-sdk compiler is not passed, someone is probably trying to invoke it directly +if [ -z "${1}" ]; then + echo -e "\n${BASH_SOURCE[0]} was invoked without the rocprofiler-sdk compiler as the first argument." + echo "This script is not indended to be directly invoked by any mechanism other" + echo -e "than through a RULE_LAUNCH_COMPILE or RULE_LAUNCH_LINK property set in CMake.\n" + exit 1 +fi + +# if rocprofiler-sdk compiler is not passed, someone is probably trying to invoke it directly +if [ -z "${2}" ]; then + echo -e "\n${BASH_SOURCE[0]} was invoked without the C++ compiler as the second argument." + echo "This script is not indended to be directly invoked by any mechanism other" + echo -e "than through a RULE_LAUNCH_COMPILE or RULE_LAUNCH_LINK property set in CMake.\n" + exit 1 +fi + +# if there aren't two args, this isn't necessarily invalid, just a bit strange +if [ -z "${3}" ]; then exit 0; fi + +# store the rocprofiler-sdk compiler +ROCPROFILER_SDK_COMPILER=${1} + +# remove the rocprofiler-sdk compiler from the arguments +shift + +# store the expected C++ compiler +CXX_COMPILER=${1} + +# remove the expected C++ compiler from the arguments +shift + +# discards the clang-tidy arguments +if [ "$(basename ${1})" = "cmake" ] && [ "${2}" = "-E" ] && [ "${3}" = "__run_co_compile" ]; then + c=1 + n=1 + for i in "${@}" + do + if [ "${i}" = "--" ]; then + break; + fi + if [ "${c}" -gt 3 ]; then + n=$((${n} + 1)) + fi + c=$((${c} + 1)) + done + + if [[ $# -gt ${c} ]]; then + n=$((${n} + 3)) # add three because of the first 3 args + for i in $(seq 1 1 ${n}) + do + shift + done + fi +fi + +if [[ "${CXX_COMPILER}" != "${1}" ]]; then + debug-message $@ + # the command does not depend on rocprofiler-sdk so just execute the command w/o re-directing to ${ROCPROFILER_SDK_COMPILER} + exec $@ +else + # the executable is the C++ compiler, so we need to re-direct to ${ROCPROFILER_SDK_COMPILER} + if [ ! -f "${ROCPROFILER_SDK_COMPILER}" ]; then + echo -e "\nError: the compiler redirect for rocprofiler-sdk was not found at ${ROCPROFILER_SDK_COMPILER}\n" + exit 1 + fi + + # discard the compiler from the command + shift + + if [ -n "$(basename ${ROCPROFILER_SDK_COMPILER} | egrep 'amdclang|amdllvm')" ]; then + # this ensures the libomptarget-amdgpu-gfx*.bc files are found + LLVM_LIB_DIR=$(cd $(dirname $(realpath ${ROCPROFILER_SDK_COMPILER}))/../lib && pwd) + debug-message export LIBRARY_PATH=${LLVM_LIB_DIR}:${LIBRARY_PATH} + export LIBRARY_PATH=${LLVM_LIB_DIR}:${LIBRARY_PATH} + fi + + debug-message ${ROCPROFILER_SDK_COMPILER} $@ + # execute ${ROCPROFILER_SDK_COMPILER} + exec ${ROCPROFILER_SDK_COMPILER} $@ +fi