10000 WIP: Migrating OCaml binding to CMake by arbipher · Pull Request #7254 · Z3Prover/z3 · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

WIP: Migrating OCaml binding to CMake #7254

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Apr 19, 2025

Conversation

arbipher
Copy link
Contributor
@arbipher arbipher commented Jun 17, 2024

It's my WIP working on migrating the building of OCaml binding to CMake.

I think the majority of the work is done. I started by mimicking the other bindings and some llvm cmake for ocaml, but then I just manually wrote enough custom commands and dependencies. The actual building commands should have the same result as the previously generated python scripts, though I think I simplified some unnecessary dependencies and compiler flags.

tldr;

  cd build && cmake \
-G "Ninja" \
-DZ3_BUILD_LIBZ3_SHARED=TRUE \
-DZ3_BUILD_OCAML_BINDINGS=TRUE \
-DZ3_USE_LIB_GMP=TRUE \
../

It should just work. I also build and run the ml_examples.ml for both bytecode and native code in the cmake to make sure it works. I observe all z3 bindings are using shared library so I wonder maybe I don't even need to make a static version for the ocaml-binding.

I also add one argument -DZ3_BUILD_OCAML_EXTERNAL_LIBZ3=/path/to/libz3.so to support building ocaml building with an external z3 library that is often installed by some other distro package managers.

Now the remaining work is :

  1. The installation part. I really don't have a good idea for non opam installation.
  2. Test it on macos. I knew the problem and the two-line fix for macos's problem. It's in the comments yet.
  3. Remove unnecessary files.
  4. Write some good document for it.
  5. Tune for the CI.
  6. (this is out of z3 but) Make opam package for this new building script. However, I guess I have to adjust both sides to try letting it work well.

p.s. for ocaml users, I also have a post for discussion.

Copy link
Contributor
@wintersteiger wintersteiger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall this looks like a good start, but it needs a lot of clean-up and extensions before it will be usable in practice.

-ocamlcflags -bin-annot \
-package zarith \
-lz3 -lstdc++ -lpthread\
-lgmp \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GMP is optional, so this should be guarded.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it.

@@ -3712,6 +3713,31 @@ end
For example:
(set_global_param "pp.decimal" "true")
will set the parameter "decimal" in the module "pp" to true.

Legal parameters are:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These parameters can change and nobody will update this list. We could perhaps try to get this list programmatically?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, this comes from my previous learning/experimenting notes so it shouldn't be included here.

I agree with your point.

set(libz3_path ${PROJECT_BINARY_DIR})
endif()

add_custom_command(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When using a custom command and target, will these always rebuild, even when there are no changes to the inputs?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. add_custom_command will check the depends and outputs to decide whether to run it. CMake also checks them statically to make sure these commands are valid.

VERBATIM
)

add_custom_command(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It shouldn't be necessary to copy source files around, the other targets that use them can just as well reference the source directory.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's subtle and I prefer to copy them. The reason is ocamlc may generate some intermediate files at the source location. It general, it can also simplify the dependencies of custom commands when some files are generated to be in the build path while some files are at the source path.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yes, that's right. We do have to make sure everything is generated in the build directory, and sometimes that might indeed require copying source files around if the OCaml tools don't provide commandline flags to set the output path.

if( APPLE )
set(ocaml_rpath "@executable_path/../libz3${so_ext}")
elseif( UNIX )
set(ocaml_rpath "\\$ORIGIN/../libz3${so_ext}")
8000
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Windows/Cygwin?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At this moment, building on Windows/Cygwin is beyond my knowledge and I think even the support for OCaml on Windows is under heavy development. I may prefer to at least postpone it until the rest is done.

p.s. I notice there is some good news in the OCaml community.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, it's always been a bit neglected, but there are users, so we should make sure it works. BTW, the Opam people are also adding a Windows CI pipeline at the moment, so it might be required for Opam packages soon.

set(ocaml_rpath "@executable_path/../../../lib${LLVM_LIBDIR_SUFFIX}")
elseif( UNIX )
set(ocaml_rpath "\\$ORIGIN/../../../lib${LLVM_LIBDIR_SUFFIX}")
endif()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Windows/Cygwin

# INCLUDES Path for header files for C sources.
# CFLAGS Additional arguments passed when compiling C stubs.
# PKG Names of ocamlfind packages this library depends on.
# LLVM Names of LLVM libraries this library depends on.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this LLVM-only? If so, we need to add support for other compilers. If not, we should change those names.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will remove it. It's the starting point of this work but later I realized the requirements for ocaml-llvm and ocaml-z3 are different.

endforeach()

install(FILES ${install_files}
DESTINATION "${LLVM_OCAML_INSTALL_PATH}/llvm")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure where this will attempt to install files to, but clearly ..../llvm will not make sense for any other compilers.

add_custom_command(TARGET "ocaml_${name}" POST_BUILD
COMMAND "${CMAKE_COMMAND}" "-E" "copy" "${install_file}"
"${LLVM_LIBRARY_DIR}/ocaml/llvm/"
COMMENT "Copying OCaml library component ${filename} to intermediate area"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will 9E19 be displayed to describe this comment to others. Learn more.

Suggested change
COMMENT "Copying OCaml library component ${filename} to intermediate area"
COMMENT "Installing OCaml library component ${filename}"

@@ -292,6 +292,9 @@ The following useful options can be passed to CMake whilst configuring.
* ``Z3_INSTALL_JAVA_BINDINGS`` - BOOL. If set to ``TRUE`` and ``Z3_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``.
* ``Z3_BUILD_OCAML_BINDINGS`` - BOOL. If set to ``TRUE`` then Z3's OCaml bindings will be built.
* ``Z3_BUILD_JULIA_BINDINGS`` - BOOL. If set to ``TRUE`` then Z3's Julia bindings will be built.
* ``Z3_INSTALL_JULIA_BINDINGS`` - BOOL. If set to ``TRUE`` and ``Z3_BUILD_JULIA_BINDINGS`` is ``TRUE`` then running the ``install`` target will install Z3's Julia bindings.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add similar option for the OCaml bindings?

@arbipher
Copy link
Contributor Author
arbipher commented Jul 2, 2024

Thank you so much for your careful examination. This is one reason I would like to make this immature draft PR.
I am learning how z3 is installed on some platforms so my change won't break them. Also, I am still thinking how the ocaml-binding should be installed.

I will check your changes one by one later.

@NikolajBjorner
Copy link
Contributor

It would be absolutely great to cmake-ify the ocaml bindings for uniform build support and allow to retarget release processes to use the more portable cmake system.

@arbipher
Copy link
Contributor Author
arbipher commented Nov 3, 2024

Aha, I was occupied by some random things after the previous effect on this issue in July. I hope to pick this up this month.

@arbipher arbipher force-pushed the cmake-ocaml-binding branch 2 times, most recently from f401083 to 4b32075 Compare April 17, 2025 07:07
@arbipher arbipher force-pushed the cmake-ocaml-binding branch 3 times, most recently from 4d6153f to 9c7e799 Compare April 18, 2025 08:27
@arbipher arbipher force-pushed the cmake-ocaml-binding branch 5 times, most recently from 42f1f44 to 63d8171 Compare April 18, 2025 18:13
@arbipher arbipher force-pushed the cmake-ocaml-binding branch 18 times, most recently from b599979 to 738954d Compare April 18, 2025 23:00
@arbipher arbipher force-pushed the cmake-ocaml-binding branch 2 times, most recently from affef6c to ea9716b Compare April 19, 2025 16:18
@arbipher arbipher force-pushed the cmake-ocaml-binding branch from ea9716b to ac10869 Compare April 19, 2025 16:26
@arbipher
Copy link
Contributor Author

I made some updates (finally) to the PR. After it looks good to you, I can cherry-pick them to the latest commit and make another PR.

For the previous review,

  • I removed all the necessary source file copying.
  • I deleted AddOCaml.make, which was used for llvm.

I added Github Action and made it work on both ubuntu and macOS. They work (finally finally) on my forked repo.

For the linking especially rpath-related, since platforms like Debian (discourage), homebrew(hacking) or even opam have its own mechanism to handle, in this build I just figured out a way (mainly for macOS) to make two working build and run as sanity check.

The next step is to allow external libz3 and allow binding to be built with them. I am still not very clear on the current Windows support for ocaml as well as the users will use a Windows native binding.

@NikolajBjorner
Copy link
Contributor

Regarding Windows + OCaml: It isn't (was never before) a big use case and nowadays it is very easy to start up wsl2/ubuntu for ocaml development.

I sometimes tease @msprotz on his past heroic efforts in this space, so thanks for the reminder.

@NikolajBjorner NikolajBjorner marked this pull request as ready for review April 19, 2025 20:23
@NikolajBjorner NikolajBjorner merged commit f7aec02 into Z3Prover:master Apr 19, 2025
10 checks passed
@arbipher
Copy link
Contributor Author

Cool for the merging. There is a debug helper makefile in it (which shouldn't be a big deal and I will remove it in the next PR for the next steps).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants
0