Add CI for example projects#667
Conversation
…ion number to the example project
… the starter guide
…o the starter guide
… the other template projects
…oblems-with-installation
| private val OS: String = | ||
| StandardSystemProperty.OS_NAME.value()!!.lowercase(Locale.getDefault()).replace(" ", "") | ||
| private val ARCH: String = | ||
| StandardSystemProperty.OS_ARCH.value()!!.lowercase(Locale.getDefault()).replace(" ", "") | ||
|
|
||
| protected val IS_WINDOWS: Boolean = OS.startsWith("windows") | ||
| private val IS_MAC: Boolean = OS.startsWith("macos") | ||
| private val IS_LINUX: Boolean = OS.startsWith("linux") | ||
|
|
||
| private val IS_ARCH_ARM64 = ARCH == "aarch64" | ||
|
|
||
| private fun isSufficientVersionOfLibcxx(library: String): Boolean { | ||
| try { | ||
| NativeLibraries.loadLibrary(library) | ||
| } catch (e: UnsatisfiedLinkError) { | ||
| for (dependency in getRequiredLibcxx(library)) { | ||
| if (e.message!!.contains("version `" + dependency + "' not found")) { | ||
| return false | ||
| } | ||
| } | ||
| } | ||
| return true | ||
| } | ||
|
|
||
| private fun getRequiredLibcxx(library: String): List<String> { | ||
| return when (library) { | ||
| "z3" -> listOf("GLIBC_2.34", "GLIBCXX_3.4.26", "GLIBCXX_3.4.29") | ||
| "bitwuzlaj" -> listOf("GLIBC_2.33", "GLIBCXX_3.4.26", "GLIBCXX_3.4.29") | ||
| "opensmtj" -> listOf("GLIBC_2.33", "GLIBCXX_3.4.26", "GLIBCXX_3.4.29") | ||
| "mathsat5j" -> listOf("GLIBC_2.33", "GLIBC_2.38") | ||
| "cvc5jni" -> listOf("GLIBC_2.32") | ||
| "yices2java" -> listOf("GLIBC_2.34") | ||
| else -> listOf() | ||
| } | ||
| } | ||
|
|
||
| /** Disable some checks on certain combinations of operating systems and solvers, because of missing dependencies. */ | ||
| private fun isSupportedOperatingSystemAndArchitecture(solver: Solvers): Boolean { | ||
| return when (solver) { | ||
| Solvers.SMTINTERPOL, Solvers.PRINCESS -> true | ||
| Solvers.BOOLECTOR, Solvers.CVC4 -> IS_LINUX && !IS_ARCH_ARM64 | ||
| Solvers.YICES2 -> (IS_LINUX && !IS_ARCH_ARM64 && isSufficientVersionOfLibcxx("yices2java")) | ||
| || (IS_WINDOWS && !IS_ARCH_ARM64) | ||
|
|
||
| Solvers.CVC5 -> (IS_LINUX && isSufficientVersionOfLibcxx("cvc5jni")) | ||
| || IS_WINDOWS | ||
| || IS_MAC | ||
|
|
||
| Solvers.OPENSMT -> IS_LINUX && isSufficientVersionOfLibcxx("opensmtj") | ||
| Solvers.BITWUZLA -> (IS_LINUX && isSufficientVersionOfLibcxx("bitwuzlaj")) | ||
| || (IS_WINDOWS && !IS_ARCH_ARM64) | ||
|
|
||
| Solvers.MATHSAT5 -> (IS_WINDOWS && !IS_ARCH_ARM64) | ||
| Solvers.Z3 -> (IS_LINUX && isSufficientVersionOfLibcxx("z3")) | ||
| || IS_WINDOWS | ||
| || IS_MAC | ||
|
|
||
| Solvers.Z3_WITH_INTERPOLATION -> IS_LINUX && !IS_ARCH_ARM64 | ||
| } | ||
| } |
There was a problem hiding this comment.
This code is taken from SolverContextFactory and clutters up the example. Maybe there's a way to make isSupportedOperatingSystemAndArchitecture part of the JavaSMT API to avoid all the duplicate code?
There was a problem hiding this comment.
Nice work, thank you!
Something to discuss (input from @kfriedberger and @PhilippWendler would be appreciated):
I noticed that we copy around files in the example projects. This might be confusing to people that use them as templates. A possible solution for this would be to extract the example projects into their own repositories and link the repositories to ours (so that they are folders that just link to the other repo).
Edit: this also seems to indicate that this would be a good idea, as it would make developing/updating in the projects easier.
| archive: false | ||
|
|
||
| kotlin: | ||
| name: Kotlin Example Project |
There was a problem hiding this comment.
Adding the used build-system would be good.
There was a problem hiding this comment.
I've renamed it to "Kotlin Gradle Project" now. Is that fine with you?
| fail-fast: false | ||
| matrix: | ||
| java-version: [ 21 ] | ||
| os: [ubuntu-24.04, ubuntu-24.04-arm, windows-2025, windows-11-arm, macos-26-intel, macos-26] |
There was a problem hiding this comment.
Selecting the OS this way would require us to manually update this file every time we have a newer OS version. This might lead to this being overseen. You can just use the latest tag with wildcards, as can be seen here for example, so that we automatically use the newest OS.
There was a problem hiding this comment.
I've now updated them to latest as far as possible. However, for the arm runners there is no latest release and the exact version needs to be provided (see here)
| steps: | ||
| - uses: actions/checkout@v6 | ||
|
|
||
| - name: Set up JDK ${{ matrix.java-version }} |
There was a problem hiding this comment.
Why not use a dependencies job as in ci.yml to set up our environment correctly, i.e. so that Java and other dependencies are present. And why don't we just extend ci.yml?
There was a problem hiding this comment.
Java is fetched by actions/setup-java and we're using caches to avoid downloading the dependencies multiple times. We could try integrating it further with ci.yml, but since the examples are using various different build systems, there may not be that much overlap
In total the example-project-ci workflow takes 7-8 minutes to run, which is probably still fine, especially as we may not have to run it as often as our regular CI jobs
| @Test | ||
| public void checkSudoku() | ||
| throws InvalidConfigurationException, InterruptedException, SolverException { | ||
| assumeTrue(isSupportedOperatingSystemAndArchitecture(solver)); |
There was a problem hiding this comment.
Wouldn't a @BeforeEach that checks this make more sense?
Note: and please name and document the expected behavior such that it becomes clear what went wrong fast.
The same thing applies to all test classes in this PR.
| an API wrapper for a collection of SMT solvers: | ||
| https://github.com/sosy-lab/java-smt | ||
|
|
||
| SPDX-FileCopyrightText: 2025 Dirk Beyer <https://www.sosy-lab.org> |
There was a problem hiding this comment.
Note: applies to several files.
|
|
||
| <target name="download-ivy" unless="skip.download"> | ||
| <mkdir dir="lib"/> | ||
| <get src="https://repo1.maven.org/maven2/org/apache/ivy/ivy/2.5.0/ivy-2.5.0.jar" |
There was a problem hiding this comment.
We install Ivy from Maven? ;D
I think it would be better to fail instead of installing something here. You can take a look at how CPAchecker fails if Ant or Ivy are missing here.
There was a problem hiding this comment.
Ivy does need to be downloaded before building as it is not included in the ant installation. However, I did change the download location to sosy-labs now
| <ivy:retrieve pattern="lib/java/[conf]/([arch]/)[artifact](-[classifier]).[ext]"/> | ||
| </target> | ||
|
|
||
| <target name="copy" depends="resolve" description="--> copy solver libraries"> |
There was a problem hiding this comment.
Since we usually don't want users to do this, we should document why we do it here!
| on: | ||
| push |
There was a problem hiding this comment.
We should remember to change this before merging. Right now it will trigger whenever anything is pushed to github. We could restrict it to only pushes to main, or maybe even have it manually triggered (whenever we release a new version of JavaSMT)
I do not know what files you are copying around nor when, why, or how a separate repository is supposed to help with that. If you want input from me please explain the current solution and its problems. |
JavaSMT requires solver binaries to be in a particular location (if you don't use custom loading mechanisms). Since the example projects are located in some nested folders, we need to move the solver binaries around after we retrieved them, so that the example projects work properly. You can see this for example here. This might be confusing for users that just copy the example projects. |
Why? How would the solver binaries end up in the example project then? And why couldn't the same mechanism be used for example projects in a subdirectory? |
Hello everyone,
this PR adds CI checks for all project examples in the
docdirectory to verify that they're working, and make sure that there are no issues with the packages that we've published to Maven. It is based on two earlier PRs that update the example projects and add another project template for using JavaSMT in Ivy. As a result, this PR now contains CI for using JavaSMT with 5 different build systems:Except for
Maven Web, all CI checks are run multiple times to cover all supported platforms. ForMaven Webthe project is a web application and we only testx64-linuxas this is most likely what the server will use. Also note, that for the web application we don't actually test if the*.waris working as this would be too difficult to do inside of a Github workflowResults from the latest CI run can be found here for my fork of the project. To make it work here we would still have to whilelist an
actionthat is used by the workflow, see hereCloses #663