From 4d82246ab5242b646fbd5f6f0f7f12637ec1d9db Mon Sep 17 00:00:00 2001 From: Cristian Adam Date: Fri, 17 Mar 2023 15:35:44 +0100 Subject: [PATCH] auto-setup: Add support for conan 2.0 Fixes: QTCREATORBUG-28865 Change-Id: Ifb801a458b4b18de218dee6604f0555cab13ec75 Reviewed-by: Alessandro Portale --- .../3rdparty/package-manager/auto-setup.cmake | 49 +++- .../package-manager/conan_support.cmake | 211 ++++++++++++++++++ tests/manual/conan/conanfile.txt | 4 +- 3 files changed, 250 insertions(+), 14 deletions(-) create mode 100644 src/share/3rdparty/package-manager/conan_support.cmake diff --git a/src/share/3rdparty/package-manager/auto-setup.cmake b/src/share/3rdparty/package-manager/auto-setup.cmake index ff57ac8d0eb..4689cc98049 100644 --- a/src/share/3rdparty/package-manager/auto-setup.cmake +++ b/src/share/3rdparty/package-manager/auto-setup.cmake @@ -46,6 +46,8 @@ macro(qtc_auto_setup_conan) message(FATAL_ERROR "conan --version failed='${result_code}: ${conan_version_output}") endif() + string(REGEX REPLACE ".*Conan version ([0-9].[0-9]).*" "\\1" conan_version "${conan_version_output}") + set(conanfile_timestamp_file "${CMAKE_BINARY_DIR}/conan-dependencies/conanfile.timestamp") file(TIMESTAMP "${conanfile_txt}" conanfile_timestamp) @@ -68,6 +70,9 @@ macro(qtc_auto_setup_conan) if (do_conan_installation) message(STATUS "Qt Creator: conan package manager auto-setup. " "Skip this step by setting QT_CREATOR_SKIP_CONAN_SETUP to ON.") + + file(COPY "${conanfile_txt}" DESTINATION "${CMAKE_BINARY_DIR}/conan-dependencies/") + file(WRITE "${CMAKE_BINARY_DIR}/conan-dependencies/toolchain.cmake" " set(CMAKE_C_COMPILER \"${CMAKE_C_COMPILER}\") set(CMAKE_CXX_COMPILER \"${CMAKE_CXX_COMPILER}\") @@ -77,17 +82,39 @@ macro(qtc_auto_setup_conan) "include(\"${CMAKE_TOOLCHAIN_FILE}\")\n") endif() - file(WRITE "${CMAKE_BINARY_DIR}/conan-dependencies/CMakeLists.txt" " - cmake_minimum_required(VERSION 3.15) - project(conan-setup) - include(\"${CMAKE_CURRENT_LIST_DIR}/conan.cmake\") - conan_cmake_run( - CONANFILE \"${conanfile_txt}\" - INSTALL_FOLDER \"${CMAKE_BINARY_DIR}/conan-dependencies\" - GENERATORS cmake_paths json - BUILD ${QT_CREATOR_CONAN_BUILD_POLICY} - ENV CONAN_CMAKE_TOOLCHAIN_FILE=\"${CMAKE_BINARY_DIR}/conan-dependencies/toolchain.cmake\" - )") + file(WRITE "${CMAKE_BINARY_DIR}/conan-dependencies/CMakeLists.txt" " + cmake_minimum_required(VERSION 3.15) + + unset(CMAKE_PROJECT_INCLUDE_BEFORE CACHE) + project(conan-setup) + + if (${conan_version} VERSION_GREATER_EQUAL 2.0) + include(\"${CMAKE_CURRENT_LIST_DIR}/conan_support.cmake\") + conan_profile_detect_default() + detect_host_profile(\"${CMAKE_BINARY_DIR}/conan-dependencies/conan_host_profile\") + + conan_install( + -pr \"${CMAKE_BINARY_DIR}/conan-dependencies/conan_host_profile\" + --build=${QT_CREATOR_CONAN_BUILD_POLICY} + -s build_type=${CMAKE_BUILD_TYPE} + -g CMakeDeps) + if (CONAN_INSTALL_SUCCESS) + file(WRITE \"${CMAKE_BINARY_DIR}/conan-dependencies/conan_paths.cmake\" \" + list(PREPEND CMAKE_PREFIX_PATH \\\"\${CONAN_GENERATORS_FOLDER}\\\") + list(PREPEND CMAKE_MODULE_PATH \\\"\${CONAN_GENERATORS_FOLDER}\\\") + \") + endif() + else() + include(\"${CMAKE_CURRENT_LIST_DIR}/conan.cmake\") + conan_cmake_run( + CONANFILE \"${conanfile_txt}\" + INSTALL_FOLDER \"${CMAKE_BINARY_DIR}/conan-dependencies\" + GENERATORS cmake_paths cmake_find_package json + BUILD ${QT_CREATOR_CONAN_BUILD_POLICY} + ENV CONAN_CMAKE_TOOLCHAIN_FILE=\"${CMAKE_BINARY_DIR}/conan-dependencies/toolchain.cmake\" + ) + endif() + ") execute_process(COMMAND ${CMAKE_COMMAND} -S "${CMAKE_BINARY_DIR}/conan-dependencies/" diff --git a/src/share/3rdparty/package-manager/conan_support.cmake b/src/share/3rdparty/package-manager/conan_support.cmake new file mode 100644 index 00000000000..f1dbccf2aaf --- /dev/null +++ b/src/share/3rdparty/package-manager/conan_support.cmake @@ -0,0 +1,211 @@ +# https://github.com/conan-io/cmake-conan/blob/develop2/conan_support.cmake +# commit: 3e088cd3e1d9d69e04b5250d565c1b8b55b0400b +# +# The MIT License (MIT) +# +# Copyright (c) 2019 JFrog +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +function(detect_os OS) + # it could be cross compilation + message(STATUS "Conan-cmake: cmake_system_name=${CMAKE_SYSTEM_NAME}") + if(CMAKE_SYSTEM_NAME AND NOT CMAKE_SYSTEM_NAME STREQUAL "Generic") + if(${CMAKE_SYSTEM_NAME} STREQUAL "Darwin") + set(${OS} Macos PARENT_SCOPE) + elseif(${CMAKE_SYSTEM_NAME} STREQUAL "QNX") + set(${OS} Neutrino PARENT_SCOPE) + else() + set(${OS} ${CMAKE_SYSTEM_NAME} PARENT_SCOPE) + endif() + endif() +endfunction() + + +function(detect_cxx_standard CXX_STANDARD) + set(${CXX_STANDARD} ${CMAKE_CXX_STANDARD} PARENT_SCOPE) + if (CMAKE_CXX_EXTENSIONS) + set(${CXX_STANDARD} "gnu${CMAKE_CXX_STANDARD}" PARENT_SCOPE) + endif() +endfunction() + + +function(detect_compiler COMPILER COMPILER_VERSION) + if(DEFINED CMAKE_CXX_COMPILER_ID) + set(_COMPILER ${CMAKE_CXX_COMPILER_ID}) + set(_COMPILER_VERSION ${CMAKE_CXX_COMPILER_VERSION}) + else() + if(NOT DEFINED CMAKE_C_COMPILER_ID) + message(FATAL_ERROR "C or C++ compiler not defined") + endif() + set(_COMPILER ${CMAKE_C_COMPILER_ID}) + set(_COMPILER_VERSION ${CMAKE_C_COMPILER_VERSION}) + endif() + + message(STATUS "Conan-cmake: CMake compiler=${_COMPILER}") + message(STATUS "Conan-cmake: CMake cmpiler version=${_COMPILER_VERSION}") + + if(_COMPILER MATCHES MSVC) + set(_COMPILER "msvc") + string(SUBSTRING ${MSVC_VERSION} 0 3 _COMPILER_VERSION) + elseif(_COMPILER MATCHES AppleClang) + set(_COMPILER "apple-clang") + string(REPLACE "." ";" VERSION_LIST ${CMAKE_CXX_COMPILER_VERSION}) + list(GET VERSION_LIST 0 _COMPILER_VERSION) + elseif(_COMPILER MATCHES Clang) + set(_COMPILER "clang") + string(REPLACE "." ";" VERSION_LIST ${CMAKE_CXX_COMPILER_VERSION}) + list(GET VERSION_LIST 0 _COMPILER_VERSION) + elseif(_COMPILER MATCHES GNU) + set(_COMPILER "gcc") + string(REPLACE "." ";" VERSION_LIST ${CMAKE_CXX_COMPILER_VERSION}) + list(GET VERSION_LIST 0 _COMPILER_VERSION) + endif() + + message(STATUS "Conan-cmake: [settings] compiler=${_COMPILER}") + message(STATUS "Conan-cmake: [settings] compiler.version=${_COMPILER_VERSION}") + + set(${COMPILER} ${_COMPILER} PARENT_SCOPE) + set(${COMPILER_VERSION} ${_COMPILER_VERSION} PARENT_SCOPE) +endfunction() + +function(detect_build_type BUILD_TYPE) + if(NOT CMAKE_CONFIGURATION_TYPES) + # Only set when we know we are in a single-configuration generator + # Note: we may want to fail early if `CMAKE_BUILD_TYPE` is not defined + set(${BUILD_TYPE} ${CMAKE_BUILD_TYPE} PARENT_SCOPE) + endif() +endfunction() + + +function(detect_host_profile output_file) + detect_os(MYOS) + detect_compiler(MYCOMPILER MYCOMPILER_VERSION) + detect_cxx_standard(MYCXX_STANDARD) + detect_build_type(MYBUILD_TYPE) + + set(PROFILE "") + string(APPEND PROFILE "include(default)\n") + string(APPEND PROFILE "[settings]\n") + if(MYOS) + string(APPEND PROFILE os=${MYOS} "\n") + endif() + if(MYCOMPILER) + string(APPEND PROFILE compiler=${MYCOMPILER} "\n") + endif() + if(MYCOMPILER_VERSION) + string(APPEND PROFILE compiler.version=${MYCOMPILER_VERSION} "\n") + endif() + if(MYCXX_STANDARD) + string(APPEND PROFILE compiler.cppstd=${MYCXX_STANDARD} "\n") + endif() + if(MYBUILD_TYPE) + string(APPEND PROFILE "build_type=${MYBUILD_TYPE}\n") + endif() + + if(NOT DEFINED output_file) + set(_FN "${CMAKE_BINARY_DIR}/profile") + else() + set(_FN ${output_file}) + endif() + + string(APPEND PROFILE "[conf]\n") + string(APPEND PROFILE "tools.cmake.cmaketoolchain:generator=${CMAKE_GENERATOR}\n") + + message(STATUS "Conan-cmake: Creating profile ${_FN}") + file(WRITE ${_FN} ${PROFILE}) + message(STATUS "Conan-cmake: Profile: \n${PROFILE}") +endfunction() + + +function(conan_profile_detect_default) + message(STATUS "Conan-cmake: Checking if a default profile exists") + execute_process(COMMAND conan profile path default + RESULT_VARIABLE return_code + OUTPUT_VARIABLE conan_stdout + ERROR_VARIABLE conan_stderr + ECHO_ERROR_VARIABLE # show the text output regardless + ECHO_OUTPUT_VARIABLE + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + if(NOT ${return_code} EQUAL "0") + message(STATUS "Conan-cmake: The default profile doesn't exist, detecting it.") + execute_process(COMMAND conan profile detect + RESULT_VARIABLE return_code + OUTPUT_VARIABLE conan_stdout + ERROR_VARIABLE conan_stderr + ECHO_ERROR_VARIABLE # show the text output regardless + ECHO_OUTPUT_VARIABLE + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + endif() +endfunction() + + +function(conan_install) + cmake_parse_arguments(ARGS CONAN_ARGS ${ARGN}) + set(CONAN_OUTPUT_FOLDER ${CMAKE_BINARY_DIR}/conan) + # Invoke "conan install" with the provided arguments + set(CONAN_ARGS ${CONAN_ARGS} -of=${CONAN_OUTPUT_FOLDER}) + message(STATUS "CMake-conan: conan install ${CMAKE_SOURCE_DIR} ${CONAN_ARGS} ${ARGN}") + execute_process(COMMAND conan install ${CMAKE_SOURCE_DIR} ${CONAN_ARGS} ${ARGN} --format=json + RESULT_VARIABLE return_code + OUTPUT_VARIABLE conan_stdout + ERROR_VARIABLE conan_stderr + ECHO_ERROR_VARIABLE # show the text output regardless + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + if(NOT "${return_code}" STREQUAL "0") + message(FATAL_ERROR "Conan install failed='${return_code}'") + else() + # the files are generated in a folder that depends on the layout used, if + # one if specified, but we don't know a priori where this is. + # TODO: this can be made more robust if Conan can provide this in the json output + string(JSON CONAN_GENERATORS_FOLDER GET ${conan_stdout} graph nodes 0 generators_folder) + # message("conan stdout: ${conan_stdout}") + message(STATUS "CMake-conan: CONAN_GENERATORS_FOLDER=${CONAN_GENERATORS_FOLDER}") + set(CONAN_GENERATORS_FOLDER "${CONAN_GENERATORS_FOLDER}" PARENT_SCOPE) + set(CONAN_INSTALL_SUCCESS TRUE CACHE BOOL "Conan install has been invoked and was successful") + endif() +endfunction() + + +function(conan_provide_dependency package_name) + if(NOT CONAN_INSTALL_SUCCESS) + message(STATUS "CMake-conan: first find_package() found. Installing dependencies with Conan") + conan_profile_detect_default() + detect_host_profile(${CMAKE_BINARY_DIR}/conan_host_profile) + if(NOT CMAKE_CONFIGURATION_TYPES) + message(STATUS "CMake-conan: Installing single configuration ${CMAKE_BUILD_TYPE}") + conan_install(-pr ${CMAKE_BINARY_DIR}/conan_host_profile --build=missing -g CMakeDeps) + else() + message(STATUS "CMake-conan: Installing both Debug and Release") + conan_install(-pr ${CMAKE_BINARY_DIR}/conan_host_profile -s build_type=Release --build=missing -g CMakeDeps) + conan_install(-pr ${CMAKE_BINARY_DIR}/conan_host_profile -s build_type=Debug --build=missing -g CMakeDeps) + endif() + if (CONAN_INSTALL_SUCCESS) + set(CONAN_GENERATORS_FOLDER "${CONAN_GENERATORS_FOLDER}" CACHE PATH "Conan generators folder") + endif() + else() + message(STATUS "CMake-conan: find_package(${package_name}) found, 'conan install' aready ran") + endif() + + if (CONAN_GENERATORS_FOLDER) + list(PREPEND CMAKE_PREFIX_PATH "${CONAN_GENERATORS_FOLDER}") + endif() + + find_package(${ARGN} BYPASS_PROVIDER) +endfunction() diff --git a/tests/manual/conan/conanfile.txt b/tests/manual/conan/conanfile.txt index bd1e4f8722d..fa99ef469bb 100644 --- a/tests/manual/conan/conanfile.txt +++ b/tests/manual/conan/conanfile.txt @@ -1,4 +1,2 @@ [requires] -fmt/8.0.0 -[generators] -cmake_find_package +fmt/9.1.0