Skip to content

Commit

Permalink
Merge pull request #249 from FeignClaims/feature/conan2
Browse files Browse the repository at this point in the history
  • Loading branch information
aminya authored Feb 25, 2024
2 parents 9550c0e + eecc2d1 commit da5f308
Show file tree
Hide file tree
Showing 11 changed files with 233 additions and 43 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ jobs:
cmake: ${{ matrix.cmake }}
ninja: true
vcpkg: true
conan: true
conan: 2.1.0
cppcheck: true
clangtidy: true
task: true
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ CMake experience following the best practices.
FetchContent, vcpkg, etc.
- `run_vcpkg`: automatic installation of vcpkg and the project
dependencies
- `ENABLE_CONAN` in `project_options`: automatic installation of Conan
and the project dependencies
- `run_conan`: automatic installation of conan and the project
dependencies
- `dynamic_project_options`: a wrapper around `project_options` to
change the options on the fly dynamically
- `target_link_system_libraries` and
Expand Down Expand Up @@ -79,6 +79,8 @@ run_vcpkg(
VCPKG_URL "https://github.com/microsoft/vcpkg.git"
VCPKG_REV "10e052511428d6b0c7fcc63a139e8024bb146032"
)
# Install conan dependencies: - should be called before defining project()
run_conan()
# Set the project name and language
project(myproject LANGUAGES CXX C)
Expand Down Expand Up @@ -119,7 +121,6 @@ project_options(
${ENABLE_CPPCHECK}
${ENABLE_CLANG_TIDY}
ENABLE_VS_ANALYSIS
# ENABLE_CONAN
# ENABLE_INTERPROCEDURAL_OPTIMIZATION
# ENABLE_NATIVE_OPTIMIZATION
${ENABLE_DOXYGEN}
Expand All @@ -142,7 +143,6 @@ project_options(
# ENABLE_BUILD_WITH_TIME_TRACE
# ENABLE_UNITY
# LINKER "lld"
# CONAN_PROFILE ${profile_path}
)
```

Expand Down
2 changes: 1 addition & 1 deletion docs/src/Readme_top.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ A general-purpose CMake library that provides functions that improve the CMake e
- using custom linkers (e.g. lld)
- `package_project`: automatic packaging/installation of the project for seamless usage via find_package/target_link through CMake's FetchContent, vcpkg, etc.
- `run_vcpkg`: automatic installation of vcpkg and the project dependencies
- `ENABLE_CONAN` in `project_options`: automatic installation of Conan and the project dependencies
- `run_conan`: automatic installation of conan and the project dependencies
- `dynamic_project_options`: a wrapper around `project_options` to change the options on the fly dynamically
- `target_link_system_libraries` and `target_include_system_directories`: linking/including external dependencies/headers without warnings
- `target_link_cuda`: linking Cuda to a target
Expand Down
4 changes: 2 additions & 2 deletions docs/src/project_options_example.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ run_vcpkg(
VCPKG_REV "10e052511428d6b0c7fcc63a139e8024bb146032"
ENABLE_VCPKG_UPDATE
)
# Install conan dependencies: - should be called before defining project()
run_conan()
# Set the project name and language
project(myproject LANGUAGES CXX C)
Expand Down Expand Up @@ -73,7 +75,6 @@ project_options(
${ENABLE_CPPCHECK}
${ENABLE_CLANG_TIDY}
ENABLE_VS_ANALYSIS
# ENABLE_CONAN
# ENABLE_INTERPROCEDURAL_OPTIMIZATION
# ENABLE_NATIVE_OPTIMIZATION
${ENABLE_DOXYGEN}
Expand All @@ -96,7 +97,6 @@ project_options(
# ENABLE_BUILD_WITH_TIME_TRACE
# ENABLE_UNITY
# LINKER "lld"
# CONAN_PROFILE ${profile_path}
)
```

Expand Down
230 changes: 206 additions & 24 deletions src/Conan.cmake
Original file line number Diff line number Diff line change
@@ -1,7 +1,45 @@
include_guard()

# Run Conan for dependency management
macro(run_conan)
function(conan_get_version conan_current_version)
find_program(conan_command "conan" REQUIRED)
execute_process(
COMMAND ${conan_command} --version
OUTPUT_VARIABLE conan_output
RESULT_VARIABLE conan_result
OUTPUT_STRIP_TRAILING_WHITESPACE
)

if(conan_result)
message(FATAL_ERROR "Error when trying to run Conan")
endif()

string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+" conan_version ${conan_output})
set(${conan_current_version} ${conan_version} PARENT_SCOPE)
endfunction()

# Run Conan 1 for dependency management
macro(_run_conan1)
set(options
DEPRECATED_CALL # For backward compability
)
set(one_value_args
DEPRECATED_PROFILE # For backward compability
)
set(multi_value_args
HOST_PROFILE
BUILD_PROFILE
INSTALL_ARGS
DEPRECATED_OPTIONS # For backward compability
)
cmake_parse_arguments(_args "${options}" "${one_value_args}" "${multi_value_args}" ${ARGN})

conan_get_version(_conan_current_version)
if(_conan_current_version VERSION_GREATER_EQUAL "2.0.0")
message(FATAL_ERROR
"ENABLE_CONAN in `project_options(...)` only supports conan 1.\n"
" If you're using conan 2, disable ENABLE_CONAN and use `run_conan(...)` before `project(...)`.")
endif()

# Download automatically, you can also just copy the conan.cmake file
if(NOT EXISTS "${CMAKE_BINARY_DIR}/conan.cmake")
message(STATUS "Downloading conan.cmake from https://github.com/conan-io/cmake-conan")
Expand Down Expand Up @@ -61,35 +99,59 @@ macro(run_conan)
set(OUTPUT_QUIET)
endif()

set(_should_detect FALSE)
if(((NOT _args_DEPRECATED_CALL) AND ((NOT _args_HOST_PROFILE) OR ("auto-cmake" IN_LIST _args_HOST_PROFILE)))
OR ((_args_DEPRECATED_CALL) AND (NOT _args_DEPRECATED_PROFILE)))
set(_should_detect TRUE)
list(REMOVE_ITEM _args_HOST_PROFILE "auto-cmake")
endif()

if(NOT _args_DEPRECATED_PROFILE)
set(CONAN_DEFAULT_PROFILE "default")
else()
set(CONAN_DEFAULT_PROFILE ${_args_DEPRECATED_PROFILE})
endif()

if(NOT _args_HOST_PROFILE)
set(CONAN_HOST_PROFILE ${CONAN_DEFAULT_PROFILE})
else()
set(CONAN_HOST_PROFILE ${_args_HOST_PROFILE})
endif()

if(NOT _args_BUILD_PROFILE)
set(CONAN_BUILD_PROFILE ${CONAN_DEFAULT_PROFILE})
else()
set(CONAN_BUILD_PROFILE ${_args_BUILD_PROFILE})
endif()

foreach(_install_args IN LISTS _args_INSTALL_ARGS)
string(REGEX MATCH "--build=.*" _possible_build_arg "${_install_args}")

if(_possible_build_arg)
string(SUBSTRING "${_possible_build_arg}" 8 -1 CONAN_BUILD_ARG)
endif()
endforeach()
if(NOT CONAN_BUILD_ARG)
set(CONAN_BUILD_ARG "missing")
set(CONAN_INSTALL_ARGS "")
else()
list(REMOVE_ITEM _args_INSTALL_ARGS "--build=${CONAN_BUILD_ARG}")
set(CONAN_INSTALL_ARGS ${_args_INSTALL_ARGS})
endif()

foreach(TYPE ${LIST_OF_BUILD_TYPES})
message(STATUS "Running Conan for build type '${TYPE}'")

if("${ProjectOptions_CONAN_PROFILE}" STREQUAL "")
if(_should_detect)
# Detects current build settings to pass into conan
conan_cmake_autodetect(settings BUILD_TYPE ${TYPE})
set(CONAN_SETTINGS SETTINGS ${settings})
set(CONAN_ENV ENV "CC=${CMAKE_C_COMPILER}" "CXX=${CMAKE_CXX_COMPILER}")
else()
elseif(_args_DEPRECATED_CALL)
# Derive all conan settings from a conan profile
set(CONAN_SETTINGS PROFILE ${ProjectOptions_CONAN_PROFILE} SETTINGS "build_type=${TYPE}")
# CONAN_ENV should be redundant, since the profile can set CC & CXX
endif()
set(CONAN_SETTINGS PROFILE ${CONAN_DEFAULT_PROFILE} SETTINGS "build_type=${TYPE}")

if("${ProjectOptions_CONAN_PROFILE}" STREQUAL "")
set(CONAN_DEFAULT_PROFILE "default")
else()
set(CONAN_DEFAULT_PROFILE ${ProjectOptions_CONAN_PROFILE})
endif()
if("${ProjectOptions_CONAN_BUILD_PROFILE}" STREQUAL "")
set(CONAN_BUILD_PROFILE ${CONAN_DEFAULT_PROFILE})
else()
set(CONAN_BUILD_PROFILE ${ProjectOptions_CONAN_BUILD_PROFILE})
endif()

if("${ProjectOptions_CONAN_HOST_PROFILE}" STREQUAL "")
set(CONAN_HOST_PROFILE ${CONAN_DEFAULT_PROFILE})
else()
set(CONAN_HOST_PROFILE ${ProjectOptions_CONAN_HOST_PROFILE})
# CONAN_ENV should be redundant, since the profile can set CC & CXX
endif()

# PATH_OR_REFERENCE ${CMAKE_SOURCE_DIR} is used to tell conan to process
Expand All @@ -99,10 +161,10 @@ macro(run_conan)
PATH_OR_REFERENCE
${CMAKE_SOURCE_DIR}
BUILD
missing
${CONAN_BUILD_ARG}
# Pass compile-time configured options into conan
OPTIONS
${ProjectOptions_CONAN_OPTIONS}
${CONAN_INSTALL_ARGS}
# Pass CMake compilers to Conan
${CONAN_ENV}
PROFILE_HOST
Expand All @@ -117,3 +179,123 @@ macro(run_conan)
endif()

endmacro()

# Run Conan 2 for dependency management
macro(_run_conan2)
set(options)
set(one_value_args)
set(multi_value_args
HOST_PROFILE
BUILD_PROFILE
INSTALL_ARGS
)
cmake_parse_arguments(_args "${options}" "${one_value_args}" "${multi_value_args}" ${ARGN})

if(CMAKE_VERSION VERSION_LESS "3.24.0")
message(FATAL_ERROR
"`run_conan(...)` with conan 2 only supports cmake 3.24+, please update your cmake.\n"
" Or you can downgrade your conan to use conan 1.")
endif()

conan_get_version(_conan_current_version)
if(_conan_current_version VERSION_LESS "2.0.5")
message(FATAL_ERROR
"`run_conan(...)` with conan 2 only supports conan 2.0.5+, please update your conan.\n"
" Or You can downgrade your conan to use conan 1.")
endif()

# Download automatically, you can also just copy the conan.cmake file
if(NOT EXISTS "${CMAKE_BINARY_DIR}/conan_provider.cmake")
message(STATUS "Downloading conan_provider.cmake from https://github.com/conan-io/cmake-conan")
file(
DOWNLOAD "https://raw.githubusercontent.com/conan-io/cmake-conan/f6464d1e13ef7a47c569f5061f9607ea63339d39/conan_provider.cmake"
"${CMAKE_BINARY_DIR}/conan_provider.cmake"
EXPECTED_HASH SHA256=0a5eb4afbdd94faf06dcbf82d3244331605ef2176de32c09ea9376e768cbb0fc

# TLS_VERIFY ON # fails on some systems
)
endif()

if(NOT _args_HOST_PROFILE)
set(_args_HOST_PROFILE "default;auto-cmake")
endif()

if(NOT _args_BUILD_PROFILE)
set(_args_BUILD_PROFILE "default")
endif()

if(NOT _args_INSTALL_ARGS)
set(_args_INSTALL_ARGS "--build=missing")
endif()

set(CONAN_HOST_PROFILE "${_args_HOST_PROFILE}" CACHE STRING "Conan host profile" FORCE)
set(CONAN_BUILD_PROFILE "${_args_BUILD_PROFILE}" CACHE STRING "Conan build profile" FORCE)
set(CONAN_INSTALL_ARGS "${_args_INSTALL_ARGS}" CACHE STRING "Command line arguments for conan install" FORCE)

# A workaround from https://github.com/conan-io/cmake-conan/issues/595
list(APPEND CMAKE_PROJECT_TOP_LEVEL_INCLUDES "${CMAKE_BINARY_DIR}/conan_provider.cmake")

# Add this to invoke conan even when there's no find_package in CMakeLists.txt.
# This helps users get the third-party package names, which is used in later find_package.
cmake_language(DEFER DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" CALL find_package Git QUIET)
endmacro()

#[[.rst:

``run_conan``
=============

Install conan and conan dependencies:

.. code:: cmake

run_conan()

.. code:: cmake

run_conan(
HOST_PROFILE default auto-cmake
BUILD_PROFILE default
INSTALL_ARGS --build=missing
)

Note that it should be called before defining ``project()``.

Named String:

- Values are semicolon separated, e.g. ``"--build=never;--update;--lockfile-out=''"``.
However, you can make use of the cmake behaviour that automatically concatenates
multiple space separated string into a semicolon seperated list, e.g.
``--build=never --update --lockfile-out=''``.

- ``HOST_PROFILE``: (Defaults to ``"default;auto-cmake"``). This option
sets the host profile used by conan. When ``auto-cmake`` is specified,
cmake-conan will invoke conan's autodetection mechanism which tries to
guess the system defaults. If multiple profiles are specified, a
`compound profile <https://docs.conan.io/2.0/reference/commands/install.html#profiles-settings-options-conf>`_
will be used - compounded from left to right, where right has the highest priority.

- ``BUILD_PROFILE``: (Defaults to ``"default"``). This option
sets the build profile used by conan. If multiple profiles are specified,
a `compound profile <https://docs.conan.io/2.0/reference/commands/install.html#profiles-settings-options-conf>`_
will be used - compounded from left to right, where right has the highest priority.

- ``INSTALL_ARGS``: (Defaults to ``"--build=missing"``). This option
customizes ``conan install`` command invocation. Note that ``--build``
must be specified, otherwise conan will revert to its default behaviour.

- Two arguments are reserved to the dependency provider implementation
and must not be set: the path to a ``conanfile.txt|.py``, and the output
format (``--format``).

]]
macro(run_conan)
conan_get_version(_conan_current_version)

if(_conan_current_version VERSION_LESS "2.0.0")
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY PROJECT_OPTIONS_SHOULD_INVOKE_CONAN1 TRUE)
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY PROJECT_OPTIONS_CONAN1_ARGS ${ARGN})
else()
_run_conan2(${ARGN})
endif()
endmacro()
5 changes: 2 additions & 3 deletions src/DynamicProjectOptions.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -64,16 +64,15 @@ Here is an example of how to use ``dynamic_project_options``:

# install vcpkg dependencies: - should be called before defining project()
# run_vcpkg()
# install conan dependencies: - should be called before defining project()
# run_conan()

# Set the project name and language
project(myproject LANGUAGES CXX C)

# Set PCH to be on by default for all non-Developer Mode Builds
set(ENABLE_PCH_USER_DEFAULT ON)

# enable Conan
set(ENABLE_CONAN_DEFAULT ON)

# Initialize project_options variable related to this project
# This overwrites `project_options` and sets `project_warnings`
# This also accepts the same arguments as `project_options`.
Expand Down
Loading

0 comments on commit da5f308

Please sign in to comment.