diff options
-rw-r--r-- | how_to_write_install_targets_for_lua_modules_in_makefiles-1.png | bin | 0 -> 4715 bytes | |||
-rw-r--r-- | how_to_write_install_targets_for_lua_modules_in_makefiles-2.png | bin | 0 -> 5723 bytes | |||
-rw-r--r-- | how_to_write_install_targets_for_lua_modules_in_makefiles.html | 312 | ||||
-rw-r--r-- | index.html | 3 |
4 files changed, 315 insertions, 0 deletions
diff --git a/how_to_write_install_targets_for_lua_modules_in_makefiles-1.png b/how_to_write_install_targets_for_lua_modules_in_makefiles-1.png Binary files differnew file mode 100644 index 0000000..0a4bed2 --- /dev/null +++ b/how_to_write_install_targets_for_lua_modules_in_makefiles-1.png diff --git a/how_to_write_install_targets_for_lua_modules_in_makefiles-2.png b/how_to_write_install_targets_for_lua_modules_in_makefiles-2.png Binary files differnew file mode 100644 index 0000000..41f85ae --- /dev/null +++ b/how_to_write_install_targets_for_lua_modules_in_makefiles-2.png diff --git a/how_to_write_install_targets_for_lua_modules_in_makefiles.html b/how_to_write_install_targets_for_lua_modules_in_makefiles.html new file mode 100644 index 0000000..a43b259 --- /dev/null +++ b/how_to_write_install_targets_for_lua_modules_in_makefiles.html @@ -0,0 +1,312 @@ +<!doctype html> +<html lang="en"> +<meta charset="utf-8"> +<meta name="viewport" content="width=device-width, initial-scale=1"> +<meta name="author" content="aki"> +<meta name="tags" content="lua, module, make, install, target, installation"> +<meta name="published-on" content="2023-12-29T21:45:00+01:00"> +<link rel="icon" type="image/png" href="favicon.png"> +<link rel="stylesheet" href="style.css"> +<style> +.comment { color: #2552d7; } +.explanation { + height: fit-content; + border-collapse: collapse; +} +.explanation td { + height: 100%; + padding: 0; +} +.explanation td > div { + height: 100%; + display: flex; + box-sizing: border-box; + flex-direction: column; +} +.explanation td > div > * { flex-grow: 1; } +.explanation td > *, .explanation td > div > * { margin-top: 0; } +.explanation td > *:last-child, .explanation td > div > *:last-child { margin-bottom: 0; } +.explanation td.description { padding: 0.6em 1em; } +</style> + +<title>How to Write Install Targets for Lua Modules in Makefiles</title> + +<nav><p><a href="https://ignore.pl">ignore.pl</a></p></nav> + +<article> +<h1>How to Write Install Targets for Lua Modules in Makefiles</h1> +<p class="subtitle">Published on 2023-12-29 21:45:00+01:00 +<p>You can skip the full context and go right to the <a href="#proposition">explanation of the proposed makefile</a>. +<p>"Installation" can mean two things: installing packages using package manager (e.g., <b>pacman</b>(8), <b>apt</b>(8)) +or copying files from one spot to another. Of course, package managers may copy files during the installation process, +but in the latter case I mean <em>only</em> copying and maybe creating destination directories.</p> +<img src="how_to_write_install_targets_for_lua_modules_in_makefiles-1.png" alt="simplified pigeon installation process"> +<p>The usual encounter goes like: download some sources, build them, run checks, then run as is or <em>install</em> to +<code>/usr/local</code> to make it available system-wide and then run. +<p>With <b>make</b>(1) it's like: +<pre> +$ make +$ make test <span class="comment"># or: check</span> +# make install +</pre> +<p>We might see many different installation targets, but if there's any, <code>install</code> should be one of them. +These targets conventionally use several variables to change their behaviour. Among those we can see: +<pre> +DESTDIR= +PREFIX=/usr/local +BINDIR=$(PREFIX)/bin +LIBDIR=$(PREFIX)/lib +INCLUDEDIR=$(PREFIX)/include +DATADIR=$(PREFIX)/share +MANDIR=$(DATADIR)/man +MAN1DIR=$(MANDIR)/man1 +</pre> +<p>When we run <code>make PREFIX=/usr install</code>, the <code>PREFIX</code> will change to <code>/usr</code> and so +will all downstream directories. Note that nothing uses <code>DESTDIR</code> yet. <code>DESTDIR</code> is used for +staging the files with their intended structure before they make it to the real target location. This is commonly used +by package maintainers along with <b>fakeroot</b>(1) or similar method. +<p>For more details about these paths consult +<a href="https://refspecs.linuxfoundation.org/FHS_3.0/index.html">Filesystem Hierarchy Standard</a>, <b>hier</b>(7), +<b>file‑hierarchy</b>(7) and system specific documentation. For more information about names of the variables see +<a href="https://www.gnu.org/software/make/manual/html_node/Standard-Targets.html">Standard Targets for Users</a> and +<a href="https://www.gnu.org/software/make/manual/html_node/Directory-Variables.html">Variables for Installation +Directories</a> from GNU Make documentation. +<p>Now consider a simple target definition: +<pre> +install: all + install -m644 -Dt $(DESTDIR)$(INCLUDEDIR) include/*.h + install -m755 -Dt $(DESTDIR)$(LIBDIR) libuseful.so.1.0.0 + ln -s $(DESTDIR)$(LIBDIR)/libuseful.so.1.0.0 $(DESTDIR)$(LIBDIR)/libuseful.so.1 + ln -s $(DESTDIR)$(LIBDIR)/libuseful.so.1 $(DESTDIR)$(LIBDIR)/libuseful.so +</pre> +<p>Note the <code>$(DESTDIR)</code> use. +<p>First we copy all header files then the shared library. Here I use <b>install</b>(1), but a combination of +<b>mkdir</b>(1), <b>cp</b>(1) and <b>chmod</b>(1) would create an equivalent result. I also make some specific-version +symbolic links for the library. Variables to hold filenames and the version could be used. They are omitted to limit +scope of the example. +<p>What about Lua? +<p>Even with standards, conventions, recommendations makefiles in the wild have a lot of variation. For Lua there are no +conventions around, so we will see even more variation among the projects. I want to respect this variation when +proposing an install target for a Lua project. Let's take a look. +<p>I selected a set of projects available in arch package repository, took a look upstream, took a look at PKGBUILDs, +searched some more through Github. From that I identified four groups of interest: +<ul> +<li>Projects that leave the entire installation process to the user (e.g., LPeg or any one-file Lua module). +<li>Projects that have makefile with <code>install</code> target or equivalent (we're interested in these). +<li> + Projects that have rockspec files and rely on Luarocks builtin installation handling or equivalent (e.g., Penlight, + Busted). +<li>Projects that have other (Luke, CMake) or hybrid installation definitions (LuaRocks+sth) (e.g., luaposix, luasdl2). +</ul> +<p>Some projects had both makefiles and rockspecs (using builtin build type). I did not try to dig out why, but I guess +it was either: migration to rockspec, developer preference, or similar. Another scenario are projects that did not have +their own rockspec got one written by a package maintainer for LuaRocks (since it's required) or distro-specific package +repository (due to preference). These kind of rockspecs could get merged to the upstream project. +<p>From projects with makefiles I selected: +<ul> +<li> + <a href="https://github.com/alerque/cldr-lua/blob/master/Makefile">cldr-lua</a>, shamelessly uses luarocks in + <code>install</code> target. +<li> + <a href="https://github.com/mascarenhas/cosmo/blob/master/Makefile">cosmo</a>, <code>LUA_DIR</code> and + <code>LUA_LIBDIR</code>. +<li> + <a href="https://github.com/luarocks/luarocks/blob/master/GNUmakefile">LuaRocks</a>, <code>luadir</code>, which is + inline with their recommendation. +<li> + <a href="https://github.com/lunarmodules/luaexpat/blob/master/Makefile">luaexpat</a>, <code>LUA_V</code> with + <code>LUA_LDIR</code> and <code>LUA_CDIR</code>. +<li> + <a href="https://github.com/LuaLanes/lanes/blob/master/Makefile">lanes</a>, <code>LUA_SHAREDIR</code> and + <code>LUA_LIBDIR</code> +<li> + <a href="https://github.com/lgi-devs/lgi/blob/master/lgi/Makefile">lgi/lgi</a>, same names with addition of + <code>LUA_VERSION</code> +<li><a href="https://github.com/hoelzro/lua-repl/blob/main/Makefile">lua-repl</a>, :) +<li> + <a href="https://github.com/libmpack/libmpack-lua/blob/master/Makefile">libmpack-lua</a>, rather unique + <code>LUA_CMOD_INSTALLDIR</code>. +<li> + <a href="https://github.com/Lua-cURL/Lua-cURLv3/blob/master/Makefile">Lua-cURLv3</a>, <code>LUA_VERSION</code> with + <code>LUA_LMOD</code> and <code>LUA_CMOD</code> +<li> + <a href="https://github.com/lunarmodules/luasocket/blob/master/src/makefile">luasocket</a>, <code>LUAV</code> with + <code>LDIR</code> and <code>CDIR</code>. +<li> + <a href="https://github.com/o-lim/luasystem/blob/master/src/Makefile">luasystem</a>, same but + <code>LUA_VERSION</code>. +<li> + <a href="https://github.com/hoelzro/lua-term/blob/master/Makefile">lua-term</a>, <code>LUA_VER</code> with + <code>LUA_SHARE</code> and <code>LUA_LIBDIR</code> +<li> + <a href="https://framagit.org/fperrad/lua-TestMore/-/blob/master/Makefile">lua-TestMore</a>, <code>LUAVER</code> + with <code>LIBDIR</code> and nothing for shared libraries +</ul> +<p>How are these makefiles used when their parent project is packaged for different OS distributions? Well, each +distribution has its own packaging processes. Let's take a quick look at two.</p> +<img src="how_to_write_install_targets_for_lua_modules_in_makefiles-2.png" alt="luarocks illusionary logo"> +<p>Debian/Ubuntu in case of Lua packages will not use them. They have <b>dh</b>(1) and <b>dh_lua</b>(1) which together +take care of the packaging process. We could try to take a look at the helper scripts, but at the time of writing they +didn't appear helpful for this article. +<p>Arch Linux and its PKGBUILDs for lua packages prefer to use LuaRocks to support package making. In some cases if a +makefile from an upstream project was close enough to a conventional makefile, it could and was used. However, at least +one package maintainer later on judged that it's simply easier to use LuaRocks for everything and even recommended +writing rockspecs if not present upstream. Despite that there's a number of packages that simply copy things around +since the upstream projects did not have makefiles, install targets or rockspecs. +<p>I think this is enough information to make decisions. I also looked at some CMakeFiles and pkg-configs. +<p>Let's set goals. Our makefiles and <code>install</code> targets must be: +<ul> +<li>Simple; they must be readable and understandable, so they can be used and trusted. +<li>Generic; they must be able to work under slightly (or more) different path conventions of different distributions. +<li> + Targeted; they must build and install our software for only one version of Lua but they need to support choosing + what that version it is (there was an interesting pattern in Arch PKGBUILDs where none of the multi-version builds + were used). Switching between versions must be simple. +<li>Consistent; they must be similar to other makefiles, Lua and beyond, we have a decent set of samples to attempt it. +<li> + No duplication; you know me, they must have exactly one set of unique variables that affect all targets, i.a., not + split between build and install stages. Of course, this might backfire in cross-compilation or another similar + context. +</ul> + + +<h2 id="proposition">Proposition</h2> +<p>There's a shorter version better suited for closer inspection and copying <a href="#makefile">below</a>. +<table class="explanation"> +<!-- This table is the ugliest HTML thing I did in a while. --> +<tr><td><div><pre> +LUA_VERSION=<u>5.4</u> +</pre></div> +<td class="description"> +<p>The first or second spot seems fitting for the version. Before build definitions, too. +<p>I couldn't decide. Full name seems the best. I was thinking about <code>LUAVERSION</code> quite a lot since I was +using it for my projects. In the end underscore is consistent with Lua's <code>LUA_PATH</code> variables. Shorter +variants like <code>LUAV</code> seem to create an impression of a library or utility name (e.g., luvit/luv, +guidanoli/luav). +<p>Change your default value from <code><u>5.4</u></code> as necessary. +<tr><td><div><pre> +PREFIX=/usr/local +<td class="description"> +<p>The first spot rival. It lost because it wouldn't need to appear before build definitions. +<p>It defines the base path for everything else. Do not mistake or mix it with <code>DESTDIR</code>. The default value +rarely changes, to understand it better consult sources listed somewhere above. +<tr><td><div><pre> +BINDIR=$(PREFIX)/bin +LIBDIR=$(PREFIX)/lib +DATADIR=$(PREFIX)/share +MANDIR=$(DATADIR)/man +MAN1DIR=$(MANDIR)/man1 +</pre></div> +<td class="description"> +<p>Not-Lua-specific install directories. Like before I skipped some since there's only a low chance of using them. +<p>We want these for consistency and to allow users do more granular path injection, e.g., <code>LIBDIR</code> with a +platform triplet. +<tr><td><div><pre> +LUA_CMOD=$(LIBDIR)/lua/$(LUA_VERSION) +LUA_LMOD=$(DATADIR)/lua/$(LUA_VERSION) +</pre></div> +<td class="description"> +<p>These are the target locations respectively for shared library and script Lua modules. +<p>These names slowly grow in me every time I review the article. They read nicely: "<code>C</code> language, so +library, <code>MOD</code>-ules for <code>LUA</code>" and similarly "pure <code>L</code>ua" or "<code>L</code>ua, so +pure". These are used mainly by pkg-config files (e.g., Arch Linux, homebrew, chromebrew) and sometimes in projects. +<p>Another candidate for pure modules was <code>LUADIR</code> which is the most popular and recommended by LuaRocks but +it is conflicting with the same name pointing at Lua include files (e.g., LPeg uses it like this). A candidate for +library modules <code>LUA_LIBDIR</code> has the exact same problem (this one is even worse, because it reads as +"<code>LIBDIR</code> for <code>LUA</code>). +<p>One concern I still think about is the broken parallel between <code>LUA_LMOD</code>/<code>LUA_CMOD</code> and +<code>LUA_PATH</code>/<code>LUA_CPATH</code>. +<tr><td><div><pre> +LUA_CFLAGS=\ + `pkg-config \ + --cflags \ + lua$(LUA_VERSION)` +LUA_LDLIBS=\ + `pkg-config \ + --libs \ + lua$(LUA_VERSION)` +</pre></div> +<td class="description"> +<p>If you need to compile some modules you will need these. I'm lazy and prefer to use <b>pkg-config</b>(1). It nicely +cooperates with the version variable allowing to meet the simple version switching goal. +<p>Now, since <b>pkg-config</b> is used rather than just writing things by hand, a question appears. More than one +actually, since a simple <code>CFLAGS</code> creates multiple questions about customization (some are answered by e.g., +<code>+=</code>), defaults, optimization. However, I don't think this is the time to discuss them. +<p>Here, I only wanted to point out that <code>LUA_VERSION</code> can and most likely should be reused when getting Lua +versioned include directories. +<p>Lines are broken for the sake of the column width, readability of this page and to save me from tweaking the style +more than I need, since I can get lost in an endless loop of moving elements by one pixel in random directions. +<tr><td><div><pre> +export LUA_PATH=<u>\</u> + <u>$(PWD)/src/?.lua;\</u> + <u>$(PWD)/src/?/init.lua;;</u> +export LUA_CPATH=<u>;;</u> +</pre></div> +<td class="description"> +<p>Occasionally, we may need to execute some Lua code as part of our makefile and use some of our code. +<p><code>export</code> is not yet part of POSIX, so workaround it with shell or <b>env</b>(1). +<p><code>LUA_CPATH</code> is an almost no-op for the sake of appearance. +<tr><td><div><pre> +LUA=lua +</pre></div> +<td class="description"> +<p>Traditionally executed commands have their own variables (btw. they are also called macros). This adds just another +opportunity to modify them since make already runs in some environment that can be tweaked. Still, it can be useful for +e.g., injecting <code>LUA_PATH</code> mentioned above. +</table> +<p>I had to break the two column view for the last part, because it would look comically. Installation target itself: +<pre> +install: all + install -m755 -Dt $(DESTDIR)$(BINDIR) wrap + install -m644 -Dt $(DESTDIR)$(MAN1DIR) wrap.1 + install -m755 -Dt $(DESTDIR)$(LUA_CMOD) useful.so + install -m644 -Dt $(DESTDIR)$(LUA_LMOD)/wrap wrap/*.lua +</pre> +<p>This assumes that: +<ul> +<li>Build produces an executable <code>wrap</code> and shared library Lua module <code>useful.so</code> in the same +directory makefile resides in. +<li>There's a <code>wrap/</code> subdirectory that contains pure Lua modules that require installation. +<li>There's <code>wrap.1</code> manpage in the makefile directory. +</ul> +<p>I adjusted two of my unfinished projects to use this convention, so that you can see a makefile without this kind of +assumptions. See <a href="https://git.ignore.pl/activity/tree/Makefile">activity</a> and +<a href="https://git.ignore.pl/lua-srcinfo/tree/Makefile">srcinfo</a>. +<p>As an alternative to direct use of <b>install</b>(1) and to increase control over commands executed with make see +<a href="https://www.gnu.org/software/make/manual/html_node/Command-Variables.html">Variables for Specifying +Commands</a>. +<p>Finally, the short version of the makefile: +<pre id="makefile"> +LUA_VERSION=5.4 + +PREFIX=/usr/local +BINDIR=$(PREFIX)/bin +LIBDIR=$(PREFIX)/lib +DATADIR=$(PREFIX)/share +MANDIR=$(DATADIR)/man +MAN1DIR=$(MANDIR)/man1 +LUA_CMOD=$(LIBDIR)/lua/$(LUA_VERSION) +LUA_LMOD=$(DATADIR)/lua/$(LUA_VERSION) + +LUA_CFLAGS=`pkg-config --cflags lua$(LUA_VERSION)` +LUA_LDLIBS=`pkg-config --libs lua$(LUA_VERSION)` +CFLAGS=$(LUA_CFLAGS) +LDLIBS=$(LUA_LDLIBS) + + +all: + touch wrap useful.so + + +install: all + install -m755 -Dt $(DESTDIR)$(BINDIR) wrap + install -m644 -Dt $(DESTDIR)$(MAN1DIR) wrap.1 + install -m755 -Dt $(DESTDIR)$(LUA_CMOD) useful.so + install -m644 -Dt $(DESTDIR)$(LUA_LMOD)/wrap wrap/*.lua +</pre> +<p>I still think I would prefer them without the underscores, but then <code>LUALMOD</code> would be one letter away +from <code>LUAMOD</code> which would be annoying to deal with since it sounds like it would hold a name of a module. +<p>What do you think? What do you use yourself (other than LuaRocks)? Do you like the two column code view thing? Until +I create some proper feedback channel, just feel free to <a href="mailto:please@ignore.pl">send me an email</a>! +</article> +<script src="https://stats.ignore.pl/track.js"></script> @@ -39,6 +39,9 @@ software and hardware engineering. I post here my projects, experiments, and wha <h2>Posts</h2> <p><a href="atom.xml">Atom feed</a> <ul> +<li> <a href="how_to_write_install_targets_for_lua_modules_in_makefiles.html">How to Write Install Targets for Lua + Modules in Makefiles</a><br> + <time>2023-12-29</time> <li> <a href="self_update_end_of_year_2023.html">Self Update: End of Year 2023</a><br> <time>2023-12-27</time> <li> <a href="alcohol_of_the_year_2022.html">Alcohol of the Year 2022</a><br> |