1
0
Fork 0
cl-sites/lispcookbook.github.io/cl-cookbook/ffi.html

206 lines
8.1 KiB
HTML
Raw Normal View History

2023-10-25 11:23:21 +02:00
<!DOCTYPE html>
<html lang="en">
<head>
<meta name="generator" content=
"HTML Tidy for HTML5 for Linux version 5.2.0">
<title>Foreign Function Interfaces</title>
<meta charset="utf-8">
<meta name="description" content="A collection of examples of using Common Lisp">
<meta name="viewport" content=
"width=device-width, initial-scale=1">
<link rel="icon" href=
"assets/cl-logo-blue.png"/>
<link rel="stylesheet" href=
"assets/style.css">
<script type="text/javascript" src=
"assets/highlight-lisp.js">
</script>
<script type="text/javascript" src=
"assets/jquery-3.2.1.min.js">
</script>
<script type="text/javascript" src=
"assets/jquery.toc/jquery.toc.min.js">
</script>
<script type="text/javascript" src=
"assets/toggle-toc.js">
</script>
<link rel="stylesheet" href=
"assets/github.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<h1 id="title-xs"><a href="index.html">The Common Lisp Cookbook</a> &ndash; Foreign Function Interfaces</h1>
<div id="logo-container">
<a href="index.html">
<img id="logo" src="assets/cl-logo-blue.png"/>
</a>
<div id="searchform-container">
<form onsubmit="duckSearch()" action="javascript:void(0)">
<input id="searchField" type="text" value="" placeholder="Search...">
</form>
</div>
<div id="toc-container" class="toc-close">
<div id="toc-title">Table of Contents</div>
<ul id="toc" class="list-unstyled"></ul>
</div>
</div>
<div id="content-container">
<h1 id="title-non-xs"><a href="index.html">The Common Lisp Cookbook</a> &ndash; Foreign Function Interfaces</h1>
<!-- Announcement we can keep for 1 month or more. I remove it and re-add it from time to time. -->
2024-05-15 18:18:38 +02:00
<!-- <p class="announce"> -->
<!-- 📢 🤶 ⭐ -->
<!-- <a style="font-size: 120%" href="https://www.udemy.com/course/common-lisp-programming/?couponCode=LISPY-XMAS2023" title="This course is under a paywall on the Udemy platform. Several videos are freely available so you can judge before diving in. vindarel is (I am) the main contributor to this Cookbook."> Discover our contributor's Lisp course with this Christmas coupon.</a> -->
<!-- <strong> -->
<!-- Recently added: 18 videos on MACROS. -->
<!-- </strong> -->
<!-- <a style="font-size: 90%" href="https://github.com/vindarel/common-lisp-course-in-videos/">Learn more</a>. -->
<!-- </p> -->
<p class="announce">
📢 New videos: <a href="https://www.youtube.com/watch?v=h_noB1sI_e8">web dev demo part 1</a>, <a href="https://www.youtube.com/watch?v=xnwc7irnc8k">dynamic page with HTMX</a>, <a href="https://www.youtube.com/watch?v=Zpn86AQRVN8">Weblocks demo</a>
</p>
2023-10-25 11:23:21 +02:00
<p class="announce-neutral">
📕 <a href="index.html#download-in-epub">Get the EPUB and PDF</a>
</p>
<div id="content"
2024-05-15 18:18:38 +02:00
<p>The ANSI Common Lisp standard doesnt mention this topic. So almost everything that can be said here depends on your OS and your implementation. However these days, we can use the <a href="https://github.com/cffi/cffi">CFFI</a> library, a portable and easy-to-use C foreign function interface.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<blockquote>
<p>CFFI, the Common Foreign Function Interface, purports to be a portable FFI for Common Lisp. It abstracts away the differences between the API of the native FFIs of the various Common Lisp implementations.</p>
</blockquote>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>Well see an example right now.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<h2 id="cffi-calling-a-c-function-from-the-mathh-header-file">CFFI: calling a C function from the <code>math.h</code> header file.</h2>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>Lets use <code>defcfun</code> to interface with the foreign <a href="https://en.cppreference.com/w/c/numeric/math/ceil">ceil</a> C function from <code>math.h</code>.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p><a href="https://cffi.common-lisp.dev/manual/html_node/defcfun.html">defcfun</a> is a macro in the cffi library that generates a function with the name you give it.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<pre><code class="language-lisp">CL-USER&gt; (cffi:defcfund ("ceil" c-ceil) :double (number :double))
2023-10-25 11:23:21 +02:00
</code></pre>
2024-05-15 18:18:38 +02:00
<p>We say that the “ceil” C function will be called “c-ceil” on our Lisp side, it takes one argument that is a double float, and it returns a number that is also a double float.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>Here is the above function macroexpanded with <code>macrostep-expand</code>:</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<pre><code class="language-lisp">(progn
nil
(defun c-ceil (number)
(let ((#:g312 number))
(cffi-sys:%foreign-funcall "ceil" (:double #:g312 :double) :convention
:cdecl :library :default))))
2023-10-25 11:23:21 +02:00
</code></pre>
2024-05-15 18:18:38 +02:00
<p>The reason we called it <code>c-ceil</code> and not <code>ceil</code> is only for the example, so we know this is a wrapper around C. You can name it “ceil”, since it doesnt designate a built-in Common Lisp function or macro.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>Now that we have a c-ceil function from <code>math.h</code>, lets use it! We must give it double float.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<pre><code class="language-lisp">CL-USER&gt; (c-ceil 5.4d0)
6.0d0
2023-10-25 11:23:21 +02:00
</code></pre>
2024-05-15 18:18:38 +02:00
<p>As you can see, it works! The double gets rounded up to <code>6.0d0</code> as expected.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<p>Lets try another one! This time, well use <a href="https://en.cppreference.com/w/c/numeric/math/floor">floor</a>, and we couldnt name it “floor” because this Common Lisp function exists.</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<pre><code class="language-lisp">CL-USER&gt; (cffi:defcfun ("floor" c-floor) :double (number :double))
C-FLOOR
CL-USER&gt; (c-floor 5d0)
5.0d0
CL-USER&gt; (c-floor 5.4d0)
5.0d0
2023-10-25 11:23:21 +02:00
</code></pre>
2024-05-15 18:18:38 +02:00
<p>Great!</p>
<p>One more, lets try <code>sqrt</code> from math.h, still with double floats:</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<pre><code class="language-lisp">CL-USER&gt; (cffi:defcfun ("sqrt" c-sqrt) :double (number :double))
C-SQRT
CL-USER&gt; (c-sqrt 36.50d0)
6.041522986797286d0
2023-10-25 11:23:21 +02:00
</code></pre>
2024-05-15 18:18:38 +02:00
<p>We can do arithmetic with our new <code>c-sqrt</code>:</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<pre><code class="language-lisp">CL-USER&gt; (+ 2 (c-sqrt 3d0))
3.732050807568877d0
2023-10-25 11:23:21 +02:00
</code></pre>
2024-05-15 18:18:38 +02:00
<p>We can even use our new shiny <code>c-sqrt</code> to map over a list of doubles and take the square root of all of them!</p>
2023-10-25 11:23:21 +02:00
2024-05-15 18:18:38 +02:00
<pre><code class="language-lisp">CL-USER&gt; (mapcar #'c-sqrt '(3d0 4d0 5d0 6d0 7.5d0 12.75d0))
(1.7320508075688772d0 2.0d0 2.23606797749979d0 2.449489742783178d0
2.7386127875258306d0 3.570714214271425d0)
2023-10-25 11:23:21 +02:00
</code></pre>
<p class="page-source">
Page source: <a href="https://github.com/LispCookbook/cl-cookbook/blob/master/ffi.md">ffi.md</a>
</p>
</div>
<script type="text/javascript">
// Don't write the TOC on the index.
if (window.location.pathname != "/cl-cookbook/") {
$("#toc").toc({
content: "#content", // will ignore the first h1 with the site+page title.
headings: "h1,h2,h3,h4"});
}
$("#two-cols + ul").css({
"column-count": "2",
});
$("#contributors + ul").css({
"column-count": "4",
});
</script>
<div>
<footer class="footer">
<hr/>
&copy; 2002&ndash;2023 the Common Lisp Cookbook Project
<div>
2024-05-15 18:18:38 +02:00
📹 Discover <a style="color: darkgrey; text-decoration: underline", href="https://www.udemy.com/course/common-lisp-programming/?referralCode=2F3D698BBC4326F94358">our contributor's Common Lisp video course on Udemy</a>
2023-10-25 11:23:21 +02:00
</div>
</footer>
</div>
<div id="toc-btn">T<br>O<br>C</div>
</div>
<script text="javascript">
HighlightLisp.highlight_auto({className: null});
</script>
<script type="text/javascript">
function duckSearch() {
var searchField = document.getElementById("searchField");
if (searchField && searchField.value) {
var query = escape("site:lispcookbook.github.io/cl-cookbook/ " + searchField.value);
window.location.href = "https://duckduckgo.com/?kj=b2&kf=-1&ko=1&q=" + query;
// https://duckduckgo.com/params
// kj=b2: blue header in results page
// kf=-1: no favicons
}
}
</script>
<script async defer data-domain="lispcookbook.github.io/cl-cookbook" src="https://plausible.io/js/plausible.js"></script>
</body>
</html>