| # Adds source files to a libclc builtin library target with deduplication. If a |
| # source with the same basename already exists in the target's SOURCES property |
| # the new file is skipped. This enables target-specific directories to override |
| # generic implementations when they are included first. |
| # |
| # Sources are specified as paths relative to CMAKE_CURRENT_SOURCE_DIR, or |
| # relative to BASE_DIR if provided. |
| function(libclc_add_sources target) |
| cmake_parse_arguments(ARG "" "BASE_DIR" "FILES" ${ARGN}) |
| if(NOT ARG_BASE_DIR) |
| set(ARG_BASE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) |
| endif() |
| |
| get_target_property(existing ${target} SOURCES) |
| |
| set(seen) |
| foreach(file IN LISTS existing) |
| get_filename_component(name "${file}" NAME) |
| list(APPEND seen "${name}") |
| endforeach() |
| |
| set(new_sources) |
| foreach(rel_src IN LISTS ARG_FILES) |
| get_filename_component(name "${rel_src}" NAME) |
| if(NOT name IN_LIST seen) |
| list(APPEND new_sources "${ARG_BASE_DIR}/${rel_src}") |
| list(APPEND seen "${name}") |
| endif() |
| endforeach() |
| |
| if(new_sources) |
| target_sources(${target} PRIVATE ${new_sources}) |
| set(inc_dirs) |
| foreach(file IN LISTS new_sources) |
| get_filename_component(dir "${file}" DIRECTORY) |
| list(APPEND inc_dirs "${dir}") |
| endforeach() |
| list(REMOVE_DUPLICATES inc_dirs) |
| target_include_directories(${target} PRIVATE ${inc_dirs}) |
| endif() |
| endfunction() |
| |
| # Appends a compile option to the given source files. Source paths are |
| # relative to CMAKE_CURRENT_SOURCE_DIR. The property is set in the |
| # top-level libclc directory scope. |
| function(libclc_set_source_options option) |
| set(srcs ${ARGN}) |
| list(TRANSFORM srcs PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/") |
| set_property(SOURCE ${srcs} |
| DIRECTORY ${LIBCLC_SOURCE_DIR} |
| APPEND PROPERTY COMPILE_OPTIONS ${option} |
| ) |
| endfunction() |
| |
| # Creates an object library target for libclc builtins and configures its |
| # compile options, include directories, and definitions. Subdirectories |
| # populate sources via libclc_add_sources() after this call. |
| function(libclc_add_builtin_library target_name) |
| cmake_parse_arguments(ARG |
| "" |
| "FOLDER;SOURCE_SUB_DIR" |
| "COMPILE_OPTIONS;INCLUDE_DIRS;COMPILE_DEFINITIONS" |
| ${ARGN} |
| ) |
| |
| if(NOT ARG_SOURCE_SUB_DIR) |
| message(FATAL_ERROR "SOURCE_SUB_DIR is required for libclc_add_builtin_library") |
| endif() |
| |
| add_library(${target_name} OBJECT) |
| target_compile_options(${target_name} PRIVATE ${ARG_COMPILE_OPTIONS}) |
| target_include_directories(${target_name} PRIVATE ${ARG_INCLUDE_DIRS}) |
| target_compile_definitions(${target_name} PRIVATE ${ARG_COMPILE_DEFINITIONS}) |
| set_target_properties(${target_name} PROPERTIES FOLDER ${ARG_FOLDER}) |
| |
| # Populate sources. |
| add_subdirectory( |
| ${LIBCLC_SOURCE_DIR}/${ARG_SOURCE_SUB_DIR} |
| ${CMAKE_CURRENT_BINARY_DIR}/${target_name} |
| ) |
| endfunction() |
| |
| # Builds a builtin library from sources, links it with any internalized |
| # dependencies, produces the final output file, and registers it for |
| # installation. |
| function(libclc_add_library target_name) |
| cmake_parse_arguments(ARG |
| "" |
| "ARCH;TRIPLE;TARGET_TRIPLE;SOURCE_TARGET;SOURCE_SUB_DIR;OUTPUT_FILENAME;PARENT_TARGET" |
| "COMPILE_OPTIONS;INCLUDE_DIRS;COMPILE_DEFINITIONS;INTERNALIZE_LIBRARIES;OPT_FLAGS" |
| ${ARGN} |
| ) |
| |
| if(NOT ARG_SOURCE_TARGET) |
| message(FATAL_ERROR "SOURCE_TARGET is required for libclc_add_library") |
| endif() |
| if(NOT ARG_OUTPUT_FILENAME) |
| message(FATAL_ERROR "OUTPUT_FILENAME is required for libclc_add_library") |
| endif() |
| if(NOT ARG_PARENT_TARGET) |
| message(FATAL_ERROR "PARENT_TARGET is required for libclc_add_library") |
| endif() |
| |
| libclc_add_builtin_library(${ARG_SOURCE_TARGET} |
| COMPILE_OPTIONS ${ARG_COMPILE_OPTIONS} |
| INCLUDE_DIRS ${ARG_INCLUDE_DIRS} |
| COMPILE_DEFINITIONS ${ARG_COMPILE_DEFINITIONS} |
| SOURCE_SUB_DIR ${ARG_SOURCE_SUB_DIR} |
| FOLDER "libclc/Device IR/Intermediate" |
| ) |
| |
| set(library_dir ${LIBCLC_OUTPUT_LIBRARY_DIR}/${ARG_TARGET_TRIPLE}) |
| file(MAKE_DIRECTORY ${library_dir}) |
| |
| # Create a combined static archive from all object libraries for installation. |
| set(archive_target ${target_name}.a) |
| add_library(${archive_target} STATIC) |
| target_link_libraries(${archive_target} PRIVATE |
| ${ARG_SOURCE_TARGET} ${ARG_INTERNALIZE_LIBRARIES} |
| ) |
| set_target_properties(${archive_target} PROPERTIES |
| OUTPUT_NAME ${ARG_OUTPUT_FILENAME} |
| PREFIX "" |
| ARCHIVE_OUTPUT_DIRECTORY ${library_dir} |
| FOLDER "libclc/Device IR/Library" |
| ) |
| |
| # Link the object files, using a temporary library for internalization. |
| set(linked_bc ${CMAKE_CURRENT_BINARY_DIR}/${target_name}.linked.bc) |
| set(link_cmd ${llvm-link_exe}) |
| set(link_deps ${llvm-link_target}) |
| |
| add_library(${target_name}-src STATIC) |
| target_link_libraries(${target_name}-src PRIVATE ${ARG_SOURCE_TARGET}) |
| set_target_properties(${target_name}-src PROPERTIES |
| FOLDER "libclc/Device IR/Library" |
| ) |
| list(APPEND link_cmd $<TARGET_FILE:${target_name}-src>) |
| list(APPEND link_deps ${target_name}-src) |
| |
| if(ARG_INTERNALIZE_LIBRARIES) |
| list(APPEND link_cmd --internalize --only-needed) |
| foreach(lib ${ARG_INTERNALIZE_LIBRARIES}) |
| add_library(${target_name}-${lib} STATIC) |
| target_link_libraries(${target_name}-${lib} PRIVATE ${lib}) |
| set_target_properties(${target_name}-${lib} PROPERTIES |
| FOLDER "libclc/Device IR/Library" |
| ) |
| list(APPEND link_cmd $<TARGET_FILE:${target_name}-${lib}>) |
| list(APPEND link_deps ${target_name}-${lib}) |
| endforeach() |
| endif() |
| list(APPEND link_cmd -o ${linked_bc}) |
| |
| add_custom_command(OUTPUT ${linked_bc} |
| COMMAND ${link_cmd} |
| DEPENDS ${link_deps} |
| ) |
| |
| string(REPLACE "-" ";" triple_parts "${ARG_TRIPLE}") |
| list(GET triple_parts 2 triple_os) |
| if(ARG_ARCH IN_LIST LIBCLC_ARCHS_SPIRV AND NOT triple_os STREQUAL vulkan) |
| # SPIR-V targets produce a .spv file from the linked bitcode. |
| set(builtins_lib ${library_dir}/${ARG_OUTPUT_FILENAME}.spv) |
| if(LIBCLC_USE_SPIRV_BACKEND) |
| add_custom_command(OUTPUT ${builtins_lib} |
| COMMAND ${CMAKE_CLC_COMPILER} -c --target=${ARG_TRIPLE} |
| -mllvm --spirv-ext=+SPV_KHR_fma |
| -x ir -o ${builtins_lib} ${linked_bc} |
| DEPENDS ${linked_bc} |
| ) |
| else() |
| add_custom_command(OUTPUT ${builtins_lib} |
| COMMAND ${llvm-spirv_exe} |
| --spirv-max-version=1.1 |
| --spirv-ext=+SPV_KHR_fma |
| -o ${builtins_lib} ${linked_bc} |
| DEPENDS ${linked_bc} |
| ) |
| endif() |
| else() |
| # All other targets produce an optimized .bc file. |
| set(builtins_lib ${library_dir}/${ARG_OUTPUT_FILENAME}.bc) |
| add_custom_command(OUTPUT ${builtins_lib} |
| COMMAND ${opt_exe} ${ARG_OPT_FLAGS} -o ${builtins_lib} ${linked_bc} |
| DEPENDS ${opt_target} ${linked_bc} |
| ) |
| endif() |
| |
| add_custom_target(${target_name} ALL DEPENDS ${builtins_lib}) |
| set_target_properties(${target_name} PROPERTIES |
| TARGET_FILE ${builtins_lib} |
| FOLDER "libclc/Device IR/Library" |
| ) |
| |
| add_dependencies(${ARG_PARENT_TARGET} ${target_name} ${archive_target}) |
| |
| install(FILES ${builtins_lib} $<TARGET_FILE:${archive_target}> |
| DESTINATION ${LIBCLC_INSTALL_DIR}/${ARG_TARGET_TRIPLE} |
| COMPONENT ${ARG_PARENT_TARGET} |
| ) |
| endfunction() |