site

bvnf.space sources
Log | Files | Refs

008-sudo-make-install.html (6722B)


      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
     12
     13
     14
     15
     16
     17
     18
     19
     20
     21
     22
     23
     24
     25
     26
     27
     28
     29
     30
     31
     32
     33
     34
     35
     36
     37
     38
     39
     40
     41
     42
     43
     44
     45
     46
     47
     48
     49
     50
     51
     52
     53
     54
     55
     56
     57
     58
     59
     60
     61
     62
     63
     64
     65
     66
     67
     68
     69
     70
     71
     72
     73
     74
     75
     76
     77
     78
     79
<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8"/>
	<meta name="viewport" content="width=device-width, initial-scale=1"/>
	<title>sudo make install</title>
    <link rel="icon" href="data:image/gif;base64,R0lGODlhEAAQAPH/AAAAAP//AAD/AP8AACH/C0NSTkcAAAAAMS4wSAAAAAIwPwAAAAJATwAAAAJQXwAAAAJgbwAAAAJwfwAAAAKAjwAAAAKQnwAAAAKgrwAAAAKwvwAAAALAzwAAAALQ3wAAAALg7wAh+QQF//8EACwAAAAAEAAQAAACOJQFqTp9j5p00IApq8X0rTtBSQCQYIeUZGBmh7qyp8fGpGvV8PyqPt9bJUKiBUYT4SBPRMuH0SgAADs="/>
    <style type="text/css">
    body {font-family: sans-serif; padding: 2ch; margin: auto; max-width: 50em; color:black; background: #fff;}
    pre { margin: 0; padding: 1ch;}
    h1 { font-size: 1.4em;}
    </style>
</head>
<body>
<h1>sudo make install</h1>

<blockquote>I originally wrote this in April 2022, but only published it now because... reasons.</blockquote>

<p>I found a weird bug. It occurred while installing <a href="https://github.com/aligrudi/neatroff_make">neatroff</a>, which is a nice, new, tidy implementation of troff. It can be used from the source dir itself, or can be installed to a <code>$(BASE)</code> like <i>/usr/local/share/neatroff</i>.</p>
<p>But when I was trying to compile some documents, the neatpdf PDF postprocessor couldn't find the requested fonts and it looked all wrong with weird or no fonts. Everything was installed in <code>$(BASE)</code> correctly. I could compile the same document in the git source directory and get the right results, so it had to be something to do with the way in which contents of files are changed for being used from <code>$(BASE)</code>.</p>


<p>The font definitions contain a line <code>fontpath /path/to/font</code> so that PDFs know where to find the fonts. This is written to using a sed call. Neatroff was meant to only be used from the source dir, so font files usually say <code>fontpath $(PWD)/fonts</code>, where <code>$(PWD)</code> hopefully refers to the toplevel source directory (ie. you're running <code>make install</code> not <code>make -f ../Makefile install</code>).</p>
<p>To permit installing neatroff to the system, the sed call changes <code>fontpath $(PWD)/fonts</code> to <code>fontpath $(BASE)/fonts</code>:</p>

<pre><code>@for f in "$(BASE)/devutf"/*; do \
    sed "/^fontpath /s=$(PWD)/fonts=$(BASE)/fonts=" &lt;$$f &gt;.fd.tmp \
    mv .fd.tmp $$f \
done</code></pre>

<p>All fine, you might think.</p>

<p>Consider where the makefile actually gets <code>$(PWD)</code> from. It isn't a defined macro at the top (<code>PWD = ...</code>), so it inherits it from the environment, which is a shell, where we can rely on <code>$PWD</code> being set. All fine.</p>
<p>This is how GNU make does it - it gets <code>$(PWD)</code> from its parent process - usually, your shell. BSD make sets <code>$(PWD)</code> explicitly.</p>
<p>However, when you run <code>make</code> under sudo (or doas, or ssu), these privilege-escalting tools do not set <code>$PWD</code> in their default configuration. Therefore, GNU make can't find a value for <code>$(PWD)</code>, so it is empty.</p>

<p>The line the sed calls act on start by looking something like</p>
<pre><code>fontpath /home/me/src/neatroff_make/fonts/NimbusRoman-Regular.t1
</code></pre>
<p>and should be turned into something like</p>
<pre><code>fontpath /usr/local/share/neatroff/fonts/NimbusRoman-Regular.t1
</code></pre>
<p>but under sudo with gmake, with <code>$(PWD)</code> unset, it actually becomes</p>
<pre><code>fontpath /fonts/NimbusRoman-Regular.t1
</code></pre>
<p>which clearly doesn't work.</p>

<p>There are ways to make sudo et al. keep <code>$PWD</code> defined (by using the <code>-E</code> flag, or a config line) but that's not something that should be relied on when doing <code>sudo make install</code>.</p>

<p>Luckily, POSIX requires that shells set PWD themselves, so we can always find the name of the current working directory by doing <code>$$(pwd)</code> (which runs the <code>pwd</code> program), or <code>$$PWD</code> (which is given to a shell as <code>$PWD</code>, which is dereferenced to what we want). Interestingly, both BSD make and GNU make set special variables with the value of PWD: BSD make sets <code>$(.CURDIR)</code>, and GNU make sets <code>$(CURDIR)</code>. See the difference? It's really annoying that the two biggest make implementations have this slight inconsistency, and POSIX doesn't require any special make macro with the value of <code>PWD</code>. (OpenGroup members, something for POSIX.1-202x?)</p>

<p>I chose to go with <code>$$PWD</code>:</p>
<pre><code>PWD = $${PWD}
</code></pre>
<p>Now, anywhere in the Makefile that uses <code>$(PWD)</code> gets sent to the shell as <code>${PWD}</code>, which is fine.</p>

<p>There's one last problem: the change from using <code>$(PWD)</code>, which is dereferenced by make, to <code>$$PWD</code>, which is dereferenced by the shell running each rule line, caused another problem with lines like</p>
<pre><code>@cd neatmkfn &amp;&amp; ./gen.sh "$(PWD)/fonts" "$(PWD)/devutf" &gt;/dev/null
</code></pre>
<p>which <code>cd</code> somewhere before doing something. They get <code>$PWD</code> of the shell in the new directory, but we want the old directory (the <code>$PWD</code> of the Makefile). I thought the most simple way to fix this was with a shell variable, like</p>
<pre><code>@pwd="$(PWD)" &amp;&amp; \
	cd neatmkfn &amp;&amp; ./gen.sh "$$pwd/fonts" "$$pwd/devutf" &gt;/dev/null
</code></pre>

<p>This is a little bit annoying but it is done to preserve the portability of the Makefile (it is POSIX.1-2017 compliant). Both GNU and BSD make have syntaxes for immediate-expansion macro definitions. These would fix this problem because it would save the string of the current working directory into <code>$(PWD)</code>, rather than a kind of nested macro which gets dereferenced later. (Note that the syntax is mostly incompatible between GNU and BSD make).</p>
<p>For example, we could do</p>
<pre><code>PWD != pwd</code></pre>
<p>which runs pwd then and there, and saves it. However, this is not in POSIX (currently).</p>
<p>In my opinion, the best solution that POSIX.1-202x should use is to require make to set the <code>PWD</code> macro itself. The whole SCCS stuff in POSIX already requires make to think about <code>PWD</code>, so I don't see why this shouldn't happen. <code>PWD</code> is a better macro than <code>CURDIR</code> or <code>.CURDIR</code> because of the discrepancies between GNU and BSD make.</p>

<p><a href="https://github.com/aligrudi/neatroff_make/commit/11956d00720d39763a7daa05077da8300f439326">The commit fixing this bug</a>.</p>

<hr />
<p>written 2022-12-28, originally 2022-04-17</p>

<p><a href="../">Home</a></p>
<p><a href="./">Blog home</a></p>
</body>
</html>