1*da58b97aSjoerg# Utility functions for packaging an LLVM distribution. See the 2*da58b97aSjoerg# BuildingADistribution documentation for more details. 306f32e7eSjoerg 4*da58b97aSjoerg# These functions assume a number of conventions that are common across all LLVM 5*da58b97aSjoerg# subprojects: 6*da58b97aSjoerg# - The generated CMake exports file for ${project} is called ${project}Targets 7*da58b97aSjoerg# (except for LLVM where it's called ${project}Exports for legacy reasons). 8*da58b97aSjoerg# - The build target for the CMake exports is called ${project}-cmake-exports 9*da58b97aSjoerg# (except LLVM where it's just cmake-exports). 10*da58b97aSjoerg# - The ${PROJECT}${distribution}_HAS_EXPORTS global property holds whether a 11*da58b97aSjoerg# project has any exports for a particular ${distribution} (where ${PROJECT} 12*da58b97aSjoerg# is the project name in uppercase). 13*da58b97aSjoerg# - The ${PROJECT}_CMAKE_DIR variable is computed by ${project}Config.cmake to 14*da58b97aSjoerg# hold the path of the installed CMake modules directory. 15*da58b97aSjoerg# - The ${PROJECT}_INSTALL_PACKAGE_DIR variable contains the install destination 16*da58b97aSjoerg# for the project's CMake modules. 17*da58b97aSjoerg 18*da58b97aSjoerginclude_guard(GLOBAL) 19*da58b97aSjoerg 20*da58b97aSjoergif(LLVM_DISTRIBUTION_COMPONENTS AND LLVM_DISTRIBUTIONS) 21*da58b97aSjoerg message(FATAL_ERROR "LLVM_DISTRIBUTION_COMPONENTS and LLVM_DISTRIBUTIONS cannot be specified together") 22*da58b97aSjoergendif() 23*da58b97aSjoerg 24*da58b97aSjoergif(LLVM_DISTRIBUTION_COMPONENTS OR LLVM_DISTRIBUTIONS) 2506f32e7eSjoerg if(LLVM_ENABLE_IDE) 2606f32e7eSjoerg message(FATAL_ERROR "LLVM_DISTRIBUTION_COMPONENTS cannot be specified with multi-configuration generators (i.e. Xcode or Visual Studio)") 2706f32e7eSjoerg endif() 2806f32e7eSjoergendif() 2906f32e7eSjoerg 30*da58b97aSjoerg# Build the map of targets to distributions that's used to look up the 31*da58b97aSjoerg# distribution for a target later. The distribution for ${target} is stored in 32*da58b97aSjoerg# the global property LLVM_DISTRIBUTION_FOR_${target}. 33*da58b97aSjoergfunction(llvm_distribution_build_target_map) 34*da58b97aSjoerg foreach(target ${LLVM_DISTRIBUTION_COMPONENTS}) 35*da58b97aSjoerg # CMake doesn't easily distinguish between properties that are unset and 36*da58b97aSjoerg # properties that are empty (you have to do a second get_property call with 37*da58b97aSjoerg # the SET option, which is unergonomic), so just use a special marker to 38*da58b97aSjoerg # denote the default (unnamed) distribution. 39*da58b97aSjoerg set_property(GLOBAL PROPERTY LLVM_DISTRIBUTION_FOR_${target} "<DEFAULT>") 40*da58b97aSjoerg endforeach() 4106f32e7eSjoerg 42*da58b97aSjoerg foreach(distribution ${LLVM_DISTRIBUTIONS}) 43*da58b97aSjoerg foreach(target ${LLVM_${distribution}_DISTRIBUTION_COMPONENTS}) 44*da58b97aSjoerg # We don't allow a target to be in multiple distributions, because we 45*da58b97aSjoerg # wouldn't know which export set to place it in. 46*da58b97aSjoerg get_property(current_distribution GLOBAL PROPERTY LLVM_DISTRIBUTION_FOR_${target}) 47*da58b97aSjoerg if(current_distribution AND NOT current_distribution STREQUAL distribution) 48*da58b97aSjoerg message(SEND_ERROR "Target ${target} cannot be in multiple distributions ${distribution} and ${current_distribution}") 49*da58b97aSjoerg endif() 50*da58b97aSjoerg set_property(GLOBAL PROPERTY LLVM_DISTRIBUTION_FOR_${target} ${distribution}) 51*da58b97aSjoerg endforeach() 52*da58b97aSjoerg endforeach() 53*da58b97aSjoergendfunction() 54*da58b97aSjoerg 55*da58b97aSjoerg# The include guard ensures this will only be called once. The rest of this file 56*da58b97aSjoerg# only defines other functions (i.e. it doesn't execute any more code directly). 57*da58b97aSjoergllvm_distribution_build_target_map() 58*da58b97aSjoerg 59*da58b97aSjoerg# Look up the distribution a particular target belongs to. 60*da58b97aSjoerg# - target: The target to look up. 61*da58b97aSjoerg# - in_distribution_var: The variable with this name is set in the caller's 62*da58b97aSjoerg# scope to indicate if the target is in any distribution. If no distributions 63*da58b97aSjoerg# have been configured, this will always be set to true. 64*da58b97aSjoerg# - distribution_var: The variable with this name is set in the caller's scope 65*da58b97aSjoerg# to indicate the distribution name for the target. If the target belongs to 66*da58b97aSjoerg# the default (unnamed) distribution, or if no distributions have been 67*da58b97aSjoerg# configured, it's set to the empty string. 68*da58b97aSjoerg# - UMBRELLA: The (optional) umbrella target that the target is a part of. For 69*da58b97aSjoerg# example, all LLVM libraries have the umbrella target llvm-libraries. 70*da58b97aSjoergfunction(get_llvm_distribution target in_distribution_var distribution_var) 71*da58b97aSjoerg if(NOT LLVM_DISTRIBUTION_COMPONENTS AND NOT LLVM_DISTRIBUTIONS) 72*da58b97aSjoerg set(${in_distribution_var} YES PARENT_SCOPE) 73*da58b97aSjoerg set(${distribution_var} "" PARENT_SCOPE) 74*da58b97aSjoerg return() 75*da58b97aSjoerg endif() 76*da58b97aSjoerg 77*da58b97aSjoerg cmake_parse_arguments(ARG "" UMBRELLA "" ${ARGN}) 78*da58b97aSjoerg get_property(distribution GLOBAL PROPERTY LLVM_DISTRIBUTION_FOR_${target}) 79*da58b97aSjoerg if(ARG_UMBRELLA) 80*da58b97aSjoerg get_property(umbrella_distribution GLOBAL PROPERTY LLVM_DISTRIBUTION_FOR_${ARG_UMBRELLA}) 81*da58b97aSjoerg if(distribution AND umbrella_distribution AND NOT distribution STREQUAL umbrella_distribution) 82*da58b97aSjoerg message(SEND_ERROR "Target ${target} has different distribution ${distribution} from its" 83*da58b97aSjoerg " umbrella target ${ARG_UMBRELLA} distribution ${umbrella_distribution}") 84*da58b97aSjoerg elseif(NOT distribution) 85*da58b97aSjoerg set(distribution ${umbrella_distribution}) 86*da58b97aSjoerg endif() 87*da58b97aSjoerg endif() 88*da58b97aSjoerg if(distribution) 89*da58b97aSjoerg set(${in_distribution_var} YES PARENT_SCOPE) 90*da58b97aSjoerg if(distribution STREQUAL "<DEFAULT>") 91*da58b97aSjoerg set(distribution "") 92*da58b97aSjoerg endif() 93*da58b97aSjoerg set(${distribution_var} "${distribution}" PARENT_SCOPE) 94*da58b97aSjoerg else() 95*da58b97aSjoerg set(${in_distribution_var} NO PARENT_SCOPE) 96*da58b97aSjoerg endif() 97*da58b97aSjoergendfunction() 98*da58b97aSjoerg 99*da58b97aSjoerg# Get the EXPORT argument to use for an install command for a target in a 100*da58b97aSjoerg# project. As explained at the top of the file, the project export set for a 101*da58b97aSjoerg# distribution is named ${project}{distribution}Targets (except for LLVM where 102*da58b97aSjoerg# it's named ${project}{distribution}Exports for legacy reasons). Also set the 103*da58b97aSjoerg# ${PROJECT}_${DISTRIBUTION}_HAS_EXPORTS global property to mark the project as 104*da58b97aSjoerg# having exports for the distribution. 105*da58b97aSjoerg# - target: The target to get the EXPORT argument for. 106*da58b97aSjoerg# - project: The project to produce the argument for. IMPORTANT: The casing of 107*da58b97aSjoerg# this argument should match the casing used by the project's Config.cmake 108*da58b97aSjoerg# file. The correct casing for the LLVM projects is Clang, Flang, LLD, LLVM, 109*da58b97aSjoerg# and MLIR. 110*da58b97aSjoerg# - export_arg_var The variable with this name is set in the caller's scope to 111*da58b97aSjoerg# the EXPORT argument for the target for the project. 112*da58b97aSjoerg# - UMBRELLA: The (optional) umbrella target that the target is a part of. For 113*da58b97aSjoerg# example, all LLVM libraries have the umbrella target llvm-libraries. 114*da58b97aSjoergfunction(get_target_export_arg target project export_arg_var) 115*da58b97aSjoerg string(TOUPPER "${project}" project_upper) 116*da58b97aSjoerg if(project STREQUAL "LLVM") 117*da58b97aSjoerg set(suffix "Exports") # legacy 118*da58b97aSjoerg else() 119*da58b97aSjoerg set(suffix "Targets") 120*da58b97aSjoerg endif() 121*da58b97aSjoerg 122*da58b97aSjoerg get_llvm_distribution(${target} in_distribution distribution ${ARGN}) 123*da58b97aSjoerg 124*da58b97aSjoerg if(in_distribution) 125*da58b97aSjoerg set(${export_arg_var} EXPORT ${project}${distribution}${suffix} PARENT_SCOPE) 126*da58b97aSjoerg if(distribution) 127*da58b97aSjoerg string(TOUPPER "${distribution}" distribution_upper) 128*da58b97aSjoerg set_property(GLOBAL PROPERTY ${project_upper}_${distribution_upper}_HAS_EXPORTS True) 129*da58b97aSjoerg else() 130*da58b97aSjoerg set_property(GLOBAL PROPERTY ${project_upper}_HAS_EXPORTS True) 131*da58b97aSjoerg endif() 132*da58b97aSjoerg else() 133*da58b97aSjoerg set(${export_arg_var} "" PARENT_SCOPE) 134*da58b97aSjoerg endif() 135*da58b97aSjoergendfunction() 136*da58b97aSjoerg 137*da58b97aSjoerg# Produce a string of CMake include() commands to include the exported targets 138*da58b97aSjoerg# files for all distributions. See the comment at the top of this file for 139*da58b97aSjoerg# various assumptions made. 140*da58b97aSjoerg# - project: The project to produce the commands for. IMPORTANT: See the comment 141*da58b97aSjoerg# for get_target_export_arg above for the correct casing of this argument. 142*da58b97aSjoerg# - includes_var: The variable with this name is set in the caller's scope to 143*da58b97aSjoerg# the string of include commands. 144*da58b97aSjoergfunction(get_config_exports_includes project includes_var) 145*da58b97aSjoerg string(TOUPPER "${project}" project_upper) 146*da58b97aSjoerg set(prefix "\${${project_upper}_CMAKE_DIR}/${project}") 147*da58b97aSjoerg if(project STREQUAL "LLVM") 148*da58b97aSjoerg set(suffix "Exports.cmake") # legacy 149*da58b97aSjoerg else() 150*da58b97aSjoerg set(suffix "Targets.cmake") 151*da58b97aSjoerg endif() 152*da58b97aSjoerg 153*da58b97aSjoerg if(NOT LLVM_DISTRIBUTIONS) 154*da58b97aSjoerg set(${includes_var} "include(\"${prefix}${suffix}\")" PARENT_SCOPE) 155*da58b97aSjoerg else() 156*da58b97aSjoerg set(includes) 157*da58b97aSjoerg foreach(distribution ${LLVM_DISTRIBUTIONS}) 158*da58b97aSjoerg list(APPEND includes "include(\"${prefix}${distribution}${suffix}\" OPTIONAL)") 159*da58b97aSjoerg endforeach() 160*da58b97aSjoerg string(REPLACE ";" "\n" includes "${includes}") 161*da58b97aSjoerg set(${includes_var} "${includes}" PARENT_SCOPE) 162*da58b97aSjoerg endif() 163*da58b97aSjoergendfunction() 164*da58b97aSjoerg 165*da58b97aSjoerg# Create the install commands and targets for the distributions' CMake exports. 166*da58b97aSjoerg# The target to install ${distribution} for a project is called 167*da58b97aSjoerg# ${project}-${distribution}-cmake-exports, where ${project} is the project name 168*da58b97aSjoerg# in lowercase and ${distribution} is the distribution name in lowercase, except 169*da58b97aSjoerg# for LLVM, where the target is just called ${distribution}-cmake-exports. See 170*da58b97aSjoerg# the comment at the top of this file for various assumptions made. 171*da58b97aSjoerg# - project: The project. IMPORTANT: See the comment for get_target_export_arg 172*da58b97aSjoerg# above for the correct casing of this argument. 173*da58b97aSjoergfunction(install_distribution_exports project) 174*da58b97aSjoerg string(TOUPPER "${project}" project_upper) 175*da58b97aSjoerg string(TOLOWER "${project}" project_lower) 176*da58b97aSjoerg if(project STREQUAL "LLVM") 177*da58b97aSjoerg set(prefix "") 178*da58b97aSjoerg set(suffix "Exports") # legacy 179*da58b97aSjoerg else() 180*da58b97aSjoerg set(prefix "${project_lower}-") 181*da58b97aSjoerg set(suffix "Targets") 182*da58b97aSjoerg endif() 183*da58b97aSjoerg set(destination "${${project_upper}_INSTALL_PACKAGE_DIR}") 184*da58b97aSjoerg 185*da58b97aSjoerg if(NOT LLVM_DISTRIBUTIONS) 186*da58b97aSjoerg get_property(has_exports GLOBAL PROPERTY ${project_upper}_HAS_EXPORTS) 187*da58b97aSjoerg if(has_exports) 188*da58b97aSjoerg install(EXPORT ${project}${suffix} DESTINATION "${destination}" 189*da58b97aSjoerg COMPONENT ${prefix}cmake-exports) 190*da58b97aSjoerg endif() 191*da58b97aSjoerg else() 192*da58b97aSjoerg foreach(distribution ${LLVM_DISTRIBUTIONS}) 193*da58b97aSjoerg string(TOUPPER "${distribution}" distribution_upper) 194*da58b97aSjoerg get_property(has_exports GLOBAL PROPERTY ${project_upper}_${distribution_upper}_HAS_EXPORTS) 195*da58b97aSjoerg if(has_exports) 196*da58b97aSjoerg string(TOLOWER "${distribution}" distribution_lower) 197*da58b97aSjoerg set(target ${prefix}${distribution_lower}-cmake-exports) 198*da58b97aSjoerg install(EXPORT ${project}${distribution}${suffix} DESTINATION "${destination}" 199*da58b97aSjoerg COMPONENT ${target}) 200*da58b97aSjoerg if(NOT LLVM_ENABLE_IDE) 201*da58b97aSjoerg add_custom_target(${target}) 202*da58b97aSjoerg add_llvm_install_targets(install-${target} COMPONENT ${target}) 203*da58b97aSjoerg endif() 204*da58b97aSjoerg endif() 205*da58b97aSjoerg endforeach() 206*da58b97aSjoerg endif() 207*da58b97aSjoergendfunction() 208*da58b97aSjoerg 209*da58b97aSjoerg# Create the targets for installing the configured distributions. The 210*da58b97aSjoerg# ${distribution} target builds the distribution, install-${distribution} 211*da58b97aSjoerg# installs it, and install-${distribution}-stripped installs a stripped version, 212*da58b97aSjoerg# where ${distribution} is the distribution name in lowercase, or "distribution" 213*da58b97aSjoerg# for the default distribution. 214*da58b97aSjoergfunction(llvm_distribution_add_targets) 215*da58b97aSjoerg set(distributions "${LLVM_DISTRIBUTIONS}") 216*da58b97aSjoerg if(NOT distributions) 217*da58b97aSjoerg # CMake seemingly doesn't distinguish between an empty list and a list 218*da58b97aSjoerg # containing one element which is the empty string, so just use a special 219*da58b97aSjoerg # marker to denote the default (unnamed) distribution and fix it in the 220*da58b97aSjoerg # loop. 221*da58b97aSjoerg set(distributions "<DEFAULT>") 222*da58b97aSjoerg endif() 223*da58b97aSjoerg 224*da58b97aSjoerg foreach(distribution ${distributions}) 225*da58b97aSjoerg if(distribution STREQUAL "<DEFAULT>") 226*da58b97aSjoerg set(distribution_target distribution) 227*da58b97aSjoerg # Preserve legacy behavior for LLVM_DISTRIBUTION_COMPONENTS. 228*da58b97aSjoerg set(distribution_components ${LLVM_DISTRIBUTION_COMPONENTS} ${LLVM_RUNTIME_DISTRIBUTION_COMPONENTS}) 229*da58b97aSjoerg else() 230*da58b97aSjoerg string(TOLOWER "${distribution}" distribution_lower) 231*da58b97aSjoerg set(distribution_target ${distribution_lower}-distribution) 232*da58b97aSjoerg set(distribution_components ${LLVM_${distribution}_DISTRIBUTION_COMPONENTS}) 233*da58b97aSjoerg endif() 234*da58b97aSjoerg 235*da58b97aSjoerg add_custom_target(${distribution_target}) 236*da58b97aSjoerg add_custom_target(install-${distribution_target}) 237*da58b97aSjoerg add_custom_target(install-${distribution_target}-stripped) 238*da58b97aSjoerg 239*da58b97aSjoerg foreach(target ${distribution_components}) 24006f32e7eSjoerg if(TARGET ${target}) 241*da58b97aSjoerg add_dependencies(${distribution_target} ${target}) 24206f32e7eSjoerg else() 24306f32e7eSjoerg message(SEND_ERROR "Specified distribution component '${target}' doesn't have a target") 24406f32e7eSjoerg endif() 24506f32e7eSjoerg 24606f32e7eSjoerg if(TARGET install-${target}) 247*da58b97aSjoerg add_dependencies(install-${distribution_target} install-${target}) 24806f32e7eSjoerg else() 24906f32e7eSjoerg message(SEND_ERROR "Specified distribution component '${target}' doesn't have an install target") 25006f32e7eSjoerg endif() 25106f32e7eSjoerg 25206f32e7eSjoerg if(TARGET install-${target}-stripped) 253*da58b97aSjoerg add_dependencies(install-${distribution_target}-stripped install-${target}-stripped) 25406f32e7eSjoerg else() 25506f32e7eSjoerg message(SEND_ERROR 25606f32e7eSjoerg "Specified distribution component '${target}' doesn't have an install-stripped target." 25706f32e7eSjoerg " Its installation target creation should be changed to use add_llvm_install_targets," 25806f32e7eSjoerg " or you should manually create the 'install-${target}-stripped' target.") 25906f32e7eSjoerg endif() 26006f32e7eSjoerg endforeach() 261*da58b97aSjoerg endforeach() 26206f32e7eSjoergendfunction() 263