mirror of
				https://github.com/Z3Prover/z3
				synced 2025-10-31 11:42:28 +00:00 
			
		
		
		
	Merge pull request #568 from delcypher/cmake_java_bindings
Teach CMake to build and install the Java bindings
This commit is contained in:
		
						commit
						e24c6c14e0
					
				
					 6 changed files with 410 additions and 98 deletions
				
			
		|  | @ -279,6 +279,10 @@ The following useful options can be passed to CMake whilst configuring. | |||
| * ``INSTALL_DOTNET_BINDINGS`` - BOOL. If set to ``TRUE`` and ``BUILD_DOTNET_BINDINGS`` is ``TRUE`` then running the ``install`` target will install Z3's .NET bindings. | ||||
| * ``DOTNET_CSC_EXECUTABLE`` - STRING. The path to the C# compiler to use. Only relevant if ``BUILD_DOTNET_BINDINGS`` is set to ``TRUE``. | ||||
| * ``DOTNET_GACUTIL_EXECUTABLE`` - STRING. The path to the gacutil program to use. Only relevant if ``BUILD_DOTNET_BINDINGS`` is set to ``TRUE``. | ||||
| * ``BUILD_JAVA_BINDINGS`` - BOOL. If set to ``TRUE`` then Z3's Java bindings will be built. | ||||
| * ``INSTALL_JAVA_BINDINGS`` - BOOL. If set to ``TRUE`` and ``BUILD_JAVA_BINDINGS`` is ``TRUE`` then running the ``install`` target will install Z3's Java bindings. | ||||
| * ``Z3_JAVA_JAR_INSTALLDIR`` - STRING. The path to directory to install the Z3 Java ``.jar`` file. This path should be relative to ``CMAKE_INSTALL_PREFIX``. | ||||
| * ``Z3_JAVA_JNI_LIB_INSTALLDIRR`` - STRING. The path to directory to install the Z3 Java JNI bridge library. This path should be relative to ``CMAKE_INSTALL_PREFIX``. | ||||
| 
 | ||||
| On the command line these can be passed to ``cmake`` using the ``-D`` option. In ``ccmake`` and ``cmake-gui`` these can be set in the user interface. | ||||
| 
 | ||||
|  | @ -286,8 +290,29 @@ Example | |||
| 
 | ||||
| ``` | ||||
| cmake -DCMAKE_BUILD_TYPE=Release -DENABLE_TRACING=FALSE ../ | ||||
| 
 | ||||
| ``` | ||||
| 
 | ||||
| ## Z3 API Bindings | ||||
| 
 | ||||
| Z3 exposes various language bindings for its API. Below are some notes on building | ||||
| and/or installing these bindings when building Z3 with CMake. | ||||
| 
 | ||||
| ### Java bindings | ||||
| 
 | ||||
| The CMake build uses the ``FindJava`` and ``FindJNI`` cmake modules to detect the | ||||
| installation of Java. If CMake fails to find your installation of Java set the | ||||
| ``JAVA_HOME`` environment variable when invoking CMake so that it points at the | ||||
| correct location. For example | ||||
| 
 | ||||
| ``` | ||||
| JAVA_HOME=/usr/lib/jvm/default cmake -DBUILD_JAVA_BINDINGS=ON ../ | ||||
| ``` | ||||
| Note that the built ``.jar`` file is named ``com.microsoft.z3-VERSION.jar`` | ||||
| where ``VERSION`` is the Z3 version. Under non Windows systems a | ||||
| symbolic link named ``com.microsoft.z3.jar`` is provided. This symbolic | ||||
| link is not created when building under Windows. | ||||
| 
 | ||||
| ## Developer/packager notes | ||||
| 
 | ||||
| These notes are help developers and packagers of Z3. | ||||
|  |  | |||
|  | @ -234,4 +234,16 @@ if (BUILD_DOTNET_BINDINGS) | |||
|   add_subdirectory(api/dotnet) | ||||
| endif() | ||||
| 
 | ||||
| ################################################################################ | ||||
| # Java bindings | ||||
| ################################################################################ | ||||
| option(BUILD_JAVA_BINDINGS "Build Java bindings for Z3" OFF) | ||||
| if (BUILD_JAVA_BINDINGS) | ||||
|   if (NOT BUILD_LIBZ3_SHARED) | ||||
|     message(FATAL_ERROR "The Java bindings will not work with a static libz3. " | ||||
|       "You either need to disable BUILD_JAVA_BINDINGS or enable BUILD_LIBZ3_SHARED") | ||||
|   endif() | ||||
|   add_subdirectory(api/java) | ||||
| endif() | ||||
| 
 | ||||
| # TODO: Implement support for other bindigns | ||||
|  |  | |||
							
								
								
									
										236
									
								
								contrib/cmake/src/api/java/CMakeLists.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										236
									
								
								contrib/cmake/src/api/java/CMakeLists.txt
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,236 @@ | |||
| find_package(Java REQUIRED) | ||||
| find_package(JNI REQUIRED) | ||||
| include(UseJava) | ||||
| 
 | ||||
| # Sanity check for dirty source tree | ||||
| foreach (file_name "enumerations" "Native.cpp" "Native.java") | ||||
|   if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${file_name}") | ||||
|     message(FATAL_ERROR "\"${CMAKE_CURRENT_SOURCE_DIR}/${file_name}\"" | ||||
|             ${z3_polluted_tree_msg}) | ||||
|   endif() | ||||
| endforeach() | ||||
| 
 | ||||
| set(Z3_JAVA_PACKAGE_NAME "com.microsoft.z3") | ||||
| 
 | ||||
| # Rule to generate ``Native.java`` and ``Native.cpp`` | ||||
| set(Z3_JAVA_NATIVE_JAVA "${CMAKE_CURRENT_BINARY_DIR}/Native.java") | ||||
| set(Z3_JAVA_NATIVE_CPP "${CMAKE_CURRENT_BINARY_DIR}/Native.cpp") | ||||
| add_custom_command(OUTPUT "${Z3_JAVA_NATIVE_JAVA}" "${Z3_JAVA_NATIVE_CPP}" | ||||
|   COMMAND "${PYTHON_EXECUTABLE}" | ||||
|     "${CMAKE_SOURCE_DIR}/scripts/update_api.py" | ||||
|     ${Z3_FULL_PATH_API_HEADER_FILES_TO_SCAN} | ||||
|     "--java-output-dir" | ||||
|     "${CMAKE_CURRENT_BINARY_DIR}" | ||||
|     "--java-package-name" | ||||
|     ${Z3_JAVA_PACKAGE_NAME} | ||||
|   DEPENDS | ||||
|     ${Z3_FULL_PATH_API_HEADER_FILES_TO_SCAN} | ||||
|     "${CMAKE_SOURCE_DIR}/scripts/update_api.py" | ||||
|     ${Z3_GENERATED_FILE_EXTRA_DEPENDENCIES} | ||||
|     # FIXME: When update_api.py no longer uses ``mk_util`` drop this dependency | ||||
|     "${CMAKE_SOURCE_DIR}/scripts/mk_util.py" | ||||
|   COMMENT "Generating \"${Z3_JAVA_NATIVE_JAVA}\" and \"${Z3_JAVA_NATIVE_CPP}\"" | ||||
|   ${ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG} | ||||
| ) | ||||
| 
 | ||||
| # Add rule to build native code that provides a bridge between | ||||
| # ``Native.java`` and libz3's interfac3. | ||||
| add_library(z3java SHARED ${Z3_JAVA_NATIVE_CPP}) | ||||
| target_link_libraries(z3java PRIVATE libz3) | ||||
| # FIXME: | ||||
| # Not sure if using all the flags used by the Z3 components is really necessary | ||||
| # here.  At the bare minimum setting _AMD64_ depending on the target is | ||||
| # necessary but seeing as the Python build system uses all the flags used for building | ||||
| # Z3's components to build ``Native.cpp`` lets do the same for now. | ||||
| target_compile_options(z3java PRIVATE ${Z3_COMPONENT_CXX_FLAGS}) | ||||
| target_compile_definitions(z3java PRIVATE ${Z3_COMPONENT_CXX_DEFINES}) | ||||
| z3_append_linker_flag_list_to_target(z3java ${Z3_DEPENDENT_EXTRA_CXX_LINK_FLAGS}) | ||||
| target_include_directories(z3java PRIVATE | ||||
|   "${CMAKE_SOURCE_DIR}/src/api" | ||||
|   "${CMAKE_BINARY_DIR}/src/api" | ||||
|   ${JNI_INCLUDE_DIRS} | ||||
| ) | ||||
| # FIXME: Should this library have SONAME and VERSION set? | ||||
| 
 | ||||
| # This prevents CMake from automatically defining ``z3java_EXPORTS`` | ||||
| set_property(TARGET z3java PROPERTY DEFINE_SYMBOL "") | ||||
| 
 | ||||
| # Rule to generate the ``com.microsoft.z3.enumerations`` package | ||||
| # FIXME: This list of files is fragile | ||||
| set(Z3_JAVA_ENUMERATION_PACKAGE_FILES | ||||
|   Z3_ast_kind.java | ||||
|   Z3_ast_print_mode.java | ||||
|   Z3_decl_kind.java | ||||
|   Z3_error_code.java | ||||
|   Z3_goal_prec.java | ||||
|   Z3_lbool.java | ||||
|   Z3_param_kind.java | ||||
|   Z3_parameter_kind.java | ||||
|   Z3_sort_kind.java | ||||
|   Z3_symbol_kind.java | ||||
| ) | ||||
| set(Z3_JAVA_ENUMERATION_PACKAGE_FILES_FULL_PATH "") | ||||
| foreach (enum_file ${Z3_JAVA_ENUMERATION_PACKAGE_FILES}) | ||||
|   list(APPEND Z3_JAVA_ENUMERATION_PACKAGE_FILES_FULL_PATH | ||||
|     "${CMAKE_CURRENT_BINARY_DIR}/enumerations/${enum_file}" | ||||
|   ) | ||||
| endforeach() | ||||
| add_custom_command(OUTPUT ${Z3_JAVA_ENUMERATION_PACKAGE_FILES_FULL_PATH} | ||||
|   COMMAND "${PYTHON_EXECUTABLE}" | ||||
|     "${CMAKE_SOURCE_DIR}/scripts/mk_consts_files.py" | ||||
|     ${Z3_FULL_PATH_API_HEADER_FILES_TO_SCAN} | ||||
|     "--java-output-dir" | ||||
|     "${CMAKE_CURRENT_BINARY_DIR}" | ||||
|     "--java-package-name" | ||||
|     ${Z3_JAVA_PACKAGE_NAME} | ||||
|   DEPENDS | ||||
|     ${Z3_FULL_PATH_API_HEADER_FILES_TO_SCAN} | ||||
|     "${CMAKE_SOURCE_DIR}/scripts/mk_consts_files.py" | ||||
|     ${Z3_GENERATED_FILE_EXTRA_DEPENDENCIES} | ||||
|   COMMENT "Generating ${Z3_JAVA_PACKAGE_NAME}.enumerations package" | ||||
|   ${ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG} | ||||
| ) | ||||
| 
 | ||||
| set(Z3_JAVA_JAR_SOURCE_FILES | ||||
|   AlgebraicNum.java | ||||
|   ApplyResultDecRefQueue.java | ||||
|   ApplyResult.java | ||||
|   ArithExpr.java | ||||
|   ArithSort.java | ||||
|   ArrayExpr.java | ||||
|   ArraySort.java | ||||
|   ASTDecRefQueue.java | ||||
|   AST.java | ||||
|   AstMapDecRefQueue.java | ||||
|   ASTMap.java | ||||
|   AstVectorDecRefQueue.java | ||||
|   ASTVector.java | ||||
|   BitVecExpr.java | ||||
|   BitVecNum.java | ||||
|   BitVecSort.java | ||||
|   BoolExpr.java | ||||
|   BoolSort.java | ||||
|   Constructor.java | ||||
|   ConstructorList.java | ||||
|   Context.java | ||||
|   DatatypeExpr.java | ||||
|   DatatypeSort.java | ||||
|   EnumSort.java | ||||
|   Expr.java | ||||
|   FiniteDomainExpr.java | ||||
|   FiniteDomainNum.java | ||||
|   FiniteDomainSort.java | ||||
|   FixedpointDecRefQueue.java | ||||
|   Fixedpoint.java | ||||
|   FPExpr.java | ||||
|   FPNum.java | ||||
|   FPRMExpr.java | ||||
|   FPRMNum.java | ||||
|   FPRMSort.java | ||||
|   FPSort.java | ||||
|   FuncDecl.java | ||||
|   FuncInterpDecRefQueue.java | ||||
|   FuncInterpEntryDecRefQueue.java | ||||
|   FuncInterp.java | ||||
|   Global.java | ||||
|   GoalDecRefQueue.java | ||||
|   Goal.java | ||||
|   IDecRefQueue.java | ||||
|   IDisposable.java | ||||
|   InterpolationContext.java | ||||
|   IntExpr.java | ||||
|   IntNum.java | ||||
|   IntSort.java | ||||
|   IntSymbol.java | ||||
|   ListSort.java | ||||
|   Log.java | ||||
|   ModelDecRefQueue.java | ||||
|   Model.java | ||||
|   OptimizeDecRefQueue.java | ||||
|   Optimize.java | ||||
|   ParamDescrsDecRefQueue.java | ||||
|   ParamDescrs.java | ||||
|   ParamsDecRefQueue.java | ||||
|   Params.java | ||||
|   Pattern.java | ||||
|   ProbeDecRefQueue.java | ||||
|   Probe.java | ||||
|   Quantifier.java | ||||
|   RatNum.java | ||||
|   RealExpr.java | ||||
|   RealSort.java | ||||
|   ReExpr.java | ||||
|   RelationSort.java | ||||
|   ReSort.java | ||||
|   SeqExpr.java | ||||
|   SeqSort.java | ||||
|   SetSort.java | ||||
|   SolverDecRefQueue.java | ||||
|   Solver.java | ||||
|   Sort.java | ||||
|   StatisticsDecRefQueue.java | ||||
|   Statistics.java | ||||
|   Status.java | ||||
|   StringSymbol.java | ||||
|   Symbol.java | ||||
|   TacticDecRefQueue.java | ||||
|   Tactic.java | ||||
|   TupleSort.java | ||||
|   UninterpretedSort.java | ||||
|   Version.java | ||||
|   Z3Exception.java | ||||
|   Z3Object.java | ||||
| ) | ||||
| set(Z3_JAVA_JAR_SOURCE_FILES_FULL_PATH "") | ||||
| foreach (java_src_file ${Z3_JAVA_JAR_SOURCE_FILES}) | ||||
|   list(APPEND Z3_JAVA_JAR_SOURCE_FILES_FULL_PATH "${CMAKE_CURRENT_SOURCE_DIR}/${java_src_file}") | ||||
| endforeach() | ||||
| # Add generated files to list | ||||
| list(APPEND Z3_JAVA_JAR_SOURCE_FILES_FULL_PATH | ||||
|   ${Z3_JAVA_NATIVE_JAVA} | ||||
|   ${Z3_JAVA_ENUMERATION_PACKAGE_FILES_FULL_PATH} | ||||
| ) | ||||
| 
 | ||||
| # Convenient top-level target | ||||
| add_custom_target(build_z3_java_bindings | ||||
|   ALL | ||||
|   DEPENDS | ||||
|     z3java | ||||
|     z3JavaJar | ||||
| ) | ||||
| 
 | ||||
| # Rule to build ``com.microsoft.z3.jar`` | ||||
| # TODO: Should we set ``CMAKE_JNI_TARGET`` to ``TRUE``? | ||||
| add_jar(z3JavaJar | ||||
|   SOURCES ${Z3_JAVA_JAR_SOURCE_FILES_FULL_PATH} | ||||
|   OUTPUT_NAME ${Z3_JAVA_PACKAGE_NAME} | ||||
|   OUTPUT_DIR "${CMAKE_BINARY_DIR}" | ||||
|   VERSION "${Z3_VERSION}" | ||||
| ) | ||||
| 
 | ||||
| ############################################################################### | ||||
| # Install | ||||
| ############################################################################### | ||||
| option(INSTALL_JAVA_BINDINGS "Install Java bindings when invoking install target" ON) | ||||
| if (INSTALL_JAVA_BINDINGS) | ||||
|   # Provide cache variables for the install locations that the user can change. | ||||
|   # This defaults to ``/usr/local/java`` which seems to be the location for ``.jar`` | ||||
|   # files on Linux distributions | ||||
|   set(Z3_JAVA_JAR_INSTALLDIR | ||||
|     "${CMAKE_INSTALL_DATAROOTDIR}/java" | ||||
|     CACHE | ||||
|     PATH | ||||
|     "Directory to install Z3 Java jar file relative to install prefix" | ||||
|   ) | ||||
|   # FIXME: I don't think this the right installation location | ||||
|   set(Z3_JAVA_JNI_LIB_INSTALLDIR | ||||
|     "${CMAKE_INSTALL_LIBDIR}" | ||||
|     CACHE | ||||
|     PATH | ||||
|     "Directory to install Z3 Java JNI bridge library relative to install prefix" | ||||
|   ) | ||||
|   install(TARGETS z3java DESTINATION "${Z3_JAVA_JNI_LIB_INSTALLDIR}") | ||||
|   # Note: Don't use ``DESTINATION`` here as the version of ``UseJava.cmake`` shipped | ||||
|   # with CMake 2.8.12.2 handles that incorrectly. | ||||
|   install_jar(z3JavaJar "${Z3_JAVA_JAR_INSTALLDIR}") | ||||
| endif() | ||||
|  | @ -17,6 +17,11 @@ def main(args): | |||
|     parser.add_argument("api_files", nargs="+") | ||||
|     parser.add_argument("--z3py-output-dir", dest="z3py_output_dir", default=None) | ||||
|     parser.add_argument("--dotnet-output-dir", dest="dotnet_output_dir", default=None) | ||||
|     parser.add_argument("--java-output-dir", dest="java_output_dir", default=None) | ||||
|     parser.add_argument("--java-package-name", | ||||
|                         dest="java_package_name", | ||||
|                         default=None, | ||||
|                         help="Name to give the Java package (e.g. ``com.microsoft.z3``).") | ||||
|     pargs = parser.parse_args(args) | ||||
| 
 | ||||
|     if not mk_genfile_common.check_files_exist(pargs.api_files): | ||||
|  | @ -41,6 +46,20 @@ def main(args): | |||
|         logging.info('Generated "{}"'.format(output)) | ||||
|         count += 1 | ||||
| 
 | ||||
|     if pargs.java_output_dir: | ||||
|         if pargs.java_package_name == None: | ||||
|             logging.error('Java package name must be specified') | ||||
|             return 1 | ||||
|         if not mk_genfile_common.check_dir_exists(pargs.java_output_dir): | ||||
|             return 1 | ||||
|         outputs = mk_genfile_common.mk_z3consts_java_internal( | ||||
|             pargs.api_files, | ||||
|             pargs.java_package_name, | ||||
|             pargs.java_output_dir) | ||||
|         for generated_file in outputs: | ||||
|             logging.info('Generated "{}"'.format(generated_file)) | ||||
|         count += 1 | ||||
| 
 | ||||
|     if count == 0: | ||||
|         logging.info('No files generated. You need to specific an output directory' | ||||
|                      ' for the relevant langauge bindings') | ||||
|  |  | |||
|  | @ -255,6 +255,116 @@ def mk_z3consts_dotnet_internal(api_files, output_dir): | |||
|     z3consts.close() | ||||
|     return z3consts_output_path | ||||
| 
 | ||||
| 
 | ||||
| def mk_z3consts_java_internal(api_files, package_name, output_dir): | ||||
|     """ | ||||
|         Generate "com.microsoft.z3.enumerations" package from the list of API | ||||
|         header files in ``api_files`` and write the package directory into | ||||
|         the ``output_dir`` directory | ||||
| 
 | ||||
|         Returns a list of the generated java source files. | ||||
|     """ | ||||
|     blank_pat      = re.compile("^ *$") | ||||
|     comment_pat    = re.compile("^ *//.*$") | ||||
|     typedef_pat    = re.compile("typedef enum *") | ||||
|     typedef2_pat   = re.compile("typedef enum { *") | ||||
|     openbrace_pat  = re.compile("{ *") | ||||
|     closebrace_pat = re.compile("}.*;") | ||||
| 
 | ||||
|     DeprecatedEnums = [ 'Z3_search_failure' ] | ||||
|     gendir = os.path.join(output_dir, "enumerations") | ||||
|     if not os.path.exists(gendir): | ||||
|         os.mkdir(gendir) | ||||
| 
 | ||||
|     generated_enumeration_files = [] | ||||
|     for api_file in api_files: | ||||
|         api = open(api_file, 'r') | ||||
| 
 | ||||
|         SEARCHING  = 0 | ||||
|         FOUND_ENUM = 1 | ||||
|         IN_ENUM    = 2 | ||||
| 
 | ||||
|         mode    = SEARCHING | ||||
|         decls   = {} | ||||
|         idx     = 0 | ||||
| 
 | ||||
|         linenum = 1 | ||||
|         for line in api: | ||||
|             m1 = blank_pat.match(line) | ||||
|             m2 = comment_pat.match(line) | ||||
|             if m1 or m2: | ||||
|                 # skip blank lines and comments | ||||
|                 linenum = linenum + 1 | ||||
|             elif mode == SEARCHING: | ||||
|                 m = typedef_pat.match(line) | ||||
|                 if m: | ||||
|                     mode = FOUND_ENUM | ||||
|                 m = typedef2_pat.match(line) | ||||
|                 if m: | ||||
|                     mode = IN_ENUM | ||||
|                     decls = {} | ||||
|                     idx   = 0 | ||||
|             elif mode == FOUND_ENUM: | ||||
|                 m = openbrace_pat.match(line) | ||||
|                 if m: | ||||
|                     mode  = IN_ENUM | ||||
|                     decls = {} | ||||
|                     idx   = 0 | ||||
|                 else: | ||||
|                     assert False, "Invalid %s, line: %s" % (api_file, linenum) | ||||
|             else: | ||||
|                 assert mode == IN_ENUM | ||||
|                 words = re.split('[^\-a-zA-Z0-9_]+', line) | ||||
|                 m = closebrace_pat.match(line) | ||||
|                 if m: | ||||
|                     name = words[1] | ||||
|                     if name not in DeprecatedEnums: | ||||
|                         efile  = open('%s.java' % os.path.join(gendir, name), 'w') | ||||
|                         generated_enumeration_files.append(efile.name) | ||||
|                         efile.write('/**\n *  Automatically generated file\n **/\n\n') | ||||
|                         efile.write('package %s.enumerations;\n\n' % package_name) | ||||
| 
 | ||||
|                         efile.write('/**\n') | ||||
|                         efile.write(' * %s\n' % name) | ||||
|                         efile.write(' **/\n') | ||||
|                         efile.write('public enum %s {\n' % name) | ||||
|                         efile.write | ||||
|                         first = True | ||||
|                         # Iterate over key-value pairs ordered by value | ||||
|                         for k, v in sorted(decls.items(), key=lambda pair: pair[1]): | ||||
|                             if first: | ||||
|                                 first = False | ||||
|                             else: | ||||
|                                 efile.write(',\n') | ||||
|                             efile.write('    %s (%s)' % (k, v)) | ||||
|                         efile.write(";\n") | ||||
|                         efile.write('\n    private final int intValue;\n\n') | ||||
|                         efile.write('    %s(int v) {\n' % name) | ||||
|                         efile.write('        this.intValue = v;\n') | ||||
|                         efile.write('    }\n\n') | ||||
|                         efile.write('    public static final %s fromInt(int v) {\n' % name) | ||||
|                         efile.write('        for (%s k: values()) \n' % name) | ||||
|                         efile.write('            if (k.intValue == v) return k;\n') | ||||
|                         efile.write('        return values()[0];\n') | ||||
|                         efile.write('    }\n\n') | ||||
|                         efile.write('    public final int toInt() { return this.intValue; }\n') | ||||
|                         #  efile.write(';\n  %s(int v) {}\n' % name) | ||||
|                         efile.write('}\n\n') | ||||
|                         efile.close() | ||||
|                     mode = SEARCHING | ||||
|                 else: | ||||
|                     if words[2] != '': | ||||
|                         if len(words[2]) > 1 and words[2][1] == 'x': | ||||
|                             idx = int(words[2], 16) | ||||
|                         else: | ||||
|                             idx = int(words[2]) | ||||
|                     decls[words[1]] = idx | ||||
|                     idx = idx + 1 | ||||
|             linenum = linenum + 1 | ||||
|         api.close() | ||||
|     return generated_enumeration_files | ||||
| 
 | ||||
| 
 | ||||
| ############################################################################### | ||||
| # Functions for generating a "module definition file" for MSVC | ||||
| ############################################################################### | ||||
|  |  | |||
|  | @ -2753,109 +2753,19 @@ def mk_z3consts_dotnet(api_files): | |||
| 
 | ||||
| # Extract enumeration types from z3_api.h, and add Java definitions | ||||
| def mk_z3consts_java(api_files): | ||||
|     blank_pat      = re.compile("^ *$") | ||||
|     comment_pat    = re.compile("^ *//.*$") | ||||
|     typedef_pat    = re.compile("typedef enum *") | ||||
|     typedef2_pat   = re.compile("typedef enum { *") | ||||
|     openbrace_pat  = re.compile("{ *") | ||||
|     closebrace_pat = re.compile("}.*;") | ||||
| 
 | ||||
|     java = get_component(JAVA_COMPONENT) | ||||
| 
 | ||||
|     DeprecatedEnums = [ 'Z3_search_failure' ] | ||||
|     gendir = os.path.join(java.src_dir, "enumerations") | ||||
|     if not os.path.exists(gendir): | ||||
|         os.mkdir(gendir) | ||||
| 
 | ||||
|     full_path_api_files = [] | ||||
|     for api_file in api_files: | ||||
|         api_file_c = java.find_file(api_file, java.name) | ||||
|         api_file   = os.path.join(api_file_c.src_dir, api_file) | ||||
| 
 | ||||
|         api = open(api_file, 'r') | ||||
| 
 | ||||
|         SEARCHING  = 0 | ||||
|         FOUND_ENUM = 1 | ||||
|         IN_ENUM    = 2 | ||||
| 
 | ||||
|         mode    = SEARCHING | ||||
|         decls   = {} | ||||
|         idx     = 0 | ||||
| 
 | ||||
|         linenum = 1 | ||||
|         for line in api: | ||||
|             m1 = blank_pat.match(line) | ||||
|             m2 = comment_pat.match(line) | ||||
|             if m1 or m2: | ||||
|                 # skip blank lines and comments | ||||
|                 linenum = linenum + 1 | ||||
|             elif mode == SEARCHING: | ||||
|                 m = typedef_pat.match(line) | ||||
|                 if m: | ||||
|                     mode = FOUND_ENUM | ||||
|                 m = typedef2_pat.match(line) | ||||
|                 if m: | ||||
|                     mode = IN_ENUM | ||||
|                     decls = {} | ||||
|                     idx   = 0 | ||||
|             elif mode == FOUND_ENUM: | ||||
|                 m = openbrace_pat.match(line) | ||||
|                 if m: | ||||
|                     mode  = IN_ENUM | ||||
|                     decls = {} | ||||
|                     idx   = 0 | ||||
|                 else: | ||||
|                     assert False, "Invalid %s, line: %s" % (api_file, linenum) | ||||
|             else: | ||||
|                 assert mode == IN_ENUM | ||||
|                 words = re.split('[^\-a-zA-Z0-9_]+', line) | ||||
|                 m = closebrace_pat.match(line) | ||||
|                 if m: | ||||
|                     name = words[1] | ||||
|                     if name not in DeprecatedEnums: | ||||
|                         efile  = open('%s.java' % os.path.join(gendir, name), 'w') | ||||
|                         efile.write('/**\n *  Automatically generated file\n **/\n\n') | ||||
|                         efile.write('package %s.enumerations;\n\n' % java.package_name) | ||||
| 
 | ||||
|                         efile.write('/**\n') | ||||
|                         efile.write(' * %s\n' % name) | ||||
|                         efile.write(' **/\n') | ||||
|                         efile.write('public enum %s {\n' % name) | ||||
|                         efile.write | ||||
|                         first = True | ||||
|                         for k in decls: | ||||
|                             i = decls[k] | ||||
|                             if first: | ||||
|                                 first = False | ||||
|                             else: | ||||
|                                 efile.write(',\n') | ||||
|                             efile.write('    %s (%s)' % (k, i)) | ||||
|                         efile.write(";\n") | ||||
|                         efile.write('\n    private final int intValue;\n\n') | ||||
|                         efile.write('    %s(int v) {\n' % name) | ||||
|                         efile.write('        this.intValue = v;\n') | ||||
|                         efile.write('    }\n\n') | ||||
|                         efile.write('    public static final %s fromInt(int v) {\n' % name) | ||||
|                         efile.write('        for (%s k: values()) \n' % name) | ||||
|                         efile.write('            if (k.intValue == v) return k;\n') | ||||
|                         efile.write('        return values()[0];\n') | ||||
|                         efile.write('    }\n\n') | ||||
|                         efile.write('    public final int toInt() { return this.intValue; }\n') | ||||
|                         #  efile.write(';\n  %s(int v) {}\n' % name) | ||||
|                         efile.write('}\n\n') | ||||
|                         efile.close() | ||||
|                     mode = SEARCHING | ||||
|                 else: | ||||
|                     if words[2] != '': | ||||
|                         if len(words[2]) > 1 and words[2][1] == 'x': | ||||
|                             idx = int(words[2], 16) | ||||
|                         else: | ||||
|                             idx = int(words[2]) | ||||
|                     decls[words[1]] = idx | ||||
|                     idx = idx + 1 | ||||
|             linenum = linenum + 1 | ||||
|         api.close() | ||||
|         full_path_api_files.append(api_file) | ||||
|     generated_files = mk_genfile_common.mk_z3consts_java_internal( | ||||
|         full_path_api_files, | ||||
|         java.package_name, | ||||
|         java.src_dir) | ||||
|     if VERBOSE: | ||||
|         print("Generated '%s'" % ('%s' % gendir)) | ||||
|         for generated_file in generated_files: | ||||
|             print("Generated '{}'".format(generated_file)) | ||||
| 
 | ||||
| # Extract enumeration types from z3_api.h, and add ML definitions | ||||
| def mk_z3consts_ml(api_files): | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue