FFI with dependencies in Racket? - raspberry-pi

I developed a very simple FFI for the Wiring PI library, to be able to control a Raspberry Pi using Racket.
This worked well, but only covers the base functionality. I wanted to extend this to also use the lcd.h from the libwiringPiDev.so, so that I could create an FFI to control an LCD.
Normally, when you compile a C file that uses the LCD, you tag both the standard library and the development library when compiling:
-lwiringPi -lwiringPiDev
In my LCD FFI I did the following:
(define-ffi-definer define-lcd
(ffi-lib "usr/lib/libwiringPiDev.so"))
However, when I try to require that racket file, I run into:
; ffi-lib: couldn't open "/usr/lib/libwiringPiDev.so"
; (/usr/lib/libwiringPiDev.so: undefined symbol: digitalRead) [,bt for
; context]
The digitalRead function exists in the base library but not in the dev library...how do I do a "FFI with dependencies" so that Racket can properly manage both libraries to be able to find the necessary symbols?

Try loading libwiringPi.so first in global mode, then load libwiringPiDev.so:
(define-ffi-definer define-lcd
(ffi-lib "/usr/lib/libwiringPi.so" #:global? #t))
(define-ffi-definer define-lcd-dev
(ffi-lib "/usr/lib/libwiringPiDev.so"))
The #:global? #t argument corresponds to setting the RTLD_GLOBAL flag in the call to dlopen, and the man page for dlopen (on my Linux system) says
RTLD_GLOBAL
The symbols defined by this shared object will be made available
for symbol resolution of subsequently loaded shared objects.

Related

Providing struct constructor from library

I'm currently working on extending racklog, which is a library I installed by running raco pkg install in the repo directory.
I'm trying to provide a new function, namely a struct constructor. Currently, I'm defining the struct as follows in racklog.rkt. I then provide it from that file.
; racklog.rkt
(struct my-struct (value))
(provide my-struct)
The main file of the library just provides everything from this file:
; main.rkt
(require "racklog.rkt")
(provide (all-from-out "racklog.rkt"))
However, when I try to use the provided constructor (which should be named my-struct) in a file requiring this module, it says that the id isn't found. In particular, I'm trying:
; test.rkt
(require racklog)
my-struct
This also happens even with non-struct things such as defined variables, functions, etc. All the other provided forms seem to be working fine. What's the way I can fix this so I can use the provided constructor? Thanks!
This is an unfortunate stale compiled file issue. Try raco setup --pkgs racklog to compile racklog and run your program again. It should now work. Alternatively, you can manually delete the compiled directories.

Unable to set up Certified Programming with Dependent Types

I am working with the book Certified Programming with Dependent Types but each time I'm finding a different error. It seems to me that the error comes from a mismatch between the compilation process from Proof General and through the makefile of the sources of the book.
If I compile the sources with make and try to run for instance Subset.v in Proof-General I get:
Error: File /home/usuario/Desktop/Coq/cpdt/src/CpdtTactics.vo has
bad magic number 81100 (expected 8600). It is corrupted or was
compiled with another version of Coq.
If I clean the makefile compiled files with make clean and try to proceed with the option Coq -> Auto Compilation -> Compile before require then it is the line:
Require Extraction.
that fails. Originally it failed with the error:
Error: Unable to locate library Extraction.
but with the above option enables it gives something like:
echo "Require Extraction." > /tmp/ProofGeneral-coqQPJTf0.v coqdep -Q /home/usuario/Desktop/Coq/cpdt/src/ -R /home/usuario/Desktop/Coq/cpdt/src Cpdt /tmp/ProofGeneral-coqQPJTf0.v
* Warning: in file /tmp/ProofGeneral-coqQPJTf0.v, library Extraction is required and has not been found in the loadpath!
* Warning: in file /tmp/ProofGeneral-coqQPJTf0.v, library Extraction is required and has not been found in the loadpath!
/tmp/ProofGeneral-coqQPJTf0.vo /tmp/ProofGeneral-coqQPJTf0.glob /tmp/ProofGeneral-coqQPJTf0.v.beautified: /tmp/ProofGeneral-coqQPJTf0.v
/tmp/ProofGeneral-coqQPJTf0.vio: /tmp/ProofGeneral-coqQPJTf0.v
How can I solve this?
Side-questions: which OS are you using? do you rely on opam?
Regarding the first error you get, it certainly comes from the following fact:
outside proofgeneral, the coqc binary corresponds to Coq 8.11, while in ProofGeneral, the coqtop binary correspond to Coq 8.6. Maybe because the PATH variable is not the same in the two contexts.
To figure out which binary is found, you can do in the terminal which coqtop, and within Emacs, M-! which coqtop RET and you should thus get different paths.
Sometimes, opening emacs directly from the terminal (emacs &) can help for this kind of issue.
But if you want to change the coqtop binary that is used in ProofGeneral, you can set the coq-prog-name option, by using one of the following steps:
Interactively, type C-u C-c C-x (to kill Coq), M-: (setq coq-prog-name "…/coqtop"), and C-c C-n
Or create a .dir-locals.el file (Emacs' standard conf-file) in the project root containing:
((coq-mode . ((coq-prog-name . "…/coqtop"))))
and close/reopen the ….v file at stake (or just do M-x normal-mode RET or C-x C-v RET in the already-opened ….v buffer)
Regarding the second error you get, I'm a bit puzzled that Require Extraction triggers this error, as this library does exist in Coq 8.6 and 8.11.
At first sight, I'd suggest to re-test the auto-compilation with Coq 8.11, asserting From Coq Require Extraction. (instead of just Require Extraction.)
But maybe there is a bug in PG's Auto Compilation -> Compile before require feature; anyway feel free to open a related issue in the PG tracker if need be, bug reports and feature requests are very welcome: https://github.com/ProofGeneral/PG/issues

Can't set up qtools in common-lisp SBCL

I'm a beginner in lisp and I'm unable to find out how to correctly use defpackage to load qtools (on arch linux).
For simplicity if I run this example project in sbcl with loaded quicklisp
https://github.com/Shinmera/qtools/tree/master/examples/helloworld
this error appears
While evaluating the form starting at line 8, column 0
of #P"/home/william/code/upol/lisp/helloworld/helloworld.lisp":
debugger invoked on a PACKAGE-DOES-NOT-EXIST in thread
#<THREAD "main thread" RUNNING {1000508083}>:
The name "CL+QT" does not designate any package.
Why "cl+qt" is not provided by any of installed packages with quickload?
Here is a list of installed packages
$ ls ~/.quicklisp/dists/quicklisp/software
Thanks for help
My resources:
https://github.com/Shinmera/qtools
https://lispcookbook.github.io/cl-cookbook/getting-started.html
Let's look at the example. The order of actions is:
compile the .asd file (for example, with C-c C-k). This creates the qtools-helloworld system.
load "qtools-helloworld" and its dependencies with Quicklisp: (ql:quickload :qtools-helloworld).
compile helloworld.lisp (again, with C-c C-k), and call its functions.
Also, look at Qtools readme: https://github.com/Shinmera/qtools#qtools-1 It says to install these 3 libraries:
(ql:quickload '(qtools qtcore qtgui))
The cl+qt package is provided by one of these systems.
update: the steps required to run the helloworld from the command line are:
load the asd definition: rlwrap sbcl --load qtools-helloworld.asd. (rlwrap is just a readline utility)
you are dropped into the Lisp REPL. Now we install the dependencies with Quicklisp, that you must have installed first. You type this into the Lisp REPL: (ql:quickload :qtools-helloworld). That is the name defined in the asd.
now you can compile the .lisp file: (load "helloworld.lisp):
* (ql:quickload :qtools-helloworld)
To load "qtools-helloworld":
Load 1 ASDF system:
qtools-helloworld
; Loading "qtools-helloworld"
[package qtools-helloworld]....
(:QTOOLS-HELLOWORLD)
it didn't show a GUI. We'll call the main function:
(qtools-helloworld::main)
and you should see the example. If you make changes to the lisp file you can load it again. This use of the REPL in the terminal works but is not as interactive as Lisp can be (far from it). You want your editor to be connected to the REPL and send changes automatically, with a keystroke.
Check out the Cookbook, editors section, Atom support is very good with SLIMA.
ps: I find Qtools a little bit difficult, passed running the provided examples. It is not as easily discoverable as other GUIs (like Ltk or IUP). Hope you'll prove me wrong though.
pps: also https://lispcookbook.github.io/cl-cookbook/gui.html#qt4
You need to install the qtools system.
A system is a way to organize software libraries
A package is a namespace
The two are theoretically unrelated. But often, when you load a system X, it defines a package named X.
In some cases (like qtools) there are many packages for one system, for example because the system wants to define different levels of API.
Another way to define multiple packages when loading one system comes from the fact that ASDF version 3.1 supports an extension copied from other build systems named package-inferred-systems, where each source file is implicitly mapped to one system and one package.
Here is a snippet of what Quicklisp shows when installing qtools:
* (ql:quickload :qtools)
To load "qtools":
Load 14 ASDF systems:
array-utils asdf bordeaux-threads cffi cl-ppcre
closer-mop dissect documentation-utils form-fiddle
named-readtables qt+libs trivial-features
trivial-garbage trivial-indent
... ... ...
To load "qtools":
Load 1 ASDF system:
qtools
; Loading "qtools"
[package uiop/package]............................
..................................................
[package cffi-sys]................................
[package cffi]....................................
..................................................
[package cffi-features]...........................
[package qt-libs].................................
[package qt]......................................
..................................................
[package deploy]..................................
[package dissect].................................
[package simple-tasks]............................
[package trivial-main-thread].....................
[package qtools]..................................
[package cl+qt]...................................
.............................
(:QTOOLS)
Quicklisp is able to intercept and print new packages when they are defined. Here above we can see that there are multiple packages defined while loading quicklisp, either (1) packages defined by the dependencies of qtools, or (2) packages defined by qtools itself. Here both qtools and cl+qt are packages defined by the qtools system.
Packages are not declared in systems, so you need to rely on documentation to know what packages a system defines.

How can I use an older version of package gregor?

Here's how to simulate it.
$ cat t1.rkt
#lang racket/base
(require gregor)
(display "hello")
I'm running Racket 6.12. But the same happens to Racket 7.2.
$ racket t1.rkt
explode-path: contract violation
expected: (or/c path-for-some-system? path-string?)
given: #f
context...:
/usr/share/racket/collects/racket/path.rkt:116:0: do-explode-path
/usr/share/racket/collects/racket/path.rkt:126:0: find-relative-path7
/home/me/.racket/6.12/pkgs/tzinfo/tzinfo/private/zoneinfo.rkt:118:2: for-loop
/home/me/.racket/6.12/pkgs/tzinfo/tzinfo/private/zoneinfo.rkt:108:0: read-tzids
/home/me/.racket/6.12/pkgs/tzinfo/tzinfo/private/zoneinfo.rkt:71:0: make-zoneinfo-source
/usr/share/racket/collects/racket/contract/private/arrow-val-first.rkt:388:18
/home/me/.racket/6.12/pkgs/tzinfo/tzinfo/main.rkt:63:0: system-tzid
/usr/share/racket/collects/racket/contract/private/arrow-val-first.rkt:388:18
/home/me/.racket/6.12/pkgs/gregor-lib/gregor/private/moment.rkt: [running body]
/home/me/.racket/6.12/pkgs/gregor-lib/gregor/private/generics.rkt: [traversing imports]
/home/me/.racket/6.12/pkgs/gregor-lib/gregor/private/clock.rkt: [traversing imports]
/home/me/.racket/6.12/pkgs/gregor-lib/gregor/main.rkt: [traversing imports]
/home/me/issue-gregor/t1.rkt: [traversing imports]
$ racket --version
Welcome to Racket v6.12.
How could I go back to an older version of gregor? I installed it this one with raco pkg install gregor and installed all its dependencies.
I'm the author of Gregor. (I don't normally post on Stack Overflow, or even use it much, but John Clements brought this to my attention.)
There's a bit of an unfortunate naming issue here, since tzdata appears to be the name of an Ubuntu package that provides the normal zoneinfo files, as well as being the name of a Racket package that also provides those files.
gregor depends on a package called tzinfo. tzinfo, in turn, conditionally depends on tzdata (the Racket one, not the Ubuntu one). Specifically, it only depends on tzdata on Windows systems. This is because I assumed that all Unix systems would have the zoneinfo files. (It never occurred to be that anyone would run a Unix without them these days.) But it is certainly the case that tzinfo (and thus gregor) will not work unless it can find zoneinfo files.
Maybe I should update the documentation with a conspicuous warning. I'd rather not make tzinfo unconditionally depend on tzdata (again, the Racket one), because most Unix systems will already have the necessary files, and it could be unduly confusing for gregor to use a version of them different from the one the system is using.

How to create a GTK plugin (cmxs) for my OCaml program

I'd like to make a GTK plugin for my OCaml application, loaded using Dynlink. How can I get ocamlbuild to include the lablgtk2 library in the generated plugin?
As a test, I have main.ml:
let () =
try
Dynlink.loadfile "_build/gtk_plugin.cmxs"
with Dynlink.Error err ->
failwith (Dynlink.error_message err)
gtk_plugin.ml:
let () =
print_endline "GTK plugin loaded!";
GMain.Main.main ()
_tags:
<main.*>: package(dynlink)
<gtk_plugin.*>: package(lablgtk2)
But I get:
$ ocamlbuild -use-ocamlfind main.native gtk_plugin.cmxs
$ ./main.native
Fatal error: exception Failure("error loading shared library:
.../_build/gtk_plugin.cmxs: undefined symbol: camlGtkMain")
Note: the main binary must not depend on libgtk (which might not be installed on the target system) - if the plugin fails to load I want to fall back to console mode.
You need to
add the linkall flag to main, otherwise it will remove parts of the OCaml runtime that will later be needed by dynamic plugins
compile the gtk_plugin.cmxs file with option -lflag lablgtk.cma (which I deduced from seeing in the _log that this option was not passed)
The way ocamlbuild deduces .cmxs dependencies is not optimal right now, and it's hard because different users may want different things (minimal plugins assuming libs are present, or on the contrary portable statically linked stuff). For modules coming from your project you can write a foo.mldylib file to be explicit about what you want excluded, but I don't know whether it's possible to include "all modules of this external library".
Note that it is also possible to distribute lablgtk.cmxs and the relevant .cmi along with your plugin, and load it dynamically first.
mkdir lablgtk
cp `ocamlfind query lablgtk2`/lablgtk.cmxs lablgtk
cp `ocamlfind query lablgtk2`/*.cmi lablgtk
echo "\"lablgtk\": not_hygienic" >> _tags
then in your main.ml
let () =
try
Dynlink.loadfile "lablgtk/lablgtk.cmxs";
Dynlink.loadfile "_build/gtk_plugin.cmxs"
...