Building against libcxxwrap-julia require definition of comparison operators between incompatible types
I am building a Julia interface to dace using libcxxwrap-julia and CxxWrap, and I recently came across a compilation error that requires me to define the "less than" operator between types for which is not defined, i.e. DACE::DA and DACE::AlgebraicMatrix<DACE::DA>.
Here is the output I obtain when trying to build the wrapper on Ubuntu 22.04 LTS: build.log config.log
I started obtaining this error after defining the comparison operators ==,!=,<,>,<=,>= between DACE::DA objects and double in interfaces/cxx/include/dace/DA.h
friend inline bool DACE_API operator==(const DA &da1, const DA &da2) { return da1.cons() == da2.cons(); }; //!< Equality comparison
friend inline bool DACE_API operator==(const DA &da, const double c) { return da.cons() == c; }; //!< Equality comparison
friend inline bool DACE_API operator==(const double c, const DA &da) { return c == da.cons(); }; //!< Equality comparison
friend inline bool DACE_API operator!=(const DA &da1, const DA &da2) { return da1.cons() != da2.cons(); }; //!< Inequality comparison
friend inline bool DACE_API operator!=(const DA &da, const double c) { return da.cons() != c; }; //!< Inequality comparison
friend inline bool DACE_API operator!=(const double c, const DA &da) { return c != da.cons(); }; //!< Inequality comparison
friend inline bool DACE_API operator<(const DA &da1, const DA &da2) { return da1.cons() < da2.cons(); }; //!< Less than comparison
friend inline bool DACE_API operator<(const DA &da, const double c) { return da.cons() < c; }; //!< Less than comparison
friend inline bool DACE_API operator<(const double c, const DA &da) { return c < da.cons(); }; //!< Less than comparison
friend inline bool DACE_API operator>(const DA &da1, const DA &da2) { return da1.cons() > da2.cons(); }; //!< Greater than comparison
friend inline bool DACE_API operator>(const DA &da, const double c) { return da.cons() > c; }; //!< Greater than comparison
friend inline bool DACE_API operator>(const double c, const DA &da) { return c > da.cons(); }; //!< Greater than comparison
friend inline bool DACE_API operator<=(const DA &da1, const DA &da2) { return da1.cons() <= da2.cons(); }; //!< Less than or equal comparison
friend inline bool DACE_API operator<=(const DA &da, const double c) { return da.cons() <= c; }; //!< Less than or equal comparison
friend inline bool DACE_API operator<=(const double c, const DA &da) { return c <= da.cons(); }; //!< Less than or equal comparison
friend inline bool DACE_API operator>=(const DA &da1, const DA &da2) { return da1.cons() >= da2.cons(); }; //!< Greater than or equal comparison
friend inline bool DACE_API operator>=(const DA &da, const double c) { return da.cons() >= c; }; //!< Greater than or equal comparison
friend inline bool DACE_API operator>=(const double c, const DA &da) { return c >= da.cons(); }; //!< Greater than or equal comparison
I am also able to overcome it by adding these dummy definitions at the top of the interface interfaces/julia/dace_julia.cxx
namespace DACE {
inline bool DACE_API operator<(const AlgebraicMatrix<DA> &mat, const DA &da) { throw std::runtime_error("Comparison between DA and AlgebraicMatrix not defined"); };
inline bool DACE_API operator<(const DA &da, const AlgebraicMatrix<DA> &mat) { throw std::runtime_error("Comparison between DA and AlgebraicMatrix not defined"); };
inline bool DACE_API operator<(const AlgebraicMatrix<DA> &mt1, const AlgebraicMatrix<DA> &mt2) { throw std::runtime_error("Comparison between two AlgebraicMatrix not defined"); };
}
but this is really a workaround that shouldn't be there.
More surprisingly, I do not encounter the same error with DACE::AlgebraicVector<DA>, which is wrapped pretty much in the same way as DACE::AlgebraicMatrix<DA> is. Building the library without the Julia wrapper bits also works, so it is really a matter of how it interacts with libcxxwrap-julia.
Do you have any insight on the root cause of this error? Thanks!
Is this against the latest libcxxwrap-julia (main branch)? It is probably related to the added support for more STL containters, maybe this check isn't working:
https://github.com/JuliaInterop/libcxxwrap-julia/blob/587f9feb6b64baa512856af2d508fec1f63583bc/include/jlcxx/stl.hpp#L657
It happens both against main and against the latest release v0.13.2. But yes, it seems related to the instantiation of STL containers. The logs I attached are actually against the latest release and not main.
OK, if you don't need sets or maps then you can comment out these lines in apply_stl as a temporary workaround. I was already working on refactoring this part of the code, so only the part of the STL that is requested gets wrapped, i.e. if you use a std::vector with your type, only vector will be wrapped and not all supported containers.
Thank you for the hint!
I did a couple of other tests, and it seems that the check you mentioned before does work in most of the cases, but it gets "confused" when the type to which the STL is applied is itself a kind of "container". What I have observed is the following:
I have my wrapped type DA on which I explicitly apply the STL, i.e.:
jlcxx::stl::apply_stl<DA>(mod)
Then I have the parametric type AlgebraicMatrix<T> which is defined for T being a DA or a double as:
mod.add_type<jlcxx::Parametric<jlcxx::TypeVar<1>>>("AlgebraicMatrix", jlcxx::julia_type("AbstractMatrix", "Base"))
.apply<AlgebraicMatrix<DA>, AlgebraicMatrix<double>>([](auto wrapped) {
...
});
The type DA is used several times as the element type of std::vectors, while AlgebraicMatrix<T> is used as element of an STL container (a vector) only once:
mod.method("hessian", [](const AlgebraicVector<DA>& vec)->std::vector<AlgebraicMatrix<DA>> { return vec.hessian(); });
Moreover, the DA type defines the "less than" and the other comparison operators between DAs, and between a DA and a double.
To get a compiler error, I need both the hessian() method being wrapped, AND the comparison operators being defined for DAs. If I remove either one of the two, the wrapper is compiled just fine, and I can call it from Julia.
Can you verify if PR #175 fixes this for you?
I recompiled the library from your branch test-compile-times, and I can confirm that it fixes my issue.
I can now define hessian() as in my previous comment, and have it return a std::vector<AlgebraicMatrix<DA>> without problems.
Tested on both Ubuntu 22.04 (gcc) and MacOS Sonoma (Apple Clang, Intel chip)
Thanks!
Thanks for testing, I'll integrate this into a new release. Unfortunately the changes are not binary compatible with previous versions, so this will become part of CxxWrap 0.17.