Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 14 | pmbaty | 1 | # Utility functions for packaging an LLVM distribution. See the |
| 2 | # BuildingADistribution documentation for more details. |
||
| 3 | |||
| 4 | # These functions assume a number of conventions that are common across all LLVM |
||
| 5 | # subprojects: |
||
| 6 | # - The generated CMake exports file for ${project} is called ${project}Targets |
||
| 7 | # (except for LLVM where it's called ${project}Exports for legacy reasons). |
||
| 8 | # - The build target for the CMake exports is called ${project}-cmake-exports |
||
| 9 | # (except LLVM where it's just cmake-exports). |
||
| 10 | # - The ${PROJECT}${distribution}_HAS_EXPORTS global property holds whether a |
||
| 11 | # project has any exports for a particular ${distribution} (where ${PROJECT} |
||
| 12 | # is the project name in uppercase). |
||
| 13 | # - The ${PROJECT}_CMAKE_DIR variable is computed by ${project}Config.cmake to |
||
| 14 | # hold the path of the installed CMake modules directory. |
||
| 15 | # - The ${PROJECT}_INSTALL_PACKAGE_DIR variable contains the install destination |
||
| 16 | # for the project's CMake modules. |
||
| 17 | |||
| 18 | include_guard(GLOBAL) |
||
| 19 | |||
| 20 | if(LLVM_DISTRIBUTION_COMPONENTS AND LLVM_DISTRIBUTIONS) |
||
| 21 | message(FATAL_ERROR "LLVM_DISTRIBUTION_COMPONENTS and LLVM_DISTRIBUTIONS cannot be specified together") |
||
| 22 | endif() |
||
| 23 | |||
| 24 | if(LLVM_DISTRIBUTION_COMPONENTS OR LLVM_DISTRIBUTIONS) |
||
| 25 | if(LLVM_ENABLE_IDE) |
||
| 26 | message(FATAL_ERROR "LLVM_DISTRIBUTION_COMPONENTS cannot be specified with multi-configuration generators (i.e. Xcode or Visual Studio)") |
||
| 27 | endif() |
||
| 28 | endif() |
||
| 29 | |||
| 30 | # Build the map of targets to distributions that's used to look up the |
||
| 31 | # distribution for a target later. The distribution for ${target} is stored in |
||
| 32 | # the global property LLVM_DISTRIBUTION_FOR_${target}. |
||
| 33 | function(llvm_distribution_build_target_map) |
||
| 34 | foreach(target ${LLVM_DISTRIBUTION_COMPONENTS}) |
||
| 35 | # CMake doesn't easily distinguish between properties that are unset and |
||
| 36 | # properties that are empty (you have to do a second get_property call with |
||
| 37 | # the SET option, which is unergonomic), so just use a special marker to |
||
| 38 | # denote the default (unnamed) distribution. |
||
| 39 | set_property(GLOBAL PROPERTY LLVM_DISTRIBUTION_FOR_${target} "<DEFAULT>") |
||
| 40 | endforeach() |
||
| 41 | |||
| 42 | foreach(distribution ${LLVM_DISTRIBUTIONS}) |
||
| 43 | foreach(target ${LLVM_${distribution}_DISTRIBUTION_COMPONENTS}) |
||
| 44 | # By default, we allow a target to be in multiple distributions, and use |
||
| 45 | # the last one to determine its export set. We disallow this in strict |
||
| 46 | # mode, emitting a single error at the end for readability. |
||
| 47 | if(LLVM_STRICT_DISTRIBUTIONS) |
||
| 48 | get_property(current_distribution GLOBAL PROPERTY LLVM_DISTRIBUTION_FOR_${target}) |
||
| 49 | if(current_distribution AND NOT current_distribution STREQUAL distribution) |
||
| 50 | set_property(GLOBAL APPEND_STRING PROPERTY LLVM_DISTRIBUTION_ERRORS |
||
| 51 | "Target ${target} cannot be in multiple distributions \ |
||
| 52 | ${distribution} and ${current_distribution}\n" |
||
| 53 | ) |
||
| 54 | endif() |
||
| 55 | endif() |
||
| 56 | set_property(GLOBAL PROPERTY LLVM_DISTRIBUTION_FOR_${target} ${distribution}) |
||
| 57 | endforeach() |
||
| 58 | endforeach() |
||
| 59 | endfunction() |
||
| 60 | |||
| 61 | # The include guard ensures this will only be called once. The rest of this file |
||
| 62 | # only defines other functions (i.e. it doesn't execute any more code directly). |
||
| 63 | llvm_distribution_build_target_map() |
||
| 64 | |||
| 65 | # Look up the distribution a particular target belongs to. |
||
| 66 | # - target: The target to look up. |
||
| 67 | # - in_distribution_var: The variable with this name is set in the caller's |
||
| 68 | # scope to indicate if the target is in any distribution. If no distributions |
||
| 69 | # have been configured, this will always be set to true. |
||
| 70 | # - distribution_var: The variable with this name is set in the caller's scope |
||
| 71 | # to indicate the distribution name for the target. If the target belongs to |
||
| 72 | # the default (unnamed) distribution, or if no distributions have been |
||
| 73 | # configured, it's set to the empty string. |
||
| 74 | # - UMBRELLA: The (optional) umbrella target that the target is a part of. For |
||
| 75 | # example, all LLVM libraries have the umbrella target llvm-libraries. |
||
| 76 | function(get_llvm_distribution target in_distribution_var distribution_var) |
||
| 77 | if(NOT LLVM_DISTRIBUTION_COMPONENTS AND NOT LLVM_DISTRIBUTIONS) |
||
| 78 | set(${in_distribution_var} YES PARENT_SCOPE) |
||
| 79 | set(${distribution_var} "" PARENT_SCOPE) |
||
| 80 | return() |
||
| 81 | endif() |
||
| 82 | |||
| 83 | cmake_parse_arguments(ARG "" UMBRELLA "" ${ARGN}) |
||
| 84 | get_property(distribution GLOBAL PROPERTY LLVM_DISTRIBUTION_FOR_${target}) |
||
| 85 | if(ARG_UMBRELLA) |
||
| 86 | get_property(umbrella_distribution GLOBAL PROPERTY LLVM_DISTRIBUTION_FOR_${ARG_UMBRELLA}) |
||
| 87 | if(LLVM_STRICT_DISTRIBUTIONS AND distribution AND umbrella_distribution AND |
||
| 88 | NOT distribution STREQUAL umbrella_distribution) |
||
| 89 | set_property(GLOBAL APPEND_STRING PROPERTY LLVM_DISTRIBUTION_ERRORS |
||
| 90 | "Target ${target} has different distribution ${distribution} from its \ |
||
| 91 | umbrella target's (${ARG_UMBRELLA}) distribution ${umbrella_distribution}\n" |
||
| 92 | ) |
||
| 93 | endif() |
||
| 94 | if(NOT distribution) |
||
| 95 | set(distribution ${umbrella_distribution}) |
||
| 96 | endif() |
||
| 97 | endif() |
||
| 98 | |||
| 99 | if(distribution) |
||
| 100 | set(${in_distribution_var} YES PARENT_SCOPE) |
||
| 101 | if(distribution STREQUAL "<DEFAULT>") |
||
| 102 | set(distribution "") |
||
| 103 | endif() |
||
| 104 | set(${distribution_var} "${distribution}" PARENT_SCOPE) |
||
| 105 | else() |
||
| 106 | set(${in_distribution_var} NO PARENT_SCOPE) |
||
| 107 | endif() |
||
| 108 | endfunction() |
||
| 109 | |||
| 110 | # Get the EXPORT argument to use for an install command for a target in a |
||
| 111 | # project. As explained at the top of the file, the project export set for a |
||
| 112 | # distribution is named ${project}{distribution}Targets (except for LLVM where |
||
| 113 | # it's named ${project}{distribution}Exports for legacy reasons). Also set the |
||
| 114 | # ${PROJECT}_${DISTRIBUTION}_HAS_EXPORTS global property to mark the project as |
||
| 115 | # having exports for the distribution. |
||
| 116 | # - target: The target to get the EXPORT argument for. |
||
| 117 | # - project: The project to produce the argument for. IMPORTANT: The casing of |
||
| 118 | # this argument should match the casing used by the project's Config.cmake |
||
| 119 | # file. The correct casing for the LLVM projects is Clang, Flang, LLD, LLVM, |
||
| 120 | # and MLIR. |
||
| 121 | # - export_arg_var The variable with this name is set in the caller's scope to |
||
| 122 | # the EXPORT argument for the target for the project. |
||
| 123 | # - UMBRELLA: The (optional) umbrella target that the target is a part of. For |
||
| 124 | # example, all LLVM libraries have the umbrella target llvm-libraries. |
||
| 125 | function(get_target_export_arg target project export_arg_var) |
||
| 126 | string(TOUPPER "${project}" project_upper) |
||
| 127 | if(project STREQUAL "LLVM") |
||
| 128 | set(suffix "Exports") # legacy |
||
| 129 | else() |
||
| 130 | set(suffix "Targets") |
||
| 131 | endif() |
||
| 132 | |||
| 133 | get_llvm_distribution(${target} in_distribution distribution ${ARGN}) |
||
| 134 | |||
| 135 | if(in_distribution) |
||
| 136 | set(${export_arg_var} EXPORT ${project}${distribution}${suffix} PARENT_SCOPE) |
||
| 137 | if(distribution) |
||
| 138 | string(TOUPPER "${distribution}" distribution_upper) |
||
| 139 | set_property(GLOBAL PROPERTY ${project_upper}_${distribution_upper}_HAS_EXPORTS True) |
||
| 140 | else() |
||
| 141 | set_property(GLOBAL PROPERTY ${project_upper}_HAS_EXPORTS True) |
||
| 142 | endif() |
||
| 143 | else() |
||
| 144 | set(${export_arg_var} "" PARENT_SCOPE) |
||
| 145 | endif() |
||
| 146 | endfunction() |
||
| 147 | |||
| 148 | # Produce a string of CMake include() commands to include the exported targets |
||
| 149 | # files for all distributions. See the comment at the top of this file for |
||
| 150 | # various assumptions made. |
||
| 151 | # - project: The project to produce the commands for. IMPORTANT: See the comment |
||
| 152 | # for get_target_export_arg above for the correct casing of this argument. |
||
| 153 | # - includes_var: The variable with this name is set in the caller's scope to |
||
| 154 | # the string of include commands. |
||
| 155 | function(get_config_exports_includes project includes_var) |
||
| 156 | string(TOUPPER "${project}" project_upper) |
||
| 157 | set(prefix "\${${project_upper}_CMAKE_DIR}/${project}") |
||
| 158 | if(project STREQUAL "LLVM") |
||
| 159 | set(suffix "Exports.cmake") # legacy |
||
| 160 | else() |
||
| 161 | set(suffix "Targets.cmake") |
||
| 162 | endif() |
||
| 163 | |||
| 164 | if(NOT LLVM_DISTRIBUTIONS) |
||
| 165 | set(${includes_var} "include(\"${prefix}${suffix}\")" PARENT_SCOPE) |
||
| 166 | else() |
||
| 167 | set(includes) |
||
| 168 | foreach(distribution ${LLVM_DISTRIBUTIONS}) |
||
| 169 | list(APPEND includes "include(\"${prefix}${distribution}${suffix}\" OPTIONAL)") |
||
| 170 | endforeach() |
||
| 171 | string(REPLACE ";" "\n" includes "${includes}") |
||
| 172 | set(${includes_var} "${includes}" PARENT_SCOPE) |
||
| 173 | endif() |
||
| 174 | endfunction() |
||
| 175 | |||
| 176 | # Create the install commands and targets for the distributions' CMake exports. |
||
| 177 | # The target to install ${distribution} for a project is called |
||
| 178 | # ${project}-${distribution}-cmake-exports, where ${project} is the project name |
||
| 179 | # in lowercase and ${distribution} is the distribution name in lowercase, except |
||
| 180 | # for LLVM, where the target is just called ${distribution}-cmake-exports. See |
||
| 181 | # the comment at the top of this file for various assumptions made. |
||
| 182 | # - project: The project. IMPORTANT: See the comment for get_target_export_arg |
||
| 183 | # above for the correct casing of this argument. |
||
| 184 | function(install_distribution_exports project) |
||
| 185 | string(TOUPPER "${project}" project_upper) |
||
| 186 | string(TOLOWER "${project}" project_lower) |
||
| 187 | if(project STREQUAL "LLVM") |
||
| 188 | set(prefix "") |
||
| 189 | set(suffix "Exports") # legacy |
||
| 190 | else() |
||
| 191 | set(prefix "${project_lower}-") |
||
| 192 | set(suffix "Targets") |
||
| 193 | endif() |
||
| 194 | set(destination "${${project_upper}_INSTALL_PACKAGE_DIR}") |
||
| 195 | |||
| 196 | if(NOT LLVM_DISTRIBUTIONS) |
||
| 197 | get_property(has_exports GLOBAL PROPERTY ${project_upper}_HAS_EXPORTS) |
||
| 198 | if(has_exports) |
||
| 199 | install(EXPORT ${project}${suffix} DESTINATION "${destination}" |
||
| 200 | COMPONENT ${prefix}cmake-exports) |
||
| 201 | endif() |
||
| 202 | else() |
||
| 203 | foreach(distribution ${LLVM_DISTRIBUTIONS}) |
||
| 204 | string(TOUPPER "${distribution}" distribution_upper) |
||
| 205 | get_property(has_exports GLOBAL PROPERTY ${project_upper}_${distribution_upper}_HAS_EXPORTS) |
||
| 206 | if(has_exports) |
||
| 207 | string(TOLOWER "${distribution}" distribution_lower) |
||
| 208 | set(target ${prefix}${distribution_lower}-cmake-exports) |
||
| 209 | install(EXPORT ${project}${distribution}${suffix} DESTINATION "${destination}" |
||
| 210 | COMPONENT ${target}) |
||
| 211 | if(NOT LLVM_ENABLE_IDE) |
||
| 212 | add_custom_target(${target}) |
||
| 213 | add_llvm_install_targets(install-${target} COMPONENT ${target}) |
||
| 214 | endif() |
||
| 215 | endif() |
||
| 216 | endforeach() |
||
| 217 | endif() |
||
| 218 | endfunction() |
||
| 219 | |||
| 220 | # Create the targets for installing the configured distributions. The |
||
| 221 | # ${distribution} target builds the distribution, install-${distribution} |
||
| 222 | # installs it, and install-${distribution}-stripped installs a stripped version, |
||
| 223 | # where ${distribution} is the distribution name in lowercase, or "distribution" |
||
| 224 | # for the default distribution. |
||
| 225 | function(llvm_distribution_add_targets) |
||
| 226 | # This function is called towards the end of LLVM's CMakeLists.txt, so all |
||
| 227 | # errors will have been seen by now. |
||
| 228 | if(LLVM_STRICT_DISTRIBUTIONS) |
||
| 229 | get_property(errors GLOBAL PROPERTY LLVM_DISTRIBUTION_ERRORS) |
||
| 230 | if(errors) |
||
| 231 | string(PREPEND errors |
||
| 232 | "Strict distribution errors (turn off LLVM_STRICT_DISTRIBUTIONS to bypass):\n" |
||
| 233 | ) |
||
| 234 | message(FATAL_ERROR "${errors}") |
||
| 235 | endif() |
||
| 236 | endif() |
||
| 237 | |||
| 238 | set(distributions "${LLVM_DISTRIBUTIONS}") |
||
| 239 | if(NOT distributions) |
||
| 240 | # CMake seemingly doesn't distinguish between an empty list and a list |
||
| 241 | # containing one element which is the empty string, so just use a special |
||
| 242 | # marker to denote the default (unnamed) distribution and fix it in the |
||
| 243 | # loop. |
||
| 244 | set(distributions "<DEFAULT>") |
||
| 245 | endif() |
||
| 246 | |||
| 247 | get_property(LLVM_DRIVER_TOOL_SYMLINKS GLOBAL PROPERTY LLVM_DRIVER_TOOL_SYMLINKS) |
||
| 248 | |||
| 249 | foreach(distribution ${distributions}) |
||
| 250 | if(distribution STREQUAL "<DEFAULT>") |
||
| 251 | set(distribution_target distribution) |
||
| 252 | # Preserve legacy behavior for LLVM_DISTRIBUTION_COMPONENTS. |
||
| 253 | set(distribution_components ${LLVM_DISTRIBUTION_COMPONENTS} ${LLVM_RUNTIME_DISTRIBUTION_COMPONENTS}) |
||
| 254 | else() |
||
| 255 | string(TOLOWER "${distribution}" distribution_lower) |
||
| 256 | set(distribution_target ${distribution_lower}-distribution) |
||
| 257 | set(distribution_components ${LLVM_${distribution}_DISTRIBUTION_COMPONENTS}) |
||
| 258 | endif() |
||
| 259 | |||
| 260 | add_custom_target(${distribution_target}) |
||
| 261 | add_custom_target(install-${distribution_target}) |
||
| 262 | add_custom_target(install-${distribution_target}-stripped) |
||
| 263 | |||
| 264 | foreach(target ${distribution_components}) |
||
| 265 | # Note that some distribution components may not have an actual target, but only an install-FOO target. |
||
| 266 | # This happens for example if a target is an INTERFACE target. |
||
| 267 | if(TARGET ${target}) |
||
| 268 | add_dependencies(${distribution_target} ${target}) |
||
| 269 | endif() |
||
| 270 | |||
| 271 | if(TARGET install-${target}) |
||
| 272 | add_dependencies(install-${distribution_target} install-${target}) |
||
| 273 | elseif(TARGET install-llvm-driver AND ${target} IN_LIST LLVM_DRIVER_TOOL_SYMLINKS) |
||
| 274 | add_dependencies(install-${distribution_target} install-llvm-driver) |
||
| 275 | else() |
||
| 276 | message(SEND_ERROR "Specified distribution component '${target}' doesn't have an install target") |
||
| 277 | endif() |
||
| 278 | |||
| 279 | if(TARGET install-${target}-stripped) |
||
| 280 | add_dependencies(install-${distribution_target}-stripped install-${target}-stripped) |
||
| 281 | elseif(TARGET install-llvm-driver-stripped AND ${target} IN_LIST LLVM_DRIVER_TOOL_SYMLINKS) |
||
| 282 | add_dependencies(install-${distribution_target}-stripped install-llvm-driver-stripped) |
||
| 283 | else() |
||
| 284 | message(SEND_ERROR |
||
| 285 | "Specified distribution component '${target}' doesn't have an install-stripped target." |
||
| 286 | " Its installation target creation should be changed to use add_llvm_install_targets," |
||
| 287 | " or you should manually create the 'install-${target}-stripped' target.") |
||
| 288 | endif() |
||
| 289 | endforeach() |
||
| 290 | endforeach() |
||
| 291 | endfunction() |