From 192dd947b2b6ba0530a4e1a8fad46038c42da12d Mon Sep 17 00:00:00 2001 From: Stephen Neuendorffer Date: Mon, 3 Aug 2020 11:24:15 -0700 Subject: [PATCH] [RFC] Factor out repetitive cmake patterns for llvm-style projects New projects (particularly out of tree) have a tendency to hijack the existing llvm configuration options and build targets (add_llvm_library, add_llvm_tool). This can lead to some confusion. 1) When querying a configuration variable, do we care about how LLVM was configured, or how these options were configured for the out of tree project? 2) LLVM has lots of defaults, which are easy to miss (e.g. LLVM_BUILD_TOOLS=ON). These options all need to be duplicated in the CMakeLists.txt for the project. In addition, with LLVM Incubators coming online, we need better ways for these incubators to do things the "LLVM way" without alot of futzing. Ideally, this would happen in a way that eases importing into the LLVM monorepo when projects mature. This patch creates some generic infrastructure in llvm/cmake/modules and refactors MLIR to use this infrastructure. This should expand to include add_xxx_library, which is by far the most complicated bit of building a project correctly, since it has to deal with lots of shared library configuration bits. (MLIR currently hijacks the LLVM infrastructure for building libMLIR.so, so this needs to get refactored anyway.) Differential Revision: https://reviews.llvm.org/D85140 --- cmake/modules/LLVMProjectOptions.cmake | 68 +++++++++++++++ cmake/modules/LLVMProjectTargets.cmake | 109 +++++++++++++++++++++++++ 2 files changed, 177 insertions(+) create mode 100644 cmake/modules/LLVMProjectOptions.cmake create mode 100644 cmake/modules/LLVMProjectTargets.cmake diff --git a/cmake/modules/LLVMProjectOptions.cmake b/cmake/modules/LLVMProjectOptions.cmake new file mode 100644 index 00000000000..ce466953280 --- /dev/null +++ b/cmake/modules/LLVMProjectOptions.cmake @@ -0,0 +1,68 @@ +# LLVM-style projects generally have the same directory structure. This file +# provides some bolierplate cmake support for projects that supports this +# directory structure. Note that generally speaking, projects should prefer +# to use their own rules for these rather than relying on the core llvm build +# targets. + +# Generally name should be lower case. +function(add_llvm_project_options name) + string(TOUPPER "${name}" uppername) + + # Define options to control the inclusion and default build behavior for + # components which may not strictly be necessary (tools, examples, and tests). + # + # This is primarily to support building smaller or faster project files. + option(${uppername}_INCLUDE_TOOLS + "Generate build targets for the ${uppername} tools." + ${LLVM_INCLUDE_TOOLS}) + option(${uppername}_BUILD_TOOLS + "Build the ${uppername} tools. If OFF, just generate build targets." + ${LLVM_BUILD_TOOLS}) + + option(${uppername}_INCLUDE_UTILS + "Generate build targets for the ${uppername} utils." + ${LLVM_INCLUDE_UTILS}) + option(${uppername}_BUILD_UTILS + "Build ${uppername} utility binaries. If OFF, just generate build targets." + ${LLVM_BUILD_UTILS}) + option(${uppername}_INSTALL_UTILS + "Include utility binaries in the 'install' target." + ${LLVM_INSTALL_UTILS}) + + # i.e. Don't install headers, for instance. + option(${uppername}_INSTALL_TOOLCHAIN_ONLY + "Only include toolchain files in the 'install' target." + ${LLVM_INSTALL_TOOLCHAIN_ONLY}) + + option(${uppername}_BUILD_EXAMPLES + "Build the ${uppername} example programs. If OFF, just generate build targets." + ${LLVM_BUILD_EXAMPLES}) + option(${uppername}_INCLUDE_EXAMPLES + "Generate build targets for the ${uppername} examples" + ${LLVM_INCLUDE_EXAMPLES}) + if(${uppername}_BUILD_EXAMPLES) + add_definitions(-DBUILD_EXAMPLES) + endif(${uppername}_BUILD_EXAMPLES) + + option(${uppername}_BUILD_TESTS + "Build ${uppername} unit tests. If OFF, just generate build targets." + ${LLVM_BUILD_TESTS}) + option(${uppername}_INCLUDE_TESTS + "Generate build targets for the ${uppername} unit tests." + ${LLVM_INCLUDE_TESTS}) + if (${uppername}_INCLUDE_TESTS) + add_definitions(-D${uppername}_INCLUDE_TESTS) + endif() + + option(${uppername}_INCLUDE_INTEGRATION_TESTS + "Generate build targets for the ${uppername} integration tests." + ${LLVM_INCLUDE_INTEGRATION_TESTS}) + if (${uppername}_INCLUDE_INTEGRATION_TESTS) + add_definitions(-D${uppername}_INCLUDE_INTEGRATION_TESTS) + endif() + + option(${uppername}_INCLUDE_DOCS + "Generate build targets for the ${uppername} docs." + ${LLVM_INCLUDE_DOCS}) + +endfunction(add_llvm_project_options) diff --git a/cmake/modules/LLVMProjectTargets.cmake b/cmake/modules/LLVMProjectTargets.cmake new file mode 100644 index 00000000000..4e73706d147 --- /dev/null +++ b/cmake/modules/LLVMProjectTargets.cmake @@ -0,0 +1,109 @@ +# For project foo, this function generates: +# add_foo_tool(name) (An executable installed by default) +# add_foo_utility(name) (An executable *not* installed by default) +# add_foo_example(name) (An executable which is built, but never installed) +# add_foo_example_library(name) (A library to go along with an example) + +# It also assumes the following configuration environment variables +# (see LLVMProjectOptions.cmake) +# FOO_TOOLS_INSTALL_DIR +# FOO_BUILD_TOOLS +# FOO_BUILD_UTILS +# FOO_INSTALL_UTILS +# FOO_BUILD_EXAMPLES +# FOO_HAS_EXPORTS +# FOO_INSTALL_TOOLCHAIN_ONLY + +function(add_llvm_project_targets projectname) + string(TOUPPER "${name}" upperprojectname) + + macro(add_${projectname}_tool name) + if( NOT ${upperprojectname}_BUILD_TOOLS ) + set(EXCLUDE_FROM_ALL ON) + endif() + add_llvm_executable(${name} ${ARGN}) + + if ( ${name} IN_LIST LLVM_TOOLCHAIN_TOOLS OR NOT ${upperprojectname}_INSTALL_TOOLCHAIN_ONLY) + if( ${upperprojectname}_BUILD_TOOLS ) + set(export_to_${projectname}exports) + if(${name} IN_LIST LLVM_DISTRIBUTION_COMPONENTS OR + NOT LLVM_DISTRIBUTION_COMPONENTS) + set(export_to_${projectname}exports EXPORT ${upperprojectname}Exports) + set_property(GLOBAL PROPERTY ${upperprojectname}_HAS_EXPORTS True) + endif() + + install(TARGETS ${name} + ${export_to_${projectname}exports} + RUNTIME DESTINATION ${${upperprojectname}_TOOLS_INSTALL_DIR} + COMPONENT ${name}) + + if (NOT LLVM_ENABLE_IDE) + add_llvm_install_targets(install-${name} + DEPENDS ${name} + COMPONENT ${name}) + endif() + endif() + endif() + if( ${upperprojectname}_BUILD_TOOLS ) + set_property(GLOBAL APPEND PROPERTY ${upperprojectname}_EXPORTS ${name}) + endif() + set_target_properties(${name} PROPERTIES FOLDER "Tools") + endmacro(add_${projectname}_tool name) + + macro(add_${projectname}_example name) + if( NOT ${upperprojectname}_BUILD_EXAMPLES ) + set(EXCLUDE_FROM_ALL ON) + endif() + add_llvm_executable(${name} ${ARGN}) + if( ${upperprojectname}_BUILD_EXAMPLES ) + install(TARGETS ${name} RUNTIME DESTINATION examples) + endif() + set_target_properties(${name} PROPERTIES FOLDER "Examples") + endmacro(add_${projectname}_example name) + + macro(add_${projectname}_example_library name) + if( NOT ${upperprojectname}_BUILD_EXAMPLES ) + set(EXCLUDE_FROM_ALL ON) + add_llvm_library(${name} BUILDTREE_ONLY ${ARGN}) + else() + add_llvm_library(${name} ${ARGN}) + endif() + + set_target_properties(${name} PROPERTIES FOLDER "Examples") + endmacro(add_${projectname}_example_library name) + + # This is a macro that is used to create targets for executables that are needed + # for development, but that are not intended to be installed by default. + macro(add_${projectname}_utility name) + if ( NOT ${upperprojectname}_BUILD_UTILS ) + set(EXCLUDE_FROM_ALL ON) + endif() + + add_llvm_executable(${name} DISABLE_LLVM_LINK_LLVM_DYLIB ${ARGN}) + set_target_properties(${name} PROPERTIES FOLDER "Utils") + if (NOT ${upperprojectname}_INSTALL_TOOLCHAIN_ONLY) + if (${upperprojectname}_INSTALL_UTILS AND ${upperprojectname}_BUILD_UTILS) + set(export_to_${projectname}exports) + if (${name} IN_LIST LLVM_DISTRIBUTION_COMPONENTS OR + NOT LLVM_DISTRIBUTION_COMPONENTS) + set(export_to_${projectname}exports EXPORT ${upperprojectname}Exports) + set_property(GLOBAL PROPERTY ${upperprojectname}_HAS_EXPORTS True) + endif() + + install(TARGETS ${name} + ${export_to_${projectname}exports} + RUNTIME DESTINATION ${LLVM_UTILS_INSTALL_DIR} + COMPONENT ${name}) + + if (NOT LLVM_ENABLE_IDE) + add_llvm_install_targets(install-${name} + DEPENDS ${name} + COMPONENT ${name}) + endif() + set_property(GLOBAL APPEND PROPERTY ${upperprojectname}_EXPORTS ${name}) + elseif(${upperprojectname}_BUILD_UTILS) + set_property(GLOBAL APPEND PROPERTY ${upperprojectname}_EXPORTS_BUILDTREE_ONLY ${name}) + endif() + endif() + endmacro(add_${projectname}_utility name) +endfunction(add_llvm_project_targets)