1include(ExternalProject) 2 3# llvm_ExternalProject_BuildCmd(out_var target) 4# Utility function for constructing command lines for external project targets 5function(llvm_ExternalProject_BuildCmd out_var target bin_dir) 6 if (CMAKE_GENERATOR MATCHES "Make") 7 # Use special command for Makefiles to support parallelism. 8 set(${out_var} "$(MAKE)" "-C" "${BINARY_DIR}" "${target}" PARENT_SCOPE) 9 else() 10 set(${out_var} ${CMAKE_COMMAND} --build ${bin_dir} --target ${target} 11 --config $<CONFIGURATION> PARENT_SCOPE) 12 endif() 13endfunction() 14 15# llvm_ExternalProject_Add(name source_dir ... 16# USE_TOOLCHAIN 17# Use just-built tools (see TOOLCHAIN_TOOLS) 18# EXCLUDE_FROM_ALL 19# Exclude this project from the all target 20# NO_INSTALL 21# Don't generate install targets for this project 22# ALWAYS_CLEAN 23# Always clean the sub-project before building 24# CMAKE_ARGS arguments... 25# Optional cmake arguments to pass when configuring the project 26# TOOLCHAIN_TOOLS targets... 27# Targets for toolchain tools (defaults to clang;lld) 28# DEPENDS targets... 29# Targets that this project depends on 30# EXTRA_TARGETS targets... 31# Extra targets in the subproject to generate targets for 32# PASSTHROUGH_PREFIXES prefix... 33# Extra variable prefixes (name is always included) to pass down 34# ) 35function(llvm_ExternalProject_Add name source_dir) 36 cmake_parse_arguments(ARG 37 "USE_TOOLCHAIN;EXCLUDE_FROM_ALL;NO_INSTALL;ALWAYS_CLEAN" 38 "SOURCE_DIR" 39 "CMAKE_ARGS;TOOLCHAIN_TOOLS;RUNTIME_LIBRARIES;DEPENDS;EXTRA_TARGETS;PASSTHROUGH_PREFIXES" 40 ${ARGN}) 41 canonicalize_tool_name(${name} nameCanon) 42 if(NOT ARG_TOOLCHAIN_TOOLS) 43 set(ARG_TOOLCHAIN_TOOLS clang lld) 44 endif() 45 foreach(tool ${ARG_TOOLCHAIN_TOOLS}) 46 if(TARGET ${tool}) 47 list(APPEND TOOLCHAIN_TOOLS ${tool}) 48 list(APPEND TOOLCHAIN_BINS $<TARGET_FILE:${tool}>) 49 endif() 50 endforeach() 51 52 if(NOT ARG_RUNTIME_LIBRARIES) 53 set(ARG_RUNTIME_LIBRARIES compiler-rt libcxx) 54 endif() 55 foreach(lib ${ARG_RUNTIME_LIBRARIES}) 56 if(TARGET ${lib}) 57 list(APPEND RUNTIME_LIBRARIES ${lib}) 58 endif() 59 endforeach() 60 61 if(ARG_ALWAYS_CLEAN) 62 set(always_clean clean) 63 endif() 64 65 list(FIND TOOLCHAIN_TOOLS clang FOUND_CLANG) 66 if(FOUND_CLANG GREATER -1) 67 set(CLANG_IN_TOOLCHAIN On) 68 endif() 69 70 if(RUNTIME_LIBRARIES AND CLANG_IN_TOOLCHAIN) 71 list(APPEND TOOLCHAIN_BINS ${RUNTIME_LIBRARIES}) 72 endif() 73 74 set(STAMP_DIR ${CMAKE_CURRENT_BINARY_DIR}/${name}-stamps/) 75 set(BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/${name}-bins/) 76 77 add_custom_target(${name}-clear 78 COMMAND ${CMAKE_COMMAND} -E remove_directory ${BINARY_DIR} 79 COMMAND ${CMAKE_COMMAND} -E remove_directory ${STAMP_DIR} 80 COMMENT "Clobbering ${name} build and stamp directories" 81 USES_TERMINAL 82 ) 83 84 # Find all variables that start with a prefix and propagate them through 85 get_cmake_property(variableNames VARIABLES) 86 87 list(APPEND ARG_PASSTHROUGH_PREFIXES ${nameCanon}) 88 foreach(prefix ${ARG_PASSTHROUGH_PREFIXES}) 89 foreach(variableName ${variableNames}) 90 if(variableName MATCHES "^${prefix}") 91 string(REPLACE ";" "\;" value "${${variableName}}") 92 list(APPEND PASSTHROUGH_VARIABLES 93 -D${variableName}=${value}) 94 endif() 95 endforeach() 96 endforeach() 97 98 if(ARG_USE_TOOLCHAIN) 99 if(CLANG_IN_TOOLCHAIN) 100 set(compiler_args -DCMAKE_C_COMPILER=${LLVM_RUNTIME_OUTPUT_INTDIR}/clang 101 -DCMAKE_CXX_COMPILER=${LLVM_RUNTIME_OUTPUT_INTDIR}/clang++) 102 endif() 103 list(APPEND ARG_DEPENDS ${TOOLCHAIN_TOOLS}) 104 endif() 105 106 add_custom_command( 107 OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${name}-clobber-stamp 108 DEPENDS ${ARG_DEPENDS} 109 COMMAND ${CMAKE_COMMAND} -E touch ${BINARY_DIR}/CMakeCache.txt 110 COMMAND ${CMAKE_COMMAND} -E touch ${STAMP_DIR}/${name}-mkdir 111 COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_CURRENT_BINARY_DIR}/${name}-clobber-stamp 112 COMMENT "Clobbering bootstrap build and stamp directories" 113 ) 114 115 add_custom_target(${name}-clobber 116 DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${name}-clobber-stamp) 117 118 if(ARG_EXCLUDE_FROM_ALL) 119 set(exclude EXCLUDE_FROM_ALL 1) 120 endif() 121 122 ExternalProject_Add(${name} 123 DEPENDS ${ARG_DEPENDS} 124 ${name}-clobber 125 PREFIX ${CMAKE_BINARY_DIR}/projects/${name} 126 SOURCE_DIR ${source_dir} 127 STAMP_DIR ${STAMP_DIR} 128 BINARY_DIR ${BINARY_DIR} 129 ${exclude} 130 CMAKE_ARGS ${${nameCanon}_CMAKE_ARGS} 131 ${compiler_args} 132 -DCMAKE_INSTALL_PREFIX=${CMAKE_INSTALL_PREFIX} 133 -DLLVM_BINARY_DIR=${PROJECT_BINARY_DIR} 134 -DLLVM_CONFIG_PATH=$<TARGET_FILE:llvm-config> 135 -DLLVM_ENABLE_WERROR=${LLVM_ENABLE_WERROR} 136 -DPACKAGE_VERSION=${PACKAGE_VERSION} 137 -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} 138 -DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM} 139 ${ARG_CMAKE_ARGS} 140 ${PASSTHROUGH_VARIABLES} 141 INSTALL_COMMAND "" 142 STEP_TARGETS configure build 143 BUILD_ALWAYS 1 144 USES_TERMINAL_CONFIGURE 1 145 USES_TERMINAL_BUILD 1 146 USES_TERMINAL_INSTALL 1 147 ) 148 149 if(ARG_USE_TOOLCHAIN) 150 set(force_deps DEPENDS ${TOOLCHAIN_BINS}) 151 endif() 152 153 llvm_ExternalProject_BuildCmd(run_clean clean ${BINARY_DIR}) 154 ExternalProject_Add_Step(${name} clean 155 COMMAND ${run_clean} 156 COMMENT "Cleaning ${name}..." 157 DEPENDEES configure 158 ${force_deps} 159 WORKING_DIRECTORY ${BINARY_DIR} 160 EXCLUDE_FROM_MAIN 1 161 USES_TERMINAL 1 162 ) 163 ExternalProject_Add_StepTargets(${name} clean) 164 165 if(ARG_USE_TOOLCHAIN) 166 add_dependencies(${name}-clean ${name}-clobber) 167 set_target_properties(${name}-clean PROPERTIES 168 SOURCES ${CMAKE_CURRENT_BINARY_DIR}/${name}-clobber-stamp) 169 endif() 170 171 if(NOT ARG_NO_INSTALL) 172 install(CODE "execute_process\(COMMAND \${CMAKE_COMMAND} -DCMAKE_INSTALL_PREFIX=\${CMAKE_INSTALL_PREFIX} -P ${BINARY_DIR}/cmake_install.cmake \)" 173 COMPONENT ${name}) 174 175 add_custom_target(install-${name} 176 DEPENDS ${name} 177 COMMAND "${CMAKE_COMMAND}" 178 -DCMAKE_INSTALL_COMPONENT=${name} 179 -P "${CMAKE_BINARY_DIR}/cmake_install.cmake" 180 USES_TERMINAL) 181 endif() 182 183 # Add top-level targets 184 foreach(target ${ARG_EXTRA_TARGETS}) 185 llvm_ExternalProject_BuildCmd(build_runtime_cmd ${target} ${BINARY_DIR}) 186 add_custom_target(${target} 187 COMMAND ${build_runtime_cmd} 188 DEPENDS ${name}-configure 189 WORKING_DIRECTORY ${BINARY_DIR} 190 VERBATIM 191 USES_TERMINAL) 192 endforeach() 193endfunction() 194