-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #69 from lanl/mauneyc/fix-poc-already-present-error
Fix "already present target" error when using submodules
- Loading branch information
Showing
1 changed file
with
148 additions
and
150 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,96 +1,95 @@ | ||
include(FetchContent) | ||
|
||
############################################################### | ||
# | ||
# ############################################################################## | ||
# | ||
# For dependency management, use the `FetchContent` pattern | ||
# | ||
# NOTE: We seek to replicate the implementation of `FetchContent` | ||
############################################################### | ||
|
||
# Constructs `FetchContent_Declare` call, and records information | ||
# for population and linking | ||
# | ||
# ::Overview | ||
# With `[email protected]` and higher, the functionality of `FetchContent_` has | ||
# been updated to provide the capability to try a `find_package` at the | ||
# content population stage. This allows for the flexibility provided by | ||
# `FetchContent_` to easily coexist with the dependency configuration | ||
# provided by `find_package`. Some benefits include: | ||
# - automated fetching of content if it is unavailable | ||
# - content population at configure. This allows for a package import | ||
# to utilize `find_package()` or `add_subdirectory()` operations | ||
# - local clones can be given priority with `FETCHCONTENT_SOURCE_DIR_<uppercaseName>`, | ||
# which lets developers use dependencies explicitly in-tree | ||
# The case where i.) the content or dependency is unavailable or ii.) it cannot | ||
# be fetched (due, for example, to a failure of a download step) is an | ||
# unavoidable error. | ||
# ############################################################################## | ||
|
||
# Constructs `FetchContent_Declare` call, and records information for population | ||
# and linking | ||
# | ||
# As this cmake version is relatively fresh, we also want to provide a bridge | ||
# to downstream code that still is pinned to an earlier releases of `cmake`. | ||
# To that end, these macros provide for replicating the main features introduced | ||
# to `FetchContent_` in `[email protected]`. Future releases of `spiner` will require | ||
# a minimum of `[email protected]`. | ||
# ::Overview With `[email protected]` and higher, the functionality of `FetchContent_` | ||
# has been updated to provide the capability to try a `find_package` at the | ||
# content population stage. This allows for the flexibility provided by | ||
# `FetchContent_` to easily coexist with the dependency configuration provided | ||
# by `find_package`. Some benefits include: - automated fetching of content if | ||
# it is unavailable - content population at configure. This allows for a package | ||
# import to utilize `find_package()` or `add_subdirectory()` operations - local | ||
# clones can be given priority with `FETCHCONTENT_SOURCE_DIR_<uppercaseName>`, | ||
# which lets developers use dependencies explicitly in-tree The case where i.) | ||
# the content or dependency is unavailable or ii.) it cannot be fetched (due, | ||
# for example, to a failure of a download step) is an unavoidable error. | ||
# | ||
# :: Arguments | ||
# pkg_name - the name of the package or content. usually the argument to `find_package(<pkg_name>)` | ||
# options: | ||
# - NO_FETCH - disables all download steps. If `find_package(<pkg_name>)` fails, produce an error | ||
# single_value: | ||
# - GIT_REPO - the URL of the git repository to clone, if necessary | ||
# - GIT_TAG - the tag or commit to use | ||
# - NAMESPACE - prefix book-keeping variables with this | ||
# multi_value: | ||
# - COMPONENTS - specify required components of <pkg_name>. same as used in to `find_package` | ||
# - EXPECTED_TARGETS - a list of targets that expected at population. | ||
# if these targets are not available after the population stage, an error is produced. | ||
# if not specified, will default to `<pkg_name>::<pkg_name>` | ||
# - ENABLE_OPTS - a list of cache vars used to configure content that is imported using `add_subdirectory()` | ||
# As this cmake version is relatively fresh, we also want to provide a bridge to | ||
# downstream code that still is pinned to an earlier releases of `cmake`. To | ||
# that end, these macros provide for replicating the main features introduced to | ||
# `FetchContent_` in `[email protected]`. Future releases of `spiner` will require a | ||
# minimum of `[email protected]`. | ||
# | ||
# :: Arguments pkg_name - the name of the package or content. usually the | ||
# argument to `find_package(<pkg_name>)` options: - NO_FETCH - disables all | ||
# download steps. If `find_package(<pkg_name>)` fails, produce an error | ||
# single_value: - GIT_REPO - the URL of the git repository to clone, if | ||
# necessary - GIT_TAG - the tag or commit to use - NAMESPACE - prefix | ||
# book-keeping variables with this multi_value: - COMPONENTS - specify required | ||
# components of <pkg_name>. same as used in to `find_package` - EXPECTED_TARGETS | ||
# - a list of targets that expected at population. if these targets are not | ||
# available after the population stage, an error is produced. if not specified, | ||
# will default to `<pkg_name>::<pkg_name>` - ENABLE_OPTS - a list of cache vars | ||
# used to configure content that is imported using `add_subdirectory()` | ||
# | ||
macro(spiner_content_declare pkg_name) | ||
set(options | ||
NO_FETCH | ||
) | ||
set(one_value_args | ||
GIT_REPO | ||
GIT_TAG | ||
NAMESPACE | ||
) | ||
set(multi_value_args | ||
COMPONENTS | ||
EXPECTED_TARGETS | ||
ENABLE_OPTS | ||
) | ||
|
||
cmake_parse_arguments(fp "${options}" "${one_value_args}" "${multi_value_args}" "${ARGN}") | ||
set(options NO_FETCH) | ||
set(one_value_args GIT_REPO GIT_TAG NAMESPACE) | ||
set(multi_value_args COMPONENTS EXPECTED_TARGETS ENABLE_OPTS) | ||
|
||
cmake_parse_arguments(fp "${options}" "${one_value_args}" | ||
"${multi_value_args}" "${ARGN}") | ||
|
||
string(TOUPPER ${pkg_name} pkg_CAP) | ||
string(REPLACE "-" "_" pkg_CAP "${pkg_CAP}") | ||
|
||
message(STATUS | ||
"[${pkg_name}] FetchContent_Declare wrapper" | ||
) | ||
# because the signature is different between versions, | ||
# we build the cmake call beforehand | ||
# loop through targets, if already present then bail | ||
foreach(expected_target ${fp_EXPECTED_TARGETS};${pkg_name}) | ||
if(TARGET ${expected_target}) | ||
message( | ||
STATUS | ||
"target \"${expected_target}\" already exists, tagging ${pkg_name} as already present" | ||
) | ||
set(${fp_NAMESPACE}_DECLARED_EXTERNAL_${pkg_CAP}_ALREADY_PRESENT TRUE) | ||
break() | ||
endif() | ||
endforeach() | ||
|
||
message(STATUS "[${pkg_name}] FetchContent_Declare wrapper") | ||
# because the signature is different between versions, we build the cmake call | ||
# beforehand | ||
set(_fetch_content_cmd "FetchContent_Declare(${pkg_name}") | ||
|
||
if(fp_NO_FETCH) | ||
message(VERBOSE | ||
message( | ||
VERBOSE | ||
" :: \"${pkg_name}\" is specified not fetchable, will rely on `find_package` for population" | ||
) | ||
string(APPEND _fetch_content_cmd " DOWNLOAD_COMMAND \":\"") | ||
string(APPEND _fetch_content_cmd " DOWNLOAD_COMMAND \":\"") | ||
set(${fp_NAMESPACE}_DECLARED_EXTERNAL_${pkg_CAP}_NOFETCH TRUE) | ||
else() | ||
message(VERBOSE | ||
message( | ||
VERBOSE | ||
" :: \"${pkg_name}\" is fetchable, will fall-back to git clone [${fp_GIT_REPO}] if other population methods fail" | ||
) | ||
string(APPEND _fetch_content_cmd " GIT_REPOSITORY ${fp_GIT_REPO} GIT_TAG ${fp_GIT_TAG}") | ||
string(APPEND _fetch_content_cmd | ||
" GIT_REPOSITORY ${fp_GIT_REPO} GIT_TAG ${fp_GIT_TAG}") | ||
endif() | ||
|
||
# bifurcation on cmake version | ||
if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.24.0") | ||
if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.24.0") | ||
# versions >= 3.24 will do an implicit `find_package`, so pass on | ||
# requirements to declaration | ||
string(APPEND _fetch_content_cmd " FIND_PACKAGE_ARGS COMPONENTS ${fp_COMPONENTS}") | ||
string(APPEND _fetch_content_cmd | ||
" FIND_PACKAGE_ARGS COMPONENTS ${fp_COMPONENTS}") | ||
endif() | ||
|
||
# close the command | ||
|
@@ -101,7 +100,7 @@ macro(spiner_content_declare pkg_name) | |
cmake_language(EVAL CODE "${_fetch_content_cmd}") | ||
# be safe and destroy the string | ||
unset(_fetch_content_cmd) | ||
|
||
# return some info | ||
|
||
list(APPEND ${fp_NAMESPACE}_DECLARED_EXTERNAL_CONTENT ${pkg_name}) | ||
|
@@ -110,102 +109,103 @@ macro(spiner_content_declare pkg_name) | |
set(${fp_NAMESPACE}_DECLARED_EXTERNAL_${pkg_CAP}_PRIORS ${fp_PRIORS}) | ||
|
||
if(fp_EXPECTED_TARGETS) | ||
set(${fp_NAMESPACE}_DECLARED_EXTERNAL_${pkg_CAP}_TARGETS ${fp_EXPECTED_TARGETS}) | ||
set(${fp_NAMESPACE}_DECLARED_EXTERNAL_${pkg_CAP}_TARGETS | ||
${fp_EXPECTED_TARGETS}) | ||
else() | ||
set(${fp_NAMESPACE}_DECLARED_EXTERNAL_${pkg_CAP}_TARGETS "${pkg_name}::${pkg_name}") | ||
set(${fp_NAMESPACE}_DECLARED_EXTERNAL_${pkg_CAP}_TARGETS | ||
"${pkg_name}::${pkg_name}") | ||
endif() | ||
|
||
endmacro() | ||
|
||
# | ||
# :: Overview | ||
# This macro wraps a call to `FetchContent_MakeAvailable`. | ||
# If we are using a `cmake` prior to 3.24, explicitly do a | ||
# `find_package()` with the declared options | ||
# :: Arguments | ||
# single_value: | ||
# - NAMESPACE - the namespace used in the corrisponding `spiner_content_declare` call | ||
# :: Overview This macro wraps a call to `FetchContent_MakeAvailable`. If we are | ||
# using a `cmake` prior to 3.24, explicitly do a `find_package()` with the | ||
# declared options :: Arguments single_value: - NAMESPACE - the namespace used | ||
# in the corrisponding `spiner_content_declare` call | ||
# | ||
macro(spiner_content_populate) | ||
set(options) | ||
set(one_value_args | ||
NAMESPACE | ||
) | ||
set(multi_value_args | ||
) | ||
|
||
cmake_parse_arguments(fp "${options}" "${one_value_args}" "${multi_value_args}" "${ARGN}") | ||
|
||
message(STATUS | ||
"[${fp_NAMESPACE}] Populating declared content" | ||
) | ||
# fill lists to populate | ||
# if [email protected]+, these are just the lists prepared in spiner_content_declare | ||
# otherwise, manually check `find_package` and remove content if found | ||
set(one_value_args NAMESPACE) | ||
set(multi_value_args) | ||
|
||
cmake_parse_arguments(fp "${options}" "${one_value_args}" | ||
"${multi_value_args}" "${ARGN}") | ||
|
||
message(STATUS "[${fp_NAMESPACE}] Populating declared content") | ||
# fill lists to populate if [email protected]+, these are just the lists prepared in | ||
# spiner_content_declare otherwise, manually check `find_package` and remove | ||
# content if found | ||
foreach(pkg_name ${${fp_NAMESPACE}_DECLARED_EXTERNAL_CONTENT}) | ||
string(TOUPPER ${pkg_name} pkg_CAP) | ||
string(REPLACE "-" "_" pkg_CAP "${pkg_CAP}") | ||
# bifurcation on cmake version | ||
if (NOT CMAKE_VERSION VERSION_GREATER_EQUAL "3.24.0") | ||
find_package(${pkg_name} | ||
COMPONENTS ${${fp_NAMESPACE}_DECLARED_EXTERNAL_${pkg_CAP}_COMPONETS} | ||
QUIET | ||
) | ||
if(${pkg_name}_FOUND) | ||
message(VERBOSE | ||
"${pkg_name} located with `find_package`" | ||
"${pkg_name}_DIR: ${${pkg_name}_DIR}" | ||
) | ||
|
||
if(NOT ${fp_NAMESPACE}_DECLARED_EXTERNAL_${pkg_CAP}_ALREADY_PRESENT) | ||
# bifurcation on cmake version | ||
if(NOT CMAKE_VERSION VERSION_GREATER_EQUAL "3.24.0") | ||
find_package( | ||
${pkg_name} | ||
COMPONENTS ${${fp_NAMESPACE}_DECLARED_EXTERNAL_${pkg_CAP}_COMPONETS} | ||
QUIET) | ||
if(${pkg_name}_FOUND) | ||
message(VERBOSE "${pkg_name} located with `find_package`" | ||
"${pkg_name}_DIR: ${${pkg_name}_DIR}") | ||
else() | ||
# if no fetching and not found, produce an error conditionally include | ||
# a custom error msg | ||
if(${fp_NAMESPACE}_DECLARED_EXTERNAL_${pkg_CAP}_NOFETCH) | ||
message( | ||
FATAL_ERROR | ||
"${pkg_name} is requested, but it was not located and is not declared as fetchable.\n" | ||
"if ${pkg_name} is installed, set \"-D${pkg_name}_ROOT=<install-dir>\"" | ||
) | ||
endif() # NOFETCH | ||
message( | ||
VERBOSE | ||
"${pkg_name} NOT located with `find_package`, appending to populate list." | ||
" Will attempt to clone repository when content is populated.") | ||
list(APPEND _fetchList ${pkg_name}) | ||
list(APPEND _fetchOpts | ||
${${fp_NAMESPACE}_DECLARED_EXTERNAL_${pkg_CAP}_ENABLEOPTS}) | ||
list(APPEND _fetchTars | ||
${${fp_NAMESPACE}_DECLARED_EXTERNAL_${pkg_CAP}_TARGETS}) | ||
|
||
endif() # FOUND | ||
else() | ||
# if no fetching and not found, produce an error | ||
# conditionally include a custom error msg | ||
if(${fp_NAMESPACE}_DECLARED_EXTERNAL_${pkg_CAP}_NOFETCH) | ||
message(FATAL_ERROR | ||
"${pkg_name} is requested, but it was not located and is not declared as fetchable.\n" | ||
"if ${pkg_name} is installed, set \"-D${pkg_name}_ROOT=<install-dir>\"" | ||
) | ||
endif() # NOFETCH | ||
message(VERBOSE | ||
"${pkg_name} NOT located with `find_package`, appending to populate list." | ||
" Will attempt to clone repository when content is populated." | ||
) | ||
list(APPEND _fetchList ${pkg_name}) | ||
list(APPEND _fetchOpts ${${fp_NAMESPACE}_DECLARED_EXTERNAL_${pkg_CAP}_ENABLEOPTS}) | ||
list(APPEND _fetchTars ${${fp_NAMESPACE}_DECLARED_EXTERNAL_${pkg_CAP}_TARGETS}) | ||
|
||
endif() # FOUND | ||
else() | ||
list(APPEND _fetchList ${pkg_name}) | ||
list(APPEND _fetchOpts ${${fp_NAMESPACE}_DECLARED_EXTERNAL_${pkg_CAP}_ENABLEOPTS}) | ||
list(APPEND _fetchTars ${${fp_NAMESPACE}_DECLARED_EXTERNAL_${pkg_CAP}_TARGETS}) | ||
endif() #CMAKE_VERSION | ||
# collect all targets, reguardless of populated | ||
list(APPEND _expectedTars ${${fp_NAMESPACE}_DECLARED_EXTERNAL_${pkg_CAP}_TARGETS}) | ||
list(APPEND _fetchOpts | ||
${${fp_NAMESPACE}_DECLARED_EXTERNAL_${pkg_CAP}_ENABLEOPTS}) | ||
list(APPEND _fetchTars | ||
${${fp_NAMESPACE}_DECLARED_EXTERNAL_${pkg_CAP}_TARGETS}) | ||
endif() # CMAKE_VERSION | ||
# collect all targets, reguardless of populated | ||
endif() # _ALREADY_PRESENT | ||
list(APPEND _expectedTars | ||
${${fp_NAMESPACE}_DECLARED_EXTERNAL_${pkg_CAP}_TARGETS}) | ||
endforeach() | ||
|
||
# for content to be populated, set some cache options given in spiner_content_declare | ||
# for content to be populated, set some cache options given in | ||
# spiner_content_declare | ||
foreach(ext_opt ${_fetchOpts}) | ||
message(DEBUG "setting \"${ext_opt}\"=ON") | ||
set(${ext_opt} ON CACHE INTERNAL "") | ||
set(${ext_opt} | ||
ON | ||
CACHE INTERNAL "") | ||
endforeach() | ||
|
||
message(VERBOSE "\n" | ||
" :: Populating dependency targets ${_fetchTars}\n" | ||
" :: Calling `FetchContent_MakeAvailable` with ${_fetchList}\n" | ||
) | ||
message(STATUS | ||
"FetchContent_MakeAvailable prepared, " | ||
"this may take a few moments if a download is required...\n" | ||
) | ||
# populate | ||
message(VERBOSE "\n" " :: Populating dependency targets ${_fetchTars}\n" | ||
" :: Calling `FetchContent_MakeAvailable` with ${_fetchList}\n") | ||
message(STATUS "FetchContent_MakeAvailable prepared, " | ||
"this may take a few moments if a download is required...\n") | ||
# populate | ||
FetchContent_MakeAvailable(${_fetchList}) | ||
|
||
# check that declared targets exist | ||
foreach(expected_target ${_expectedTars}) | ||
if(NOT TARGET ${expected_target}) | ||
message(FATAL_ERROR | ||
message( | ||
FATAL_ERROR | ||
"target \"${expected_target}\" was expected, but does not exist after population!" | ||
) # NOT TARGET | ||
) # NOT TARGET | ||
endif() | ||
endforeach() | ||
|
||
|
@@ -220,15 +220,13 @@ macro(spiner_content_populate) | |
unset(${fp_NAMESPACE}_DECLARED_EXTERNAL_CONTENT) | ||
endmacro() | ||
|
||
|
||
# © 2021. Triad National Security, LLC. All rights reserved. This | ||
# program was produced under U.S. Government contract 89233218CNA000001 | ||
# for Los Alamos National Laboratory (LANL), which is operated by Triad | ||
# National Security, LLC for the U.S. Department of Energy/National | ||
# Nuclear Security Administration. All rights in the program are | ||
# reserved by Triad National Security, LLC, and the U.S. Department of | ||
# Energy/National Nuclear Security Administration. The Government is | ||
# granted for itself and others acting on its behalf a nonexclusive, | ||
# paid-up, irrevocable worldwide license in this material to reproduce, | ||
# prepare derivative works, distribute copies to the public, perform | ||
# © 2021. Triad National Security, LLC. All rights reserved. This program was | ||
# produced under U.S. Government contract 89233218CNA000001 for Los Alamos | ||
# National Laboratory (LANL), which is operated by Triad National Security, LLC | ||
# for the U.S. Department of Energy/National Nuclear Security Administration. | ||
# All rights in the program are reserved by Triad National Security, LLC, and | ||
# the U.S. Department of Energy/National Nuclear Security Administration. The | ||
# Government is granted for itself and others acting on its behalf a | ||
# nonexclusive, paid-up, irrevocable worldwide license in this material to | ||
# reproduce, prepare derivative works, distribute copies to the public, perform | ||
# publicly and display publicly, and to permit others to do so. |