diff --git a/clang/cmake/caches/MultiDistributionExample.cmake b/clang/cmake/caches/MultiDistributionExample.cmake new file mode 100644 --- /dev/null +++ b/clang/cmake/caches/MultiDistributionExample.cmake @@ -0,0 +1,74 @@ +# This file sets up a CMakeCache for a simple build with multiple distributions. +# Note that for a real distribution, you likely want to perform a boostrap +# build; see clang/cmake/caches/DistributionExample.cmake and the +# BuildingADistribution documentation for details. This cache file doesn't +# demonstrate bootstrapping so it can focus on the configuration details +# specific to multiple distributions instead. + +# Build an optimized toolchain for an example set of targets. +set(CMAKE_BUILD_TYPE Release CACHE STRING "") +set(LLVM_TARGETS_TO_BUILD + AArch64 + ARM + X86 + CACHE STRING "") + +# Enable the LLVM projects and runtimes. +set(LLVM_ENABLE_PROJECTS + clang + lld + CACHE STRING "") +set(LLVM_ENABLE_RUNTIMES + compiler-rt + libcxx + libcxxabi + CACHE STRING "") + +# We'll build two distributions: Toolchain, which just holds the tools +# (intended for most end users), and Development, which has libraries (for end +# users who wish to develop their own tooling using those libraries). This will +# produce the install-toolchain-distribution and install-development-distribution +# targets to install the distributions. +set(LLVM_DISTRIBUTIONS + Toolchain + Development + CACHE STRING "") + +# We want to include the C++ headers in our distribution. +set(LLVM_RUNTIME_DISTRIBUTION_COMPONENTS + cxx-headers + CACHE STRING "") + +# You likely want more tools; this is just an example :) Note that we need to +# include cxx-headers explicitly here (in addition to it being added to +# LLVM_RUNTIME_DISTRIBUTION_COMPONENTS above). +set(LLVM_Toolchain_DISTRIBUTION_COMPONENTS + builtins + clang + clang-resource-headers + cxx-headers + lld + llvm-objdump + CACHE STRING "") + +# Note that we need to include the CMake exports targets for the distribution +# (development-cmake-exports and clang-development-cmake-exports), as well as +# the general CMake exports target for each project (cmake-exports and +# clang-cmake-exports), in our list of targets. The distribution CMake exports +# targets just install the CMake exports file for the distribution's targets, +# whereas the project CMake exports targets install the rest of the project's +# CMake exports (which are needed in order to import the project from other +# CMake_projects via find_package, and include the distribution's CMake exports +# file to get the exported targets). +set(LLVM_Development_DISTRIBUTION_COMPONENTS + # LLVM + cmake-exports + development-cmake-exports + llvm-headers + llvm-libraries + # Clang + clang-cmake-exports + clang-development-cmake-exports + clang-headers + clang-libraries + CACHE STRING "") diff --git a/clang/cmake/modules/AddClang.cmake b/clang/cmake/modules/AddClang.cmake --- a/clang/cmake/modules/AddClang.cmake +++ b/clang/cmake/modules/AddClang.cmake @@ -1,3 +1,5 @@ +include(LLVMDistributionSupport) + function(clang_tablegen) # Syntax: # clang_tablegen output-file [tablegen-arg ...] SOURCE source-file @@ -113,11 +115,10 @@ if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY OR ARG_INSTALL_WITH_TOOLCHAIN) set(export_to_clangtargets) - if(${lib} IN_LIST LLVM_DISTRIBUTION_COMPONENTS OR - "clang-libraries" IN_LIST LLVM_DISTRIBUTION_COMPONENTS OR - NOT LLVM_DISTRIBUTION_COMPONENTS) - set(export_to_clangtargets EXPORT ClangTargets) - set_property(GLOBAL PROPERTY CLANG_HAS_EXPORTS True) + get_llvm_distribution(${name} in_distribution distribution UMBRELLA clang-libraries) + if(in_distribution) + set(export_to_clangtargets EXPORT Clang${distribution}Targets) + set_property(GLOBAL PROPERTY CLANG${distribution}_HAS_EXPORTS True) endif() install(TARGETS ${lib} @@ -162,10 +163,10 @@ if (CLANG_BUILD_TOOLS) set(export_to_clangtargets) - if(${name} IN_LIST LLVM_DISTRIBUTION_COMPONENTS OR - NOT LLVM_DISTRIBUTION_COMPONENTS) - set(export_to_clangtargets EXPORT ClangTargets) - set_property(GLOBAL PROPERTY CLANG_HAS_EXPORTS True) + get_llvm_distribution(${name} in_distribution distribution) + if(in_distribution) + set(export_to_clangtargets EXPORT Clang${distribution}Targets) + set_property(GLOBAL PROPERTY CLANG${distribution}_HAS_EXPORTS True) endif() install(TARGETS ${name} diff --git a/clang/cmake/modules/CMakeLists.txt b/clang/cmake/modules/CMakeLists.txt --- a/clang/cmake/modules/CMakeLists.txt +++ b/clang/cmake/modules/CMakeLists.txt @@ -1,3 +1,5 @@ +include(LLVMDistributionSupport) + # Generate a list of CMake library targets so that other CMake projects can # link against them. LLVM calls its version of this file LLVMExports.cmake, but # the usual CMake convention seems to be ${Project}Targets.cmake. @@ -14,7 +16,7 @@ # Generate ClangConfig.cmake for the build tree. set(CLANG_CONFIG_CMAKE_DIR "${clang_cmake_builddir}") set(CLANG_CONFIG_LLVM_CMAKE_DIR "${llvm_cmake_builddir}") -set(CLANG_CONFIG_EXPORTS_FILE "${clang_cmake_builddir}/ClangTargets.cmake") +set(clang_config_include_exports "include(\"${clang_cmake_builddir}/ClangTargets.cmake\")") set(CLANG_CONFIG_INCLUDE_DIRS "${CLANG_SOURCE_DIR}/include" "${CLANG_BINARY_DIR}/include" @@ -25,7 +27,6 @@ @ONLY) set(CLANG_CONFIG_CMAKE_DIR) set(CLANG_CONFIG_LLVM_CMAKE_DIR) -set(CLANG_CONFIG_EXPORTS_FILE) # Generate ClangConfig.cmake for the install tree. set(CLANG_CONFIG_CODE " @@ -40,7 +41,7 @@ endforeach(p) set(CLANG_CONFIG_CMAKE_DIR "\${CLANG_INSTALL_PREFIX}/${CLANG_INSTALL_PACKAGE_DIR}") set(CLANG_CONFIG_LLVM_CMAKE_DIR "\${CLANG_INSTALL_PREFIX}/${LLVM_INSTALL_PACKAGE_DIR}") -set(CLANG_CONFIG_EXPORTS_FILE "\${CLANG_CMAKE_DIR}/ClangTargets.cmake") +get_config_exports_includes(Clang clang_config_include_exports) set(CLANG_CONFIG_INCLUDE_DIRS "\${CLANG_INSTALL_PREFIX}/include" ) @@ -50,14 +51,9 @@ @ONLY) set(CLANG_CONFIG_CODE) set(CLANG_CONFIG_CMAKE_DIR) -set(CLANG_CONFIG_EXPORTS_FILE) if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY) - get_property(clang_has_exports GLOBAL PROPERTY CLANG_HAS_EXPORTS) - if(clang_has_exports) - install(EXPORT ClangTargets DESTINATION ${CLANG_INSTALL_PACKAGE_DIR} - COMPONENT clang-cmake-exports) - endif() + install_distribution_exports(Clang) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/ClangConfig.cmake diff --git a/clang/cmake/modules/ClangConfig.cmake.in b/clang/cmake/modules/ClangConfig.cmake.in --- a/clang/cmake/modules/ClangConfig.cmake.in +++ b/clang/cmake/modules/ClangConfig.cmake.in @@ -11,7 +11,7 @@ set(CLANG_LINK_CLANG_DYLIB "@CLANG_LINK_CLANG_DYLIB@") # Provide all our library targets to users. -include("@CLANG_CONFIG_EXPORTS_FILE@") +@clang_config_include_exports@ # By creating clang-tablegen-targets here, subprojects that depend on Clang's # tablegen-generated headers can always depend on this target whether building diff --git a/flang/cmake/modules/AddFlang.cmake b/flang/cmake/modules/AddFlang.cmake --- a/flang/cmake/modules/AddFlang.cmake +++ b/flang/cmake/modules/AddFlang.cmake @@ -1,3 +1,5 @@ +include(LLVMDistributionSupport) + macro(set_flang_windows_version_resource_properties name) if (DEFINED windows_resource_file) set_windows_version_resource_properties(${name} ${windows_resource_file} @@ -64,11 +66,10 @@ if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY OR ${name} STREQUAL "libflang") set(export_to_flangtargets) - if (${name} IN_LIST LLVM_DISTRIBUTION_COMPONENTS OR - "flang-libraries" IN_LIST LLVM_DISTRIBUTION_COMPONENTS OR - NOT LLVM_DISTRIBUTION_COMPONENTS) - set(export_to_flangtargets EXPORT FlangTargets) - set_property(GLOBAL PROPERTY FLANG_HAS_EXPORTS True) + get_llvm_distribution(${name} in_distribution distribution UMBRELLA flang-libraries) + if (in_distribution) + set(export_to_flangtargets EXPORT Flang${distribution}Targets) + set_property(GLOBAL PROPERTY FLANG${distribution}_HAS_EXPORTS True) endif() install(TARGETS ${name} @@ -111,10 +112,10 @@ if (FLANG_BUILD_TOOLS) set(export_to_flangtargets) - if (${name} IN_LIST LLVM_DISTRIBUTION_COMPONENTS OR - NOT LLVM_DISTRIBUTION_COMPONENTS) - set(export_to_flangtargets EXPORT FlangTargets) - set_property(GLOBAL PROPERTY FLANG_HAS_EXPORTS True) + get_llvm_distribution(${name} in_distribution distribution) + if (in_distribution) + set(export_to_flangtargets EXPORT Flang${distribution}Targets) + set_property(GLOBAL PROPERTY FLANG${distribution}_HAS_EXPORTS True) endif() install(TARGETS ${name} diff --git a/flang/cmake/modules/CMakeLists.txt b/flang/cmake/modules/CMakeLists.txt --- a/flang/cmake/modules/CMakeLists.txt +++ b/flang/cmake/modules/CMakeLists.txt @@ -14,7 +14,7 @@ # Generate FlangConfig.cmake for the build tree. set(FLANG_CONFIG_CMAKE_DIR "${flang_cmake_builddir}") set(FLANG_CONFIG_LLVM_CMAKE_DIR "${llvm_cmake_builddir}") -set(FLANG_CONFIG_EXPORTS_FILE "${flang_cmake_builddir}/FlangTargets.cmake") +set(flang_config_include_exports "include(\"${flang_cmake_builddir}/FlangTargets.cmake\")") set(FLANG_CONFIG_INCLUDE_DIRS "${FLANG_SOURCE_DIR}/include" "${FLANG_BINARY_DIR}/include" @@ -25,7 +25,6 @@ @ONLY) set(FLANG_CONFIG_CMAKE_DIR) set(FLANG_CONFIG_LLVM_CMAKE_DIR) -set(FLANG_CONFIG_EXPORTS_FILE) # Generate FlangConfig.cmake for the install tree. set(FLANG_CONFIG_CODE " @@ -41,7 +40,7 @@ set(FLANG_CONFIG_CMAKE_DIR "\${FLANG_INSTALL_PREFIX}/${FLANG_INSTALL_PACKAGE_DIR}") set(FLANG_CONFIG_LLVM_CMAKE_DIR "\${FLANG_INSTALL_PREFIX}/${LLVM_INSTALL_PACKAGE_DIR}") -set(FLANG_CONFIG_EXPORTS_FILE "\${FLANG_CMAKE_DIR}/FlangTargets.cmake") +get_config_exports_includes(Flang flang_config_include_exports) set(FLANG_CONFIG_INCLUDE_DIRS "\${FLANG_INSTALL_PREFIX}/include") configure_file( @@ -54,11 +53,7 @@ set(FLANG_CONFIG_EXPORTS_FILE) if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY) - get_property(flang_has_exports GLOBAL PROPERTY FLANG_HAS_EXPORTS) - if(flang_has_exports) - install(EXPORT FlangTargets DESTINATION ${FLANG_INSTALL_PACKAGE_DIR} - COMPONENT flang-cmake-exports) - endif() + install_distribution_exports(Flang) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/FlangConfig.cmake diff --git a/flang/cmake/modules/FlangConfig.cmake.in b/flang/cmake/modules/FlangConfig.cmake.in --- a/flang/cmake/modules/FlangConfig.cmake.in +++ b/flang/cmake/modules/FlangConfig.cmake.in @@ -10,4 +10,4 @@ set(FLANG_INCLUDE_DIRS "@FLANG_CONFIG_INCLUDE_DIRS@") # Provide all our library targets to users. -include("@FLANG_CONFIG_EXPORTS_FILE@") +@flang_config_include_exports@ diff --git a/lld/cmake/modules/AddLLD.cmake b/lld/cmake/modules/AddLLD.cmake --- a/lld/cmake/modules/AddLLD.cmake +++ b/lld/cmake/modules/AddLLD.cmake @@ -1,3 +1,5 @@ +include(LLVMDistributionSupport) + macro(add_lld_library name) cmake_parse_arguments(ARG "SHARED" @@ -11,10 +13,10 @@ set_target_properties(${name} PROPERTIES FOLDER "lld libraries") if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY) - if(${name} IN_LIST LLVM_DISTRIBUTION_COMPONENTS OR - NOT LLVM_DISTRIBUTION_COMPONENTS) - set(export_to_lldtargets EXPORT LLDTargets) - set_property(GLOBAL PROPERTY LLD_HAS_EXPORTS True) + get_llvm_distribution(${name} in_distribution distribution) + if(in_distribution) + set(export_to_lldtargets EXPORT LLD${distribution}Targets) + set_property(GLOBAL PROPERTY LLD${distribution}_HAS_EXPORTS True) endif() install(TARGETS ${name} @@ -46,10 +48,10 @@ add_lld_executable(${name} ${ARGN}) if (LLD_BUILD_TOOLS) - if(${name} IN_LIST LLVM_DISTRIBUTION_COMPONENTS OR - NOT LLVM_DISTRIBUTION_COMPONENTS) - set(export_to_lldtargets EXPORT LLDTargets) - set_property(GLOBAL PROPERTY LLD_HAS_EXPORTS True) + get_llvm_distribution(${name} in_distribution distribution) + if(in_distribution) + set(export_to_lldtargets EXPORT LLD${distribution}Targets) + set_property(GLOBAL PROPERTY LLD${distribution}_HAS_EXPORTS True) endif() install(TARGETS ${name} diff --git a/lld/cmake/modules/CMakeLists.txt b/lld/cmake/modules/CMakeLists.txt --- a/lld/cmake/modules/CMakeLists.txt +++ b/lld/cmake/modules/CMakeLists.txt @@ -14,7 +14,7 @@ # Generate LLDConfig.cmake for the build tree. set(LLD_CONFIG_CMAKE_DIR "${lld_cmake_builddir}") set(LLD_CONFIG_LLVM_CMAKE_DIR "${llvm_cmake_builddir}") -set(LLD_CONFIG_EXPORTS_FILE "${lld_cmake_builddir}/LLDTargets.cmake") +set(lld_config_include_exports "include(\"${lld_cmake_builddir}/LLDTargets.cmake\")") set(LLD_CONFIG_INCLUDE_DIRS "${LLD_SOURCE_DIR}/include" "${LLD_BINARY_DIR}/include" @@ -25,7 +25,6 @@ @ONLY) set(LLD_CONFIG_CMAKE_DIR) set(LLD_CONFIG_LLVM_CMAKE_DIR) -set(LLD_CONFIG_EXPORTS_FILE) # Generate LLDConfig.cmake for the install tree. set(LLD_CONFIG_CODE " @@ -40,7 +39,7 @@ endforeach(p) set(LLD_CONFIG_CMAKE_DIR "\${LLD_INSTALL_PREFIX}/${LLD_INSTALL_PACKAGE_DIR}") set(LLD_CONFIG_LLVM_CMAKE_DIR "\${LLD_INSTALL_PREFIX}/${LLVM_INSTALL_PACKAGE_DIR}") -set(LLD_CONFIG_EXPORTS_FILE "\${LLD_CMAKE_DIR}/LLDTargets.cmake") +get_config_exports_includes(LLD lld_config_include_exports) set(LLD_CONFIG_INCLUDE_DIRS "\${LLD_INSTALL_PREFIX}/include") configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/LLDConfig.cmake.in @@ -48,14 +47,9 @@ @ONLY) set(LLD_CONFIG_CODE) set(LLD_CONFIG_CMAKE_DIR) -set(LLD_CONFIG_EXPORTS_FILE) if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY) - get_property(lld_has_exports GLOBAL PROPERTY LLD_HAS_EXPORTS) - if(lld_has_exports) - install(EXPORT LLDTargets DESTINATION ${LLD_INSTALL_PACKAGE_DIR} - COMPONENT lld-cmake-exports) - endif() + install_distribution_exports(LLD) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/LLDConfig.cmake diff --git a/lld/cmake/modules/LLDConfig.cmake.in b/lld/cmake/modules/LLDConfig.cmake.in --- a/lld/cmake/modules/LLDConfig.cmake.in +++ b/lld/cmake/modules/LLDConfig.cmake.in @@ -10,4 +10,4 @@ set(LLD_INCLUDE_DIRS "@LLD_CONFIG_INCLUDE_DIRS@") # Provide all our library targets to users. -include("@LLD_CONFIG_EXPORTS_FILE@") +@lld_config_include_exports@ diff --git a/llvm/cmake/modules/AddLLVM.cmake b/llvm/cmake/modules/AddLLVM.cmake --- a/llvm/cmake/modules/AddLLVM.cmake +++ b/llvm/cmake/modules/AddLLVM.cmake @@ -1,3 +1,4 @@ +include(LLVMDistributionSupport) include(LLVMProcessSources) include(LLVM-Config) include(DetermineGCCCompatible) @@ -756,13 +757,16 @@ set_property(GLOBAL APPEND PROPERTY LLVM_EXPORTS_BUILDTREE_ONLY ${name}) else() if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY OR ARG_INSTALL_WITH_TOOLCHAIN) - set(export_to_llvmexports) - if(${name} IN_LIST LLVM_DISTRIBUTION_COMPONENTS OR - (in_llvm_libs AND "llvm-libraries" IN_LIST LLVM_DISTRIBUTION_COMPONENTS) OR - NOT LLVM_DISTRIBUTION_COMPONENTS) - set(export_to_llvmexports EXPORT LLVMExports) - set_property(GLOBAL PROPERTY LLVM_HAS_EXPORTS True) + if(in_llvm_libs) + set(umbrella UMBRELLA llvm-libraries) + else() + set(umbrella) + endif() + get_llvm_distribution(${name} in_distribution distribution ${umbrella}) + if(in_distribution) + set(export_to_llvmexports EXPORT LLVM${distribution}Exports) + set_property(GLOBAL PROPERTY LLVM${distribution}_HAS_EXPORTS True) endif() install(TARGETS ${name} @@ -1171,10 +1175,10 @@ if ( ${name} IN_LIST LLVM_TOOLCHAIN_TOOLS OR NOT LLVM_INSTALL_TOOLCHAIN_ONLY) if( LLVM_BUILD_TOOLS ) set(export_to_llvmexports) - if(${name} IN_LIST LLVM_DISTRIBUTION_COMPONENTS OR - NOT LLVM_DISTRIBUTION_COMPONENTS) - set(export_to_llvmexports EXPORT LLVMExports) - set_property(GLOBAL PROPERTY LLVM_HAS_EXPORTS True) + get_llvm_distribution(${name} in_distribution distribution) + if(in_distribution) + set(export_to_llvmexports EXPORT LLVM${distribution}Exports) + set_property(GLOBAL PROPERTY LLVM${distribution}_HAS_EXPORTS True) endif() install(TARGETS ${name} @@ -1230,10 +1234,10 @@ if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY) if (LLVM_INSTALL_UTILS AND LLVM_BUILD_UTILS) set(export_to_llvmexports) - if (${name} IN_LIST LLVM_DISTRIBUTION_COMPONENTS OR - NOT LLVM_DISTRIBUTION_COMPONENTS) - set(export_to_llvmexports EXPORT LLVMExports) - set_property(GLOBAL PROPERTY LLVM_HAS_EXPORTS True) + get_llvm_distribution(${name} in_distribution distribution) + if (in_distribution) + set(export_to_llvmexports EXPORT LLVM${distribution}Exports) + set_property(GLOBAL PROPERTY LLVM${distribution}_HAS_EXPORTS True) endif() install(TARGETS ${name} diff --git a/llvm/cmake/modules/CMakeLists.txt b/llvm/cmake/modules/CMakeLists.txt --- a/llvm/cmake/modules/CMakeLists.txt +++ b/llvm/cmake/modules/CMakeLists.txt @@ -1,3 +1,5 @@ +include(LLVMDistributionSupport) + set(LLVM_INSTALL_PACKAGE_DIR lib${LLVM_LIBDIR_SUFFIX}/cmake/llvm) set(llvm_cmake_builddir "${LLVM_BINARY_DIR}/${LLVM_INSTALL_PACKAGE_DIR}") @@ -77,8 +79,8 @@ # LLVM_CONFIG_CMAKE_DIR being the source directory. In contrast in the install # tree, both the generated LLVMExports.cmake file and the rest of the cmake # source files are put in the same cmake directory. -set(LLVM_CONFIG_EXPORTS_FILE "${LLVM_EXPORTS_FILE}") set(LLVM_CONFIG_EXPORTS "${LLVM_EXPORTS};${LLVM_EXPORTS_BUILDTREE_ONLY}") +set(llvm_config_include_exports "include(\"${LLVM_EXPORTS_FILE}\")") set(llvm_config_include_buildtree_only_exports "include(\"${LLVM_BUILDTREEONLY_EXPORTS_FILE}\")") configure_file( @@ -121,7 +123,7 @@ set(LLVM_CONFIG_DEFAULT_EXTERNAL_LIT "${LLVM_CONFIG_TOOLS_BINARY_DIR}/llvm-lit") endif() -set(LLVM_CONFIG_EXPORTS_FILE "\${LLVM_CMAKE_DIR}/LLVMExports.cmake") +get_config_exports_includes(LLVM llvm_config_include_exports) set(LLVM_CONFIG_EXPORTS "${LLVM_EXPORTS}") configure_file( LLVMConfig.cmake.in @@ -135,11 +137,7 @@ @ONLY) if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY) - get_property(llvm_has_exports GLOBAL PROPERTY LLVM_HAS_EXPORTS) - if(llvm_has_exports) - install(EXPORT LLVMExports DESTINATION ${LLVM_INSTALL_PACKAGE_DIR} - COMPONENT cmake-exports) - endif() + install_distribution_exports(LLVM) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/LLVMConfig.cmake diff --git a/llvm/cmake/modules/LLVMConfig.cmake.in b/llvm/cmake/modules/LLVMConfig.cmake.in --- a/llvm/cmake/modules/LLVMConfig.cmake.in +++ b/llvm/cmake/modules/LLVMConfig.cmake.in @@ -110,8 +110,7 @@ set(LLVM_ENABLE_SHARED_LIBS @BUILD_SHARED_LIBS@) if(NOT TARGET LLVMSupport) - set(LLVM_EXPORTED_TARGETS "@LLVM_CONFIG_EXPORTS@") - include("@LLVM_CONFIG_EXPORTS_FILE@") + @llvm_config_include_exports@ @llvm_config_include_buildtree_only_exports@ endif() diff --git a/llvm/cmake/modules/LLVMDistributionSupport.cmake b/llvm/cmake/modules/LLVMDistributionSupport.cmake --- a/llvm/cmake/modules/LLVMDistributionSupport.cmake +++ b/llvm/cmake/modules/LLVMDistributionSupport.cmake @@ -1,36 +1,228 @@ +# Utility functions for packaging an LLVM distribution. See the +# BuildingADistribution documentation for more details. -if(LLVM_DISTRIBUTION_COMPONENTS) +# These functions assume a number of conventions that are common across all LLVM +# subprojects: +# - The generated CMake exports file for ${project} is called ${project}Targets +# (except for LLVM where it's called ${project}Exports for legacy reasons). +# - The build target for the CMake exports is called ${project}-cmake-exports +# (except LLVM where it's just cmake-exports). +# - The ${PROJECT}${distribution}_HAS_EXPORTS global property holds whether a +# project has any exports for a particular ${distribution} (where ${PROJECT} +# is the project name in uppercase). +# - The ${PROJECT}_CMAKE_DIR variable is computed by ${project}Config.cmake to +# hold the path of the installed CMake modules directory. +# - The ${PROJECT}_INSTALL_PACKAGE_DIR variable contains the install destination +# for the project's CMake modules. + +include_guard(GLOBAL) + +if(LLVM_DISTRIBUTION_COMPONENTS AND LLVM_DISTRIBUTIONS) + message(FATAL_ERROR "LLVM_DISTRIBUTION_COMPONENTS and LLVM_DISTRIBUTIONS cannot be specified together") +endif() + +if(LLVM_DISTRIBUTION_COMPONENTS OR LLVM_DISTRIBUTIONS) if(LLVM_ENABLE_IDE) message(FATAL_ERROR "LLVM_DISTRIBUTION_COMPONENTS cannot be specified with multi-configuration generators (i.e. Xcode or Visual Studio)") endif() endif() -function(llvm_distribution_add_targets) - add_custom_target(distribution) - add_custom_target(install-distribution) - add_custom_target(install-distribution-stripped) - - foreach(target ${LLVM_DISTRIBUTION_COMPONENTS} - ${LLVM_RUNTIME_DISTRIBUTION_COMPONENTS}) - if(TARGET ${target}) - add_dependencies(distribution ${target}) - else() - message(SEND_ERROR "Specified distribution component '${target}' doesn't have a target") +# Build the map of targets to distributions that's used to look up the +# distribution for a target later. The distribution for ${target} is stored in +# the global property LLVM_DISTRIBUTION_FOR_${target}. +function(llvm_distribution_build_target_map) + foreach(target ${LLVM_DISTRIBUTION_COMPONENTS}) + # CMake doesn't easily distinguish between properties that are unset and + # properties that are empty (you have to do a second get_property call with + # the SET option, which is unergonomic), so just use a special marker to + # denote the default (unnamed) distribution. + set_property(GLOBAL PROPERTY LLVM_DISTRIBUTION_FOR_${target} "") + endforeach() + + foreach(distribution ${LLVM_DISTRIBUTIONS}) + foreach(target ${LLVM_${distribution}_DISTRIBUTION_COMPONENTS}) + # We don't allow a target to be in multiple distributions, because we + # wouldn't know which export set to place it in. + get_property(current_distribution GLOBAL PROPERTY LLVM_DISTRIBUTION_FOR_${target}) + if(current_distribution AND NOT current_distribution STREQUAL distribution) + message(SEND_ERROR "Target ${target} cannot be in multiple distributions ${distribution} and ${current_distribution}") + endif() + set_property(GLOBAL PROPERTY LLVM_DISTRIBUTION_FOR_${target} ${distribution}) + endforeach() + endforeach() +endfunction() + +# The include guard ensures this will only be called once. The rest of this file +# only defines other functions (i.e. it doesn't execute any more code directly). +llvm_distribution_build_target_map() + +# Look up the distribution a particular target belongs to. By convention, the +# project calling this should set the ${PROJECT}${distribution}_HAS_EXPORTS +# global property to true if the target is in ${distribution} (${PROJECT} is the +# project name in uppercase). +# - target: The target to look up. +# - in_distribution_var: The variable with this name is set in the caller's +# scope to indicate if the target is in any distribution. If no distributions +# have been configured, this will always be set to true. +# - distribution_var: The variable with this name is set in the caller's scope +# to indicate the distribution name for the target. If the target belongs to +# the default (unnamed) distribution, or if no distributions have been +# configured, it's set to the empty string. +# - UMBRELLA: The (optional) umbrella target that the target is a part of. For +# example, all LLVM libraries have the umbrella target llvm-libraries. +function(get_llvm_distribution target in_distribution_var distribution_var) + if(NOT LLVM_DISTRIBUTION_COMPONENTS AND NOT LLVM_DISTRIBUTIONS) + set(${in_distribution_var} YES PARENT_SCOPE) + set(${distribution_var} "" PARENT_SCOPE) + return() + endif() + + cmake_parse_arguments(ARG "" UMBRELLA "" ${ARGN}) + get_property(distribution GLOBAL PROPERTY LLVM_DISTRIBUTION_FOR_${target}) + if(ARG_UMBRELLA) + get_property(umbrella_distribution GLOBAL PROPERTY LLVM_DISTRIBUTION_FOR_${ARG_UMBRELLA}) + if(distribution AND umbrella_distribution AND NOT distribution STREQUAL umbrella_distribution) + message(SEND_ERROR "Target ${target} has different distribution ${distribution} from its" + " umbrella target ${ARG_UMBRELLA} distribution ${umbrella_distribution}") + elseif(NOT distribution) + set(distribution ${umbrella_distribution}) endif() + endif() + if(distribution) + set(${in_distribution_var} YES PARENT_SCOPE) + if(distribution STREQUAL "") + set(distribution "") + endif() + set(${distribution_var} "${distribution}" PARENT_SCOPE) + else() + set(${in_distribution_var} NO PARENT_SCOPE) + endif() +endfunction() - if(TARGET install-${target}) - add_dependencies(install-distribution install-${target}) - else() - message(SEND_ERROR "Specified distribution component '${target}' doesn't have an install target") +# Produce a string of CMake include() commands to include the exported targets +# files for all distributions. See the comment at the top of this file for +# various assumptions made. +# - project: The project to produce the commands for. IMPORTANT: The casing of +# this argument should match the casing used by the project's Config.cmake +# file. The correct casing for the LLVM projects is Clang, Flang, LLD, LLVM, +# and MLIR. +# - includes_var: The variable with this name is set in the caller's scope to +# the string of include commands. +function(get_config_exports_includes project includes_var) + string(TOUPPER "${project}" project_upper) + set(prefix "\${${project_upper}_CMAKE_DIR}/${project}") + if(project STREQUAL "LLVM") + set(suffix "Exports.cmake") # legacy + else() + set(suffix "Targets.cmake") + endif() + + if(NOT LLVM_DISTRIBUTIONS) + set(${includes_var} "include(\"${prefix}${suffix}\")" PARENT_SCOPE) + else() + set(includes) + foreach(distribution ${LLVM_DISTRIBUTIONS}) + list(APPEND includes "include(\"${prefix}${distribution}${suffix}\" OPTIONAL)") + endforeach() + string(REPLACE ";" "\n" includes "${includes}") + set(${includes_var} "${includes}" PARENT_SCOPE) + endif() +endfunction() + +# Create the install commands and targets for the distributions' CMake exports. +# The target to install ${distribution} for a project is called +# ${project}-${distribution}-cmake-exports, where ${project} is the project name +# in lowercase and ${distribution} is the distribution name in lowercase, except +# for LLVM, where the target is just called ${distribution}-cmake-exports. See +# the comment at the top of this file for various assumptions made. +# - project: The project. See the comment for get_config_exports_includes above +# for the correct casing of this argument. +function(install_distribution_exports project) + string(TOUPPER "${project}" project_upper) + string(TOLOWER "${project}" project_lower) + if(project STREQUAL "LLVM") + set(prefix "") + set(suffix "Exports") # legacy + else() + set(prefix "${project_lower}-") + set(suffix "Targets") + endif() + set(destination "${${project_upper}_INSTALL_PACKAGE_DIR}") + + if(NOT LLVM_DISTRIBUTIONS) + get_property(has_exports GLOBAL PROPERTY ${project_upper}_HAS_EXPORTS) + if(has_exports) + install(EXPORT ${project}${suffix} DESTINATION "${destination}" + COMPONENT ${prefix}cmake-exports) endif() + else() + foreach(distribution ${LLVM_DISTRIBUTIONS}) + get_property(has_exports GLOBAL PROPERTY ${project_upper}${distribution}_HAS_EXPORTS) + if(has_exports) + string(TOLOWER ${distribution} distribution_lower) + set(target ${prefix}${distribution_lower}-cmake-exports) + install(EXPORT ${project}${distribution}${suffix} DESTINATION "${destination}" + COMPONENT ${target}) + if(NOT LLVM_ENABLE_IDE) + add_custom_target(${target}) + add_llvm_install_targets(install-${target} COMPONENT ${target}) + endif() + endif() + endforeach() + endif() +endfunction() + +# Create the targets for installing the configured distributions. The +# ${distribution} target builds the distribution, install-${distribution} +# installs it, and install-${distribution}-stripped installs a stripped version, +# where ${distribution} is the distribution name in lowercase, or "distribution" +# for the default distribution. +function(llvm_distribution_add_targets) + set(distributions "${LLVM_DISTRIBUTIONS}") + if(NOT distributions) + # CMake seemingly doesn't distinguish between an empty list and a list + # containing one element which is the empty string, so just use a special + # marker to denote the default (unnamed) distribution and fix it in the + # loop. + set(distributions "") + endif() - if(TARGET install-${target}-stripped) - add_dependencies(install-distribution-stripped install-${target}-stripped) + foreach(distribution ${distributions}) + if(distribution STREQUAL "") + set(distribution_target distribution) + # Preserve legacy behavior for LLVM_DISTRIBUTION_COMPONENTS. + set(distribution_components ${LLVM_DISTRIBUTION_COMPONENTS} ${LLVM_RUNTIME_DISTRIBUTION_COMPONENTS}) else() - message(SEND_ERROR - "Specified distribution component '${target}' doesn't have an install-stripped target." - " Its installation target creation should be changed to use add_llvm_install_targets," - " or you should manually create the 'install-${target}-stripped' target.") + string(TOLOWER ${distribution} distribution_lower) + set(distribution_target ${distribution_lower}-distribution) + set(distribution_components ${LLVM_${distribution}_DISTRIBUTION_COMPONENTS}) endif() + + add_custom_target(${distribution_target}) + add_custom_target(install-${distribution_target}) + add_custom_target(install-${distribution_target}-stripped) + + foreach(target ${distribution_components}) + if(TARGET ${target}) + add_dependencies(${distribution_target} ${target}) + else() + message(SEND_ERROR "Specified distribution component '${target}' doesn't have a target") + endif() + + if(TARGET install-${target}) + add_dependencies(install-${distribution_target} install-${target}) + else() + message(SEND_ERROR "Specified distribution component '${target}' doesn't have an install target") + endif() + + if(TARGET install-${target}-stripped) + add_dependencies(install-${distribution_target}-stripped install-${target}-stripped) + else() + message(SEND_ERROR + "Specified distribution component '${target}' doesn't have an install-stripped target." + " Its installation target creation should be changed to use add_llvm_install_targets," + " or you should manually create the 'install-${target}-stripped' target.") + endif() + endforeach() endforeach() endfunction() diff --git a/llvm/docs/BuildingADistribution.rst b/llvm/docs/BuildingADistribution.rst --- a/llvm/docs/BuildingADistribution.rst +++ b/llvm/docs/BuildingADistribution.rst @@ -87,6 +87,40 @@ the list. This is a convenience build target to allow building just the distributed pieces without needing to build all configured targets. +.. _Multi-distribution configurations: + +Multi-distribution configurations +--------------------------------- + +The ``install-distribution`` target described above is for building a single +distribution. LLVM's build system also supports building multiple distributions, +which can be used to e.g. have one distribution containing just tools and +another for libraries (to enable development). These are configured by setting +the *LLVM_DISTRIBUTIONS* variable to hold a list of all distribution names +(which conventionally start with an uppercase letter, e.g. "Development"), and +then setting the *LLVM__DISTRIBUTION_COMPONENTS* variable to the +list of targets for that distribution. For each distribution, the build system +generates an ``install-${distribution}-distribution`` target, where +``${distribution}`` is the name of the distribution in lowercase, to install +that distribution. Each target can only be in one distribution. + +Each distribution creates its own set of CMake exports, and the target to +install the CMake exports for a particular distribution for a project is named +``${project}-${distribution}-cmake-exports``, where ``${project}`` is the name +of the project in lowercase and ``${distribution}`` is the name of the +distribution in lowercase, unless the project is LLVM, in which case the target +is just named ``${distribution}-cmake-exports``. These targets need to be +explicitly included in the *LLVM__DISTRIBUTION_COMPONENTS* +variable in order to be included as part of the distribution. + +Unlike with the single distribution setup, when building multiple distributions, +any components specified in *LLVM_RUNTIME_DISTRIBUTION_COMPONENTS* are not +automatically added to any distribution. Instead, you must include the targets +explicitly in some *LLVM__DISTRIBUTION_COMPONENTS* list. + +We strongly encourage looking at ``clang/cmake/caches/MultiDistributionExample.cmake`` +as an example of configuring multiple distributions. + Special Notes for Library-only Distributions -------------------------------------------- @@ -179,6 +213,11 @@ of the libraries and runtimes. Component names match the names of the build system targets. +**LLVM_DISTRIBUTIONS**:STRING + This variable can be set to a semi-colon separated list of distributions. See + the :ref:`Multi-distribution configurations` section above for details on this + and other CMake variables to configure multiple distributions. + **LLVM_RUNTIME_DISTRIBUTION_COMPONENTS**:STRING This variable can be set to a semi-colon separated list of runtime library components. This is used in conjunction with *LLVM_ENABLE_RUNTIMES* to specify diff --git a/mlir/cmake/modules/AddMLIR.cmake b/mlir/cmake/modules/AddMLIR.cmake --- a/mlir/cmake/modules/AddMLIR.cmake +++ b/mlir/cmake/modules/AddMLIR.cmake @@ -1,3 +1,5 @@ +include(LLVMDistributionSupport) + function(mlir_tablegen ofn) tablegen(MLIR ${ARGV}) set(TABLEGEN_OUTPUT ${TABLEGEN_OUTPUT} ${CMAKE_CURRENT_BINARY_DIR}/${ofn} @@ -141,11 +143,10 @@ function(add_mlir_library_install name) if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY) set(export_to_mlirtargets) - if (${name} IN_LIST LLVM_DISTRIBUTION_COMPONENTS OR - "mlir-libraries" IN_LIST LLVM_DISTRIBUTION_COMPONENTS OR - NOT LLVM_DISTRIBUTION_COMPONENTS) - set(export_to_mlirtargets EXPORT MLIRTargets) - set_property(GLOBAL PROPERTY MLIR_HAS_EXPORTS True) + get_llvm_distribution(${name} in_distribution distribution UMBRELLA mlir-libraries) + if (in_distribution) + set(export_to_mlirtargets EXPORT MLIR${distribution}Targets) + set_property(GLOBAL PROPERTY MLIR${distribution}_HAS_EXPORTS True) endif() install(TARGETS ${name} diff --git a/mlir/cmake/modules/CMakeLists.txt b/mlir/cmake/modules/CMakeLists.txt --- a/mlir/cmake/modules/CMakeLists.txt +++ b/mlir/cmake/modules/CMakeLists.txt @@ -1,3 +1,5 @@ +include(LLVMDistributionSupport) + # Generate a list of CMake library targets so that other CMake projects can # link against them. LLVM calls its version of this file LLVMExports.cmake, but # the usual CMake convention seems to be ${Project}Targets.cmake. @@ -19,7 +21,7 @@ # Generate MlirConfig.cmake for the build tree. set(MLIR_CONFIG_CMAKE_DIR "${mlir_cmake_builddir}") set(MLIR_CONFIG_LLVM_CMAKE_DIR "${llvm_cmake_builddir}") -set(MLIR_CONFIG_EXPORTS_FILE "\${MLIR_CMAKE_DIR}/MLIRTargets.cmake") +set(mlir_config_include_exports "include(\"\${MLIR_CMAKE_DIR}/MLIRTargets.cmake\")") set(MLIR_CONFIG_INCLUDE_DIRS "${MLIR_SOURCE_DIR}/include" "${MLIR_BINARY_DIR}/include" @@ -30,7 +32,6 @@ @ONLY) set(MLIR_CONFIG_CMAKE_DIR) set(MLIR_CONFIG_LLVM_CMAKE_DIR) -set(MLIR_CONFIG_EXPORTS_FILE) set(MLIR_CONFIG_INCLUDE_DIRS) # For compatibility with projects that include(MLIRConfig) @@ -55,7 +56,7 @@ endforeach(p) set(MLIR_CONFIG_CMAKE_DIR "\${MLIR_INSTALL_PREFIX}/${MLIR_INSTALL_PACKAGE_DIR}") set(MLIR_CONFIG_LLVM_CMAKE_DIR "\${MLIR_INSTALL_PREFIX}/${LLVM_INSTALL_PACKAGE_DIR}") -set(MLIR_CONFIG_EXPORTS_FILE "\${MLIR_CMAKE_DIR}/MLIRTargets.cmake") +get_config_exports_includes(MLIR mlir_config_include_exports) set(MLIR_CONFIG_INCLUDE_DIRS "\${MLIR_INSTALL_PREFIX}/include" ) @@ -66,17 +67,12 @@ set(MLIR_CONFIG_CODE) set(MLIR_CONFIG_CMAKE_DIR) set(MLIR_CONFIG_LLVM_CMAKE_DIR) -set(MLIR_CONFIG_EXPORTS_FILE) set(MLIR_CONFIG_INCLUDE_DIRS) if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY) # Not TOOLCHAIN ONLY, so install the MLIR parts as well # Include the cmake files so other tools can use mlir-tblgen, etc. - get_property(mlir_has_exports GLOBAL PROPERTY MLIR_HAS_EXPORTS) - if(mlir_has_exports) - install(EXPORT MLIRTargets DESTINATION ${MLIR_INSTALL_PACKAGE_DIR} - COMPONENT mlir-cmake-exports) - endif() + install_distribution_exports(MLIR) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/MLIRConfig.cmake diff --git a/mlir/cmake/modules/MLIRConfig.cmake.in b/mlir/cmake/modules/MLIRConfig.cmake.in --- a/mlir/cmake/modules/MLIRConfig.cmake.in +++ b/mlir/cmake/modules/MLIRConfig.cmake.in @@ -20,7 +20,7 @@ set_property(GLOBAL PROPERTY MLIR_TRANSLATION_LIBS "@MLIR_TRANSLATION_LIBS@") # Provide all our library targets to users. -include("@MLIR_CONFIG_EXPORTS_FILE@") +@mlir_config_include_exports@ # By creating these targets here, subprojects that depend on MLIR's # tablegen-generated headers can always depend on these targets whether building