cl-cxx icon indicating copy to clipboard operation
cl-cxx copied to clipboard

README Improvements

Open Symbolics opened this issue 5 years ago • 11 comments

I found this in my search for common lisp CFFI bindings to Boost mathematical libraries. On the surface this seems related, but I can't be sure. Perhaps a bit more explanation in the README, and a note about how this would be used for a binding?

Symbolics avatar Oct 27 '19 08:10 Symbolics

@Symbolics I think this is what you need: cl-cxx-eigen

You can use the same way to add boost functions.

Sorry for the late response as I was traveling for 2 months.

Islam0mar avatar Dec 27 '19 08:12 Islam0mar

This looks like it has a lot of potential. Is this an experiment or proof of concept, or have you been able to use it to wrap a large library. On the surface it seems to solve a lot of the problems encountered in wrapping lisp, as many libraries seem to be written exclusively in C++ these days.

Symbolics avatar Feb 03 '20 17:02 Symbolics

I think it has no problem to wrap large library such as eigen lib.

#include <clcxx/clcxx.hpp>
#include <string>
#include "clcxx_eigen.hpp"

CLCXX_PACKAGE EIGEN(clcxx::Package& pack) {
  using EigenMat = EigenMatWrapper<Eigen::MatrixXd, double>;

  pack.defclass<EigenMat, true>("Matrix")
      .constructor<Eigen::Index, Eigen::Index>()
      .defmethod("m.resize",
                 static_cast<void (EigenMat::*)(Eigen::Index, Eigen::Index)>(
                     &EigenMat::resize))
      .defmethod("m.block", &EigenMat::getBlock)
      .defmethod("m.row", &EigenMat::getRow)
      .defmethod("m.col", &EigenMat::getCol)
      .defmethod("m.size", &EigenMat::size)
      .defmethod("m.rows", &EigenMat::rows)
      .defmethod("m.cols", &EigenMat::cols)
      .defmethod("m.get-at-index", &EigenMat::get)
      .defmethod(
          "m.set-at-index",
          static_cast<void (EigenMat::*)(Eigen::Index, Eigen::Index, double)>(
              &EigenMat::set))
      .defmethod(
          "m.set-matrix",
          static_cast<void (EigenMat::*)(const EigenMat&)>(&EigenMat::set))
      .defmethod("m.set-zero", &EigenMat::set0)
      .defmethod("m.set-ones", &EigenMat::set1)
      .defmethod("m.set-identity", &EigenMat::setId)
      .defmethod("%m.set-from-array", &EigenMat::setFromArray)
      .defmethod("m.trace", &EigenMat::trace)
      .defmethod("m.sum", &EigenMat::sum)
      .defmethod("m.prod", &EigenMat::prod)
      .defmethod("m.mean", &EigenMat::mean)
      .defmethod("m.norm", &EigenMat::norm)
      .defmethod("m.squared-norm", &EigenMat::squaredNorm)
      .defmethod("m.print", &EigenMat::print)
      .defmethod("m.scale", &EigenMat::scale)
      .defmethod("m.add-scalar",
                 static_cast<void (EigenMat::*)(const double&)>(&EigenMat::add))
      .defmethod("m.add-mat", static_cast<void (EigenMat::*)(const EigenMat&)>(
                                  &EigenMat::add))
      .defmethod("m.multiply", &EigenMat::multiply)
      .defmethod("m.inverse", &EigenMat::inv)
      .defmethod("m.full-inverse", &EigenMat::mInv)
      .defmethod("m.transpose", &EigenMat::trans)
      .defmethod("m.determinant", &EigenMat::det)
      .defmethod("m.full-determinant", &EigenMat::mDet)
      .defmethod("m.rank", &EigenMat::rankLU)
      .defmethod("m.full-q", &EigenMat::mQ)
      .defmethod("m.full-p", &EigenMat::mP)
      .defmethod("m.p", &EigenMat::squareMP)
      .defmethod("m.l", &EigenMat::squareML)
      .defmethod("m.u", &EigenMat::squareMU)
      .defmethod("m.lower-Cholesky", &EigenMat::mLCholesky)
      .defmethod("m.upper-Cholesky", &EigenMat::mUCholesky)
      .defmethod("m.eigen-values", &EigenMat::eigenVals)
      .defmethod("m.full-solve", &EigenMat::solveLU)
      .defmethod("m.solve", &EigenMat::solveSquareLU)
      .defmethod("m.solve-Cholesky", &EigenMat::solveCholesky)
      .defmethod("m.full-lower", &EigenMat::mU)
      .defmethod("m.full-upper", &EigenMat::mL);

  pack.defun("m*", [](const EigenMat& x, const EigenMat& y) -> EigenMat {
    return static_cast<EigenMat>(x * y);
  });
  pack.defun("m+", [](const EigenMat& x, const EigenMat& y) -> EigenMat {
    return static_cast<EigenMat>(x + y);
  });
}

eigen

for my work it was acceptable.

Try to wrap your large library.

Islam0mar avatar Feb 03 '20 22:02 Islam0mar

Pull request #4 will also bring in some documentation improvements, though I think more documentation is required than I have knowledge to write.

Symbolics avatar Feb 06 '20 20:02 Symbolics

Could you specify the documentation parts that would be added?

Islam0mar avatar Feb 18 '20 12:02 Islam0mar

I would suggest a few sections:

Introduction - Explain where the concepts were taken from, (Julia), high level description of how it works. limitation Architecture - Block diagram, sequence diagrams for the calls from Lisp to C++ Examples - 2 or 3 end to end examples, with extensive documentation Future Direction - What is planned next, if anything. E.g. Auto-wrap style wrapping so you can point to a header. Roadmap for the C++ features that are missing. Help Wanted - what can contributors help with, by skill level.

cl-cuda and cl-autowrap have pretty good documentation and would be useful as a guide.

You might also consider contacting rpav to see if this could somehow be folded into cl-autowrap.

Symbolics avatar Feb 19 '20 08:02 Symbolics

The example of cl-cxx doesn't show how to instantiate classes, set slots and use class methods. Could you specify how this is done? I need this for a port to link and it'd be amazing if I could get it working (the lib already compiles...)!

The following code doesn't work here after loading the compiled lib from the example into lisp:

(cxx:add-package "TEST" "TEST") ;;; ok so far

(defparameter *test* (make-instance 'test::xx)) ;;; ok, but the CXX-CLASS-PTR slot of *test* is NIL

(setf (slot-value *test* 'test::y 32)) ;;; works

(test::foo *test*) ;;; doesn't work:
-> The value
  NIL
is not of type
  SB-SYS:SYSTEM-AREA-POINTER
when binding SB-ALIEN::VALUE

ormf avatar Feb 05 '23 18:02 ormf

To load a C++ class you have to call it's constructor function that is exposed from C++pack.defclass<xx, false>("xx").constructor<int, int>(), so in this example it would be called test:create-xx2 -> (test:create-xx2 1 3).

Now (make-instance 'test::xx) should give you an error message to call c++ constructor function.

Islam0mar avatar Feb 06 '23 18:02 Islam0mar

I forked your repository, created a new branch "documentation-added", added an extensive README and a working full example. I'm going to add more examples in scratch.lisp but basically it should be done. Before issuing a merge request I'd like to get your opinion, suggestions, etc.

I added the README in a new doc folder. It's completely rewritten according to the suggestions of @Symbolics . Feel free to merge with your own README, replace it or leave it in the doc folder, pointing to it or whatever. Hope you like it. It's my attempt at thanking you for your help and work, expecially in the recent week!!!

ormf avatar Feb 12 '23 11:02 ormf

Thanks a bunch. looks great.

Islam0mar avatar Feb 12 '23 18:02 Islam0mar

@ormf Could you please open a PR from your fork?

Islam0mar avatar Jul 18 '23 19:07 Islam0mar