diff --git a/cmake/legate_helper_functions.cmake b/cmake/legate_helper_functions.cmake index eb967fb00..762e2b30a 100644 --- a/cmake/legate_helper_functions.cmake +++ b/cmake/legate_helper_functions.cmake @@ -58,18 +58,24 @@ function(legate_default_cpp_install target) ) endfunction() -function(legate_add_cffi header) +function(legate_add_cffi header target) execute_process( COMMAND ${CMAKE_C_COMPILER} -E -P "${header}" ECHO_ERROR_VARIABLE - OUTPUT_VARIABLE header_content + OUTPUT_VARIABLE header_output COMMAND_ERROR_IS_FATAL ANY ) +string(JOIN "\n" header_content + "${header_output}" + "void ${target}_perform_registration();" +) set(install_info_in [=[ +from pathlib import Path + def get_libpath(): import os, sys, platform join = os.path.join @@ -85,15 +91,17 @@ def get_libpath(): }[platform.system()] def find_lib(libdir): - target = "@target" - if exists(join(libdir, f"lib{target}{so_ext}")): - return libdir + target = f"libhello{so_ext}*" + search_path = Path(libdir) + matches = [m for m in search_path.rglob(target)] + if matches: + return matches[0].parent return None return ( - find_libcunumeric(join(cn_path, "build", "lib")) or - find_libcunumeric(join(dirname(dirname(dirname(cn_path))), "lib")) or - find_libcunumeric(join(dirname(dirname(sys.executable)), "lib")) or + find_lib("@CMAKE_BINARY_DIR@") or + find_lib(join(dirname(dirname(dirname(cn_path))), "lib")) or + find_lib(join(dirname(dirname(sys.executable)), "lib")) or "" ) @@ -182,3 +190,195 @@ function(legate_add_cpp_subdirectory dir target) endif() endfunction() + +function(legate_cpp_library_template target output_sources_variable) + set(file_template +[=[ +#pragma once + +#include "legate.h" + +namespace @target@ { + +struct Registry { + public: + template + static void record_variant(Args&&... args) + { + get_registrar().record_variant(std::forward(args)...); + } + static legate::LegateTaskRegistrar& get_registrar(); +}; + +template +struct Task : public legate::LegateTask { + using Registrar = Registry; + static constexpr int TASK_ID = ID; +}; + +} +]=]) + string(CONFIGURE "${file_template}" file_content @ONLY) + file(WRITE ${CMAKE_CURRENT_SOURCE_DIR}/legate_library.h "${file_content}") + + set(file_template +[=[ +#include "legate_library.h" +#include "core/mapping/base_mapper.h" + +namespace @target@ { + +class Mapper : public legate::mapping::BaseMapper { + + public: + Mapper(Legion::Runtime* rt, Legion::Machine machine, const legate::LibraryContext& context) + : BaseMapper(rt, machine, context) + { + } + + virtual ~Mapper(void) {} + + private: + Mapper(const Mapper& rhs) = delete; + Mapper& operator=(const Mapper& rhs) = delete; + + // Legate mapping functions + public: + bool is_pure() const override { return true; } + + legate::mapping::TaskTarget task_target( + const legate::mapping::Task& task, + const std::vector& options) override { + return *options.begin(); + } + + std::vector store_mappings( + const legate::mapping::Task& task, + const std::vector& options) override { + using legate::mapping::StoreMapping; + std::vector mappings; + auto& inputs = task.inputs(); + auto& outputs = task.outputs(); + for (auto& input : inputs) { + mappings.push_back(StoreMapping::default_mapping(input, options.front())); + mappings.back().policy.exact = true; + } + for (auto& output : outputs) { + mappings.push_back(StoreMapping::default_mapping(output, options.front())); + mappings.back().policy.exact = true; + } + return std::move(mappings); + } + + legate::Scalar tunable_value(legate::TunableID tunable_id) override { + return 0; + } +}; + +static const char* const library_name = "hello"; + +Legion::Logger log_hello("hello"); + +/*static*/ legate::LegateTaskRegistrar& Registry::get_registrar() +{ + static legate::LegateTaskRegistrar registrar; + return registrar; +} + +void registration_callback(Legion::Machine machine, + Legion::Runtime* runtime, + const std::set& local_procs) +{ + legate::ResourceConfig config; + config.max_mappers = 1; + config.max_tasks = 1024; + config.max_reduction_ops = 8; + legate::LibraryContext context(runtime, library_name, config); + + Registry::get_registrar().register_all_tasks(runtime, context); + + // Now we can register our mapper with the runtime + context.register_mapper(new Mapper(runtime, machine, context), 0); +} + +} // namespace @target@ + +extern "C" { + +void @target@_perform_registration(void) +{ + // Tell the runtime about our registration callback so we hook it + // in before the runtime starts and make it global so that we know + // that this call back is invoked everywhere across all nodes + Legion::Runtime::perform_registration_callback(@target@::registration_callback, true /*global*/); +} + +} +]=]) + string(CONFIGURE "${file_template}" file_content @ONLY) + file(WRITE ${CMAKE_CURRENT_SOURCE_DIR}/legate_library.cc "${file_content}") + + set(${output_sources_variable} + legate_library.h + legate_library.cc + PARENT_SCOPE + ) +endfunction() + +function(legate_python_library_template target) +set(file_template +[=[ +from legate.core import ( + Library, + ResourceConfig, + get_legate_runtime, +) +import os +from typing import Any + +class UserLibrary(Library): + def __init__(self, name: str) -> None: + self.name = name + self.shared_object: Any = None + + @property + def cffi(self) -> Any: + return self.shared_object + + def get_name(self) -> str: + return self.name + + def get_shared_library(self) -> str: + from hello.install_info import libpath + return os.path.join(libpath, f"lib@target@{self.get_library_extension()}") + + def get_c_header(self) -> str: + from hello.install_info import header + + return header + + def get_registration_callback(self) -> str: + return "hello_perform_registration" + + def get_resource_configuration(self) -> ResourceConfig: + assert self.shared_object is not None + config = ResourceConfig() + config.max_tasks = 1024 + config.max_mappers = 1 + config.max_reduction_ops = 8 + config.max_projections = 0 + config.max_shardings = 0 + return config + + def initialize(self, shared_object: Any) -> None: + self.shared_object = shared_object + + def destroy(self) -> None: + pass + +user_lib = UserLibrary("@target@") +user_context = get_legate_runtime().register_library(user_lib) +]=]) + string(CONFIGURE "${file_template}" file_content @ONLY) + file(WRITE ${CMAKE_SOURCE_DIR}/${target}/library.py "${file_content}") +endfunction()