#
# Copyright (C) 2011-15 DyND Developers
# BSD 2-Clause License, see LICENSE.txt
#

cmake_minimum_required(VERSION 2.8.11)
project(libdynd)

set(CMAKE_OSX_DEPLOYMENT_TARGET 10.9)

set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/")

set(LIB_SUFFIX "" CACHE STRING
    "Typically an empty string or 64. Controls installation to lib or lib64")

if(NOT WIN32)
  set(CMAKE_CXX_FLAGS_DEBUG "-O0 -g")
  set(CMAKE_C_FLAGS_DEBUG "-O0 -g")
endif()

# Only add these options if this is the top level CMakeLists.txt
if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}")
################################################
# Some options configurable from the CMAKE command execution
#
# -DDYND_SHARED_LIB=ON/OFF, whether to build a shared or a static library.
    option(DYND_SHARED_LIB
        "Build a libdynd shared library instead of a static library"
        ON)
# -DDYND_CUDA=ON/OFF, whether to build libdynd with or without the CUDA Toolkit
    option(DYND_CUDA
        "Build a libdynd library with CUDA"
        OFF) # While CUDA support is in development, we default to OFF.
# -DDYND_FFTW=ON/OFF, whether to build libdynd with or without FFTW
    option(DYND_FFTW
        "Build a libdynd library with FFTW"
        OFF)
# -DDYND_LLVM=ON/OFF, whether to build libdynd with or without LLVM support
    option(DYND_LLVM
        "Build a libdynd library with LLVM"
        OFF)
#
# -DDYND_INSTALL_LIB=ON/OFF, whether to install libdynd into the
#   CMAKE_INSTALL_PREFIX. Its main purpose is to allow dynd-python and
#   libdynd to be built inside the source tree of another project, like
#   in the libraries/libdynd subdirectory of dynd-python.
    option(DYND_INSTALL_LIB
        "Do installation of the built libdynd library to the CMAKE_INSTALL_PREFIX"
        ON)
# -DDYND_BUILD_TESTS=ON/OFF, whether to build the googletest unit tests.
    option(DYND_BUILD_TESTS
        "Build the googletest unit tests for libdynd."
        ON)
# -DDYND_BUILD_BENCHMARKS=ON/OFF, whether to build the Google benchmarks
    option(DYND_BUILD_BENCHMARKS
        "Build the Google benchmarks for libdynd."
        ON)
#
################################################
endif()

if(DYND_LLVM)
  find_package(LLVM CONFIG)
endif()

if(DYND_CUDA)
    # CUDA 6.5, which has experimental C++11 support, is the minimum required
    find_package(CUDA_DyND 6.5 REQUIRED)
    add_definitions(-DDYND_CUDA)
endif()

list(APPEND CMAKE_MODULE_PATH
    "${CMAKE_CURRENT_SOURCE_DIR}/cmake/")

set(CMAKE_VERBOSE_MAKEFILE 1)

if(WIN32)
    set(DYND_BUILD_BENCHMARKS OFF)
endif()

if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
    # -WX: Treat warnings as errors
    # -bigobj: Allow lots of symbols (assignment_kernels.cpp and assignment_kernels.cu need this flag)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -WX -EHsc -bigobj -wd4503")

    if (${CMAKE_CXX_COMPILER_VERSION} VERSION_LESS 19)
        message(FATAL_ERROR "Only MSVC 2015 (Version 19.0) and later are supported by LibDyND. Found version ${CMAKE_CXX_COMPILER_VERSION}.")
    endif ()
else()
    if(WIN32)
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -std=c++14 -fomit-frame-pointer -fstrict-aliasing -Wall -Wextra -Werror -Wno-missing-field-initializers")
    else()
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O3 -fomit-frame-pointer -fstrict-aliasing -Wall -Wextra -Wno-missing-field-initializers -fPIC -Wno-ignored-attributes -Werror")
    endif()
    if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
        if ("${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS 4.9)
            message(FATAL_ERROR "Only GCC 4.9 and later are supported by LibDyND. Found version ${CMAKE_CXX_COMPILER_VERSION}.")
        endif()
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -fmax-errors=20 -Wno-type-limits")
    elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1y -ferror-limit=20")
    endif()
endif()

# Embedded libraries
add_subdirectory(thirdparty/cephes)
add_subdirectory(thirdparty/datetime)
include_directories(thirdparty/datetime/include)

# LLVM, disabled for now
#add_definitions(${LLVM_DEFINITIONS})
#include_directories(${LLVM_INCLUDE_DIRS})
#llvm_map_components_to_libnames(LLVM_LINK_LIBS core option target bitreader support profiledata codegen irreader linker instrumentation objcarcopts lto)

set(DYND_LINK_LIBS cephes datetime)

# Get the git revision
include(GetGitRevisionDescriptionDyND)
get_git_head_revision("${CMAKE_CURRENT_SOURCE_DIR}" GIT_REFSPEC DYND_GIT_SHA1)
git_describe("${CMAKE_CURRENT_SOURCE_DIR}" DYND_VERSION_STRING
             --dirty --always --match "v*")
message(STATUS "DyND version: ${DYND_VERSION_STRING}")
configure_file(
    "${CMAKE_CURRENT_SOURCE_DIR}/src/dynd/git_version.cpp.in"
    "${CMAKE_CURRENT_BINARY_DIR}/src/dynd/git_version.cpp" @ONLY)

if(DYND_SHARED_LIB)
    set(DYND_SHARED_LIB_VAL 1)
else()
    set(DYND_SHARED_LIB_VAL 0)
endif()

configure_file(
    "${CMAKE_CURRENT_SOURCE_DIR}/include/dynd/visibility.hpp.in"
    "${CMAKE_CURRENT_BINARY_DIR}/include/dynd/visibility.hpp" @ONLY)

# Extract the version number from the version string
string(REPLACE "v" "" DYND_VERSION "${DYND_VERSION_STRING}")
string(REPLACE "-" ";" DYND_VERSION "${DYND_VERSION}")
list(GET DYND_VERSION 0 "${DYND_VERSION}")

set(config_cpp src/dynd/config.cpp)

set(libdynd_SRC
    # Types
    src/dynd/types/adapt_type.cpp
    src/dynd/types/any_kind_type.cpp
    src/dynd/types/array_type.cpp
    src/dynd/types/base_bytes_type.cpp
    src/dynd/types/base_type.cpp
    src/dynd/types/base_expr_type.cpp
    src/dynd/types/base_memory_type.cpp
    src/dynd/types/base_string_type.cpp
    src/dynd/types/base_dim_type.cpp
    src/dynd/types/busdate_type.cpp
    src/dynd/types/bytes_type.cpp
    src/dynd/types/categorical_type.cpp
    src/dynd/types/categorical_kind_type.cpp
    src/dynd/types/c_contiguous_type.cpp
    src/dynd/types/char_type.cpp
    src/dynd/types/convert_type.cpp
    src/dynd/types/cuda_host_type.cpp
    src/dynd/types/cuda_device_type.cpp
    src/dynd/types/datashape_formatter.cpp
    src/dynd/types/datashape_parser.cpp
    src/dynd/types/date_parser.cpp
    src/dynd/types/date_type.cpp
    src/dynd/types/date_util.cpp
    src/dynd/types/datetime_parser.cpp
    src/dynd/types/datetime_type.cpp
    src/dynd/types/datetime_util.cpp
    src/dynd/types/dim_fragment_type.cpp
    src/dynd/types/ellipsis_dim_type.cpp
    src/dynd/types/fixed_dim_type.cpp
    src/dynd/types/fixed_dim_kind_type.cpp
    src/dynd/types/fixed_bytes_kind_type.cpp
    src/dynd/types/fixed_bytes_type.cpp
    src/dynd/types/fixed_string_kind_type.cpp
    src/dynd/types/fixed_string_type.cpp
    src/dynd/types/callable_type.cpp
    src/dynd/types/int_kind_sym_type.cpp
    src/dynd/types/kind_sym_type.cpp
    src/dynd/types/option_type.cpp
    src/dynd/types/pointer_type.cpp
    src/dynd/types/string_type.cpp
    src/dynd/types/struct_type.cpp
    src/dynd/types/substitute_shape.cpp
    src/dynd/types/substitute_typevars.cpp
    src/dynd/types/time_parser.cpp
    src/dynd/types/time_type.cpp
    src/dynd/types/time_util.cpp
    src/dynd/types/tuple_type.cpp
    src/dynd/types/type_alignment.cpp
    src/dynd/types/type_id.cpp
    src/dynd/types/type_type.cpp
    src/dynd/types/typevar_constructed_type.cpp
    src/dynd/types/typevar_dim_type.cpp
    src/dynd/types/pow_dimsym_type.cpp
    src/dynd/types/scalar_kind_type.cpp
    src/dynd/types/typevar_type.cpp
    src/dynd/types/var_dim_type.cpp
    src/dynd/types/view_type.cpp
    include/dynd/types/adapt_type.hpp
    include/dynd/types/any_kind_type.hpp
    include/dynd/types/array_type.hpp
    include/dynd/types/callable_type.hpp
    include/dynd/types/base_bytes_type.hpp
    include/dynd/types/base_type.hpp
    include/dynd/types/base_memory_type.hpp
    include/dynd/types/base_expr_type.hpp
    include/dynd/types/base_string_type.hpp
    include/dynd/types/base_dim_type.hpp
    include/dynd/types/busdate_type.hpp
    include/dynd/types/bytes_type.hpp
    include/dynd/types/c_contiguous_type.hpp
    include/dynd/types/categorical_type.hpp
    include/dynd/types/categorical_kind_type.hpp
    include/dynd/types/char_type.hpp
    include/dynd/types/convert_type.hpp
    include/dynd/types/cuda_host_type.hpp
    include/dynd/types/cuda_device_type.hpp
    include/dynd/types/datashape_formatter.hpp
    include/dynd/types/datashape_parser.hpp
    include/dynd/types/date_parser.hpp
    include/dynd/types/date_type.hpp
    include/dynd/types/date_util.hpp
    include/dynd/types/datetime_parser.hpp
    include/dynd/types/datetime_type.hpp
    include/dynd/types/datetime_util.hpp
    include/dynd/types/dim_fragment_type.hpp
    include/dynd/types/ellipsis_dim_type.hpp
    include/dynd/types/fixed_dim_type.hpp
    include/dynd/types/fixed_dim_kind_type.hpp
    include/dynd/types/fixed_bytes_kind_type.hpp
    include/dynd/types/fixed_bytes_type.hpp
    include/dynd/types/fixed_string_kind_type.hpp
    include/dynd/types/fixed_string_type.hpp
    include/dynd/types/int_kind_sym_type.hpp
    include/dynd/types/kind_sym_type.hpp
    include/dynd/types/option_type.hpp
    include/dynd/types/pointer_type.hpp
    include/dynd/types/pow_dimsym_type.hpp
    include/dynd/types/scalar_kind_type.hpp
    include/dynd/types/string_type.hpp
    include/dynd/types/struct_type.hpp
    include/dynd/types/substitute_shape.hpp
    include/dynd/types/substitute_typevars.hpp
    include/dynd/types/time_parser.hpp
    include/dynd/types/time_type.hpp
    include/dynd/types/time_util.hpp
    include/dynd/types/tuple_type.hpp
    include/dynd/types/type_alignment.hpp
    include/dynd/types/type_id.hpp
    include/dynd/types/type_type.hpp
    include/dynd/types/typevar_constructed_type.hpp
    include/dynd/types/typevar_dim_type.hpp
    include/dynd/types/typevar_type.hpp
    include/dynd/types/var_dim_type.hpp
    include/dynd/types/view_type.hpp
    # Callables
    src/dynd/callables/base_callable.cpp
    include/dynd/callables/base_callable.hpp
    # Eval
    src/dynd/eval/eval_context.cpp
    include/dynd/eval/eval_context.hpp
    # Func
    src/dynd/func/arithmetic.cpp
    src/dynd/func/callable_registry.cpp
    src/dynd/func/assignment.cpp
    src/dynd/func/comparison.cpp
    src/dynd/func/compose.cpp
    src/dynd/func/compound.cpp
    src/dynd/func/copy.cpp
    src/dynd/func/constant.cpp
    src/dynd/func/elwise.cpp
    src/dynd/func/fft.cpp
    src/dynd/func/reduction.cpp
    src/dynd/func/math.cpp
    src/dynd/func/max.cpp
    src/dynd/func/min.cpp
    src/dynd/func/mean.cpp
    src/dynd/func/neighborhood.cpp
    src/dynd/func/outer.cpp
    src/dynd/func/permute.cpp
    src/dynd/func/random.cpp
    src/dynd/func/rolling.cpp
    src/dynd/func/sum.cpp
    src/dynd/func/take.cpp
    src/dynd/func/take_by_pointer.cpp
    src/dynd/func/view.cpp
    include/dynd/func/arithmetic.hpp
    include/dynd/func/callable_registry.hpp
    include/dynd/func/assignment.hpp
    include/dynd/func/copy.hpp
    include/dynd/func/comparison.hpp
    include/dynd/func/compose.hpp
    include/dynd/func/compound.hpp
    include/dynd/func/constant.hpp
    include/dynd/func/elwise.hpp
    include/dynd/func/fft.hpp
    include/dynd/func/reduction.hpp
    include/dynd/func/math.hpp
    include/dynd/func/max.hpp
    include/dynd/func/mean.hpp
    include/dynd/func/min.hpp
    include/dynd/func/neighborhood.hpp
    include/dynd/func/outer.hpp
    include/dynd/func/permute.hpp
    include/dynd/func/random.hpp
    include/dynd/func/rolling.hpp
    include/dynd/func/sum.hpp
    include/dynd/func/take.hpp
    include/dynd/func/take_by_pointer.hpp
    include/dynd/func/view.hpp
    # Kernels
    src/dynd/kernels/byteswap_kernels.cpp
    src/dynd/kernels/compare_kernels.cpp
    src/dynd/kernels/copy_kernel.cpp
    src/dynd/kernels/expression_assignment_kernels.cpp
    src/dynd/kernels/fft_kernel.cpp
    src/dynd/kernels/kernel_builder.cpp
    src/dynd/kernels/multidispatch_kernel.cpp
    src/dynd/kernels/option_assignment_kernels.cpp
    src/dynd/kernels/rolling_kernel.cpp
    src/dynd/kernels/struct_assignment_kernels.cpp
    src/dynd/kernels/take_kernel.cpp
    src/dynd/kernels/tuple_assignment_kernels.cpp
    include/dynd/kernels/apply.hpp
    include/dynd/kernels/arithmetic.hpp
    include/dynd/kernels/assign_na_kernel.hpp
    include/dynd/kernels/assignment_kernels.hpp
    include/dynd/kernels/base_kernel.hpp
    include/dynd/kernels/byteswap_kernels.hpp
    include/dynd/kernels/ckernel_prefix.hpp
    include/dynd/kernels/compare_kernels.hpp
    include/dynd/kernels/compose_kernel.hpp
    include/dynd/kernels/compound_kernel.hpp
    include/dynd/kernels/copy_kernel.hpp
    include/dynd/kernels/constant_kernel.hpp
    include/dynd/kernels/cuda_launch.hpp
    include/dynd/kernels/elwise.hpp
    include/dynd/kernels/expression_assignment_kernels.hpp
    include/dynd/kernels/fft_kernel.hpp
    include/dynd/kernels/index_kernel.hpp
    include/dynd/kernels/is_na_kernel.hpp
    include/dynd/kernels/kernel_builder.hpp
    include/dynd/kernels/max_kernel.hpp
    include/dynd/kernels/min_kernel.hpp
    include/dynd/kernels/multidispatch_kernel.hpp
    include/dynd/kernels/option_assignment_kernels.hpp
    include/dynd/kernels/outer.hpp
    include/dynd/kernels/reduction_kernel.hpp
    include/dynd/kernels/rolling_kernel.hpp
    include/dynd/kernels/sort_kernel.hpp
    include/dynd/kernels/string_concat_kernel.hpp
    include/dynd/kernels/string_count_kernel.hpp
    include/dynd/kernels/string_find_kernel.hpp
    include/dynd/kernels/string_replace_kernel.hpp
    include/dynd/kernels/struct_assignment_kernels.hpp
    include/dynd/kernels/take_kernel.hpp
    include/dynd/kernels/tuple_assignment_kernels.hpp
    include/dynd/kernels/uniform_kernel.hpp
    include/dynd/kernels/view_kernel.hpp
    # MemBlock
    src/dynd/memblock/memory_block.cpp
    src/dynd/memblock/executable_memory_block_windows_x64.cpp
    src/dynd/memblock/executable_memory_block_darwin_x64.cpp
    src/dynd/memblock/executable_memory_block_linux_x64.cpp
    src/dynd/memblock/external_memory_block.cpp
    src/dynd/memblock/fixed_size_pod_memory_block.cpp
    src/dynd/memblock/memmap_memory_block.cpp
    src/dynd/memblock/pod_memory_block.cpp
    src/dynd/memblock/array_memory_block.cpp
    src/dynd/memblock/objectarray_memory_block.cpp
    src/dynd/memblock/zeroinit_memory_block.cpp
    include/dynd/memblock/memory_block.hpp
    include/dynd/memblock/executable_memory_block.hpp
    include/dynd/memblock/external_memory_block.hpp
    include/dynd/memblock/fixed_size_pod_memory_block.hpp
    include/dynd/memblock/memmap_memory_block.hpp
    include/dynd/memblock/pod_memory_block.hpp
    include/dynd/memblock/array_memory_block.hpp
    include/dynd/memblock/objectarray_memory_block.hpp
    include/dynd/memblock/zeroinit_memory_block.hpp
    # Main
    src/dynd/array.cpp
    src/dynd/array_range.cpp
    src/dynd/asarray.cpp
    src/dynd/callable.cpp
    # src/dynd/config.cpp
    src/dynd/convert.cpp
    src/dynd/float16.cpp
    src/dynd/float128.cpp
    src/dynd/functional.cpp
    src/dynd/int128.cpp
    src/dynd/option.cpp
    src/dynd/search.cpp
    src/dynd/sort.cpp
    src/dynd/type.cpp
    src/dynd/type_registry.cpp
    src/dynd/type_promotion.cpp
    src/dynd/exceptions.cpp
    src/dynd/git_version.cpp.in # Included here for ease of editing in IDEs
    ${CMAKE_CURRENT_BINARY_DIR}/src/dynd/git_version.cpp
    src/dynd/index.cpp
    src/dynd/json_formatter.cpp
    src/dynd/json_parser.cpp
    src/dynd/logic.cpp
    src/dynd/parse.cpp
    src/dynd/shape_tools.cpp
    src/dynd/special.cpp
    src/dynd/string.cpp
    src/dynd/string_encodings.cpp
    src/dynd/uint128.cpp
    src/dynd/view.cpp
    include/dynd/array.hpp
    include/dynd/array_range.hpp
    include/dynd/array_iter.hpp
    include/dynd/arrmeta_holder.hpp
    include/dynd/asarray.hpp
    include/dynd/bool1.hpp
    include/dynd/bytes.hpp
    include/dynd/callable.hpp
    include/dynd/cephes.hpp
    include/dynd/cmake_config.hpp.in # Included here for ease of editing in IDEs
    ${CMAKE_CURRENT_BINARY_DIR}/include/dynd/cmake_config.hpp
    include/dynd/complex.hpp
    include/dynd/config.hpp
    include/dynd/cling_all.hpp
    include/dynd/convert.hpp
    include/dynd/diagnostics.hpp
    include/dynd/ensure_immutable_contig.hpp
    include/dynd/float16.hpp
    include/dynd/float128.hpp
    include/dynd/int128.hpp
    include/dynd/iterator.hpp
    include/dynd/logic.hpp
    include/dynd/math.hpp
    include/dynd/sort.hpp
    include/dynd/string.hpp
    include/dynd/string_search.hpp
    include/dynd/type.hpp
    include/dynd/type_registry.hpp
    include/dynd/type_sequence.hpp
    include/dynd/type_promotion.hpp
    include/dynd/exceptions.hpp
    include/dynd/fpstatus.hpp
    include/dynd/functional.hpp
    include/dynd/json_formatter.hpp
    include/dynd/json_parser.hpp
    include/dynd/index.hpp
    include/dynd/irange.hpp
    include/dynd/option.hpp
    include/dynd/parse.hpp
    include/dynd/platform_definitions.hpp
    include/dynd/shortvector.hpp
    include/dynd/shape_tools.hpp
    include/dynd/special.hpp
    include/dynd/string_encodings.hpp
    include/dynd/uint128.hpp
    include/dynd/view.hpp
    ${CMAKE_CURRENT_BINARY_DIR}/include/dynd/visibility.hpp
    include/dynd/with.hpp
    )

include_directories(
    include
    thirdparty/utf8/source
    )

source_group("Main Source" REGULAR_EXPRESSION "src/dynd/.*cpp")
source_group("Main Headers" REGULAR_EXPRESSION "include/dynd/.*hpp")
source_group("Types Source" REGULAR_EXPRESSION "src/dynd/types/.*cpp")
source_group("Types Headers" REGULAR_EXPRESSION "include/dynd/types/.*hpp")
source_group("Eval Source" REGULAR_EXPRESSION "src/dynd/eval/.*cpp")
source_group("Eval Headers" REGULAR_EXPRESSION "include/dynd/eval/.*hpp")
source_group("Func Source" REGULAR_EXPRESSION "src/dynd/func/.*cpp")
source_group("Func Headers" REGULAR_EXPRESSION "include/dynd/func/.*hpp")
source_group("Iter Source" REGULAR_EXPRESSION "src/dynd/iter/.*cpp")
source_group("Iter Headers" REGULAR_EXPRESSION "include/dynd/iter/.*hpp")
source_group("Kernels Source" REGULAR_EXPRESSION "src/dynd/kernels/.*cpp")
source_group("Kernels Headers" REGULAR_EXPRESSION "include/dynd/kernels/.*hpp")
source_group("MemBlock Source" REGULAR_EXPRESSION "src/dynd/memblock/.*cpp")
source_group("MemBlock Headers" REGULAR_EXPRESSION "include/dynd/memblock/.*hpp")
source_group("Internal Headers" REGULAR_EXPRESSION "src/dynd/.*hpp")

#set_source_files_properties(include/dynd/kernels/compare_kernels.hpp PROPERTIES COMPILE_FLAGS -Wno-sign-compare)
#set_source_files_properties(src/dynd/func/comparison.cpp PROPERTIES COMPILE_FLAGS -Wno-sign-compare)

if (DYND_CUDA)
    # Replace some source files with their CUDA versions
    foreach(filename_CPP
            src/dynd/float16.cpp
            src/dynd/float128.cpp
            src/dynd/int128.cpp
            src/dynd/uint128.cpp
            # Func
            src/dynd/func/arithmetic.cpp
            src/dynd/func/elwise.cpp
            src/dynd/func/math.cpp
            src/dynd/func/permute.cpp
            src/dynd/func/random.cpp
            # Kernels
            src/dynd/kernels/assignment_kernels.cpp
            src/dynd/kernels/kernel_builder.cpp
        )
        list(REMOVE_ITEM libdynd_SRC ${filename_CPP})
        list(APPEND libdynddev_SRC ${filename_CPP})
        set_property(SOURCE ${filename_CPP} PROPERTY CUDA_SOURCE_FILE TRUE)
    endforeach(filename_CPP)

    set(CUDA_SEPARABLE_COMPILATION ON)

    if(NOT WIN32)
        set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS};-std=c++14;-Xcompiler;-fPIC;-Xcompiler;-O3)
    endif()

    # Make some warnings into errors and inhibit other warnings
    set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS};-Werror=cross-execution-space-call;
        -Xcudafe;--diag_suppress=boolean_controlling_expr_is_constant;
        -Xcudafe;--diag_suppress=cc_clobber_ignored;)
    if(NOT WIN32)
        set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS};
            -Xcompiler;-Wno-unused;-Xcompiler;-Wno-unused-parameter)
    endif()
endif()

if (DYND_FFTW)
    find_path(FFTW_PATH fftw3.h)
    include_directories(${FFTW_PATH})
    set(DYND_LINK_LIBS ${DYND_LINK_LIBS} fftw3 fftw3f)
endif()

if ((NOT DYND_SHARED_LIB) AND (DYND_INSTALL_LIB))
    # If we're making an installable static library,
    # include the sublibraries source directly because
    # including static libraries in other static libraries
    # is a hassle
    get_directory_property(cephes_SRC
                           DIRECTORY "thirdparty/cephes"
                           DEFINITION cephes_SRC)
    get_directory_property(datetime_SRC
                           DIRECTORY "thirdparty/datetime"
                           DEFINITION datetime_SRC)
    set(libdynd_SRC
        ${libdynd_SRC}
        ${cephes_SRC}
        ${datetime_SRC}
        )
endif()

include_directories(${CMAKE_CURRENT_BINARY_DIR}/include)

add_library(dynd_OBJ OBJECT ${libdynd_SRC})

if(DYND_LLVM)
  if(LLVM_FOUND)
    add_subdirectory(plugin)

    add_dependencies(dynd_OBJ dynd_plugin)
    set_target_properties(dynd_OBJ PROPERTIES COMPILE_FLAGS "-Xclang -load -Xclang plugin/libdynd_plugin.so")
  endif()
endif()

if (DYND_SHARED_LIB)
    if (DYND_CUDA)
        cuda_add_library(libdynd SHARED ${config_cpp} ${libdynddev_SRC} $<TARGET_OBJECTS:dynd_OBJ>)
    else()
        # xcode doesn't like when all cpp files are contained in an OBJECT library
        add_library(libdynd SHARED ${config_cpp} $<TARGET_OBJECTS:dynd_OBJ>)
    endif()
    set_target_properties(libdynd
        PROPERTIES
        OUTPUT_NAME "dynd"
        PREFIX "${CMAKE_SHARED_LIBRARY_PREFIX}"
        )
else()
    if (DYND_CUDA)
        cuda_add_library(libdynd STATIC ${config_cpp} ${libdynddev_SRC} $<TARGET_OBJECTS:dynd_OBJ>)
    else()
        add_library(libdynd STATIC ${config_cpp} $<TARGET_OBJECTS:dynd_OBJ>)
    endif()
    set_target_properties(libdynd
        PROPERTIES
        OUTPUT_NAME "dynd"
        PREFIX "${CMAKE_STATIC_LIBRARY_PREFIX}"
        )
endif()

if (DYND_CUDA)
    cuda_add_cufft_to_target(libdynd)

    add_library(libdynddev STATIC ${config_cpp} $<TARGET_OBJECTS:dynd_OBJ> ${libdynd_SEPARABLE_COMPILATION_OBJECTS})
    cuda_add_cufft_to_target(libdynddev)
    set_target_properties(libdynddev PROPERTIES LINKER_LANGUAGE CXX)
    set_target_properties(libdynddev
        PROPERTIES
        OUTPUT_NAME "dynddev"
        PREFIX "${CMAKE_STATIC_LIBRARY_PREFIX}"
        )
endif()

set_property(
    TARGET libdynd dynd_OBJ
    PROPERTY COMPILE_DEFINITIONS DYND_EXPORT
)

# Add preprocessor definitions from CMake
configure_file("include/dynd/cmake_config.hpp.in"
               "${CMAKE_CURRENT_BINARY_DIR}/include/dynd/cmake_config.hpp")

# Copy the headers from cephes that need to be installed with libdynd
file(COPY thirdparty/cephes/rename.h
     DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/include/dynd/cephes)
file(COPY thirdparty/cephes/protos.h
     DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/include/dynd/cephes)

if(WIN32)
    set_target_properties(libdynd
        PROPERTIES
        PREFIX "lib"
        IMPORT_PREFIX "lib"
        )
elseif(APPLE)
    # The rpath stuff is confusing, and this is our attempt to get it right.
    # It's been complicated by a bug in certain versions of CMake that plays
    # particularly badly with CUDA. If anyone knows the "right" way to do this,
    # that would be great.
    #
    # See http://stackoverflow.com/questions/22885207/opencv-and-pcl-builds-on-osx-result-in-malformed-object-load-command-cmdsize
    #
    set_target_properties(libdynd
        PROPERTIES
        BUILD_WITH_INSTALL_RPATH ON
        INSTALL_NAME_DIR "@rpath"
    )
endif()

if (DYND_SHARED_LIB OR (NOT DYND_INSTALL_LIB))
    # If we're not making an installable static library,
    # link the sublibraries normally
    target_link_libraries(libdynd ${DYND_LINK_LIBS})
    if (DYND_CUDA)
        target_link_libraries(libdynddev ${DYND_LINK_LIBS})
    endif ()
endif()

if(DYND_BUILD_TESTS)
    add_subdirectory(tests)
endif()

if(DYND_BUILD_BENCHMARKS)
    add_subdirectory(benchmarks)
endif()

add_subdirectory(examples)

# Create a libdynd-config script
get_property(dynd_library_prefix TARGET libdynd PROPERTY PREFIX)
get_property(dynd_output_name TARGET libdynd PROPERTY OUTPUT_NAME)
set(DYND_LINK_FLAG "-l${dynd_output_name}")
if (DYND_SHARED_LIB)
    if ("${CMAKE_IMPORT_LIBRARY_SUFFIX}" STREQUAL "")
        set(DYND_LIB_FILE "${dynd_library_prefix}${dynd_output_name}${CMAKE_SHARED_LIBRARY_SUFFIX}")
    else()
        set(DYND_LIB_FILE "${dynd_library_prefix}${dynd_output_name}${CMAKE_IMPORT_LIBRARY_SUFFIX}")
    endif()
else()
    set(DYND_LIB_FILE "${dynd_library_prefix}${dynd_output_name}${CMAKE_STATIC_LIBRARY_SUFFIX}")
endif()
if(WIN32)
    if (DYND_SHARED_LIB)
        set(DYND_STATIC_LIB_DIR "")
    else()
        set(DYND_STATIC_LIB_DIR "\\static")
    endif()
    configure_file(
        "${CMAKE_CURRENT_SOURCE_DIR}/libdynd-config.bat.in"
        "${CMAKE_CURRENT_BINARY_DIR}/libdynd-config.bat" @ONLY)
else()
    if (DYND_SHARED_LIB)
        set(DYND_STATIC_LIB_DIR "")
    else()
        set(DYND_STATIC_LIB_DIR "/static")
    endif()
    configure_file(
        "${CMAKE_CURRENT_SOURCE_DIR}/libdynd-config.in"
        "${CMAKE_CURRENT_BINARY_DIR}/libdynd-config" @ONLY)
endif()

# If requested, install the .lib/.so/.dll file and headers to the install prefix
if (DYND_INSTALL_LIB)
    # Install the libdynd binary
    install(TARGETS libdynd
        RUNTIME DESTINATION lib${LIB_SUFFIX}
        LIBRARY DESTINATION lib${LIB_SUFFIX}
        ARCHIVE DESTINATION lib${LIB_SUFFIX}${DYND_STATIC_LIB_DIR})
    # Install the libdynddev binary
    if(DYND_CUDA)
        install(TARGETS libdynddev
            RUNTIME DESTINATION lib${LIB_SUFFIX}
            LIBRARY DESTINATION lib${LIB_SUFFIX}
            ARCHIVE DESTINATION lib${LIB_SUFFIX})
    endif()
    # Install the libdynd headers
    install(DIRECTORY "include/dynd"
            DESTINATION "${CMAKE_INSTALL_PREFIX}/include")
    install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/include/dynd"
            DESTINATION "${CMAKE_INSTALL_PREFIX}/include")
    # Install the libdynd-config script
    if(WIN32)
        install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/libdynd-config.bat"
            DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
        if(DYND_SHARED_LIB)
            install(FILES "$<TARGET_FILE_DIR:libdynd>/libdynd.dll"
                DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
        endif()
    else()
        install(PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/libdynd-config"
            DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
    endif()
endif()
