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() |