aboutsummaryrefslogtreecommitdiffstats
path: root/z3/subprojects
diff options
context:
space:
mode:
Diffstat (limited to 'z3/subprojects')
-rw-r--r--z3/subprojects/solver-darwin-aarch64/build.gradle.kts36
-rw-r--r--z3/subprojects/solver-darwin-x86-64/build.gradle.kts36
-rw-r--r--z3/subprojects/solver-linux-aarch64/build.gradle.kts14
-rwxr-xr-xz3/subprojects/solver-linux-aarch64/src/main/resources/z3java-linux-aarch64/libz3.sobin0 -> 30654912 bytes
-rw-r--r--z3/subprojects/solver-linux-aarch64/src/main/resources/z3java-linux-aarch64/libz3.so.license6
-rwxr-xr-xz3/subprojects/solver-linux-aarch64/src/main/resources/z3java-linux-aarch64/libz3java.sobin0 -> 308224 bytes
-rw-r--r--z3/subprojects/solver-linux-aarch64/src/main/resources/z3java-linux-aarch64/libz3java.so.license6
-rw-r--r--z3/subprojects/solver-linux-x86-64/build.gradle.kts36
-rw-r--r--z3/subprojects/solver-win32-x86-64/build.gradle.kts38
-rw-r--r--z3/subprojects/solver/build.gradle.kts107
-rw-r--r--z3/subprojects/solver/src/main/java/tools/refinery/z3/Z3SolverLoader.java154
-rw-r--r--z3/subprojects/solver/src/test/java/tools/refinery/z3/Z3SolverLoaderTest.java30
12 files changed, 463 insertions, 0 deletions
diff --git a/z3/subprojects/solver-darwin-aarch64/build.gradle.kts b/z3/subprojects/solver-darwin-aarch64/build.gradle.kts
new file mode 100644
index 00000000..21c9739c
--- /dev/null
+++ b/z3/subprojects/solver-darwin-aarch64/build.gradle.kts
@@ -0,0 +1,36 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7plugins {
8 id("tools.refinery.z3.gradle.java-library")
9}
10
11val classifier = "z3-${version}-arm64-osx-11.0"
12val library = "z3java-darwin-aarch64"
13
14dependencies {
15 z3("Z3Prover:z3:${version}:${classifier}@zip")
16}
17
18val extractZ3Libs by tasks.registering(Sync::class) {
19 dependsOn(configurations.z3)
20 from({
21 val zipFile = configurations.z3.map { it.singleFile }
22 zipTree(zipFile).matching {
23 include("${classifier}/bin/*.so")
24 includeEmptyDirs = false
25 }
26 })
27 eachFile {
28 val pathInBin = relativePath.segments.drop(2).toTypedArray()
29 relativePath = RelativePath(true, library, *pathInBin)
30 }
31 into(layout.buildDirectory.dir("z3-extracted"))
32}
33
34sourceSets.main {
35 resources.srcDir(extractZ3Libs)
36}
diff --git a/z3/subprojects/solver-darwin-x86-64/build.gradle.kts b/z3/subprojects/solver-darwin-x86-64/build.gradle.kts
new file mode 100644
index 00000000..75e59267
--- /dev/null
+++ b/z3/subprojects/solver-darwin-x86-64/build.gradle.kts
@@ -0,0 +1,36 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7plugins {
8 id("tools.refinery.z3.gradle.java-library")
9}
10
11val classifier = "z3-${version}-x64-osx-10.16"
12val library = "z3java-darwin-x86-64"
13
14dependencies {
15 z3("Z3Prover:z3:${version}:${classifier}@zip")
16}
17
18val extractZ3Libs by tasks.registering(Sync::class) {
19 dependsOn(configurations.z3)
20 from({
21 val zipFile = configurations.z3.map { it.singleFile }
22 zipTree(zipFile).matching {
23 include("${classifier}/bin/*.so")
24 includeEmptyDirs = false
25 }
26 })
27 eachFile {
28 val pathInBin = relativePath.segments.drop(2).toTypedArray()
29 relativePath = RelativePath(true, library, *pathInBin)
30 }
31 into(layout.buildDirectory.dir("z3-extracted"))
32}
33
34sourceSets.main {
35 resources.srcDir(extractZ3Libs)
36}
diff --git a/z3/subprojects/solver-linux-aarch64/build.gradle.kts b/z3/subprojects/solver-linux-aarch64/build.gradle.kts
new file mode 100644
index 00000000..a8e7e259
--- /dev/null
+++ b/z3/subprojects/solver-linux-aarch64/build.gradle.kts
@@ -0,0 +1,14 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7plugins {
8 id("tools.refinery.z3.gradle.java-library")
9}
10
11tasks.jar {
12 // License information is redundant here, since it already gets added to the POM.
13 exclude("**/*.license")
14}
diff --git a/z3/subprojects/solver-linux-aarch64/src/main/resources/z3java-linux-aarch64/libz3.so b/z3/subprojects/solver-linux-aarch64/src/main/resources/z3java-linux-aarch64/libz3.so
new file mode 100755
index 00000000..574ee3ab
--- /dev/null
+++ b/z3/subprojects/solver-linux-aarch64/src/main/resources/z3java-linux-aarch64/libz3.so
Binary files differ
diff --git a/z3/subprojects/solver-linux-aarch64/src/main/resources/z3java-linux-aarch64/libz3.so.license b/z3/subprojects/solver-linux-aarch64/src/main/resources/z3java-linux-aarch64/libz3.so.license
new file mode 100644
index 00000000..0993dbf7
--- /dev/null
+++ b/z3/subprojects/solver-linux-aarch64/src/main/resources/z3java-linux-aarch64/libz3.so.license
@@ -0,0 +1,6 @@
1Copyright (c) Microsoft Corporations
2
3SPDX-License-Identifier: MIT
4
5This file was created from the Z3 4.12.6 release sources using the
6z3/docker/cross_build.sh script in this repository.
diff --git a/z3/subprojects/solver-linux-aarch64/src/main/resources/z3java-linux-aarch64/libz3java.so b/z3/subprojects/solver-linux-aarch64/src/main/resources/z3java-linux-aarch64/libz3java.so
new file mode 100755
index 00000000..aace2c30
--- /dev/null
+++ b/z3/subprojects/solver-linux-aarch64/src/main/resources/z3java-linux-aarch64/libz3java.so
Binary files differ
diff --git a/z3/subprojects/solver-linux-aarch64/src/main/resources/z3java-linux-aarch64/libz3java.so.license b/z3/subprojects/solver-linux-aarch64/src/main/resources/z3java-linux-aarch64/libz3java.so.license
new file mode 100644
index 00000000..0993dbf7
--- /dev/null
+++ b/z3/subprojects/solver-linux-aarch64/src/main/resources/z3java-linux-aarch64/libz3java.so.license
@@ -0,0 +1,6 @@
1Copyright (c) Microsoft Corporations
2
3SPDX-License-Identifier: MIT
4
5This file was created from the Z3 4.12.6 release sources using the
6z3/docker/cross_build.sh script in this repository.
diff --git a/z3/subprojects/solver-linux-x86-64/build.gradle.kts b/z3/subprojects/solver-linux-x86-64/build.gradle.kts
new file mode 100644
index 00000000..89c737b6
--- /dev/null
+++ b/z3/subprojects/solver-linux-x86-64/build.gradle.kts
@@ -0,0 +1,36 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7plugins {
8 id("tools.refinery.z3.gradle.java-library")
9}
10
11val classifier = "z3-${version}-x64-glibc-2.31"
12val library = "z3java-linux-x86-64"
13
14dependencies {
15 z3("Z3Prover:z3:${version}:${classifier}@zip")
16}
17
18val extractZ3Libs by tasks.registering(Sync::class) {
19 dependsOn(configurations.z3)
20 from({
21 val zipFile = configurations.z3.map { it.singleFile }
22 zipTree(zipFile).matching {
23 include("${classifier}/bin/*.so")
24 includeEmptyDirs = false
25 }
26 })
27 eachFile {
28 val pathInBin = relativePath.segments.drop(2).toTypedArray()
29 relativePath = RelativePath(true, library, *pathInBin)
30 }
31 into(layout.buildDirectory.dir("z3-extracted"))
32}
33
34sourceSets.main {
35 resources.srcDir(extractZ3Libs)
36}
diff --git a/z3/subprojects/solver-win32-x86-64/build.gradle.kts b/z3/subprojects/solver-win32-x86-64/build.gradle.kts
new file mode 100644
index 00000000..c5fa0421
--- /dev/null
+++ b/z3/subprojects/solver-win32-x86-64/build.gradle.kts
@@ -0,0 +1,38 @@
1/*
2 * SPDX-FileCopyrightText: 2021-2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7plugins {
8 id("tools.refinery.z3.gradle.java-library")
9}
10
11val classifier = "z3-${version}-x64-win"
12val library = "z3java-win32-x86-64"
13
14dependencies {
15 z3("Z3Prover:z3:${version}:${classifier}@zip")
16}
17
18val extractZ3Libs by tasks.registering(Sync::class) {
19 dependsOn(configurations.z3)
20 from({
21 val zipFile = configurations.z3.map { it.singleFile }
22 zipTree(zipFile).matching {
23 include("${classifier}/bin/*.dll")
24 // Do not include .NET assembly.
25 exclude("${classifier}/bin/Microsoft.Z3.dll")
26 includeEmptyDirs = false
27 }
28 })
29 eachFile {
30 val pathInBin = relativePath.segments.drop(2).toTypedArray()
31 relativePath = RelativePath(true, library, *pathInBin)
32 }
33 into(layout.buildDirectory.dir("z3-extracted"))
34}
35
36sourceSets.main {
37 resources.srcDir(extractZ3Libs)
38}
diff --git a/z3/subprojects/solver/build.gradle.kts b/z3/subprojects/solver/build.gradle.kts
new file mode 100644
index 00000000..7e898b3e
--- /dev/null
+++ b/z3/subprojects/solver/build.gradle.kts
@@ -0,0 +1,107 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7import tools.refinery.z3.gradle.ClassFilePatcher
8
9plugins {
10 id("tools.refinery.z3.gradle.java-library")
11}
12
13val classifier = "z3-${version}-x64-glibc-2.31"
14val extractedClassesDir = layout.buildDirectory.dir("z3-extracted")
15val extractedSourcesDir = layout.buildDirectory.dir("z3-sources")
16
17java {
18 withJavadocJar()
19 withSourcesJar()
20}
21
22val z3Source: Configuration by configurations.creating {
23 isCanBeConsumed = false
24 isCanBeResolved = true
25}
26
27val extractZ3Jar by tasks.registering(Sync::class) {
28 dependsOn(configurations.z3)
29 from({
30 val zipFile = configurations.z3.map { it.singleFile }
31 val jarFile = zipTree(zipFile).matching {
32 include("${classifier}/bin/com.microsoft.z3.jar")
33 }.singleFile
34 zipTree(jarFile).matching {
35 exclude("META-INF/MANIFEST.MF")
36 includeEmptyDirs = false
37 }
38 })
39 into(extractedClassesDir)
40 doLast {
41 // The class initializer off {@see com.microsoft.z3.Native} will try to load the Z3 native libraries
42 // from the system default library path unless the {@code z3.skipLibraryLoad} system property is set.
43 // Since we don't control the library path or system properties, we remove the class initializer entirely.
44 val nativeClassFile = extractedClassesDir.get().file("com/microsoft/z3/Native.class").asFile
45 ClassFilePatcher.removeClassInitializer(nativeClassFile)
46 }
47}
48
49val extractZ3Source by tasks.registering(Sync::class) {
50 dependsOn(z3Source)
51 from({
52 val zipFile = z3Source.singleFile
53 zipTree(zipFile).matching {
54 include("z3-z3-${version}/src/api/java/**/*")
55 includeEmptyDirs = false
56 }
57 })
58 eachFile {
59 val pathInBin = relativePath.segments.drop(4).toTypedArray()
60 relativePath = RelativePath(true, "com", "microsoft", "z3", *pathInBin)
61 }
62 into(extractedSourcesDir)
63}
64
65tasks.jar {
66 // Add class files to our jar manually.
67 from(extractZ3Jar)
68}
69
70tasks.test {
71 useJUnitPlatform()
72}
73
74tasks.named<Jar>("sourcesJar") {
75 from(extractZ3Source)
76}
77
78tasks.named<Javadoc>("javadoc") {
79 source(sourceSets.main.map { it.allJava })
80 source(fileTree(extractedSourcesDir) {
81 builtBy(extractZ3Source)
82 include("**/*.java")
83 })
84 options {
85 this as StandardJavadocDocletOptions
86 addBooleanOption("Xdoclint:none", true)
87 // {@code -Xmaxwarns 0} will print all warnings, so we must keep at least one.
88 addStringOption("Xmaxwarns", "1")
89 quiet()
90 }
91}
92
93dependencies {
94 z3("Z3Prover:z3:${version}:${classifier}@zip")
95 z3Source("Z3Prover:z3:${version}@zip")
96 // This dependency doesn't get added to Maven metadata, so we have to add the class files to our jar manually.
97 api(files(extractZ3Jar))
98 implementation(libs.jna)
99 implementation(project(":refinery-z3-solver-darwin-aarch64"))
100 implementation(project(":refinery-z3-solver-darwin-x86-64"))
101 implementation(project(":refinery-z3-solver-linux-aarch64"))
102 implementation(project(":refinery-z3-solver-linux-x86-64"))
103 implementation(project(":refinery-z3-solver-win32-x86-64"))
104 testImplementation(libs.junit.api)
105 testRuntimeOnly(libs.junit.engine)
106 testRuntimeOnly("org.junit.platform:junit-platform-launcher")
107}
diff --git a/z3/subprojects/solver/src/main/java/tools/refinery/z3/Z3SolverLoader.java b/z3/subprojects/solver/src/main/java/tools/refinery/z3/Z3SolverLoader.java
new file mode 100644
index 00000000..84f99540
--- /dev/null
+++ b/z3/subprojects/solver/src/main/java/tools/refinery/z3/Z3SolverLoader.java
@@ -0,0 +1,154 @@
1/*
2 * Copyright 2010-2022 Google LLC
3 * Copyright 2023 The Refinery Authors <https://refinery.tools/>
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * This file is based on
8 * https://github.com/google/or-tools/blob/f3d1d5f6a67356ec38a7fd2ab607624eea8ad3a6/ortools/java/com/google/ortools/Loader.java
9 * We adapted the loader logic to extract the JNI libraries of Z3 and the corresponding dependencies instead of the
10 * Google OR-Tools JNI libraries.
11 */
12package tools.refinery.z3;
13
14import com.sun.jna.Platform;
15
16import java.io.IOException;
17import java.net.URI;
18import java.net.URISyntaxException;
19import java.nio.file.*;
20import java.nio.file.attribute.BasicFileAttributes;
21import java.util.Map;
22
23public final class Z3SolverLoader {
24 private static final String JNI_LIBRARY_NAME = "z3java";
25 private static final String SOLVER_LIBRARY_NAME = "z3";
26
27 private static boolean loaded;
28
29 private Z3SolverLoader() {
30 throw new IllegalStateException("This is a static utility class and should not be instantiated directly");
31 }
32
33 public static synchronized void loadNativeLibraries() {
34 if (loaded) {
35 return;
36 }
37 try {
38 System.loadLibrary(getOsSpecificLibraryName(JNI_LIBRARY_NAME));
39 loaded = true;
40 return;
41 } catch (UnsatisfiedLinkError e) {
42 // Continue, we'll have to extract the libraries from the classpath.
43 }
44 try {
45 extractAndLoad();
46 loaded = true;
47 } catch (IOException e) {
48 throw new IllegalStateException("Could not extract and load " + JNI_LIBRARY_NAME, e);
49 }
50 }
51
52 private static void extractAndLoad() throws IOException {
53 var resourceName = JNI_LIBRARY_NAME + "-" + Platform.RESOURCE_PREFIX;
54 var resource = Z3SolverLoader.class.getClassLoader().getResource(resourceName);
55 if (resource == null) {
56 throw new IllegalStateException("Resource %s was not found".formatted(resourceName));
57 }
58 URI resourceUri;
59 try {
60 resourceUri = resource.toURI();
61 } catch (URISyntaxException e) {
62 throw new IllegalStateException("Invalid resource URI: " + resource);
63 }
64 FileSystem fileSystem = null;
65 boolean newFileSystem = false;
66 Path extractedPath;
67 try {
68 try {
69 fileSystem = FileSystems.newFileSystem(resourceUri, Map.of());
70 newFileSystem = true;
71 } catch (FileSystemAlreadyExistsException e) {
72 fileSystem = FileSystems.getFileSystem(resourceUri);
73 }
74 var resourcePath = fileSystem.provider().getPath(resourceUri);
75 if (fileSystem.equals(FileSystems.getDefault())) {
76 extractedPath = resourcePath;
77 } else {
78 extractedPath = extract(resourcePath);
79 }
80 } finally {
81 if (newFileSystem) {
82 fileSystem.close();
83 }
84 }
85 // We can't rely on RPATH, so we load libraries in reverse dependency order manually.
86 try {
87 loadFromPath(extractedPath, SOLVER_LIBRARY_NAME);
88 } catch (UnsatisfiedLinkError e) {
89 if (Platform.isWindows()) {
90 // Try again with our packaged msvcp140 if the system one is missing.
91 loadFromPathExactName(extractedPath, "vcruntime140.dll");
92 loadFromPathExactName(extractedPath, "vcruntime140_1.dll");
93 loadFromPathExactName(extractedPath, "msvcp140.dll");
94 loadFromPath(extractedPath, SOLVER_LIBRARY_NAME);
95 } else {
96 throw e;
97 }
98 }
99 loadFromPath(extractedPath, JNI_LIBRARY_NAME);
100 }
101
102 private static Path extract(Path resourcePath) throws IOException {
103 var tempDir = Files.createTempDirectory(JNI_LIBRARY_NAME).toAbsolutePath();
104 tempDir.toFile().deleteOnExit();
105 Files.walkFileTree(resourcePath, new SimpleFileVisitor<>() {
106 @Override
107 public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
108 var result = super.preVisitDirectory(dir, attrs);
109 var targetPath = getTargetPath(dir, resourcePath, tempDir);
110 if (!Files.exists(targetPath)) {
111 Files.createDirectory(targetPath);
112 targetPath.toFile().deleteOnExit();
113 }
114 return result;
115 }
116
117 @Override
118 public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
119 var result = super.visitFile(file, attrs);
120 var targetPath = getTargetPath(file, resourcePath, tempDir);
121 Files.copy(file, targetPath);
122 targetPath.toFile().deleteOnExit();
123 return result;
124 }
125 });
126 return tempDir;
127 }
128
129 private static Path getTargetPath(Path sourcePath, Path resourcePath, Path tempDir) {
130 var targetPath = tempDir.resolve(resourcePath.relativize(sourcePath).toString()).normalize();
131 if (!targetPath.startsWith(tempDir)) {
132 throw new IllegalStateException("Target path '%s' for '%s' is outside '%s'"
133 .formatted(targetPath, sourcePath, tempDir));
134 }
135 return targetPath;
136 }
137
138 private static String getOsSpecificLibraryName(String libraryName) {
139 var osSpecificLibraryNamePrefix = Platform.isWindows() ? "lib" : "";
140 return osSpecificLibraryNamePrefix + libraryName;
141 }
142
143 private static void loadFromPath(Path extractedPath, String libraryName) {
144 var osSpecificLibraryName = getOsSpecificLibraryName(libraryName);
145 loadFromPathExactName(extractedPath, System.mapLibraryName(osSpecificLibraryName));
146 }
147
148 private static void loadFromPathExactName(Path extractedPath, String exactName) {
149 var library = extractedPath.resolve(exactName)
150 .toAbsolutePath()
151 .toString();
152 System.load(library);
153 }
154}
diff --git a/z3/subprojects/solver/src/test/java/tools/refinery/z3/Z3SolverLoaderTest.java b/z3/subprojects/solver/src/test/java/tools/refinery/z3/Z3SolverLoaderTest.java
new file mode 100644
index 00000000..df3139cc
--- /dev/null
+++ b/z3/subprojects/solver/src/test/java/tools/refinery/z3/Z3SolverLoaderTest.java
@@ -0,0 +1,30 @@
1/*
2 * SPDX-FileCopyrightText: 2023 The Refinery Authors <https://refinery.tools/>
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6package tools.refinery.z3;
7
8import com.microsoft.z3.*;
9import org.junit.jupiter.api.Test;
10
11import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
12import static org.junit.jupiter.api.Assertions.assertEquals;
13
14class Z3SolverLoaderTest {
15 @Test
16 void testLoad() {
17 assertDoesNotThrow(Z3SolverLoader::loadNativeLibraries);
18 try (var context = new Context()) {
19 var solver = context.mkSolver();
20 var a = context.mkConst("a", context.getIntSort());
21 var b = context.mkConst("b", context.getIntSort());
22 solver.add(context.mkEq(a, context.mkInt(3)));
23 solver.add(context.mkEq(b, context.mkMul(context.mkInt(2), a)));
24 assertEquals(Status.SATISFIABLE, solver.check());
25 var model = solver.getModel();
26 var bValue = (IntNum) model.getConstInterp(b);
27 assertEquals(6, bValue.getInt());
28 }
29 }
30}