diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ba16a82 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.idea +.dew +dist +__pycache__ +codegen.egg-info diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..52cb9de --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,80 @@ +cmake_minimum_required(VERSION 3.12) +include(CMakePackageConfigHelpers) + +project(codegen VERSION 0.1.0) + +find_package(PythonInterp 3.6 REQUIRED) + +add_library(codegen INTERFACE) +target_compile_definitions( + codegen + INTERFACE + WITH_CODEGEN +) + +add_custom_target( + codegen_sdist + ALL + COMMAND + "${PYTHON_EXECUTABLE}" "${PROJECT_SOURCE_DIR}/setup.py" "sdist" "-d" "${PROJECT_BINARY_DIR}/dist" + WORKING_DIRECTORY + "${PROJECT_SOURCE_DIR}" +) +add_dependencies(codegen codegen_sdist) + +# Install the CMake Module +install( + DIRECTORY "${PROJECT_SOURCE_DIR}/cmake" + DESTINATION "share" +) + +# Install the python package +install( + FILES "${PROJECT_BINARY_DIR}/dist/codegen-${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}.tar.gz" + DESTINATION "share/codegen/" +) + +# Install the project headers +install( + DIRECTORY "${PROJECT_SOURCE_DIR}/include/codegen" + DESTINATION "include/codegen" +) + + +set(version_config_file "${PROJECT_BINARY_DIR}/codegenConfigVersion.cmake") +set(config_file "${PROJECT_BINARY_DIR}/codegenConfig.cmake") +set(config_install_dir "lib/cmake/codegen") + + +# Associate target with export +install( + TARGETS codegen + EXPORT codegenTargets + INCLUDES DESTINATION "include/codegen" +) + +# Install the target config files +install( + EXPORT codegenTargets + NAMESPACE "codegen::" + DESTINATION "${config_install_dir}" +) + +# Generate version config file +write_basic_package_version_file( + "${version_config_file}" + COMPATIBILITY SameMajorVersion +) + +# Generate config file +configure_package_config_file( + "Config.cmake.in" + "${config_file}" + INSTALL_DESTINATION "lib/cmake/codegen" +) + +# Install the config files +install( + FILES "${config_file}" "${version_config_file}" + DESTINATION ${config_install_dir} +) diff --git a/Config.cmake.in b/Config.cmake.in new file mode 100644 index 0000000..f32cd31 --- /dev/null +++ b/Config.cmake.in @@ -0,0 +1,4 @@ +@PACKAGE_INIT@ + +include("${CMAKE_CURRENT_LIST_DIR}/codegenTargets.cmake") +check_required_components(codegen) \ No newline at end of file diff --git a/cmake/Modules/codegen.cmake b/cmake/Modules/codegen.cmake new file mode 100644 index 0000000..d4bc382 --- /dev/null +++ b/cmake/Modules/codegen.cmake @@ -0,0 +1,217 @@ +cmake_minimum_required(VERSION 3.12) + +function(add_codegen_targets + source_files + generated_files_var + input_root + output_root + include_directories +) + # + # Find our python interpreter, and set up some python related variables. + # + find_package(PythonInterp 3.6 REQUIRED) + set(venv_path "${CMAKE_CURRENT_BINARY_DIR}/codegen_venv") + set(venv_dummy "${CMAKE_CURRENT_BINARY_DIR}/codegen_venv_dummy") + set(package_dummy "${CMAKE_CURRENT_BINARY_DIR}/codegen_package_dummy") + + set(missing_requirements FALSE) + + # + # Find libclang. + # + find_library(CLANG_LIBRARY NAMES clang libclang REQUIRED) + if ("${CLANG_LIBRARY}" STREQUAL "CLANG_LIBRARY-NOTFOUND") + message(SEND_ERROR "libclang not found") + set(missing_requirements TRUE) + endif() + + # + # Find the codegen python package file + # + if ("${CODEGEN_PACKAGE}" STREQUAL "") + foreach (prefix ${CMAKE_PREFIX_PATH}) + set(codegen_package_candidate "${prefix}/share/codegen/codegen-0.1.0.tar.gz") + if (EXISTS "${codegen_package_candidate}") + set(CODEGEN_PACKAGE "${codegen_package_candidate}") + break() + endif() + endforeach() + if ("${CODEGEN_PACKAGE}" STREQUAL "") + set(CODEGEN_PACKAGE "CODEGEN_PACKAGE-NOTFOUND" CACHE FILEPATH) + endif() + endif() + if ("${CODEGEN_PACKAGE}" STREQUAL "CODEGEN_PACKAGE-NOTFOUND") + message(SEND_ERROR "codegen package not found") + set(missing_requirements TRUE) + endif() + + if (missing_requirements) + message(FATAL_ERROR "Missing requirements") + endif() + + # + # Get name of python executable. We gotta add a '.exe' prefix if we're on windows, obviously. + # + if (WIN32) + set(sep ";") + set(python_executable_name "python.exe") + else() + set(sep ":") + set(python_executable_name "python") + endif() + + # + # Determine the path of the virtual env python wrapper. It's different on Windows. + # + set(venv_python_executable_path "bin/${python_executable_name}") + if (NOT EXISTS "${venv_python_executable_path}" AND WIN32) + set(venv_python_executable_path "Scripts/${python_executable_name}") + endif() + + # + # Setup the virtual env for the codegen tool to use if it hasn't been set up. + # + if (NOT EXISTS "${venv_dummy}") + message(STATUS "Creating virtual env at ${venv_path}") + execute_process( + COMMAND "${PYTHON_EXECUTABLE}" -m ensurepip + RESULT_VARIABLE update_venv_result + OUTPUT_VARIABLE update_venv_output + ERROR_VARIABLE update_venv_error + ) + if (NOT update_venv_result EQUAL 0) + # ensurepip module failed not installed. Check if pip is installed, and cause an error if it's not installed. + execute_process( + COMMAND "${PYTHON_EXECUTABLE}" -m pip --version + RESULT_VARIABLE pip_version_result + ) + if (NOT pip_version_result EQUAL 0) + message(FATAL_ERROR "Failed to run ensurepip module, and pip is not installed. Please install pip manually.") + endif() + endif() + + execute_process( + COMMAND "${PYTHON_EXECUTABLE}" -m pip install virtualenv + RESULT_VARIABLE update_venv_result + OUTPUT_VARIABLE update_venv_output + ERROR_VARIABLE update_venv_error + ) + if (NOT update_venv_result EQUAL 0) + message(FATAL_ERROR "Failed to install virtualenv with pip: result: ${update_venv_result}. stderr:\n${update_venv_error}") + endif() + + execute_process( + COMMAND "${PYTHON_EXECUTABLE}" -m virtualenv "${venv_path}" + RESULT_VARIABLE update_venv_result + OUTPUT_VARIABLE update_venv_output + ERROR_VARIABLE update_venv_error + ) + if (NOT update_venv_result EQUAL 0) + message(FATAL_ERROR "Cannot update codegen tool venv: result: ${update_venv_result}. stderr:\n${update_venv_error}") + endif() + + # + # Install the codegen package with pip + # + execute_process( + COMMAND + "${venv_path}/${venv_python_executable_path}" "-m" "pip" + "install" "${CODEGEN_PACKAGE}" + RESULT_VARIABLE pip_result + ERROR_VARIABLE pip_error + ) + if (NOT pip_result EQUAL 0) + message(FATAL_ERROR "Failed to install codegen packages into codegen virtualenv. result: ${pip_result}. stderr:\n${pip_error}") + endif() + file(TOUCH "${package_dummy}") + + # + # Create the dummy file to signify that we have successfully created the venv. + # + file(TOUCH "${venv_dummy}") + endif() + + # + # Add build-time target to update the codegen package if it's touched. + # + add_custom_command( + OUTPUT + "${package_dummy}" + COMMAND + "${venv_path}/${venv_python_executable_path}" "-m" "pip" + "install" "${CODEGEN_PACKAGE}" + COMMAND + "${CMAKE_COMMAND}" "-E" "touch" "${package_dummy}" + DEPENDS + "${CODEGEN_PACKAGE}" + ) + + set(include_directories_arguments "") + foreach(include_directory include_directories) + list(APPEND include_directories_arguments "-I") + list(APPEND include_directories_arguments "${include_directory}") + endforeach() + + message(STATUS "Updating codegen targets") + + # + # Set up targets for all files which will be generated by the codegen tool. + # + set(all_output_files "") + foreach(current_source_file ${source_files}) + # + # Determine which files are generated by this source file at configure time + # + execute_process( + COMMAND + "${venv_path}/${venv_python_executable_path}" "-m" "codegen" + "get_output_files" + "${current_source_file}" + ${include_directories_arguments} + "--libclangpath" "${CLANG_LIBRARY}" + "--source-root" "${input_root}" + "--output-root" "${output_root}" + OUTPUT_VARIABLE current_output_files + ERROR_VARIABLE tool_error + RESULT_VARIABLE tool_result + ) + if (NOT tool_result EQUAL 0) + message(SEND_ERROR "Error running codegen tool. result: ${tool_result}. stderr:\n${tool_error}") + continue() + endif() + + # + # Set up a build target for the outputs given to us by the above commands. + # + string(STRIP "${current_output_files}" current_output_files) + list(LENGTH current_output_files current_output_files_len) + if ("${current_output_files_len}" EQUAL 0) + continue() + endif() + + foreach(current_output_file ${current_output_files}) + list(APPEND all_output_files "${current_output_file}") + endforeach() + + add_custom_command( + OUTPUT "${current_output_files}" + COMMAND + "${venv_path}/${venv_python_executable_path}" "-m" "codegen" + "generate" + "${current_source_file}" + ${include_directories_arguments} + "--libclangpath" "${CLANG_LIBRARY}" + "--source-root" "${input_root}" + "--output-root" "${output_root}" + DEPENDS "${current_source_file}" "${package_dummy}" + ) + + endforeach() + + # + # "Return" a list of all files that will be generated during build time. + # + set("${generated_files_var}" "${all_output_files}" PARENT_SCOPE) + +endfunction() diff --git a/codegen/__init__.py b/codegen/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/codegen/__main__.py b/codegen/__main__.py new file mode 100644 index 0000000..099b616 --- /dev/null +++ b/codegen/__main__.py @@ -0,0 +1,3 @@ +import codegen.cli + +exit(codegen.cli.main()) diff --git a/codegen/cli.py b/codegen/cli.py new file mode 100644 index 0000000..c3d1ac6 --- /dev/null +++ b/codegen/cli.py @@ -0,0 +1,50 @@ +import sys +import argparse +from typing import List + +from codegen import codegen + + +class ArgumentData(object): + def __init__(self) -> None: + self.command = '' + self.source_file = '' + self.libclangpath = '' + self.include_paths: List[str] = [] + self.source_root = '' + self.output_root = '' + + +argparser = argparse.ArgumentParser() +argparser.add_argument('command', help='What to do') +argparser.add_argument('source_file', help='Source file to use') +argparser.add_argument('--libclangpath', help='Path to libclang library file', required=True) +argparser.add_argument('--include', '-I', help='Define an include path', dest='include_paths', action='append') +argparser.add_argument('--source-root', help='Root path of all source files', required=True) +argparser.add_argument('--output-root', help='Root path of all files to be output', required=True) + + +def main() -> int: + args = ArgumentData() + + # noinspection PyTypeChecker + argparser.parse_args(namespace=args) + + if args.command.lower() == 'get_output_files': + return do_get_output_files_command(args) + if args.command.lower() == 'generate': + return do_generate_command(args) + + sys.stderr.write('Invalid Command\n') + return 1 + + +def do_get_output_files_command(args: ArgumentData) -> int: + output_files = codegen.get_output_files(args.source_file, args.include_paths, args.libclangpath, args.source_root, args.output_root) + sys.stdout.write(';'.join(output_files)) + return 0 + + +def do_generate_command(args: ArgumentData) -> int: + codegen.RunCodegen(args.source_file, args.include_paths, args.libclangpath, args.source_root, args.output_root) + return 0 diff --git a/codegen.py b/codegen/codegen.py similarity index 64% rename from codegen.py rename to codegen/codegen.py index 077b4d2..6330a6a 100644 --- a/codegen.py +++ b/codegen/codegen.py @@ -1,13 +1,13 @@ # C++ code generation using clang import clang.cindex import cProfile -import glob import mako.template import os -import sys + +from typing import List, Iterable # Directory that the codegen script file is stored in -ScriptDir = os.path.dirname(__file__) +TemplateDir = os.path.normpath(os.path.join(os.path.dirname(__file__), 'data')) # [debug] Whether to enable profiling EnableProfiling = False @@ -16,10 +16,10 @@ EnableProfiling = False PrintAST = False # [debug] Path to store auto-generated codegen source files -ExportPath = "build\\codegen" +ExportPath = "build/codegen" # [debug] Path to store the final output cpp file -OutputCppSource = "%s\\auto_codegen.cpp" % ExportPath +OutputCppSource = "%s/auto_codegen.cpp" % ExportPath # [debug] Path to find the source files SourceRoot = "." @@ -33,6 +33,7 @@ InputViaCommandLine = True # Whether to always do a full regen ForceFullRegen = False + def GetCursorFullyQualifiedName(Cursor): """ Return the fully qualified name of the object represented by Cursor, including any parent scopes """ OutName = Cursor.spelling @@ -150,7 +151,7 @@ class ScopedDeclare: def DebugPrint(self): print( self.GenerateText(0) ) - + class SourceFile: """ A C++ source code file """ def __init__(self, FilePath): @@ -158,17 +159,17 @@ class SourceFile: self.Enums = [] self.RootDeclare = ScopedDeclare("", "") - def GetCodegenFile(self): + def GetCodegenFile(self, SourceRoot: str, OutputRoot: str): """ Returns the path to store the auto-generated code for this source file """ - if os.path.isabs(self.FilePath): - RelativePath = self.FilePath[3:] - return "%s\\%s.codegen.inl" % (ExportPath, RelativePath) - else: - return "%s\\%s.codegen.inl" % (ExportPath, self.FilePath) + abspath = os.path.abspath(self.FilePath) + relpath = os.path.relpath(abspath, SourceRoot) + reldir, filename = os.path.split(relpath) + filename_no_ext, _ = os.path.splitext(filename) + return os.path.join(OutputRoot, reldir, filename_no_ext + '_codegen.cpp') def LastModifiedTime(self): """ Returns the last modified time for this source file """ - return os.path.getmtime( self.FilePath ) + return os.path.getmtime(self.FilePath) def Analyze(self, ClangIndex, CompileEnvironment): """ Analyzes the AST for any components that need generated code """ @@ -179,23 +180,21 @@ class SourceFile: if PrintAST: DebugPrintCursorRecursive(TranslationUnit.cursor, self.FilePath) print("") - - # Generate code + + def Generate(self, OutputPath: str): if self.Enums: - MakoTemplateFile = open("%s/template.mako" % ScriptDir, "r") - MakoTemplateText = MakoTemplateFile.read() - MakoTemplateFile.close() - + with open("%s/template.mako" % TemplateDir, "r") as MakoTemplateFile: + MakoTemplateText = MakoTemplateFile.read() + MakoTemplate = mako.template.Template(MakoTemplateText) - GeneratedCode = MakoTemplate.render(Enums=self.Enums, IncludeFile=self.FilePath, ForwardDeclares=self.RootDeclare.Children) - - OutPath = self.GetCodegenFile() - OutDir = os.path.dirname(OutPath) + GeneratedCode = MakoTemplate.render(Enums=self.Enums, IncludeFile=self.FilePath, + ForwardDeclares=self.RootDeclare.Children) + + OutDir = os.path.dirname(OutputPath) os.makedirs(OutDir, exist_ok=True) - - OutCodegenFile = open(OutPath, "w") - OutCodegenFile.write(GeneratedCode) - OutCodegenFile.close() + + with open(OutputPath, "w") as file: + file.write(GeneratedCode) def CursorRecurse(self, Cursor, Depth): """ Recursive function that performs the actual analysis work of the AST """ @@ -248,114 +247,36 @@ class SourceFile: else: self.CursorRecurse(Child, Depth + 1) -def RunCodegen(): - # Source files to parse - SourceFiles = [] - IncludePaths = [] - OutCodegenSource = "" - if ParseCmdLine: - global InputViaCommandLine - - for i in range(0, len(sys.argv)): - arg = sys.argv[i] - - if InputViaCommandLine is True and arg == "-sourcefiles" or arg == "-include": - i += 1 - - while i < len(sys.argv) and sys.argv[i][0] != '-': - File = sys.argv[i] - - if arg == "-sourcefiles": - # this isn't the best way to handle this since the output file is provided via commandline arg - if "auto_codegen" not in File: - SourceFiles.append(File) - else: - IncludePaths.append(File) - - i += 1 - - i -= 1 - - # The only time we don't use commandline input is for debugging - if arg == "-cmdinput": - InputViaCommandLine = True - - if arg == "-full": - global ForceFullRegen - ForceFullRegen = True - - if arg == "-o": - i += 1 - OutCodegenSource = sys.argv[i] - - global ExportPath - ExportPath = os.path.dirname(OutCodegenSource) - - if arg == "-pwd": - i += 1 - WorkingDirectory = sys.argv[i] - os.chdir(WorkingDirectory) - - if not InputViaCommandLine: - SourceFiles = glob.glob("%s\\**\\*.cpp" % SourceRoot, recursive=True) - SourceFiles += glob.glob("%s\\**\\*.hpp" % SourceRoot, recursive=True) - SourceFiles += glob.glob("%s\\**\\*.h" % SourceRoot, recursive=True) - OutCodegenSource = OutputCppSource - - print("Codegen Input: " + " ".join(SourceFiles)) - print("Build Dir: " + ExportPath) - +def RunCodegen(file_path: str, include_paths: Iterable[str], lib_clang_path: str, source_root: str, output_root: str): + file = GetAnalyzedSourceFile(file_path, include_paths, lib_clang_path) + output_path = file.GetCodegenFile(source_root, output_root) + file.Generate(output_path) + + +# if EnableProfiling: +# cProfile.run('RunCodegen()') +# else: +# RunCodegen() + + +def GetAnalyzedSourceFile(FilePath: str, IncludePaths: Iterable[str], LibClangPath: str) -> SourceFile: # Clang index - #@todo - this definitely isn't portable??? how should I be setting this??? - clang.cindex.Config.set_library_file('C:\\Program Files\\LLVM\\bin\\libclang.dll') + clang.cindex.Config.set_library_file(LibClangPath) ClangIndex = clang.cindex.Index.create() # C++ environment CompileEnvironment = CxxCompileEnvironment(IncludePaths) - # Process all source files - LastRegenTime = os.path.getmtime(OutCodegenSource) if os.path.isfile(OutCodegenSource) else 0 - OutFiles = [] + NewFile = SourceFile(FilePath) + NewFile.Analyze(ClangIndex, CompileEnvironment) + return NewFile - for FilePath in SourceFiles: - # If the file doesn't exist, just skip it. - # This mirrors qmake behavior. - if not os.path.isfile(FilePath): - continue - - NewFile = SourceFile(FilePath) - NewFileOut = NewFile.GetCodegenFile() - - # Only run codegen on this file if it has been modified since last time - if ForceFullRegen or NewFile.LastModifiedTime() > LastRegenTime: - NewFile.Analyze(ClangIndex, CompileEnvironment) - - if NewFile.Enums: - # Register this as a file that needs to be included in the output source - OutFiles.append(NewFileOut) - else: - # Delete codegen file if it exists - if os.path.isfile(NewFileOut): - os.remove(NewFileOut) - - # If the file hasn't been modified, we still want to make sure it gets included in the output source - else: - if os.path.isfile(NewFileOut): - OutFiles.append(NewFileOut) - # Create final output cpp - OutDir = os.path.dirname(OutCodegenSource) - os.makedirs(OutDir, exist_ok=True) +def get_output_files(source_file: str, include_paths: Iterable[str], lib_clang_path: str, source_root: str, output_root: str) -> List[str]: + file = GetAnalyzedSourceFile(source_file, include_paths, lib_clang_path) - OutFile = open(OutCodegenSource, "w") - OutFile.write("#pragma warning( push )\n") - OutFile.write("#pragma warning( disable : 4146 )\n") # Suppress C4146: unary minus operator applied to unsigned type, result still unsgined - [OutFile.write("#include \"%s\"\n" % os.path.normpath(CodegenFile)) for CodegenFile in OutFiles] - OutFile.write("#pragma warning( pop )\n") - OutFile.close() + if not file.Enums: + return [] -if EnableProfiling: - cProfile.run('RunCodegen()') -else: - RunCodegen() \ No newline at end of file + return [file.GetCodegenFile(source_root, output_root)] diff --git a/codegen/data/template.mako b/codegen/data/template.mako new file mode 100644 index 0000000..89d1d15 --- /dev/null +++ b/codegen/data/template.mako @@ -0,0 +1,30 @@ +% if Enums: +#include +% endif +#include "${IncludeFile}" + +#pragma warning( push ) +#pragma warning( disable : 4146 ) // Suppress C4146: unary minus operator applied to unsigned type, result still unsgined + +## % for Decl in ForwardDeclares: +## ${Decl.GenerateText(0)} +## % endfor + +% for Enum in Enums: +template <> +const CEnumNameMap TEnumReflection<${Enum.FullName}>::skNameMap = { +<% ValueSet = set() %> \ + % for Constant in Enum.Constants: + % if Constant.Value not in ValueSet: + { ${Constant.Value}, "${Constant.Name}" }, +<% ValueSet.add(Constant.Value) %> \ + % endif + % endfor +}; + +template <> +const int TEnumReflection<${Enum.FullName}>::skErrorValue = ${Enum.ErrorValue}; + +% endfor + +#pragma warning( pop ) diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..218e891 --- /dev/null +++ b/setup.py @@ -0,0 +1,201 @@ +"""A setuptools based setup module. +See: +https://packaging.python.org/en/latest/distributing.html +https://github.com/pypa/sampleproject +""" + +# Always prefer setuptools over distutils +from setuptools import setup, find_packages +from os import path +# io.open is needed for projects that support Python 2.7 +# It ensures open() defaults to text mode with universal newlines, +# and accepts an argument to specify the text encoding +# Python 3 only projects can skip this import +from io import open + +here = path.abspath(path.dirname(__file__)) + +# Get the long description from the README file +with open(path.join(here, 'README.md'), encoding='utf-8') as f: + long_description = f.read() + +# Arguments marked as "Required" below must be included for upload to PyPI. +# Fields marked as "Optional" may be commented out. + +setup( + # This is the name of your project. The first time you publish this + # package, this name will be registered for you. It will determine how + # users can install this project, e.g.: + # + # $ pip install sampleproject + # + # And where it will live on PyPI: https://pypi.org/project/sampleproject/ + # + # There are some restrictions on what makes a valid project name + # specification here: + # https://packaging.python.org/specifications/core-metadata/#name + name='codegen', # Required + + # Versions should comply with PEP 440: + # https://www.python.org/dev/peps/pep-0440/ + # + # For a discussion on single-sourcing the version across setup.py and the + # project code, see + # https://packaging.python.org/en/latest/single_source_version.html + version='0.1.0', # Required + + # This is a one-line description or tagline of what your project does. This + # corresponds to the "Summary" metadata field: + # https://packaging.python.org/specifications/core-metadata/#summary + # description='A sample Python project', # Optional + + # This is an optional longer description of your project that represents + # the body of text which users will see when they visit PyPI. + # + # Often, this is the same as your README, so you can just read it in from + # that file directly (as we have already done above) + # + # This field corresponds to the "Description" metadata field: + # https://packaging.python.org/specifications/core-metadata/#description-optional + long_description=long_description, # Optional + + # Denotes that our long_description is in Markdown; valid values are + # text/plain, text/x-rst, and text/markdown + # + # Optional if long_description is written in reStructuredText (rst) but + # required for plain-text or Markdown; if unspecified, "applications should + # attempt to render [the long_description] as text/x-rst; charset=UTF-8 and + # fall back to text/plain if it is not valid rst" (see link below) + # + # This field corresponds to the "Description-Content-Type" metadata field: + # https://packaging.python.org/specifications/core-metadata/#description-content-type-optional + long_description_content_type='text/markdown', # Optional (see note above) + + # This should be a valid link to your project's main homepage. + # + # This field corresponds to the "Home-Page" metadata field: + # https://packaging.python.org/specifications/core-metadata/#home-page-optional + url='https://github.com/arukibree/CodeGen', # Optional + + # This should be your name or the name of the organization which owns the + # project. + author='arukibree', # Optional + + # This should be a valid email address corresponding to the author listed + # above. + # author_email='pypa-dev@googlegroups.com', # Optional + + # Classifiers help users find your project by categorizing it. + # + # For a list of valid classifiers, see https://pypi.org/classifiers/ + classifiers=[ # Optional + # How mature is this project? Common values are + # 3 - Alpha + # 4 - Beta + # 5 - Production/Stable + 'Development Status :: 3 - Alpha', + + # Indicate who your project is intended for + 'Intended Audience :: Developers', + 'Topic :: Software Development :: Build Tools', + + # Pick your license as you wish + 'License :: OSI Approved :: MIT License', + + # Specify the Python versions you support here. In particular, ensure + # that you indicate whether you support Python 2, Python 3 or both. + #'Programming Language :: Python :: 2', + #'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + ], + + # This field adds keywords for your project which will appear on the + # project page. What does your project relate to? + # + # Note that this is a string of words separated by whitespace, not a list. + # keywords='sample setuptools development', # Optional + + # You can just specify package directories manually here if your project is + # simple. Or you can use find_packages(). + # + # Alternatively, if you just want to distribute a single Python file, use + # the `py_modules` argument instead as follows, which will expect a file + # called `my_module.py` to exist: + # + # py_modules=["my_module"], + # + packages=find_packages(exclude=['contrib', 'docs', 'tests']), # Required + + # This field lists other packages that your project depends on to run. + # Any package you put here will be installed by pip when your project is + # installed, so they must be valid existing projects. + # + # For an analysis of "install_requires" vs pip's requirements files see: + # https://packaging.python.org/en/latest/requirements.html + install_requires=[ + 'clang==5.0', + 'Mako==1.0.7' + ], + + # List additional groups of dependencies here (e.g. development + # dependencies). Users will be able to install these using the "extras" + # syntax, for example: + # + # $ pip install sampleproject[dev] + # + # Similar to `install_requires` above, these must be valid existing + # projects. + extras_require={ # Optional + 'dev': [], + 'test': [], + }, + + # If there are data files included in your packages that need to be + # installed, specify them here. + # + # If using Python 2.6 or earlier, then these have to be included in + # MANIFEST.in as well. + package_data={ # Optional + 'codegen': ['data/*.mako'], + }, + + # Although 'package_data' is the preferred approach, in some case you may + # need to place data files outside of your packages. See: + # http://docs.python.org/3.4/distutils/setupscript.html#installing-additional-files + # + # In this case, 'data_file' will be installed into '/my_data' + # data_files=[('my_data', ['data/data_file'])], # Optional + + # To provide executable scripts, use entry points in preference to the + # "scripts" keyword. Entry points provide cross-platform support and allow + # `pip` to create the appropriate form of executable for the target + # platform. + # + # For example, the following would provide a command called `sample` which + # executes the function `main` from this package when invoked: + # entry_points={ # Optional + # 'console_scripts': [ + # 'sample=sample:main', + # ], + # }, + + # List additional URLs that are relevant to your project as a dict. + # + # This field corresponds to the "Project-URL" metadata fields: + # https://packaging.python.org/specifications/core-metadata/#project-url-multiple-use + # + # Examples listed include a pattern for specifying where the package tracks + # issues, where the source is hosted, where to say thanks to the package + # maintainers, and where to support the project financially. The key is + # what's used to render the link text on PyPI. + # project_urls={ # Optional + # 'Bug Reports': 'https://github.com/pypa/sampleproject/issues', + # 'Funding': 'https://donate.pypi.org', + # 'Say Thanks!': 'http://saythanks.io/to/example', + # 'Source': 'https://github.com/pypa/sampleproject/', + # }, +) diff --git a/template.mako b/template.mako deleted file mode 100644 index 43eff67..0000000 --- a/template.mako +++ /dev/null @@ -1,21 +0,0 @@ -% if Enums: -#include -% endif - -% for Decl in ForwardDeclares: -${Decl.GenerateText(0)} -% endfor - -% for Enum in Enums: -const CEnumNameMap TEnumReflection::skNameMap = { -<% ValueSet = set() %> \ - % for Constant in Enum.Constants: - % if Constant.Value not in ValueSet: - { ${Constant.Value}, "${Constant.Name}" }, -<% ValueSet.add(Constant.Value) %> \ - % endif - % endfor -}; -const int TEnumReflection::skErrorValue = ${Enum.ErrorValue}; - -% endfor