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