Skip to content
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

Chuffed: initial commit #6

Merged
merged 5 commits into from
Oct 4, 2023
Merged

Conversation

Kieranoski702
Copy link
Contributor

@Kieranoski702 Kieranoski702 commented Oct 2, 2023

This PR copies previous work on these bindings (in a private repository) into the repo. This is a proof of concept currently, and has no functionality apart from calling chuffed's build system, linking with the generated static library (libchuffed.a), and generating the automatic bindings using bindgen.

The next steps for this are:

  • Document chuffed's existing API
  • To setup some basic CI
  • Allow the functions, constants, etc. required to create a real example such as solving a sudoku puzzle

@yigityazicilar
Copy link

This is more a general thing across solvers but I will also list it here so that it can be applied in the future. It might be good to include

#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]

at the top of lib.rs files so that Rust does not complain about the C/C++ code not fitting Rust conventions.

@niklasdewally
Copy link
Collaborator

@OcEaNvS is there a way to do this by module, or is it by function or by crate only?

The C++ bindings (in my case at least) are their own module, so if it is possible it would be nice to make it module only :).

@yigityazicilar
Copy link

@niklasdewally When you add those to the lib.rs of your module it stops Rust complaining about the generated bindings when they are included. This effect happens module wide. https://rust-lang.github.io/rust-bindgen/tutorial-4.html

@yigityazicilar
Copy link

@Kieranoski702 I am getting a linking error while using the createVar function. Before trying to use any of the C++ functions this library compiled without any problems. I am not sure if this is just an error on my side but I am including the error message in case it is not.

  = note: /usr/bin/ld: ./solvers/chuffed/vendor/build//libchuffed.a(engine.cpp.o): in function `Engine::search(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)':
          engine.cpp:(.text+0x3312): undefined reference to `FlatZinc::FlatZincSpace::onRestart(Engine*)'
          /usr/bin/ld: engine.cpp:(.text+0x3d2f): undefined reference to `FlatZinc::FlatZincSpace::onRestart(Engine*)'
          /usr/bin/ld: engine.cpp:(.text+0x4ee8): undefined reference to `FlatZinc::FlatZincSpace::onRestart(Engine*)'
          /usr/bin/ld: ./solvers/chuffed/vendor/build//libchuffed.a(engine.cpp.o): in function `Engine::constrain()':
          engine.cpp:(.text._ZN6Engine9constrainEv[_ZN6Engine9constrainEv]+0x88): undefined reference to `FlatZinc::FlatZincSpace::storeSolution()'
          /usr/bin/ld: engine.cpp:(.text._ZN6Engine9constrainEv[_ZN6Engine9constrainEv]+0x157): undefined reference to `FlatZinc::FlatZincSpace::onRestart(Engine*)'
          collect2: error: ld returned 1 exit status

To check if this is just on my side you can add .allowlist_function(createVar) to ./solvers/chuffed/build.rs and change ./solvers/chuffed/src/main.rs to the following:

use chuffed_rs::bindings::createVar;
use chuffed_rs::bindings::IntVar;

pub fn main() {
    let mut var = std::mem::MaybeUninit::<IntVar>::uninit();
    unsafe {
        createVar(&mut var.as_mut_ptr(), 0, 5, false);
    }
}

@@ -0,0 +1,5 @@
pub mod bindings {

Choose a reason for hiding this comment

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

Suggested change
pub mod bindings {
#![allow(non_upper_case_globals)]
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
pub mod bindings {

// from project root
println!("cargo:rustc-link-search=all=./solvers/chuffed/vendor/build/");
println!("cargo:rustc-link-lib=static=chuffed");

Choose a reason for hiding this comment

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

The linking issue can be fixed by adding the following code.

Suggested change
println!("cargo:rustc-link-lib=static=chuffed_fzn");


The chuffed solver is tightly integrated with the flatzinc modelling language. The flatzinc files are not included in the libchuffed.a library. These files get compiled to a separate library called libchuffed_fzn.a.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've added this along with your suggested changes to lib.rs. I've also tried to run your example main function after putting createVar into the allow list in build.rs. I get a different error from you when trying to compile now even after adding the link to libchuffed_fzn.a. Were you able to get your example main running after you made those changes?

Choose a reason for hiding this comment

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

Could you send the error that you are getting so that I can look into it? I was able to get it to run on my end.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Could you send the error that you are getting so that I can look into it? I was able to get it to run on my end.

Yeah sure thing, it's quite a lot so just gonna show a snippet

error: linking with `cc` failed: exit status: 1
  |
  = note: LC_ALL="C" PATH="/home/kf77/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/bin:/home/kf77/.opam/default/bin:/home/kf77/local/bin:/home/kf77/local/bin:/home/kf77/local/bin:/home/kf77/local/bin:/home/kf77/.cargo/bin:/home/kf77/.cabal/bin:/home/kf77/.ghcup/bin:/home/kf77/.local/bin:/home/kf77/bin:/usr/share/Modules/bin:/usr/local/julia/bin:/home/kf77/usr/bin:/cs/home/kf77/usr/bin:/usr/local/maven/bin:/usr/local/amazon-corretto-17/bin:/usr/lib64/ccache:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/home/kf77/.dotnet/tools" VSLANG="1033" "cc" "-m64" "/tmp/rustcyP3VVJ/symbols.o" "/home/kf77/conjure-oxide/target/debug/deps/chuffed_rs-3916e90f286e3739.38o4ig1bt7kkyjdv.rcgu.o" "/home/kf77/conjure-oxide/target/debug/deps/chuffed_rs-3916e90f286e3739.3po8wt4hdebzumrt.rcgu.o" "/home/kf77/conjure-oxide/target/debug/deps/chuffed_rs-3916e90f286e3739.4jresi8mttp46v6o.rcgu.o" "/home/kf77/conjure-oxide/target/debug/deps/chuffed_rs-3916e90f286e3739.4jyq2iwe1v1mymye.rcgu.o" "/home/kf77/conjure-oxide/target/debug/deps/chuffed_rs-3916e90f286e3739.520za8226h1pu3p6.rcgu.o" "/home/kf77/conjure-oxide/target/debug/deps/chuffed_rs-3916e90f286e3739.5brh85kw9qop90tt.rcgu.o" "-Wl,--as-needed" "-L" "/home/kf77/conjure-oxide/target/debug/deps" "-L" "./solvers/chuffed/vendor/build/" "-L" "/home/kf77/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-Wl,-Bstatic" "/home/kf77/conjure-oxide/target/debug/deps/libchuffed_rs-d37182f69c381980.rlib" "/home/kf77/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-b850d2b001350814.rlib" "/home/kf77/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libpanic_unwind-a3d926e3ce38f6cc.rlib" "/home/kf77/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libobject-0a660adf51e0d01c.rlib" "/home/kf77/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libmemchr-49252de8bfa771e2.rlib" "/home/kf77/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libaddr2line-6f52a21444f37c70.rlib" "/home/kf77/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libgimli-57e8575f0ca731a2.rlib" "/home/kf77/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_demangle-da4065b9a8ae7be4.rlib" "/home/kf77/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd_detect-1ad47776352198ff.rlib" "/home/kf77/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libhashbrown-7075f8a8dc932a7c.rlib" "/home/kf77/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_std_workspace_alloc-a494eb4ddbb000f0.rlib" "/home/kf77/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libminiz_oxide-672778ed8628861b.rlib" "/home/kf77/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libadler-9bba1c59dcc21440.rlib" "/home/kf77/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libunwind-b9849fb628ce12eb.rlib" "/home/kf77/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcfg_if-0ea4fcc08eb96f77.rlib" "/home/kf77/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/liblibc-a8ba743c059cc198.rlib" "/home/kf77/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/liballoc-e4195ee2443e1656.rlib" "/home/kf77/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/librustc_std_workspace_core-04991604e2730fd6.rlib" "/home/kf77/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcore-f02db372677d4667.rlib" "/home/kf77/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib/libcompiler_builtins-448eba810c83029d.rlib" "-Wl,-Bdynamic" "-lstdc++" "-lgcc_s" "-lutil" "-lrt" "-lpthread" "-lm" "-ldl" "-lc" "-Wl,--eh-frame-hdr" "-Wl,-z,noexecstack" "-L" "/home/kf77/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/lib" "-o" "/home/kf77/conjure-oxide/target/debug/deps/chuffed_rs-3916e90f286e3739" "-Wl,--gc-sections" "-pie" "-Wl,-z,relro,-z,now" "-nodefaultlibs"
  = note: /usr/bin/ld: /home/kf77/conjure-oxide/target/debug/deps/libchuffed_rs-d37182f69c381980.rlib(modelling.cpp.o): relocation R_X86_64_32 against symbol `sat' can not be used when making a PIE object; recompile with -fPIE
          /usr/bin/ld: /home/kf77/conjure-oxide/target/debug/deps/libchuffed_rs-d37182f69c381980.rlib(bool-view.cpp.o): relocation R_X86_64_32 against `.LC4' can not be used when making a PIE object; recompile with -fPIE
          /usr/bin/ld: /home/kf77/conjure-oxide/target/debug/deps/libchuffed_rs-d37182f69c381980.rlib(sat.cpp.o): relocation R_X86_64_32 against `.LC3' can not be used when making a PIE object; recompile with -fPIE
          /usr/bin/ld: /home/kf77/conjure-oxide/target/debug/deps/libchuffed_rs-d37182f69c381980.rlib(conflict.cpp.o): relocation R_X86_64_32 against `.LC1' can not be used when making a PIE object; recompile with -fPIE
          /usr/bin/ld: /home/kf77/conjure-oxide/target/debug/deps/libchuffed_rs-d37182f69c381980.rlib(int-var.cpp.o): relocation R_X86_64_32S against `.rodata' can not be used when making a PIE object; recompile with -fPIE
          /usr/bin/ld: /home/kf77/conjure-oxide/target/debug/deps/libchuffed_rs-d37182f69c381980.rlib(int-var-el.cpp.o): relocation R_X86_64_32 against `.LC3' can not be used when making a PIE object; recompile with -fPIE
          /usr/bin/ld: /home/kf77/conjure-oxide/target/debug/deps/libchuffed_rs-d37182f69c381980.rlib(int-var-sl.cpp.o): relocation R_X86_64_32S against symbol `_ZN10Propagator6wakeupEii' can not be used when making a PIE object; recompile with -fPIE
          /usr/bin/ld: /home/kf77/conjure-oxide/target/debug/deps/libchuffed_rs-d37182f69c381980.rlib(int-var-ll.cpp.o): relocation R_X86_64_32 against `.LC0' can not be used when making a PIE object; recompile with -fPIE
          /usr/bin/ld: /home/kf77/conjure-oxide/target/debug/deps/libchuffed_rs-d37182f69c381980.rlib(ldsb.cpp.o): relocation R_X86_64_32 against symbol `sat' can not be used when making a PIE object; recompile with -fPIE

Choose a reason for hiding this comment

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

Hmmmm, that seems weird. I am not having any issues on my side. Let me clone your branch and try again.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For history's sake, this is due to the issues with AlmaLinux discussed here: #6 (comment)

@ozgurakgun
Copy link
Contributor

Are we able to add a simple CI test for this?

@Kieranoski702 Kieranoski702 mentioned this pull request Oct 3, 2023
4 tasks
@Kieranoski702
Copy link
Contributor Author

Are we able to add a simple CI test for this?

I'll add some CI tests ASAP but me, Nik and Yigit discovered some issues when building on the lab machines (AlmaLinux) that might have implications for CI tests.

This fork builds on Ubuntu, Arch and Mac but the lab machines seem to have issues linking libchuffed.a/libchuffed_fzn.a. Nik spun up a VM of AlmaLinux, installed cmake, build essentials, clang, rust, etc and encountered the same problem so it seems OS specific not specific to the lab machines specifically.

I was thinking of adding some CI build tests for Ubuntu, Arch, Mac as well as some others but wondered if you think it's a good idea to put effort into fixing the build issues on AlmaLinux or just accept that it builds on most platforms for now?

@niklasdewally
Copy link
Collaborator

niklasdewally commented Oct 3, 2023

For clarification, minion and other things build fine on alma, it is specifically chuffed.

@yigityazicilar
Copy link

After more research the Null Pointer way is how I believe that functions that take double pointers should be wrapped. Previously, I looked into MaybeUninit but that does not get used for its intended purpose after returning the mutable pointer using the .as_mut_ptr() function. When the pointer that is returned is initialized using the C++ function the .assume_init() function inside MaybeUninit returns random memory. I am still including the MaybeUninit version that does not use .assume_init() as a reference. Please let me know if you have any other ideas on how to correctly do this. @ChrisJefferson @ozgurakgun

Null Pointer way

// The signature of createVar is below for reference.
// createVar(x: *mut *mut IntVar, min: ::std::os::raw::c_int, max: ::std::os::raw::c_int, el: bool)
pub fn create_var(min: i32, max: i32, el: bool) -> Box<IntVar> {
    let mut ptr: *mut IntVar = ptr::null_mut();

    unsafe {
        createVar(&mut ptr, min, max, el);
        return Box::from_raw(ptr);
    }
}

MaybeUninit way

// The signature of createVar is below for reference.
// createVar(x: *mut *mut IntVar, min: ::std::os::raw::c_int, max: ::std::os::raw::c_int, el: bool)
pub fn create_var(min: i32, max: i32, el: bool) -> Box<IntVar> {
    let mut uninit: MaybeUninit<IntVar> = MaybeUninit::uninit();
    let mut ptr = uninit.as_mut_ptr();

    unsafe {
        createVar(&mut ptr, min, max, el);
        return Box::from_raw(ptr);
    }
}

@ChrisJefferson
Copy link
Contributor

Hi, replying on my phone as away from computer until Monday! Am happy to look more when I am back.

The null pointer feels more right in this case, as the C++ code is using the double pointer because what it actually wants is to give you its own pointer -- so it needs to take a pointer to pointer so it can change the inner pointer.

I'm not actually sure it is safe to the put that pointer in a Box, as that will, I believe, free the memory pointed to when the Box goes out of scope, but freeing memory allocated when creating C++ classes via a rust box might not work. It will certainly break in some situations, not sure about here. I would make a custom Var type and shove the pointer in there, just leak it for now (does chuffed even support freeing variables? Not sure)

@niklasdewally
Copy link
Collaborator

@Kieranoski702 @yigityazicilar I have moved the Alma issues into #9.

Also breaks on fedora, but with a different message?

niklasdewally

This comment was marked as duplicate.

Copy link
Collaborator

@niklasdewally niklasdewally left a comment

Choose a reason for hiding this comment

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

What about Cargo Test on CI?

Copy link
Collaborator

@niklasdewally niklasdewally left a comment

Choose a reason for hiding this comment

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

LGTM 🚀

@ozgurakgun ozgurakgun merged commit cda01a7 into conjure-cp:main Oct 4, 2023
3 checks passed
@ozgurakgun ozgurakgun mentioned this pull request Oct 4, 2023
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.

5 participants