Skip to content

Commit

Permalink
Merge pull request #174 from sosy-lab/boolector_integration
Browse files Browse the repository at this point in the history
Integration of the SMT Solver Boolector into JavaSMT
  • Loading branch information
kfriedberger authored Nov 29, 2019
2 parents 99a20b0 + abadda1 commit 31123b9
Show file tree
Hide file tree
Showing 55 changed files with 7,170 additions and 183 deletions.
98 changes: 98 additions & 0 deletions build/build-publish-solvers.xml
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,104 @@
svn ci repository/${ivy.organisation}/${ivy.module} -m"publish version ${cvc4.version} of CVC4 Solver"
to make the new version publicly available.</echo>
</target>

<!-- SECTION: Publishing Boolector {{{1
==================================================================
-->
<target name="package-boolector" depends=""
description="Copy Boolector repository to the root folder along with the version postfix.">
<fail unless="boolector.path">
Please specify the path to Boolector with the flag -Dboolector.path=/path/to/boolector.
The path has to point to the root Boolector folder, i.e.,
a checkout of the official git repositoy from 'https://github.com/boolector/boolector'.
Note that shell substitutions do not work and a full absolute path has to be specified.
</fail>
<fail unless="boolector.customRev">
Please specify a custom revision with the flag -Dboolector.customRev=XXX.
The custom revision has to be unique amongst the already known version
numbers from the ivy repository. The script will append the git revision.
</fail>

<!-- get a nive version -->
<exec executable="git" dir="${boolector.path}" outputproperty="boolector.revision">
<arg value="show"/>
<arg value="-s"/>
<arg value="--format=%h"/>
</exec>
<property name="boolector.version" value="${boolector.customRev}-g${boolector.revision}"/>
<echo message="Building Boolector in version '${boolector.version}'"/>

<!-- add JNI wrapper before compiling Boolector -->
<exec executable="cp">
<arg value="lib/native/source/libboolector/interface_wrap.c"/>
<arg value="lib/native/source/libboolector/include_interface_and_jni.patch"/>
<arg value="${boolector.path}/src/"/>
</exec>
<exec executable="git" dir="${boolector.path}">
<arg value="apply"/>
<arg value="src/include_interface_and_jni.patch"/>
</exec>

<!-- build Boolector -->
<exec executable="./contrib/setup-picosat.sh" dir="${boolector.path}"/>
<exec executable="./contrib/setup-minisat.sh" dir="${boolector.path}"/>
<exec executable="./contrib/setup-lingeling.sh" dir="${boolector.path}"/>
<exec executable="./contrib/setup-cadical.sh" dir="${boolector.path}"/>
<exec executable="./contrib/setup-btor2tools.sh" dir="${boolector.path}"/>
<exec executable="./configure.sh" dir="${boolector.path}">
<arg value="-fno-strict-aliasing"/>
<arg value="-fpic"/>
<arg value="--shared"/>
</exec>
<exec executable="make" dir="${boolector.path}/build/">
<arg value="-j4" />
</exec>

<!-- remove unneeded symbols -->
<exec executable="strip" dir="${boolector.path}/deps/install/lib/">
<arg value="libpicosat.so" />
</exec>
<exec executable="strip" dir="${boolector.path}/deps/install/lib/">
<arg value="libminisat.so" />
</exec>
<exec executable="strip" dir="${boolector.path}/build/lib/">
<arg value="libboolector.so" />
</exec>

<!-- fix RPATH and library dependencies -->
<exec executable="patchelf" dir="${boolector.path}/build/lib/">
<arg value="--set-rpath"/><arg value="$ORIGIN"/>
<arg value="--replace-needed"/><arg value="libminisat.so.2"/><arg value="libminisat.so"/>
<arg value="libboolector.so"/>
</exec>

<!-- copy library files into directory to be published for IVY -->
<copy file="${boolector.path}/deps/install/lib/libminisat.so" tofile="libminisat-${boolector.version}.so"/>
<copy file="${boolector.path}/deps/install/lib/libpicosat.so" tofile="libpicosat-${boolector.version}.so"/>
<copy file="${boolector.path}/build/lib/libboolector.so" tofile="libboolector-${boolector.version}.so"/>
</target>

<target name="publish-boolector" depends="package-boolector, load-ivy"
description="Publish Boolector binaries to Ivy repository.">

<ivy:resolve conf="solver-boolector" file="solvers_ivy_conf/ivy_boolector.xml" />
<available property="ivy.hasrepository" file="repository/${ivy.organisation}/${ivy.module}" />
<fail unless="ivy.hasrepository"
message="Cannot publish without 'repository' dir, please run 'svn co https://svn.sosy-lab.org/software/ivy/repository/${ivy.organisation}/${ivy.module} repository/${ivy.organisation}/${ivy.module}'." />

<ivy:publish
pubrevision="${boolector.version}"
resolver="Sosy-Lab-Publish"
artifactspattern="[artifact]-[revision].[ext]"
status="release"
/>
<echo>
You now want to run
svn add repository/${ivy.organisation}/${ivy.module}/*-${boolector.version}*
svn ci repository/${ivy.organisation}/${ivy.module} -m"publish version ${boolector.version} of Boolector Solver"
to make the new version publicly available.</echo>
</target>

<!-- SECTION: Publishing [Opti-]MathSAT {{{1
===============================================================
-->
Expand Down
4 changes: 3 additions & 1 deletion lib/ivy.xml
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,10 @@
<conf name="runtime-princess" extends="core" description="only one solver included"/>
<conf name="runtime-z3" extends="core" description="only one solver included"/>
<conf name="runtime-cvc4" extends="core" description="only one solver included"/>
<conf name="runtime-boolector" extends="core" description="only one solver included"/>

<!-- The normal dependencies with all solvers included. -->
<conf name="runtime" extends="runtime-mathsat,runtime-optimathsat,runtime-smtinterpol,runtime-princess,runtime-z3,runtime-cvc4" description="all solvers included"/>
<conf name="runtime" extends="runtime-mathsat,runtime-optimathsat,runtime-smtinterpol,runtime-princess,runtime-z3,runtime-cvc4,runtime-boolector" description="all solvers included"/>

<!-- Dependencies needed for building or running tests. -->
<conf name="test" visibility="private" description="for developing and testing"/>
Expand Down Expand Up @@ -137,6 +138,7 @@
<dependency org="org.sosy_lab" name="javasmt-solver-z3" rev="4.7.1" conf="runtime-z3->solver-z3" />
<dependency org="org.sosy_lab" name="javasmt-solver-optimathsat" rev="1.6.3" conf="runtime-optimathsat->solver-optimathsat" />
<dependency org="org.sosy_lab" name="javasmt-solver-cvc4" rev="1.8-prerelease-2019-10-05-g6972cfa" conf="runtime-cvc4->solver-cvc4" />
<dependency org="org.sosy_lab" name="javasmt-solver-boolector" rev="3.0.0-2019-11-11-g9d06cc0" conf="runtime-boolector->solver-boolector" />

<!-- Guava has a dependency on error_prone_annotations without a revision number, need an override. -->
<override org="com.google.errorprone" module="error_prone_annotations" rev="2.3.2"/>
Expand Down
85 changes: 85 additions & 0 deletions lib/native/source/libboolector/Boolector Build Documentation.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#################################################################

INFO 2019-11-11:
This file might be outdated, please use 'ant publish-boolector'
for building Boolector and publishing into Ivy.
The ant steps are based on this documentation.

#################################################################


NOTICE: This is a bare minimum guide that worked for me. I do not take responsibility in any damage or frustration you may encounter using this!

In the following the steps to update or change boolector and its JNI are outlined:

There are 2 files, both located in boolector/src/, that need (potential) editing to compile Boolector with JNI:

-interface_wrap.c (containing the JNI interface)
-CMakeLists.c (the cmakefile)


MakeFile:
CMakeLists.c needs to include ALL JNI .c files you want in its set(libboolector_src_files ...) list at the beginning. (interface_wrap.c should be there!)
Additionally it needs to find the JNI libs and set the path for linking.
Example:

find_package(JNI)
if(JNI_FOUND)
message (STATUS "JNI_INCLUDE_DIRS=${JNI_INCLUDE_DIRS}")
message (STATUS "JNI_LIBRARIES=${JNI_LIBRARIES}")
target_include_directories(boolector PRIVATE ${JNI_INCLUDE_DIRS})
target_link_libraries(boolector ${JNI_LIBRARIES})
endif()

(should be set and ready to go in the provided version of the cmakefile but here is a copy that should be working if copied in directly before the linking of the SAT solvers)

JNI (interface_wrap.c):
To change or update methods just edit this file! (DON'T CHANGE BOOLECTOR NATIVE CODE!)
The interface is set up with all C API methods (taken from the interfaces via SWIG, see SWIG part at the end of this) of Boolector.
Important: every pointer in Boolector is returned to Java via a Jlong. Just use this as a pointer once given back, but cast it properly!
Be careful, method names need the package in them, see JNI for more details!
There are multiple helper methods at the very end of the file, do not change them unless you know what you are doing!
Since Boolector sometimes writes to given objects, we need those to get the information back to Java. (Explanation via comments in the code)
In case you add new methods, remember to add them to the Java code as well. (Should be BtorJNI.java in the Boolector package)


To compile you need to follow these steps EVERY time since Boolector does not save your preferences:

1. (Optional) Download new Boolector/Update Boolector and edit/create JNI interface and cmakefile
2. Open terminal and switch to the boolector folder (java-smt3-boolector/lib/native/native boolector/boolector)
3. Set up your build (See https://github.com/Boolector/boolector for more information. Important: do not try to include MiniSAT in a shared lib, it won't compile!(October 2019) But check for updates on this!)
Example:
./contrib/setup-cadical.sh
./contrib/setup-lingeling.sh
./contrib/setup-picosat.sh
./contrib/setup-btor2tools.sh

4. Build Boolector shared lib (you can add more options if you wish):
./configure.sh -fno-strict-aliasing -fpic --shared && cd build && make

5. Your shared lib can be found in boolector/build/lib
6. Copy it to java-smt3-boolector/lib/native/x86_64-linux/ and override the old lib
7. Update your JNI Java files


If you choose to use SWIG (Java/C):
(Careful, you need to check your methods later anyway, SWIG tends to make mistakes. Example: it gives pointers back instead of the object, or a Jlong instead of an Jint etc.)
Download: http://www.swig.org/download.html && Install Guide: https://github.com/swig/swig/wiki/Getting-Started

Create an interface file (example: exampleinterface.i)
Lets say you want the C header file "stuff.h" with the function "int fact(int n)" in Java, enter it in the interface file as seen below. (Names are important, even filenames!)
/* File: exampleInterface.i */
%module test
%{
#include "stuff.h"
%}
int fact(int n);

If you want all methods of the header in your interface, just replace the methods and enter %include "stuff.h" where the methods used to be.
After finishing the interface file, execute SWIG with it and the header(s) you want (all in the same folder).
See documentation of SWIG for more details. (This will propably do: %swig -java exampleinterface.i )
Swig has loads of options and customizations, read the doku! (Example: -package <name> will specify the java package, as it is important for method names)
Dokumentation, Java Command Line 26.2.2 : http://www.swig.org/Doc4.0/SWIGDocumentation.pdf
After executing SWIG correctly, there should be some .c and some .java files.
The .c part has to be bound to the native C code as described above, Java in Java.

27 changes: 27 additions & 0 deletions lib/native/source/libboolector/include_interface_and_jni.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index e2781eb..b838d8e 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,6 +1,7 @@
set(libboolector_src_files
aigprop.c
boolector.c
+ interface_wrap.c
boolectormc.c
btorabort.c
btoraig.c
@@ -96,6 +97,14 @@ target_include_directories(boolector
target_include_directories(boolector PRIVATE ${Btor2Tools_INCLUDE_DIR})
target_link_libraries(boolector ${Btor2Tools_LIBRARIES})

+find_package(JNI)
+if(JNI_FOUND)
+ message (STATUS "JNI_INCLUDE_DIRS=${JNI_INCLUDE_DIRS}")
+ message (STATUS "JNI_LIBRARIES=${JNI_LIBRARIES}")
+ target_include_directories(boolector PRIVATE ${JNI_INCLUDE_DIRS})
+ target_link_libraries(boolector ${JNI_LIBRARIES})
+endif()
+
if(GMP_FOUND)
target_include_directories(boolector PRIVATE ${GMP_INCLUDE_DIR})
target_link_libraries(boolector ${GMP_LIBRARIES})
Loading

0 comments on commit 31123b9

Please sign in to comment.