diff --git a/README.md b/README.md index 1d008fed..959e2ddc 100644 --- a/README.md +++ b/README.md @@ -124,6 +124,24 @@ conan_cmake_install(PATH_OR_REFERENCE . SETTINGS ${settings}) ``` +## conan_cmake_lock_create() + +This function is an additional wrapper for the [conan lock +create](https://docs.conan.io/en/latest/reference/commands/misc/lock.html#conan-lock-create) +sub-command of conan lock command to enable lockfile based workflows. You can pass all the arguments +that the command supports. Also, you can pass the auto-detected settings from +`conan_cmake_autodetect` in the `SETTINGS` argument. + +It can receive as arguments: `PATH`, `REFERENCE`, `UPDATE`, `BASE`, `REMOTE`, `LOCKFILE`, +`LOCKFILE_OUT`, `LOCKFILE_NODE_ID`, `INSTALL_FOLDER`, `GENERATOR`, `BUILD`, `ENV`, `ENV_HOST`, +`ENV_BUILD`, `OPTIONS`, `OPTIONS_HOST`, `OPTIONS_BUILD`, `PROFILE`, `PROFILE_HOST`, `PROFILE_BUILD`, +`SETTINGS`, `SETTINGS_HOST`, `SETTINGS_BUILD`. For more information, check [conan lock +create](https://docs.conan.io/en/latest/reference/commands/misc/lock.html#conan-lock-create) +documentation. + +It will also accept `OUTPUT_QUIET` and `ERROR_QUIET` arguments so that when it runs the `conan +install` command the output is quiet or the error is bypassed (or both). + ## Using conan_cmake_autodetect() and conan_cmake_install() with Multi Configuration generators The recommended approach when using Multi Configuration generators like Visual Studio or Xcode is diff --git a/conan.cmake b/conan.cmake index 774b2af9..5cba1d39 100644 --- a/conan.cmake +++ b/conan.cmake @@ -654,6 +654,109 @@ function(conan_cmake_install) endfunction() +function(conan_cmake_lock_create) + if(DEFINED CONAN_COMMAND) + set(CONAN_CMD ${CONAN_COMMAND}) + else() + conan_check(REQUIRED) + endif() + + set(lockCreateOptions UPDATE BASE OUTPUT_QUIET ERROR_QUIET) + set(lockCreateOneValueArgs PATH REFERENCE REMOTE LOCKFILE LOCKFILE_OUT) + set(lockCreateMultiValueArgs BUILD ENV ENV_HOST ENV_BUILD OPTIONS_HOST OPTIONS OPTIONS_BUILD PROFILE + PROFILE_HOST PROFILE_BUILD SETTINGS SETTINGS_HOST SETTINGS_BUILD) + cmake_parse_arguments(ARGS "${lockCreateOptions}" "${lockCreateOneValueArgs}" "${lockCreateMultiValueArgs}" ${ARGN}) + foreach(arg ${lockCreateOptions}) + if(ARGS_${arg}) + set(${arg} ${${arg}} ${ARGS_${arg}}) + endif() + endforeach() + foreach(arg ${lockCreateOneValueArgs}) + if(DEFINED ARGS_${arg}) + if("${arg}" STREQUAL "REMOTE") + set(flag "--remote") + elseif("${arg}" STREQUAL "LOCKFILE") + set(flag "--lockfile") + elseif("${arg}" STREQUAL "LOCKFILE_OUT") + set(flag "--lockfile-out") + endif() + set(${arg} ${${arg}} ${flag} ${ARGS_${arg}}) + endif() + endforeach() + foreach(arg ${lockCreateMultiValueArgs}) + if(DEFINED ARGS_${arg}) + if("${arg}" STREQUAL "BUILD") + set(flag "--build") + elseif("${arg}" STREQUAL "ENV") + set(flag "--env") + elseif("${arg}" STREQUAL "ENV_HOST") + set(flag "--env:host") + elseif("${arg}" STREQUAL "ENV_BUILD") + set(flag "--env:build") + elseif("${arg}" STREQUAL "OPTIONS") + set(flag "--options") + elseif("${arg}" STREQUAL "OPTIONS_HOST") + set(flag "--options:host") + elseif("${arg}" STREQUAL "OPTIONS_BUILD") + set(flag "--options:build") + elseif("${arg}" STREQUAL "PROFILE") + set(flag "--profile") + elseif("${arg}" STREQUAL "PROFILE_HOST") + set(flag "--profile:host") + elseif("${arg}" STREQUAL "PROFILE_BUILD") + set(flag "--profile:build") + elseif("${arg}" STREQUAL "SETTINGS") + set(flag "--settings") + elseif("${arg}" STREQUAL "SETTINGS_HOST") + set(flag "--settings:host") + elseif("${arg}" STREQUAL "SETTINGS_BUILD") + set(flag "--settings:build") + endif() + list(LENGTH ARGS_${arg} numargs) + foreach(item ${ARGS_${arg}}) + if(${item} STREQUAL "all" AND ${arg} STREQUAL "BUILD") + set(${arg} "--build") + break() + endif() + set(${arg} ${${arg}} ${flag} ${item}) + endforeach() + endif() + endforeach() + if(DEFINED UPDATE) + set(UPDATE --update) + endif() + if(DEFINED BASE) + set(BASE --base) + endif() + set(lock_create_Args lock create ${PATH} ${REFERENCE} ${UPDATE} ${BASE} ${REMOTE} ${LOCKFILE} ${LOCKFILE_OUT} ${LOCKFILE_NODE_ID} ${INSTALL_FOLDER} + ${GENERATOR} ${BUILD} ${ENV} ${ENV_HOST} ${ENV_BUILD} ${OPTIONS} ${OPTIONS_HOST} ${OPTIONS_BUILD} + ${PROFILE} ${PROFILE_HOST} ${PROFILE_BUILD} ${SETTINGS} ${SETTINGS_HOST} ${SETTINGS_BUILD}) + + string(REPLACE ";" " " _lock_create_Args "${lock_create_Args}") + message(STATUS "Conan executing: ${CONAN_CMD} ${_lock_create_Args}") + + if(ARGS_OUTPUT_QUIET) + set(OUTPUT_OPT OUTPUT_QUIET) + endif() + if(ARGS_ERROR_QUIET) + set(ERROR_OPT ERROR_QUIET) + endif() + + execute_process(COMMAND ${CONAN_CMD} ${lock_create_Args} + RESULT_VARIABLE return_code + ${OUTPUT_OPT} + ${ERROR_OPT} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + + if(NOT "${return_code}" STREQUAL "0") + if (ARGS_ERROR_QUIET) + message(WARNING "Conan lock create failed='${return_code}'") + else() + message(FATAL_ERROR "Conan lock create failed='${return_code}'") + endif() + endif() +endfunction() + function(conan_cmake_setup_conanfile) conan_parse_arguments(${ARGV}) if(ARGUMENTS_CONANFILE) diff --git a/tests.py b/tests.py index f0509ec2..11ad89aa 100644 --- a/tests.py +++ b/tests.py @@ -223,6 +223,33 @@ def test_conan_cmake_install_find_package(self): run("cmake .. {} -DCMAKE_BUILD_TYPE=Release".format(generator)) run("cmake --build . --config Release") + def test_conan_lock_create(self): + content = textwrap.dedent(""" + cmake_minimum_required(VERSION 3.5) + project(FormatOutput CXX) + list(APPEND CMAKE_MODULE_PATH ${CMAKE_BINARY_DIR}) + list(APPEND CMAKE_PREFIX_PATH ${CMAKE_BINARY_DIR}) + + add_definitions("-std=c++11") + include(conan.cmake) + conan_cmake_configure(REQUIRES fmt/6.1.2 GENERATORS cmake_find_package) + conan_cmake_autodetect(settings) + conan_cmake_lock_create(PATH conanfile.txt LOCKFILE_OUT mylockfile.lock SETTINGS ${settings}) + conan_cmake_install(PATH_OR_REFERENCE . + REMOTE conancenter + LOCKFILE mylockfile.lock + BUILD missing) + find_package(fmt) + add_executable(main main.cpp) + target_link_libraries(main fmt::fmt) + """) + save("CMakeLists.txt", content) + os.makedirs("build") + os.chdir("build") + run("cmake .. {} -DCMAKE_BUILD_TYPE=Release".format(generator)) + assert os.path.exists("mylockfile.lock") + run("cmake --build . --config Release") + def test_conan_cmake_autodetect_cxx_standard(self): content = textwrap.dedent(""" cmake_minimum_required(VERSION 3.5)