Recently I was talking about LLVM with a colleague and the question arose of exactly why the OpenBSD project has an issue with the LLVM license change that occurred a couple of years ago. As I knew only a cursory level reason as to why this occurred, I started to do a little digging into the history and thought it may be of interest. Here is what I came up with.
Initially the LLVM project was placed under the NCSA license which is a very open license, much like the license that BSD uses in general. If anyone isn't aware of the BSD license model please take some time and research it separate from this entry if you want to fully understand it. There are many licensing models out there and if you think that the Apache 2, GNU, and ISC are all basically the same, I would suggest doing some reading, as that is where much of the reasoning behind this issue stems from, the nuances of the licenses. OpenBSD has a very clearly stated policy at https://www.openbsd.org/policy.html that outlines what they consider acceptable licenses for code that goes into their project.
It turns out that the Apache 2 license is free, but the change to it is what is actually in question. The one called out by OpenBSD in particular is that it was possible to change the license without the consent of the people who are listed as contributors in the NCSA license. In addition, what Theo expanded on was the LLVM team’s apparent “IANAL but let’s do it anyway” attitude that seems to indicate they really did not consult someone as to if it was possible to change the license mid stream as they did. The email in this case it isn’t a piece of software that a single person contributed to, and they would be available to provide consent to the license change, this software had been created by a team of contributors. What happens when someone at a time in the future who is listed on the NCSA license calls them out for not getting their permission to perform the license type change?
At the end of the day the OpenBSD project has been forced to stick with the last NCSA licensed version of LLVM. They generally have forked products in the past when this occurs and then will move forward in one of two ways. Either they will create their own version as in the case of LibreSSL and PF, or they will move to another piece of open source software as they did in the case of going from GCC to Clang. Unfortunately now this has bitten them there may be a tendency to write their own, but that is a huge undertaking. I tend to think they will not go the route they have with LibreSSL just due to the scale of building out a compiler toolchain, but one never knows.
This is how it ended for ipfilter. It occurred midstream in a release cycle, with no packet filter in place that could be used at the time. One had to be written from scratch and within the timelines. This is how PF was born. from the CVS commit message:
Remove ipf. Darren Reed has interpreted his (old, new, whichever) license in a way that makes ipf not free according to the rules we established over 5 years ago, at www.openbsd.org/goals.html (and those same basic rules govern the other *BSD projects too). Specifically, Darren says that modified versions are not permitted. But software which OpenBSD uses and redistributes must be free to all (be they people or companies), for any purpose they wish to use it, including modification, use, peeing on, or even integration into baby mulching machines or atomic bombs to be dropped on Australia. Furthermore, we know of a number of companies using ipf with modification like us, who are now in the same situation, and we hope that some of them will work with us to fill this gap that now exists in OpenBSD (temporarily, we hope)
Until the next blog, don't talk about it...
Using LSP (Language Server Protocol) in Emacs brings some of the convenience items present in contemporary IDE's into the Emacs environment that we are all familiar with. Clojure has proven to me to be similar from a development standpoint where it is a relatively small core language with a large number of supporting libraries, similar in many ways to Common LISP.
Having the ability to leverage Emacs with LSP for Clojure development was a really high item on my list of integrations as I saw what clojure-lsp does in a FreeBSD and Debian Linux environment and I wanted to have those capabilities available to me in OpenBSD.
The main issue faced when working with OpenBSD is generally its compatibility with various libraries used frequently in the Linux community. Linux users generally are happy when they get their code working in that environment, stopping at that point with porting to other environments. Sometimes FreeBSD will be ported to, but OpenBSD is generally left to fend for itself. Also the OpenBSD environment is not one that is as easy to get working due to its more locked down state.
In the case of clojure-lsp, the default binary found at https://github.com/snoe/clojure-lsp does not include support for OpenBSD for the required sqlite-jdbc driver within the download provided. The sqlite DB is used by LSP for maintaining the details of a project in a quickly accessible location I believe. (Disclaimer I haven't looked at the code to confirm this, it's an assumption) Once Emacs has been configured to leverage clojure-lsp, it tries to create a sqlite DB in a directory ".lsp" at the root of the project. When this is attempted in OpenBSD, the sqlite-jdbc driver isn't contained in the shipped binary, so even though the OS is detected, it doesn't have the proper jdbc binary available to make the connection to the DB, and fails. In Emacs it simply appears at the bottom of the screen as "Connecting" and continues to sit there spinning.
Luckily lsp-clojure by default logs to a file /tmp/lsp.out that contained information regarding this failure, giving us a clue to what is happening. Below is an example of the error.
{:type java.lang.Exception
:message No native library is found for os.name=OpenBSD and
os.arch=x86_64.
path=/org/sqlite/native/OpenBSD/x86_64
:at [org.sqlite.SQLiteJDBCLoader loadSQLiteNativeLibrary
SQLiteJDBCLoader.java 333]}
Its pretty apparent from the error that we have a library missing in the shipped binary for
Getting lsp-clojure functional in OpenBSD requires a couple of things to happen.
The next section walks through the process
#native-all: native win32 win64 mac64 linux32 linux64 linux-arm
#linux-armv7 linux-arm64 linux-android-arm linux-ppc64 alpine-linux64
native-all: native
% gmake
Once its built, we need to have this installed in the local .m2 repository of the user's home directory. This is needed as when we build clojure-lsp we need to have this driver available. We use maven to perform the installation locally. This will run through some tests as part of the install process and at the end of the process an INFO line shows where it was installed.
$ mvn install
[INFO] Scanning for projects...
[INFO]
[INFO] -----------------------< org.xerial:sqlite-jdbc >-----------------------
[INFO] Building SQLite JDBC 3.31.2-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
[INFO] --- maven-install-plugin:2.4:install (default-install) @ sqlite-jdbc ---
[INFO] Installing
/home/roger/Downloads/sqlite-jdbc-master/target/
sqlite-jdbc-3.31.2-SNAPSHOT.jar
to /home/roger/.m2/repository/org/
xerial/sqlite-jdbc/3.31.2-SNAPSHOT/sqlite-jdbc-3.31.2-SNAPSHOT.jar
[INFO] Installing /home/roger/Downloads/sqlite-jdbc-master/pom.xml to
/home/roger/.m2/repository/org/xerial/sqlite-jdbc/3.31.2-SNAPSHOT/
sqlite-jdbc-3.31.2-SNAPSHOT.pom
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 11.980 s
[INFO] Finished at: 2020-06-07T15:49:36-04:00
[INFO] ------------------------------------------------------------------------
Now that the driver is ready and installed, go to the git cloned directory for clojure-lsp and make the following changes to the deps.edn file. Make sure that the versions being built match your individual versions. By default Leiningen will look to the .m2 directory of the user running the build first, if it doesn't find the file there, it the searches these: clojars.org and Maven Central. By installing the library to the local cache, it will not go out to look for it. If it does try to look outside of the local repo, obviously this will fail.
;;org.xerial/sqlite-jdbc {:mvn/version "3.21.0.1"}
org.xerial/sqlite-jdbc {:mvn/version "3.31.2-SNAPSHOT"}
Now its time to build a new version of clojure-lsp with support for OpenBSD. By default lein does not allow SNAPSHOTS in release build libraries as dependencies, it will trigger an error. If a SNAPSHOT was used as above, its necessary to tell Leiningen this is OK before we build clojure-lsp.
% cd <CLOJURE_LSP_DIR>
% LEIN_SNAPSHOTS_IN_RELEASE=1
% export LEIN_SNAPSHOTS_IN_RELEASE
% <PATH TO LEIN> bin
WARNING: You have $CLASSPATH set, probably by accident.
It is strongly recommended to unset this before proceeding.
WARNING: seqable? already refers to: #'clojure.core/seqable? in
namespace:
clojure.core.incubator, being replaced by: #'clojure.core
.incubator/seqable?
WARNING: seqable? already refers to: #'clojure.core/seqable? in
namespace:
clostache.parser, being replaced by: #'clojure.core.incub
ator/seqable?
Compiling 1 source files to /home/roger/src/clojure/clojure-lsp/target/classes
Compiling clojure-lsp.clojure-core
Compiling clojure-lsp.crawler
Compiling clojure-lsp.db
Compiling clojure-lsp.handlers
Compiling clojure-lsp.interop
Compiling clojure-lsp.main
Compiling clojure-lsp.parser
Compiling clojure-lsp.refactor.edit
Compiling clojure-lsp.refactor.transform
Compiling clojure-lsp.shared
Created /home/roger/src/clojure/clojure-lsp/target/
clojure-lsp-release-20200514T134144.jar
Created /home/roger/src/clojure/clojure-lsp/target/
clojure-lsp-release-20200514T134144-standalone.jar
Creating standalone executable: /home/roger/src/clojure/clojure-lsp/
target/clojure-lsp
Re-aligning zip offsets
Copy the clojure-lsp file created as "standalone executable" to a location available in your PATH within your .emacs.
Open Emacs and load a clojure file from a project into Emacs.
When this is performed, it should launch the lsp process and you will see some message indicating STATUS:starting at the bottom of the Emacs window. After some time.. depending upon the processor, maybe 20-30 seconds, that should change to:
LSP :: clojure-lsp:\<PID\> initialized successfully
If a message like this appears, you did not set the environment variable properly
Release versions may not depend upon snapshots.
Freeze snapshots to dated versions or set the
LEIN_SNAPSHOTS_IN_RELEASE environment variable to override.
Congratulations, you now have clojure-lsp working in OpenBSD!
If this doesn't happen and you have failures, or you see it sitting in the "starting" state for a long time, check the /tmp/lsp.out file to see what the error is.
When the driver is in place, once the nrepl server starts, it notices the DB was not present in the file system. Note, the only time that this particular warning was logged was when the system was able to load the OpenBSD version of the sqlite-jdbc driver.
INFO clojure-lsp.main: :initialize 55577 ()
INFO clojure-lsp.main: Shutting down
INFO clojure-lsp.main: Server started
INFO clojure-lsp.main: ====== LSP nrepl server started on port 32021
WARN clojure-lsp.main: Initialize
WARN clojure-lsp.db: Could not load db [SQLITE_ERROR] SQL error or
missing database (no such table: project)
Enjoy your new installation!
Until the next blog, don't talk about it...