https://github.com/halide/Halide
Tip revision: 9f9a64cc1fb2f4aebbbd53a4c7e6f6b6ceadff6d authored by Andrew Adams on 07 December 2017, 19:16:54 UTC
Merge remote-tracking branch 'origin/master' into alina-strided-store
Merge remote-tracking branch 'origin/master' into alina-strided-store
Tip revision: 9f9a64c
CMakeLists.txt
project(Halide)
cmake_minimum_required(VERSION 3.2)
find_package(Threads QUIET)
if("${HALIDE_REQUIRE_LLVM_VERSION}" STREQUAL "")
# Find any version present.
find_package(LLVM REQUIRED CONFIG)
else()
# Find a specific version.
string(SUBSTRING "${HALIDE_REQUIRE_LLVM_VERSION}" 0 1 MAJOR)
string(SUBSTRING "${HALIDE_REQUIRE_LLVM_VERSION}" 1 1 MINOR)
message("Looking for LLVM version ${MAJOR}.${MINOR}")
find_package(LLVM "${MAJOR}.${MINOR}" REQUIRED CONFIG)
if(NOT "${LLVM_VERSION_MAJOR}${LLVM_VERSION_MINOR}" STREQUAL "${MAJOR}${MINOR}")
message(FATAL_ERROR "LLVM version error: required ${MAJOR}${MINOR} but found ${LLVM_VERSION_MAJOR}${LLVM_VERSION_MINOR}")
endif()
endif()
# Notify the user what paths and LLVM version we are using
message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}")
message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}")
if (MSVC)
# LLVM5.x on Windows can include "$(Configuration) in the path";
# fix this so we can use the paths right away.
string(REPLACE "$(Configuration)" ${CMAKE_BUILD_TYPE} LLVM_TOOLS_BINARY_DIR "${LLVM_TOOLS_BINARY_DIR}")
endif()
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
if(${CMAKE_SYSTEM_NAME} MATCHES "Windows")
set(CMAKE_OBJECT_PATH_MAX 260)
message("Windows: setting CMAKE_OBJECT_PATH_MAX to ${CMAKE_OBJECT_PATH_MAX}")
endif()
# Require C++11 for everything.
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_MACOSX_RPATH ON)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
set(LLVM_VERSION "${LLVM_VERSION_MAJOR}${LLVM_VERSION_MINOR}")
file(TO_NATIVE_PATH "${LLVM_TOOLS_BINARY_DIR}/llvm-as${CMAKE_EXECUTABLE_SUFFIX}" LLVM_AS)
file(TO_NATIVE_PATH "${LLVM_TOOLS_BINARY_DIR}/llvm-nm${CMAKE_EXECUTABLE_SUFFIX}" LLVM_NM)
file(TO_NATIVE_PATH "${LLVM_TOOLS_BINARY_DIR}/clang${CMAKE_EXECUTABLE_SUFFIX}" CLANG)
file(TO_NATIVE_PATH "${LLVM_TOOLS_BINARY_DIR}/llvm-config${CMAKE_EXECUTABLE_SUFFIX}" LLVM_CONFIG)
# LLVM doesn't appear to expose --system-libs via its CMake interface,
# so we must shell out to llvm-config to find this info
execute_process(COMMAND ${LLVM_CONFIG} --system-libs --link-static OUTPUT_VARIABLE HALIDE_SYSTEM_LIBS_RAW)
string(STRIP "${HALIDE_SYSTEM_LIBS_RAW}" HALIDE_SYSTEM_LIBS_RAW) # strip whitespace from start & end
string(REPLACE " " ";" HALIDE_SYSTEM_LIBS "${HALIDE_SYSTEM_LIBS_RAW}") # convert into a list
if("${HALIDE_SYSTEM_LIBS}" STREQUAL "")
# It's theoretically possible that this could be legitimately empty,
# but in practice that doesn't really happen, so we'll assume it means we
# aren't configured correctly.
message(WARNING "'llvm-config --system-libs --link-static' is empty; this is possibly wrong.")
endif()
# Check LLVM
function(check_dir VARNAME PATH)
if (NOT IS_ABSOLUTE "${PATH}")
message(FATAL_ERROR "\"${PATH}\" (${VARNAME}) must be an absolute path")
endif()
if (NOT IS_DIRECTORY "${PATH}")
message(FATAL_ERROR "\"${PATH}\" (${VARNAME}) must be a directory")
endif()
endfunction()
function(check_tool_exists NAME PATH)
# Need to convert to CMake path so that backslashes don't get
# interpreted as an escape.
file(TO_CMAKE_PATH "${PATH}" TOOL_PATH)
if (NOT EXISTS "${TOOL_PATH}")
message(FATAL_ERROR "Tool ${NAME} not found at ${TOOL_PATH}")
endif()
message(STATUS "Using ${NAME} at ${TOOL_PATH}")
endfunction()
# Check LLVM tools exist
check_tool_exists(llvm-as "${LLVM_AS}")
check_tool_exists(llvm-nm "${LLVM_NM}")
check_tool_exists(clang "${CLANG}")
# Check reported LLVM version
if (NOT "${LLVM_VERSION}" MATCHES "^[0-9][0-9]$")
message(FATAL_ERROR "LLVM_VERSION not specified correctly. Must be <major><minor> E.g. LLVM 4.0 is \"40\"")
endif()
if (LLVM_VERSION LESS 40)
message(FATAL_ERROR "LLVM version must be 4.0 or newer")
endif()
function(check_llvm_target TARGET HAS_TARGET)
set(${HAS_TARGET} OFF PARENT_SCOPE)
set(_llvm_required_version ${LLVM_VERSION})
if (ARGV2)
set(_llvm_required_version ${ARGV2})
endif()
if (NOT LLVM_VERSION LESS _llvm_required_version)
list(FIND LLVM_TARGETS_TO_BUILD ${TARGET} _found_target)
if (_found_target GREATER -1)
set(${HAS_TARGET} ON PARENT_SCOPE)
else()
set(${HAS_TARGET} OFF PARENT_SCOPE)
endif()
endif()
endfunction()
check_llvm_target(X86 WITH_X86)
check_llvm_target(ARM WITH_ARM)
check_llvm_target(AArch64 WITH_AARCH64)
check_llvm_target(Hexagon WITH_HEXAGON 40)
check_llvm_target(Mips WITH_MIPS)
check_llvm_target(PowerPC WITH_POWERPC)
check_llvm_target(NVPTX WITH_NVPTX)
option(TARGET_NATIVE_CLIENT "Include Native Client" OFF)
option(TARGET_X86 "Include x86 target" ${WITH_X86})
option(TARGET_ARM "Include ARM target" ${WITH_ARM})
option(TARGET_AARCH64 "Include AARCH64 (arm64) target" ${WITH_AARCH64})
option(TARGET_HEXAGON "Include Hexagon target" ${WITH_HEXAGON})
option(TARGET_METAL "Include Metal target" ON)
option(TARGET_MIPS "Include MIPS target" ${WITH_MIPS})
option(TARGET_POWERPC "Include POWERPC target" ${WITH_POWERPC})
option(TARGET_PTX "Include PTX target" ${WITH_NVPTX})
option(TARGET_OPENCL "Include OpenCL-C target" ON)
option(TARGET_OPENGL "Include OpenGL/GLSL target" ON)
option(TARGET_OPENGLCOMPUTE "Include OpenGLCompute target" ON)
option(HALIDE_SHARED_LIBRARY "Build as a shared library" ON)
if (HALIDE_SHARED_LIBRARY)
set(HALIDE_LIBRARY_TYPE SHARED)
else()
set(HALIDE_LIBRARY_TYPE STATIC)
endif()
function(halide_project name folder)
add_executable("${name}" ${ARGN})
if (MSVC)
else()
target_compile_options("${name}" PUBLIC "-fno-rtti")
endif()
target_link_libraries("${name}" PRIVATE Halide ${CMAKE_DL_LIBS} ${CMAKE_THREAD_LIBS_INIT})
target_include_directories("${name}" PRIVATE "${CMAKE_SOURCE_DIR}/src")
target_include_directories("${name}" PRIVATE "${CMAKE_SOURCE_DIR}/tools")
set_target_properties("${name}" PROPERTIES FOLDER "${folder}")
if (MSVC)
target_link_libraries("${name}" PRIVATE Kernel32)
endif()
endfunction(halide_project)
# Set warnings globally
option(WARNINGS_AS_ERRORS "Treat warnings as errors" ON)
if (WARNINGS_AS_ERRORS)
message(STATUS "WARNINGS_AS_ERRORS enabled")
else()
message(STATUS "WARNINGS_AS_ERRORS disabled")
endif()
if (NOT MSVC)
add_compile_options(-Wall
-Wno-unused-function
-Wcast-qual
-Woverloaded-virtual
-Wignored-qualifiers)
if (WARNINGS_AS_ERRORS)
add_compile_options(-Werror)
endif()
else()
add_compile_options(/W3)
add_compile_options(/wd4018) # disable "signed/unsigned mismatch"
add_compile_options(/wd4503) # disable "decorated name length exceeded, name was truncated"
add_compile_options(/wd4267) # disable "conversion from 'size_t' to 'int', possible loss of data"
if (WARNINGS_AS_ERRORS)
add_compile_options(/WX)
endif()
endif()
# These tools are needed by several subdirectories
add_executable(build_halide_h tools/build_halide_h.cpp)
add_executable(binary2cpp tools/binary2cpp.cpp)
if (MSVC)
# disable irrelevant "POSIX name" warnings
target_compile_options(build_halide_h PUBLIC /wd4996)
target_compile_options(binary2cpp PUBLIC /wd4996)
endif()
# Look for OpenMP
find_package(OpenMP QUIET)
if (OPENMP_FOUND)
message(STATUS "Found OpenMP")
endif()
# For in-tree builds, we need to set the input variables for halide.cmake
# to specific values, rather than relying on HALIDE_DISTRIB_DIR to be set correctly.
set(HALIDE_INCLUDE_DIR "${CMAKE_BINARY_DIR}/include")
set(HALIDE_TOOLS_DIR "${CMAKE_SOURCE_DIR}/tools")
set(HALIDE_COMPILER_LIB Halide)
set(HALIDE_DISTRIB_DIR "/bad-path")
include(halide.cmake)
# -----------------------------------------------------------------------------
# Option to enable/disable assertions
# -----------------------------------------------------------------------------
# Filter out definition of NDEBUG definition from the default build
# configuration flags. # We will add this ourselves if we want to disable
# assertions.
# FIXME: Perhaps our own default ``cxx_flags_overrides.cmake`` file would be better?
foreach (build_config Debug Release RelWithDebInfo MinSizeRel)
string(TOUPPER ${build_config} upper_case_build_config)
foreach (language CXX C)
set(VAR_TO_MODIFY "CMAKE_${language}_FLAGS_${upper_case_build_config}")
string(REGEX REPLACE "(^| )[/-]D *NDEBUG($| )"
" "
replacement
"${${VAR_TO_MODIFY}}"
)
#message("Original (${VAR_TO_MODIFY}) is ${${VAR_TO_MODIFY}} replacement is ${replacement}")
set(${VAR_TO_MODIFY} "${replacement}" CACHE STRING "Default flags for ${build_config} configuration" FORCE)
endforeach()
endforeach()
function(define_test_group GROUP)
if(TARGET "${GROUP}")
message(FATAL_ERROR "Group ${GROUP} is already defined.")
endif()
add_custom_target("${GROUP}")
set_target_properties("${GROUP}" PROPERTIES EXCLUDE_FROM_ALL TRUE)
endfunction()
define_test_group(build_tests)
define_test_group(run_tests)
# Make a target that aggregates a number of other targets;
# this can be used to group builds (e.g. "build_tests")
# or to execute targets (by adding executable custom-commands);
# the latter is used to execute test targets.
#
# Note that the target will be excluded from the "all" target, so it won't
# be built by "make all" by default.
#
# TODO: this is intended to eventually replicate all of the interesting test targets
# from our Make build, but not all are implemented yet:
# TODO(srj): add test_aotcpp_generators support
# TODO(srj): add test_valgrind variant
# TODO(srj): add test_avx512 variant
# TODO(srj): add test_bazel variant
# TODO(srj): add test_python variant
# TODO(srj): add test_apps variant
function(add_test TARGET)
set(options EXPECT_FAILURE)
set(oneValueArgs WORKING_DIRECTORY)
set(multiValueArgs GROUPS)
cmake_parse_arguments(args "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
foreach(GROUP ${args_GROUPS})
if(NOT TARGET "${GROUP}")
define_test_group("${GROUP}")
endif()
endforeach()
set(BUILD_NAME "${TARGET}")
# add_custom_target("${BUILD_NAME}" DEPENDS "${TARGET}")
set_target_properties("${BUILD_NAME}" PROPERTIES EXCLUDE_FROM_ALL TRUE)
add_dependencies(build_tests "${BUILD_NAME}")
set(EXEC_NAME "run_${TARGET}")
get_target_property(TARGET_TYPE "${TARGET}" TYPE)
if("${TARGET_TYPE}" STREQUAL "EXECUTABLE")
if(${args_EXPECT_FAILURE})
set(COMMAND "${CMAKE_SOURCE_DIR}/test/common/expect_failure.sh" "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TARGET}")
else()
set(COMMAND "${TARGET}")
endif()
add_custom_target("${EXEC_NAME}"
COMMAND ${COMMAND}
WORKING_DIRECTORY ${args_WORKING_DIRECTORY}
COMMENT "Executing ${TARGET}"
DEPENDS "${TARGET}")
elseif("${TARGET_TYPE}" STREQUAL "UTILITY")
# It's probably a custom target or a group: just depend on it.
add_custom_target("${EXEC_NAME}" DEPENDS "${TARGET}")
else()
message(FATAL_ERROR "add_test(): unsupported type ${TARGET_TYPE} for ${TARGET}")
endif()
set_target_properties("${EXEC_NAME}" PROPERTIES EXCLUDE_FROM_ALL TRUE)
foreach(GROUP ${args_GROUPS})
add_dependencies("${GROUP}" "${EXEC_NAME}")
endforeach()
endfunction()
# Only groups that are defined in *this file* will have projects reliably
# defined for them in MSVC builds; pre-define the targets we want to be available
# here to ensure that happens.
define_test_group(test_auto_schedule)
define_test_group(test_correctness)
define_test_group(test_error)
define_test_group(test_generator)
define_test_group(test_opengl)
define_test_group(test_performance)
define_test_group(test_tutorial)
define_test_group(test_warning)
add_subdirectory(src)
option(WITH_TESTS "Build tests" ON)
if (WITH_TESTS)
message(STATUS "Building tests enabled")
add_subdirectory(test)
else()
message(STATUS "Building tests disabled")
endif()
option(WITH_APPS "Build apps" ON)
if (WITH_APPS)
if (NOT WIN32)
message(STATUS "Building apps enabled")
add_subdirectory(apps)
else()
message(WARNING "Apps cannot be built under Windows using cmake. Try the makefile in an msys2 shell.")
endif()
else()
message(STATUS "Building apps disabled")
endif()
option(WITH_TUTORIALS "Build Tutorials" ON)
if (WITH_TUTORIALS)
message(STATUS "Building tutorials enabled")
add_subdirectory(tutorial)
else()
message(STATUS "Building tutorials disabled")
endif()
option(WITH_DOCS "Enable building of documentation" OFF)
if (WITH_DOCS)
find_package(Doxygen)
if (NOT DOXYGEN_FOUND)
message(FATAL_ERROR "Could not find Doxygen. Either install it or set WITH_DOCS to OFF")
endif()
configure_file(${CMAKE_SOURCE_DIR}/Doxyfile.in ${CMAKE_BINARY_DIR}/Doxyfile @ONLY)
# Note documentation is not built by default, the user needs to build the "doc" target
add_custom_target(doc
COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_BINARY_DIR}/Doxyfile
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
COMMENT "Building Doxygen documentation"
)
endif()
option(WITH_UTILS "Build utils" ON)
if (WITH_UTILS)
message(STATUS "Building utils enabled")
add_subdirectory(util)
else()
message(STATUS "Building utils disabled")
endif()
# ------------------------------------------------
# 'make distrib' support
add_custom_target(build_distrib_dir)
set(DISTRIB_DIR "${CMAKE_BINARY_DIR}/distrib")
function(_make_distrib_subdir TARGET DIR)
set(NAME "_make_distrib_dir_${TARGET}")
add_custom_target("${NAME}"
COMMAND cmake -E make_directory "${DISTRIB_DIR}/${DIR}")
set_target_properties("${NAME}" PROPERTIES EXCLUDE_FROM_ALL TRUE)
add_dependencies("${TARGET}" "${NAME}" )
endfunction()
# Copy the file produced by TARGET into the distrib folder, in the subdir DIR
function(add_to_distrib TARGET DIR)
set(options )
set(oneValueArgs )
set(multiValueArgs DEPS)
cmake_parse_arguments(args "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if(TARGET "${TARGET}")
set(NAME "_distrib_${TARGET}")
get_target_property(TARGET_TYPE "${TARGET}" TYPE)
if("${TARGET_TYPE}" STREQUAL "EXECUTABLE" OR
"${TARGET_TYPE}" STREQUAL "STATIC_LIBRARY" OR
"${TARGET_TYPE}" STREQUAL "SHARED_LIBRARY")
add_custom_target("${NAME}"
COMMAND cmake -E copy $<TARGET_FILE:${TARGET}> "${DISTRIB_DIR}/${DIR}"
DEPENDS "${TARGET}")
_make_distrib_subdir("${NAME}" "${DIR}")
else()
message(FATAL_ERROR "TARGET ${TARGET} has type ${TARGET_TYPE}")
endif()
set_target_properties("${NAME}" PROPERTIES EXCLUDE_FROM_ALL TRUE)
else()
get_filename_component(FNAME "${TARGET}" NAME)
set(NAME "_distrib_${DIR}_${FNAME}")
string(REPLACE "/" "_" NAME "${NAME}")
string(REPLACE "\\" "_" NAME "${NAME}")
add_custom_target("${NAME}"
COMMAND cmake -E copy "${TARGET}" "${DISTRIB_DIR}/${DIR}"
DEPENDS "${TARGET}")
_make_distrib_subdir("${NAME}" "${DIR}")
endif()
if(NOT "${args_DEPS}" STREQUAL "")
add_dependencies("${NAME}" ${args_DEPS})
endif()
add_dependencies(build_distrib_dir "${NAME}")
endfunction()
# ---- libHalide
if("${HALIDE_LIBRARY_TYPE}" STREQUAL "SHARED")
add_to_distrib(Halide bin)
else()
add_to_distrib(Halide lib)
endif()
# ---- Header files
add_to_distrib("${CMAKE_BINARY_DIR}/include/Halide.h" include
DEPS HalideIncludes)
add_to_distrib("${CMAKE_BINARY_DIR}/include/HalideBuffer.h" include)
file(GLOB FILES "${CMAKE_BINARY_DIR}/include/HalideRuntime*.h")
foreach(F ${FILES})
add_to_distrib(${F} include)
endforeach()
# ---- Tutorials
foreach(EXT cpp h sh)
set(DIR "${CMAKE_SOURCE_DIR}/tutorial")
file(GLOB FILES "${DIR}/*.${EXT}")
foreach(F ${FILES})
add_to_distrib(${F} tutorial)
endforeach()
endforeach()
foreach(EXT gif jpg mp4)
set(DIR "${CMAKE_SOURCE_DIR}/tutorial/figures")
file(GLOB FILES "${DIR}/*.${EXT}")
foreach(F ${FILES})
add_to_distrib(${F} tutorial/figures)
endforeach()
endforeach()
foreach(EXT png)
set(DIR "${CMAKE_SOURCE_DIR}/tutorial/images")
file(GLOB FILES "${DIR}/*.${EXT}")
foreach(F ${FILES})
add_to_distrib(${F} tutorial/images)
endforeach()
endforeach()
# ---- Tools
foreach(F mex_halide.m
GenGen.cpp
RunGen.cpp
RunGenStubs.cpp
halide_benchmark.h
halide_image.h
halide_image_io.h
halide_image_info.h)
add_to_distrib("${CMAKE_SOURCE_DIR}/tools/${F}" tools)
endforeach()
# ---- README
file(GLOB FILES "${CMAKE_SOURCE_DIR}/*.md")
foreach(F ${FILES})
add_to_distrib(${F} "")
endforeach()
# ---- Bazel
file(GLOB FILES "${CMAKE_SOURCE_DIR}/bazel/*")
foreach(F ${FILES})
add_to_distrib(${F} "")
endforeach()
# ---- CMake
file(GLOB FILES "${CMAKE_SOURCE_DIR}/*.cmake")
foreach(F ${FILES})
add_to_distrib(${F} "")
endforeach()
# ---- halide_config
file(GLOB FILES "${CMAKE_SOURCE_DIR}/tools/halide_config.*.tpl")
foreach(F ${FILES})
# Can't rely on sed on Windows, so just do the trivial transform we need right here.
file(READ ${F} CONTENTS)
get_filename_component(FNAME "${F}" NAME) # Extract filename
string(REGEX REPLACE "\\.tpl$" "" FNAME "${FNAME}") # Strip .tpl extension
string(REPLACE "\${LLVM_SYSTEM_LIBS}" "${HALIDE_SYSTEM_LIBS_RAW}" NEW_CONTENTS "${CONTENTS}")
file(WRITE "${CMAKE_BINARY_DIR}/${FNAME}" ${NEW_CONTENTS})
add_to_distrib("${CMAKE_BINARY_DIR}/${FNAME}" "")
endforeach()
# ---- distrib.tgz and distrib.zip
file(TO_NATIVE_PATH "${DISTRIB_DIR}" NATIVE_DISTRIB_DIR)
file(TO_NATIVE_PATH "${DISTRIB_DIR}/../" NATIVE_ARCHIVE_DIR)
if (MSVC)
# 'cmake -E tar' can create zipfiles as of v3.2+
add_custom_target(halide_archive
DEPENDS build_distrib_dir
COMMAND cmake -E tar -cf "${NATIVE_ARCHIVE_DIR}/halide.zip" --format=zip "${NATIVE_DISTRIB_DIR}")
else()
add_custom_target(halide_archive
DEPENDS build_distrib_dir
COMMAND cmake -E tar -czf "${NATIVE_ARCHIVE_DIR}/halide.tgz" "${NATIVE_DISTRIB_DIR}")
endif()
add_custom_target(distrib)
add_dependencies(distrib build_distrib_dir halide_archive)