From 4c22b73ebdff052b04b4ab6ab9b830378aa521e1 Mon Sep 17 00:00:00 2001 From: Lars Melchior Date: Thu, 11 Apr 2019 10:13:28 +0200 Subject: [PATCH] Use FetchContent (#9) * remove CPM_RESET in favor of CPM_OFFLINE * Use FetchContent * update travis * update travis * update travis * update travis * update travis --- .travis.yml | 5 + README.md | 14 +- cmake/CPM.cmake | 93 +++++------ cmake/CPMProject.CMakeLists.cmake.in | 27 ---- cmake/DownloadProject.CMakeLists.cmake.in | 17 -- cmake/DownloadProject.cmake | 182 ---------------------- tests/complex/CMakeLists.txt | 15 +- 7 files changed, 65 insertions(+), 288 deletions(-) delete mode 100644 cmake/CPMProject.CMakeLists.cmake.in delete mode 100755 cmake/DownloadProject.CMakeLists.cmake.in delete mode 100755 cmake/DownloadProject.cmake diff --git a/.travis.yml b/.travis.yml index f48959f..d42f786 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,6 +34,11 @@ before_install: # Update compilers - eval "${MATRIX_EVAL}" - echo "CC=$CC CXX=$CXX" + # Install a supported cmake version (>= 3.14) + - wget -O cmake.sh https://cmake.org/files/v3.14/cmake-3.14.0-Linux-x86_64.sh + - sudo sh cmake.sh --skip-license --exclude-subdir --prefix=/usr/local + - export PATH=/usr/local/bin:$PATH + - cmake --version script: - cmake -Htests/simple -Bbuild/simple diff --git a/README.md b/README.md index 21dbc48..44c565f 100644 --- a/README.md +++ b/README.md @@ -2,14 +2,14 @@ # CPM -CPM is a minimalistic package manager written in Cmake based on the amazing [DownloadProject](https://github.com/Crascit/DownloadProject) script. It is extremely easy to use and drastically simplifies the inclusion of other Cmake-based projects from github. +CPM is a minimalistic package manager written in Cmake using `find_package` and `FetchContent` as a fallback to download non locally installed packages. # Usage To add a new dependency to your project simply add the Projects target name, the git URL and the version. If the git tag for this version does not match the pattern `v$VERSION`, then the exact branch or tag can be specified with the `GIT_TAG` argument. ```cmake -cmake_minimum_required(VERSION 3.5 FATAL_ERROR) +cmake_minimum_required(VERSION 3.14 FATAL_ERROR) project(MyParser) @@ -18,9 +18,9 @@ include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/CPM.cmake) CPMAddPackage( NAME LarsParser - VERSION 1.4 + VERSION 1.4 # optional, used for find_package GIT_REPOSITORY https://github.com/TheLartians/Parser.git - GIT_TAG master # optional + GIT_TAG v1.4 # optional if TAG matches v$VERSION ) # add executable @@ -29,16 +29,12 @@ add_executable(my-parser my-parser.cpp) target_link_libraries(cpm-test LarsParser) ``` -# Offline mode - -After including CPM CMake will try to update remote repositories at every new buld. To continue working offline, set the parameter `CPM_OFFLINE=On`. - # Adding CPM To add CPM to your current project, copy the scripts in the `cmake` directory into you current project project. The command below will perform this automatically. ```bash -wget -qO- https://github.com/TheLartians/CPM/releases/download/v0.4/cmake.zip | bsdtar -xvf- +wget -O cmake/CPM.cmake https://raw.githubusercontent.com/TheLartians/CPM/master/cmake/CPM.cmake ``` # Advantages diff --git a/cmake/CPM.cmake b/cmake/CPM.cmake index 62cd2ef..9dea11d 100644 --- a/cmake/CPM.cmake +++ b/cmake/CPM.cmake @@ -1,66 +1,71 @@ -set(_CPM_Dir "${CMAKE_CURRENT_LIST_DIR}") +cmake_minimum_required(VERSION 3.14 FATAL_ERROR) -include(CMakeParseArguments) -include(${_CPM_Dir}/DownloadProject.cmake) - -option(CPM_OFFLINE "CPM offline mode" OFF) - -if(NOT ${CPM_OFFLINE}) - set(CPM_PACKAGES "" CACHE INTERNAL "CPM Packages") +if(CPM_DIRECTORY) + if(NOT ${CPM_DIRECTORY} MATCHES ${CMAKE_CURRENT_LIST_DIR}) + return() + endif() endif() +set(CPM_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} CACHE INTERNAL "") +set(CPM_PACKAGES "" CACHE INTERNAL "") + +include(FetchContent) +include(CMakeParseArguments) + +option(CPM_LOCAL_PACKAGES_ONLY "Use only locally installed packages" OFF) +option(CPM_REMOTE_PACKAGES_ONLY "Always download packages" OFF) + + function(CPMAddPackage) - set(options QUIET) set(oneValueArgs NAME - GIT_REPOSITORY VERSION GIT_TAG - BINARY_DIR - UPDATE_DISCONNECTED ) - set(multiValueArgs "") - - cmake_parse_arguments(CPM_ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - - if (NOT CPM_PACKAGES) - set(CPM_PACKAGES "") - endif() - - if (NOT CPM_ARGS_BINARY_DIR) - set(CPM_ARGS_BINARY_DIR ${CMAKE_BINARY_DIR}/CPM-projects/${CPM_ARGS_NAME}) - endif() - - if (NOT CPM_PROJECT_DIR) - set(CPM_PROJECT_DIR "${CPM_ARGS_BINARY_DIR}") - endif() + cmake_parse_arguments(CPM_ARGS QUIET "${oneValueArgs}" "" ${ARGN}) if (NOT CPM_ARGS_GIT_TAG) set(CPM_ARGS_GIT_TAG v${CPM_ARGS_VERSION}) endif() - SET(CPM_TARGET_CMAKE_FILE "${CPM_PROJECT_DIR}") - if (${CPM_ARGS_NAME} IN_LIST CPM_PACKAGES) - message(STATUS "CPM: package ${CPM_ARGS_NAME} already added") - else() - message(STATUS "CPM: adding package ${CPM_ARGS_NAME}@${CPM_ARGS_VERSION}") - # update package data - LIST(APPEND CPM_PACKAGES ${CPM_ARGS_NAME}) - # save package data - set(CPM_PACKAGES "${CPM_PACKAGES}" CACHE INTERNAL "CPM Packages") - - configure_file( - "${_CPM_Dir}/CPMProject.CMakeLists.cmake.in" - "${CPM_TARGET_CMAKE_FILE}/CMakeLists.txt" - @ONLY - ) + message(STATUS "CPM: not adding ${CPM_ARGS_NAME}@${CPM_ARGS_GIT_TAG}: already addded package ${CPM_ARGS_NAME}") endif() - if (NOT TARGET ${CPM_ARGS_NAME}) - add_subdirectory(${CPM_TARGET_CMAKE_FILE} ${CPM_ARGS_BINARY_DIR}) + LIST(APPEND CPM_PACKAGES ${CPM_ARGS_NAME}) + set(CPM_PACKAGES ${CPM_PACKAGES} CACHE INTERNAL "") + + if (NOT ${CPM_REMOTE_PACKAGES_ONLY}) + find_package(${CPM_ARGS_NAME} ${CPM_ARGS_VERSION} QUIET) + set(CPM_PACKAGE_FOUND ${CPM_ARGS_NAME}_FOUND) + + if(${CPM_PACKAGE_FOUND}) + message(STATUS "CPM: using local package ${CPM_ARGS_NAME}@${CPM_ARGS_VERSION}") + set_target_properties(${CPM_ARGS_NAME} + PROPERTIES + IMPORTED_GLOBAL True + ) + return() + endif() + endif() + + if (NOT ${CPM_LOCAL_PACKAGES_ONLY}) + + message(STATUS "CPM: fetching package ${CPM_ARGS_NAME}@${CPM_ARGS_GIT_TAG}") + + set(CPM_PACKAGE_CONTENT ${CPM_ARGS_NAME}_CONTENT) + + FetchContent_Declare( + ${CPM_PACKAGE_CONTENT} + GIT_TAG ${CPM_ARGS_GIT_TAG} + ${CPM_ARGS_UNPARSED_ARGUMENTS} + ) + + FetchContent_MakeAvailable(${CPM_PACKAGE_CONTENT}) + else() + MESSAGE(ERROR "CPM could not find the local package ${CPM_ARGS_NAME}@${CPM_ARGS_VERSION}") endif() endfunction() diff --git a/cmake/CPMProject.CMakeLists.cmake.in b/cmake/CPMProject.CMakeLists.cmake.in deleted file mode 100644 index 477e7dd..0000000 --- a/cmake/CPMProject.CMakeLists.cmake.in +++ /dev/null @@ -1,27 +0,0 @@ -cmake_minimum_required(VERSION 3.5 FATAL_ERROR) - -if(TARGET @CPM_ARGS_NAME@) - return() -endif() - -find_package(@CPM_ARGS_NAME@ @CPM_ARGS_VERSION@ QUIET) - -if(${PACKAGE_FOUND}) - set_target_properties(@CPM_ARGS_NAME@ - PROPERTIES - IMPORTED_GLOBAL True - ) -else() - - download_project( - PROJ @CPM_ARGS_NAME@ - GIT_REPOSITORY @CPM_ARGS_GIT_REPOSITORY@ - GIT_TAG @CPM_ARGS_GIT_TAG@ - UPDATE_DISCONNECTED @CPM_OFFLINE@ - GIT_SHALLOW 1 - PREFIX @CPM_ARGS_BINARY_DIR@/dl - QUIET - ) - - add_subdirectory(${@CPM_ARGS_NAME@_SOURCE_DIR} ${@CPM_ARGS_NAME@_BINARY_DIR}) -endif() diff --git a/cmake/DownloadProject.CMakeLists.cmake.in b/cmake/DownloadProject.CMakeLists.cmake.in deleted file mode 100755 index 89be4fd..0000000 --- a/cmake/DownloadProject.CMakeLists.cmake.in +++ /dev/null @@ -1,17 +0,0 @@ -# Distributed under the OSI-approved MIT License. See accompanying -# file LICENSE or https://github.com/Crascit/DownloadProject for details. - -cmake_minimum_required(VERSION 2.8.2) - -project(${DL_ARGS_PROJ}-download NONE) - -include(ExternalProject) -ExternalProject_Add(${DL_ARGS_PROJ}-download - ${DL_ARGS_UNPARSED_ARGUMENTS} - SOURCE_DIR "${DL_ARGS_SOURCE_DIR}" - BINARY_DIR "${DL_ARGS_BINARY_DIR}" - CONFIGURE_COMMAND "" - BUILD_COMMAND "" - INSTALL_COMMAND "" - TEST_COMMAND "" -) diff --git a/cmake/DownloadProject.cmake b/cmake/DownloadProject.cmake deleted file mode 100755 index e300f42..0000000 --- a/cmake/DownloadProject.cmake +++ /dev/null @@ -1,182 +0,0 @@ -# Distributed under the OSI-approved MIT License. See accompanying -# file LICENSE or https://github.com/Crascit/DownloadProject for details. -# -# MODULE: DownloadProject -# -# PROVIDES: -# download_project( PROJ projectName -# [PREFIX prefixDir] -# [DOWNLOAD_DIR downloadDir] -# [SOURCE_DIR srcDir] -# [BINARY_DIR binDir] -# [QUIET] -# ... -# ) -# -# Provides the ability to download and unpack a tarball, zip file, git repository, -# etc. at configure time (i.e. when the cmake command is run). How the downloaded -# and unpacked contents are used is up to the caller, but the motivating case is -# to download source code which can then be included directly in the build with -# add_subdirectory() after the call to download_project(). Source and build -# directories are set up with this in mind. -# -# The PROJ argument is required. The projectName value will be used to construct -# the following variables upon exit (obviously replace projectName with its actual -# value): -# -# projectName_SOURCE_DIR -# projectName_BINARY_DIR -# -# The SOURCE_DIR and BINARY_DIR arguments are optional and would not typically -# need to be provided. They can be specified if you want the downloaded source -# and build directories to be located in a specific place. The contents of -# projectName_SOURCE_DIR and projectName_BINARY_DIR will be populated with the -# locations used whether you provide SOURCE_DIR/BINARY_DIR or not. -# -# The DOWNLOAD_DIR argument does not normally need to be set. It controls the -# location of the temporary CMake build used to perform the download. -# -# The PREFIX argument can be provided to change the base location of the default -# values of DOWNLOAD_DIR, SOURCE_DIR and BINARY_DIR. If all of those three arguments -# are provided, then PREFIX will have no effect. The default value for PREFIX is -# CMAKE_BINARY_DIR. -# -# The QUIET option can be given if you do not want to show the output associated -# with downloading the specified project. -# -# In addition to the above, any other options are passed through unmodified to -# ExternalProject_Add() to perform the actual download, patch and update steps. -# The following ExternalProject_Add() options are explicitly prohibited (they -# are reserved for use by the download_project() command): -# -# CONFIGURE_COMMAND -# BUILD_COMMAND -# INSTALL_COMMAND -# TEST_COMMAND -# -# Only those ExternalProject_Add() arguments which relate to downloading, patching -# and updating of the project sources are intended to be used. Also note that at -# least one set of download-related arguments are required. -# -# If using CMake 3.2 or later, the UPDATE_DISCONNECTED option can be used to -# prevent a check at the remote end for changes every time CMake is run -# after the first successful download. See the documentation of the ExternalProject -# module for more information. It is likely you will want to use this option if it -# is available to you. Note, however, that the ExternalProject implementation contains -# bugs which result in incorrect handling of the UPDATE_DISCONNECTED option when -# using the URL download method or when specifying a SOURCE_DIR with no download -# method. Fixes for these have been created, the last of which is scheduled for -# inclusion in CMake 3.8.0. Details can be found here: -# -# https://gitlab.kitware.com/cmake/cmake/commit/bdca68388bd57f8302d3c1d83d691034b7ffa70c -# https://gitlab.kitware.com/cmake/cmake/issues/16428 -# -# If you experience build errors related to the update step, consider avoiding -# the use of UPDATE_DISCONNECTED. -# -# EXAMPLE USAGE: -# -# include(DownloadProject) -# download_project(PROJ googletest -# GIT_REPOSITORY https://github.com/google/googletest.git -# GIT_TAG master -# UPDATE_DISCONNECTED 1 -# QUIET -# ) -# -# add_subdirectory(${googletest_SOURCE_DIR} ${googletest_BINARY_DIR}) -# -#======================================================================================== - - -set(_DownloadProjectDir "${CMAKE_CURRENT_LIST_DIR}") - -include(CMakeParseArguments) - -function(download_project) - - set(options QUIET) - set(oneValueArgs - PROJ - PREFIX - DOWNLOAD_DIR - SOURCE_DIR - BINARY_DIR - # Prevent the following from being passed through - CONFIGURE_COMMAND - BUILD_COMMAND - INSTALL_COMMAND - TEST_COMMAND - ) - set(multiValueArgs "") - - cmake_parse_arguments(DL_ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - - # Hide output if requested - if (DL_ARGS_QUIET) - set(OUTPUT_QUIET "OUTPUT_QUIET") - else() - unset(OUTPUT_QUIET) - message(STATUS "Downloading/updating ${DL_ARGS_PROJ}") - endif() - - # Set up where we will put our temporary CMakeLists.txt file and also - # the base point below which the default source and binary dirs will be. - # The prefix must always be an absolute path. - if (NOT DL_ARGS_PREFIX) - set(DL_ARGS_PREFIX "${CMAKE_BINARY_DIR}") - else() - get_filename_component(DL_ARGS_PREFIX "${DL_ARGS_PREFIX}" ABSOLUTE - BASE_DIR "${CMAKE_CURRENT_BINARY_DIR}") - endif() - if (NOT DL_ARGS_DOWNLOAD_DIR) - set(DL_ARGS_DOWNLOAD_DIR "${DL_ARGS_PREFIX}/${DL_ARGS_PROJ}-download") - endif() - - # Ensure the caller can know where to find the source and build directories - if (NOT DL_ARGS_SOURCE_DIR) - set(DL_ARGS_SOURCE_DIR "${DL_ARGS_PREFIX}/${DL_ARGS_PROJ}-src") - endif() - if (NOT DL_ARGS_BINARY_DIR) - set(DL_ARGS_BINARY_DIR "${DL_ARGS_PREFIX}/${DL_ARGS_PROJ}-build") - endif() - set(${DL_ARGS_PROJ}_SOURCE_DIR "${DL_ARGS_SOURCE_DIR}" PARENT_SCOPE) - set(${DL_ARGS_PROJ}_BINARY_DIR "${DL_ARGS_BINARY_DIR}" PARENT_SCOPE) - - # The way that CLion manages multiple configurations, it causes a copy of - # the CMakeCache.txt to be copied across due to it not expecting there to - # be a project within a project. This causes the hard-coded paths in the - # cache to be copied and builds to fail. To mitigate this, we simply - # remove the cache if it exists before we configure the new project. It - # is safe to do so because it will be re-generated. Since this is only - # executed at the configure step, it should not cause additional builds or - # downloads. - file(REMOVE "${DL_ARGS_DOWNLOAD_DIR}/CMakeCache.txt") - - # Create and build a separate CMake project to carry out the download. - # If we've already previously done these steps, they will not cause - # anything to be updated, so extra rebuilds of the project won't occur. - # Make sure to pass through CMAKE_MAKE_PROGRAM in case the main project - # has this set to something not findable on the PATH. - configure_file("${_DownloadProjectDir}/DownloadProject.CMakeLists.cmake.in" - "${DL_ARGS_DOWNLOAD_DIR}/CMakeLists.txt") - execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" - -D "CMAKE_MAKE_PROGRAM:FILE=${CMAKE_MAKE_PROGRAM}" - . - RESULT_VARIABLE result - ${OUTPUT_QUIET} - WORKING_DIRECTORY "${DL_ARGS_DOWNLOAD_DIR}" - ) - if(result) - message(FATAL_ERROR "CMake step for ${DL_ARGS_PROJ} failed: ${result}") - endif() - execute_process(COMMAND ${CMAKE_COMMAND} --build . - RESULT_VARIABLE result - ${OUTPUT_QUIET} - WORKING_DIRECTORY "${DL_ARGS_DOWNLOAD_DIR}" - ) - if(result) - message(FATAL_ERROR "Build step for ${DL_ARGS_PROJ} failed: ${result}") - endif() - -endfunction() diff --git a/tests/complex/CMakeLists.txt b/tests/complex/CMakeLists.txt index 8454572..cc2582e 100644 --- a/tests/complex/CMakeLists.txt +++ b/tests/complex/CMakeLists.txt @@ -10,27 +10,24 @@ CPMAddPackage( VERSION 0.4 ) +CPMAddPackage( + NAME LHC + GIT_REPOSITORY https://github.com/TheLartians/LHC.git + VERSION 0.1 +) + CPMAddPackage( NAME LarsEvent GIT_REPOSITORY https://github.com/TheLartians/Event.git VERSION 1.0 - GIT_TAG master ) -# Add project that depends on previous project CPMAddPackage( NAME LarsParser GIT_REPOSITORY https://github.com/TheLartians/Parser.git VERSION 1.4 ) -# add project twice (will be ignored) -CPMAddPackage( - NAME LHC - GIT_REPOSITORY https://github.com/TheLartians/LHC.git - VERSION 0.1 -) - # add executable set (CMAKE_CXX_STANDARD 17) add_executable(cpm-test test.cpp)