From d41b04806ea660922af963952bd54155a3c8df6d Mon Sep 17 00:00:00 2001 From: jjwilke Date: Thu, 6 Apr 2023 10:40:45 -0700 Subject: [PATCH] add python generator script for project templates --- cmake/cpp_header_template | 39 +++++ cmake/cpp_source_template | 104 +++++++++++++ cmake/legate_gen_library.in | 211 ++++++++++++++++++++++++++ cmake/legate_helper_functions.cmake | 223 +--------------------------- cmake/python_template | 65 ++++++++ legate_core_cpp.cmake | 17 +++ setup.py | 2 +- 7 files changed, 440 insertions(+), 221 deletions(-) create mode 100644 cmake/cpp_header_template create mode 100644 cmake/cpp_source_template create mode 100644 cmake/legate_gen_library.in create mode 100644 cmake/python_template diff --git a/cmake/cpp_header_template b/cmake/cpp_header_template new file mode 100644 index 000000000..ac75f8461 --- /dev/null +++ b/cmake/cpp_header_template @@ -0,0 +1,39 @@ +/* Copyright 2023 NVIDIA Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#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::TaskRegistrar& get_registrar(); +}; + +template +struct Task : public legate::LegateTask { + using Registrar = Registry; + static constexpr int TASK_ID = ID; +}; + +} diff --git a/cmake/cpp_source_template b/cmake/cpp_source_template new file mode 100644 index 000000000..8a783102f --- /dev/null +++ b/cmake/cpp_source_template @@ -0,0 +1,104 @@ +/* Copyright 2023 NVIDIA Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "legate_library.h" +#include "core/mapping/mapping.h" + +namespace @target@ { + +class Mapper : public legate::mapping::LegateMapper { + public: + Mapper(){} + + private: + Mapper(const Mapper& rhs) = delete; + Mapper& operator=(const Mapper& rhs) = delete; + + // Legate mapping functions + public: + void set_machine(const legate::mapping::MachineQueryInterface* machine) override { + machine_ = machine; + } + + 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; + } + + private: + const legate::mapping::MachineQueryInterface* machine_; +}; + +static const char* const library_name = "@target@"; + +Legion::Logger log_@target@(library_name); + +/*static*/ legate::TaskRegistrar& Registry::get_registrar() +{ + static legate::TaskRegistrar registrar; + return registrar; +} + +void registration_callback() +{ + legate::ResourceConfig config; + config.max_mappers = 1; + config.max_tasks = 1024; + config.max_reduction_ops = 8; + legate::LibraryContext context(library_name, config); + + Registry::get_registrar().register_all_tasks(context); + + // Now we can register our mapper with the runtime + context.register_mapper(std::make_unique(), 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 + legate::Core::perform_registration<@target@::registration_callback>(); +} + +} diff --git a/cmake/legate_gen_library.in b/cmake/legate_gen_library.in new file mode 100644 index 000000000..295355b89 --- /dev/null +++ b/cmake/legate_gen_library.in @@ -0,0 +1,211 @@ +#! /usr/bin/env python + +from __future__ import annotations + +import os +import stat +import sys +from pathlib import Path +from typing import Union + +if len(sys.argv) != 2: + sys.exit("Must give a single argument with the library name") +libname = sys.argv[1] + +cpp_source_template = """ +@cpp_source_template@ +""" + +cpp_header_template = """ +@cpp_header_template@ +""" + +python_template = """ +@python_template@ +""" + + +cmake_toplevel_template = """ +#============================================================================= +# Copyright 2023 NVIDIA Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#============================================================================= + +cmake_minimum_required(VERSION 3.22.1 FATAL_ERROR) + +project($target VERSION 1.0 LANGUAGES C CXX) + +set(CMAKE_CXX_STANDARD 17) +set(BUILD_SHARED_LIBS ON) + +find_package(legate_core REQUIRED) + +legate_add_cpp_subdirectory(src TARGET $target EXPORT $target-export) + +legate_add_cffi(${CMAKE_CURRENT_SOURCE_DIR}/src/$target_cffi.h TARGET $target) +legate_default_python_install($target EXPORT $target-export) +""" + +cmake_src_template = """ +#============================================================================= +# Copyright 2023 NVIDIA Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#============================================================================= + +add_library( + $target + legate_library.h + legate_library.cc +) + +target_include_directories($target + PRIVATE + $ + INTERFACE + $ +) + +target_link_libraries($target PRIVATE legate::core) +""" + +setup_template = """ +#!/usr/bin/env python3 + +# Copyright 2023 NVIDIA Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +import os +from pathlib import Path + +from setuptools import find_packages +from skbuild import setup + +import legate.install_info as lg_install_info + +legate_dir = Path(lg_install_info.libpath).parent.as_posix() + +cmake_flags = [ + f"-Dlegate_core_ROOT:STRING={legate_dir}", +] + +env_cmake_args = os.environ.get("CMAKE_ARGS") +if env_cmake_args is not None: + cmake_flags.append(env_cmake_args) +os.environ["CMAKE_ARGS"] = " ".join(cmake_flags) + + +setup( + name="Legate $target", + version="0.1", + description="$target for Legate", + author="NVIDIA Corporation", + license="Apache 2.0", + classifiers=[ + "Intended Audience :: Developers", + "Topic :: Database", + "Topic :: Scientific/Engineering", + "License :: OSI Approved :: Apache Software License", + "Programming Language :: Python", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + ], + packages=find_packages( + where=".", + include=["$target", "$target.*"], + ), + include_package_data=True, + zip_safe=False, +) +""" + +editable_script = """ +legate_root=`python -c 'import legate.install_info as i; from pathlib import Path; print(Path(i.libpath).parent.resolve())'` +echo "Using Legate at $legate_root" +cmake -S . -B build -D legate_core_ROOT=$legate_root +cmake --build build +python -m pip install -e . -vv +""" + +install_script = """ +python -m pip install . +""" + +def generate_file(libname: str, template: str, path: Union[Path,str], executable: bool = False): + target_path = Path(libname) / Path(path) + if not target_path.parent.is_dir(): + target_path.parent.mkdir(parents=True) + + text = template.replace("$target", libname) + text = text.replace("@" "target" "@", libname) + with open(target_path, "w") as f: + f.write(text) + + if executable: + st = os.stat(target_path) + os.chmod(target_path, st.st_mode | stat.S_IRWXU) + +cffi_template = """ +/* Copyright 2023 NVIDIA Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +enum $targetOpCode { +}; +""" + +generate_file(libname, cpp_source_template, "src/legate_library.cc") +generate_file(libname, cpp_header_template, "src/legate_library.h") +generate_file(libname, python_template, Path(libname) / f"{libname}.py") +generate_file(libname, "", Path(libname) / "__init__.py") +generate_file(libname, setup_template, "setup.py") +generate_file(libname, editable_script, "editable-install.sh", executable=True) +generate_file(libname, install_script, "install.sh", executable=True) +generate_file(libname, cmake_toplevel_template, "CMakeLists.txt") +generate_file(libname, cmake_src_template, "src/CMakeLists.txt") +generate_file(libname, cffi_template, f"src/{libname}_cffi.h") diff --git a/cmake/legate_helper_functions.cmake b/cmake/legate_helper_functions.cmake index 703053880..4bb021ade 100644 --- a/cmake/legate_helper_functions.cmake +++ b/cmake/legate_helper_functions.cmake @@ -268,159 +268,10 @@ function(legate_add_cpp_subdirectory dir) endfunction() function(legate_cpp_library_template target output_sources_variable) - set(file_template -[=[ -/* Copyright 2023 NVIDIA Corporation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#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::TaskRegistrar& get_registrar(); -}; - -template -struct Task : public legate::LegateTask { - using Registrar = Registry; - static constexpr int TASK_ID = ID; -}; - -} -]=]) - string(CONFIGURE "${file_template}" file_content @ONLY) + string(CONFIGURE "${Legate_CPP_HEADER_TEMPLATE}" file_content @ONLY) file(WRITE ${CMAKE_CURRENT_SOURCE_DIR}/legate_library.h "${file_content}") - set(file_template -[=[ -/* Copyright 2023 NVIDIA Corporation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -#include "legate_library.h" -#include "core/mapping/mapping.h" - -namespace @target@ { - -class Mapper : public legate::mapping::LegateMapper { - public: - Mapper(){} - - private: - Mapper(const Mapper& rhs) = delete; - Mapper& operator=(const Mapper& rhs) = delete; - - // Legate mapping functions - public: - void set_machine(const legate::mapping::MachineQueryInterface* machine) override { - machine_ = machine; - } - - 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; - } - - private: - const legate::mapping::MachineQueryInterface* machine_; -}; - -static const char* const library_name = "@target@"; - -Legion::Logger log_@target@(library_name); - -/*static*/ legate::TaskRegistrar& Registry::get_registrar() -{ - static legate::TaskRegistrar registrar; - return registrar; -} - -void registration_callback() -{ - legate::ResourceConfig config; - config.max_mappers = 1; - config.max_tasks = 1024; - config.max_reduction_ops = 8; - legate::LibraryContext context(library_name, config); - - Registry::get_registrar().register_all_tasks(context); - - // Now we can register our mapper with the runtime - context.register_mapper(std::make_unique(), 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 - legate::Core::perform_registration<@target@::registration_callback>(); -} - -} -]=]) - string(CONFIGURE "${file_template}" file_content @ONLY) + string(CONFIGURE "${Legate_CPP_SOURCE_TEMPLATE}" file_content @ONLY) file(WRITE ${CMAKE_CURRENT_SOURCE_DIR}/legate_library.cc "${file_content}") set(${output_sources_variable} @@ -431,74 +282,6 @@ void @target@_perform_registration(void) endfunction() function(legate_python_library_template target) -set(file_template -[=[ -# Copyright 2023 NVIDIA Corporation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -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 @target@.install_info import libpath - return os.path.join(libpath, f"lib@target@{self.get_library_extension()}") - - def get_c_header(self) -> str: - from @target@.install_info import header - - return header - - def get_registration_callback(self) -> str: - return "@target@_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) + string(CONFIGURE "${Legate_PYTHON_TEMPLATE}" file_content @ONLY) file(WRITE ${CMAKE_SOURCE_DIR}/${target}/library.py "${file_content}") endfunction() diff --git a/cmake/python_template b/cmake/python_template new file mode 100644 index 000000000..795414410 --- /dev/null +++ b/cmake/python_template @@ -0,0 +1,65 @@ +# Copyright 2023 NVIDIA Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +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 @target@.install_info import libpath + return os.path.join(libpath, f"lib@target@{self.get_library_extension()}") + + def get_c_header(self) -> str: + from @target@.install_info import header + + return header + + def get_registration_callback(self) -> str: + return "@target@_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) diff --git a/legate_core_cpp.cmake b/legate_core_cpp.cmake index 588a15b83..91518e994 100644 --- a/legate_core_cpp.cmake +++ b/legate_core_cpp.cmake @@ -449,6 +449,14 @@ Imported Targets: ]=]) file(READ ${CMAKE_CURRENT_SOURCE_DIR}/cmake/legate_helper_functions.cmake helper_functions) +file(READ ${CMAKE_CURRENT_SOURCE_DIR}/cmake/cpp_source_template cpp_source_template) +file(READ ${CMAKE_CURRENT_SOURCE_DIR}/cmake/cpp_header_template cpp_header_template) +file(READ ${CMAKE_CURRENT_SOURCE_DIR}/cmake/python_template python_template) + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/legate_gen_library.in + ${CMAKE_CURRENT_SOURCE_DIR}/legate_gen_library + FILE_PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ + @ONLY) string(JOIN "\n" code_string [=[ @@ -466,6 +474,15 @@ if(Legion_NETWORKS) find_package(MPI REQUIRED COMPONENTS CXX) endif() ]=] +"set(Legate_CPP_HEADER_TEMPLATE [=[" +"${cpp_header_template}" +"]=])" +"set(Legate_CPP_SOURCE_TEMPLATE [=[" +"${cpp_source_template}" +"]=])" +"set(Legate_PYTHON_TEMPLATE [=[" +"${python_template}" +"]=])" "${helper_functions}" ) diff --git a/setup.py b/setup.py index 83912f31f..a0e2dd68c 100755 --- a/setup.py +++ b/setup.py @@ -67,7 +67,7 @@ "lgpatch = legate.lgpatch:main", ], }, - scripts=["bind.sh"], + scripts=["bind.sh", "gen_library"], cmdclass=versioneer.get_cmdclass(), install_requires=["numpy>=1.22"], zip_safe=False,