Hello, everyone.
This talk is on literate documentation
with Emacs and org-mode.
I'm going to take just a moment here
to unpack what I just said.
Emacs, as most of us probably already know,
is a powerful text editor and list programming environment
from the 1970s.
Chances are, if you're attending this talk,
you already know a bit about Emacs.
org-mode is an Emacs major mode and authoring tool
that helps you write documents in a plain text markup
language called Org.
These Org documents can be exported
to a number of different document formats,
like HTML, PDF, ODT, Markdown, and more.
org-mode has a lot of features.
It can be an outliner, a to-do list manager,
an agenda, organizer, and much more.
Today, we're going to be demonstrating
what I consider to be org-mode's killer feature called
Org Babel.
Babel allows you to take human language prose,
computer language source code blocks, and their outputs
and weave them together seamlessly
to form a cohesive document.
It is seriously cool.
Literate documentation is a play on the term
literate programming, popularized by Donald Knuth
in the early 1980s.
Knuth's literate programming idea
was that computer programs could be
expressed in a natural language and be
human-readable documents rather than written exclusively
for machines to read.
In a traditional program, you might
have a bunch of machine-readable source code
and a handful of human-readable comments,
which attempt to describe what the program is doing.
Literate programming flips this on its head.
A literate program is a document that
describes how the program works with machine-readable source
code blocks inside of it.
These source code blocks are later
tangled out of the document and submitted to the machine
either to be compiled or interpreted and ultimately run.
Throughout this presentation, you'll
see my browser window here on the left side of the screen.
And on the right side, I've got a terminal session
running tmux.
This allows us to have a virtual terminal window connected
to two separate Linux machines, one running Ubuntu Server 2204
and another running Fedora Server 38.
I've specifically chosen these two distributions for my demo
because they are representative of the two dominant flavors
of GNU Linux, Debian and RedHat.
In both cases, these are bare-bones server additions
with the stock packages installed.
I've manually installed a few packages like Git, emacs-noex
to get the terminal version of emacs, and tmux.
But otherwise, these Linux installs
are what you'd get right out of the box.
For this demo, I've created a literate org-mode document
that describes how to build GNU Emacs from its source code
on both Debian and RedHat-based systems.
While both operating systems are very similar,
they differ substantially on which packages
are installed out of the box, how optional packages are
named, searched, and installed, and of course,
the distributions have different names,
like Ubuntu or Fedora.
I chose building Emacs from source
as a topic for this demonstration
because while the process is largely
the same on both RedHat and Debian,
there are a lot of minor little differences
that need to be accounted for, which really prohibits you
from hard coding names of packages and package management
tools and distributions into your document.
I suppose you could create two versions of the same document,
one specifically for RedHat and one specifically for Debian,
but that would be really tedious to maintain.
Like if, for example, you updated some prose
in one document, you'd have to remember
to do it in the other one too.
And if you weren't careful, the two documents
could drift out of sync.
In this demo, I'll show you techniques
for creating dynamic, literate documents that
can change based on parameters and constants embedded
into the non-exported regions of the document.
I'll show how with a single org-mode source document,
you can press a couple of keys to configure
it to export a RedHat-specific version of my building
Emacs from source essay or a Debian-specific version.
All right, let's get started.
We'll begin by firing up a new terminal Emacs session
on my Ubuntu machine.
Now, I installed Emacs on this machine using apt-get.
And doing that, you get version 27.1,
which is, hey, only two major versions
behind the current version of Emacs.
This is another reason why I thought
writing a guide on how to build Emacs from source code
might be a good idea.
You can get a much newer version of Emacs on Ubuntu
if you install it via Snap, but, uh, Snaps.
Don't get me started.
Now, I wanted to use a completely vanilla
terminal mode install of Emacs for this demonstration
because my personal Emacs config has a ton of packages
installed and is heavily modified.
I want folks to be able to follow along
with a bog-standard, out-of-the-box Emacs config.
The Emacs config on this Ubuntu machine
has just two settings.
I require org-tempo because my fingers are hardwired
to use some of the handy shortcuts that it provides.
And I also turn off the menu bar
because I just can't stand to look at it.
Let's begin by opening a file called buildemacs.org,
which will be the source code
for our literate org-mode document.
Now, in preparation for this talk,
I've already written this document,
and we'll take a look at the finished product
here in a bit, but let's first take a look
at how we might approach this task.
We'll start at the top of the document
by filling out some export keywords.
These keywords are something that every backend exporter,
be it LaTeX or plain text or ODT or whatever, understands,
and they're essentially document metadata.
As you can see, I'm typing `#+`
followed by a couple characters
and then `M-TAB` to auto-complete.
If you hit #+ by itself and then M-TAB,
you can see all the possible completions.
And as you can see, there's a lot.
The next thing we're gonna do is make a README section
at the top of this document.
This section is intended for folks
who are looking at the org-mode document,
trying to figure out what it's for.
We don't want to actually export the section heading,
so we're gonna tag it with the :noexport: tag.
And then here, we just write something quick
to let folks know that this document
can potentially execute code
and just a little something about what the document is for.
Okay, so now that we've written some text,
let's try our hand at writing a code block.
I'm getting pretty sick of looking at
the default Emacs theme.
All that blue and purple in the document
makes it look bruised.
Let's make an Emacs Lisp code block
that switches the theme
to one of my favorite built-in themes, Leuven.
Leuven was created by my man, Fabrice Niessen,
who I personally have learned a ton of org-mode stuff about
just by studying his work.
Now, if we cruise back up to the code block,
we should be able to hit `C-c C-c`,
and have it execute.
And there you have it, a high-contrast color theme
that was designed to look great in org-mode.
So that's great and all,
but there are a couple of things I don't like.
First of all, we don't need to see a #+RESULTS block here,
and that's because we're not really interested
in what the Emacs Lisp function `load-theme` returns.
I mean, it's great it returned t and all to indicate success,
we just don't need to see it.
We can slap a `:results none` header arg
on the code block to keep things nice and clean.
There are a lot of different header args,
and I often confuse and misremember them.
So I'll always refer back to the org-mode manual
when working with them.
The second thing I don't like is that
when we hit C-c C-c to execute the block,
Emacs prompted us if we really wanted to run the block.
Emacs Lisp is Emacs' mother tongue,
and I don't wanna be hassled when speaking
my native language.
There's a variable that controls this
called `org-confirm-babel-evaluate`.
And this can be either set to t or nil
to either always confirm or never confirm.
If however, you provided a lambda, an anonymous function,
Org will call your function with the name of the language
and the source block that it's about to run.
And your function can make the decision
about if Emacs should ask you for confirmation or not.
What I'm doing here is setting `org-confirm-babel-evaluate`
as a "file local variable".
This means whenever the file is opened by Emacs,
it'll set this variable to be a lambda that returns nil,
meaning don't confirm, on Elisp code blocks.
As you can see, the variable is currently set
to its default value of t, meaning always confirm.
Now if we save the buffer, exit Emacs,
and pop back in again,
`org-confirm-babel-evaluate` should be set how we like it.
We were however prompted for confirmation
on setting the file-local variable,
which controls if we're prompted
for Elisp source code block evaluation.
I feel like there's a Yo Dawg joke here somewhere.
When we were prompted, we hit the exclamation mark,
which automatically marks this variable as being safe.
So you won't be bothered the next time you open this file.
This variable is called `safe-local-variable-values`
and if we pop over to our .emacs file,
you can see that Emacs' customize tooling
helpfully updated this variable in our config file for us.
Now that's great and all,
but I really don't like having to hit `C-c C-c`
on that source block every time I open this document
just to bring up the Leuven theme.
Let's have this source block run automatically
every time the document is opened.
Now I know what you're thinking.
Shouldn't you just put all of this configuration stuff
in your .emacs file and keep it out of the document?
Well, that's what I've done with my personal Emacs config,
but we want this document to be able to be used by folks
with a completely vanilla Emacs setup,
or even a completely tricked out Emacs setup,
so we can't assume anything.
The idea is if the Emacs user who opens the document
agrees to setting all of the variables
and running all of the code within,
they'll be able to export the document
as well as run all of the code blocks inside of it
just as we intended.
And the differences in base Emacs configuration
will be completely minimized.
Now it's worth pointing out that the file-local variables
we're setting here are local, in this case, buffer-local.
The configuration we use in this document
won't override someone's carefully constructed
org-mode setup.
The first thing we're gonna wanna do
in order to make this block execute
when the document is loaded is to give it a name.
It's always a good idea to give every source block
you create in your document a unique name,
even if you don't refer to it elsewhere.
I do this because when I'm debugging my documents,
Emacs will prompt me about running a block.
If the block has a name, Emacs mentions it,
and I know there's a problem with the result caching
or something with the "foo" block.
But if the block doesn't have a name,
it can be really hard to figure out
which block Emacs is complaining about.
So I always name my blocks.
Now we're gonna add another file local variable,
but this one is special.
If your "variable"
just happens to be named "eval",
it means that Emacs should evaluate
the Lisp expression that follows.
Here we'll use the progn function
to sequentially run two elisp functions
and return the value of the last one executed.
The first function is `org-babel-goto-named-source-block`,
which jumps us to the startup block.
The second one is `org-babel-execute-src-block`,
which executes the current source block.
That should get the job done.
Now all we have to do is save the document,
exit Emacs, jump back in,
and once we've confirmed that we're willing
to run the new "eval" line in our file local variables,
we're good to go.
Now if we want to add new configuration stuff
to the document, we can just add it to the startup block
and not have to muck about with confirmations
or adding new file-local variables or whatever.
And just like before, we'll let Emacs' customize system
save this decision to our .emacs file.
Now that all that business with confirmations,
file-local variables, and the startup block
are out of the way,
we can get on with writing our introduction.
We'll create a new top level headline called introduction
and explain to the reader of the exported document
what this is all about.
Now as you can see, we've actually hard-coded
the name of the Linux distro in our prose.
I promised you a single document that could be
for either RedHat or Debian distros,
so we can't have this.
Astute members in the audience have probably been uneasy
ever since I hard coded the name "Debian"
in the README section above.
One way of solving this problem is by using exclude tags.
Let's add the `#+EXCLUDE_TAGS` export keyword to our document.
This keyword tells the exporter,
"Hey, if you see a headline tagged with any of these tags,
don't export it."
By default, the tag `:noexport:` is excluded.
And if you'll notice, we tagged our README section
with that tag, so it doesn't show up
in the exported document.
We'll keep this tag in the list,
but we'll also add the tag `:redhat:` as a tag to exclude.
Now it's just a matter of creating two introduction
sections, one for Debian, one for RedHat.
And if you want the RedHat version of the document,
you can just modify the `#+EXCLUDE_TAGS` line
at the top of the document.
Awesome, right?
Right?
OK, this is not that great.
Well, it does work.
And you can see if we export the document,
we'll get something that only references Debian,
and the `:noexport:` and `:redhat:`
tagged headlines are omitted.
This strategy would work great
when the RedHat- and Debian-specific sections
are substantially different, but that's not
the case with the introduction.
We definitely don't want to have to maintain
two distinct introductions.
I also noticed that the export tags are included
in the exported document.
That's a terrible default. We'll fix that,
and we'll also ensure that my email address appears
at the top of the document.
Let's also take this opportunity to get rid
of the table of contents.
We don't need it.
These are all export option settings
and can be modified using the options keyword
at the top of the doc.
The manual is really your friend here,
as there are a ton of export options.
Now when we export the document again,
it should look a lot better.
Now that we've cleaned up the look of the exported document,
we'll take a look at a better way
of solving the problem with the introduction.
Thinking like a programmer for a moment,
what I really want here is a way of specifying a constant.
Rather than hard-coding the name "Debian" or "RedHat"
or whatever into my document,
I want to substitute that text with a symbolic constant,
named something like "distro", that can dynamically change
to "Debian" or "RedHat" or "Slackware" or whatever,
depending on how the document is configured.
In the past, I've come up with some pretty cumbersome ways
of doing this, but eventually I stumbled upon the idea
of using Org-mode properties
as a way of storing these constants.
Like it says in the docs, properties are key-value pairs
that are associated with an entry
and they live in a collapsible properties drawer.
Let's do a bit of cleanup on our document
and we'll put things into sections.
We'll also add a section for document constants.
And that's where we'll put the properties drawer
with the "distro" property.
Now the question is,
how do we reference these properties in the document?
It turns out there's an Elisp function
called `org-property-values`, which does what we want.
If we run it and give it the name of our property,
it returns a list with the string "Debian" in it.
It's worth noting that this function is named
`org-property-values` with values being plural.
In org-mode, there could be a property named "foo"
that has different values depending on which heading level
you're at in the document,
which is why the function returns a list.
For our purposes though,
we can just pull off the first value in the list with car
and we're good to go.
Now we'll make an Emacs Lisp list function called `get_prop`
that does just that.
This function takes one argument called `prop`,
which is the property to look up
and we'll give it a default value of "distro".
So we can hit `C-c C-c` on the block
to verify that it works.
Now we just have to make an inline call
to our `get_prop` function
within the prose of the introduction section.
And that should get us much closer
to not hard coding distro names into our document.
But before we do that,
I need to clean up something that's been bothering me.
By default, Emacs' `fill-column` variable
is set to 70 characters,
which may have been appropriate for 1970,
but it's not great for 2023.
We'll just cruise up to our startup block
and set the variable there.
We'll hit `C-c C-c`,
and now our document will wrap at 100 columns,
which for our purposes, I think is much more reasonable.
The org-mode syntax for making an inline function call
within the prose of your document is `call_`,
followed by the name of the function,
some optional header arguments,
and then the function arguments.
Now, when we export the document,
we see that it's replaced our previously hard coded "Debian"
with the value from the property. Huzzah!
Now this is close to, but not exactly what we want.
You can see that "Debian" is surrounded by a backtick
and a single quote,
which is the plain text exporters way
of showing you verbatim text.
In more sophisticated document backends,
verbatim text is rendered in monospace.
We can fix that by adding a ":results raw" header argument
to the inline call.
Now, when we export the document,
it looks like what we'd expect.
Now this is getting better, but it's still not great.
The `call_` syntax is pretty cumbersome,
and it's a lot to type every time we want
to reference a constant
and not have it be marked up as verbatim.
This is where org-mode macros come to our rescue.
If we head to the top of the document,
we can create a couple of macros
using the `#+MACRO:` export keyword.
We'll define two macros with short names.
One named "p" for "property",
and the other one named "pr" for "property raw".
Org-mode macros are expanded when the document is exported,
and any positional arguments provided
are referenced by their number.
Now in the introduction,
we can use the macro replacement syntax,
which is three curly braces,
followed by the macro name and any arguments,
and then three ending curly braces.
You see why I kept the macro name short.
That's six curly braces in total we're typing,
which still takes up a fair amount of space.
Now let's take a look at how we might use
these properties in practice.
Debian and RedHat distros differ
on how they install packages.
So we're gonna want an "install" property,
where in Debian we use `sudo apt-get install -qq`,
and on RedHat we'll use something like
`sudo dnf install -y`.
Now development packages
also have a different naming convention.
For example, the `ncurses` library on Debian
is called `libncurses-dev`,
where on RedHat it's called `ncurses-devel`.
There are likely going to be
many more little differences like this
that we'll need to solve with properties.
Now I already don't like where this is going.
Switching between the Debian and RedHat
versions of the document is gonna mean
commenting and uncommenting out
a bunch of different properties,
which is pretty janky.
Luckily we can solve this problem
with a little bit of Emacs Lisp.
We'll start by modifying our properties,
so their property names are prefixed
with either `deb_` or `rh_`
to signify which distro the property applies to.`
We'll also create a single property called "prefix",
which will be prepended to the property name
by the `get_prop` function
if the requested property is not found.
This way, when we want to switch between
the Debian and RedHat versions of the document,
we just need to change the prefix property.
So now we'll change the Elisp code.
So we'll use a let expression with two bound variables.
The first one is called ret,
which determines if the initial call
to `org-property-values` succeeds.
The second variable is called prefix,
which is the prefix property.
If the first call to `org-property-values` succeeds,
we return it as normal.
If not, we concatenate the property value
that was passed into the function
onto the prefix and try again.
Now when we call the `get_prop` function with "distro"
as the prop argument, it won't be found.
So the code will slap our prefix tag on the front,
making it something like `rh_distro`,
and it will be found and returned.
Let's see that in action.
All right, now we're talking.
This setup is starting to look pretty good,
but there are just a few things
that I want to add before we move on.
First of all, I think the document should have a subtitle,
something that tells you if you're looking at the RedHat
or the Debian version of the document.
I also think it would be great
if the file name of the exported document
reflected the distribution as well.
I also want to add a quick Debian only section
to the document that explains how it got its name.
Now let's see what happens when we export the document.
This did not work out as we wanted.
As you can see, the macro we used in the subtitles
didn't expand properly,
and as a result, our subtitle didn't render right.
Sadly, you can't use macros
or inline function calls everywhere.
And one place where they don't work
is inside of certain export keywords.
So we're gonna have to hard code them here.
Another mistake that we made is we forgot to update
the `#+EXCLUDE_TAGS` export keyword,
because with the RedHat version of the document,
we want to exclude the Debian tag.
Now when we export the document,
everything should be correct.
The word RedHat should appear in the subtitle,
and the Debian fun fact section should not be present.
Now we just need to add a section to the README
that explains the steps you need to take
in order to switch the document
from RedHat to Debian.
Okay, let's see here.
We have to change `#+SUBTITLE`, change the `#+EXCLUDE_TAGS`,
change the `#+EXPORT_FILE_NAME`,
and change the `prefix` property.
This is OK, but it's not great.
Emacs Lisp can once again come to our rescue.
What we'll do is make an Elisp code block
that will invite the user to hit `C-c C-c` on.
And the code block will essentially make all these changes
in the document for them.
This code block, which we'll call `switch_distro`,
takes one argument called `os`,
which by default is set to "Debian".
It starts out with a let expression
that defines three bound variables.
The `debian` variable is a boolean that is true
if the distro we're switching to is Debian.
Based on the value of this boolean,
we'll set the `noexport` and `prefix` variables accordingly.
The `save-excursion` block tells Emacs
that we're going to be moving around in the document
and to remember to put our point back where we started
when the block finishes.
After that, we essentially go to the top of the document
and search and replace the subtitle, `exclude_tags`,
`export_file_name`, and the `prefix`.
Pretty cool.
Let's see this in action.
If we hit `C-c C-c` on this block,
we should see the document automatically change a bit.
And now when we export it,
we get the Debian version of the doc.
If we want to change it back,
we can just head back over to the code block
and change the default value for the os variable
from "Debian" to "RedHat" and hit `C-c C-c` again.
And now when we re-export,
we're looking at the RedHat version of the document.
Just as an aside, if you ever thought to yourself,
"I should learn Emacs Lisp someday"
Make it someday soon. You'll be happy you did.
Not only is it a fun programming language,
but you can do powerful things with it in Emacs,
which I hope is a point that folks take away from this talk.
All right, that was a lot.
Now that we've spent the past 20 minutes or so
digging into some of the tips and tricks I used
when creating my build Emacs from source document,
we'll say goodbye to this document we've been working on
and we'll start a tour
of the actual literate document I wrote.
A document that I'll demonstrate actually downloading
and building a new Emacs when I export it
on both my Ubuntu and RedHat virtual machines.
I'll also show you how org-mode can generate
slick professional looking PDF files
through the power of LaTeX.
We'll start here at the orgdemo2 directory,
which I've cloned from GitLab.
This repository has all the source materials for this talk.
The buildemacs.org file is where most of the good stuff is.
So that's where we'll start.
There's a lot of file-local variables
that we'll need to confirm.
So we'll do that too.
So the first thing we're gonna do
is hit `C-u TAB` twice,
which will give us a top-level overview
of all of our headings.
As you can see, we've got a lot
of the same familiar export keywords we had before.
`#+TITLE`, `#+SUBTITLE`, `#+AUTHOR`, `#+EMAIL`,
plus a few we haven't seen before.
For example, I've squirreled away
a lot of the `#+LATEX_HEADER` export keywords
in this file called latex.setup.
And I did this just so they don't clutter up the document.
Much of the LaTeX magic
that makes the exported document look good
is in these headers.
LaTeX commands begin with a backslash.
And a common one we use a lot here is `\usepackage`.
This lets us bring in packages like geometry,
svg for the cool SeaGL SVG logo,
`fancyhdr` and fancy verbatim [`fancyvrb`]
to keep things looking pretty fancy.
Using a scalable vector image format
makes it possible for us to do really cool things
like having a scaled-down version of the SeaGL logo
appear in the fancy footer below.
I also include some macros in a separate file
just to help keep things tidy in the main document.
Here I've got the familiar macros
we've seen before for `get_prop`.
But here I use different permutations
depending on if I want results raw
or raw verbatim or just verbatim.
I also have a couple of macros here at the top of the file
that are for pulling strings out of results blocks
and then trimming them
so there's no white space on either side.
Like in the version of the document
we worked on at the start of this talk,
the real document also has a README section
marked with the `:noexport:` tag.
It also has a section about choosing
which version of the document to export
and a code block on how to switch between them.
It's also got a lot of helpful information in it
like what OS and Emacs versions
the document has been tested to "run" on,
a section on the LaTeX prerequisites
and the section on executing
the document's various code blocks.
The latter two sections we'll take a look at now.
Out of the box on Fedora and Ubuntu server distros,
the TeX typesetting system
also by noted computer scientist Donald Knuth
is not installed.
So we'll need to install some packages.
Starting out we'll need the `texlive` package
which gets you a fully featured TeX setup.
This also gets you LaTeX
which can be viewed as a distribution of TeX macros.
You'll also need XeTeX.
This gets you Unicode support and lets you use modern fonts.
We'll also want to install pdfTeX.
This gets us the ability to generate PDFs from TeX sources.
And finally, we're gonna need to install latexmk
which is a Perl script
that knows how to run LaTeX multiple times
in order to properly deal with intra-document links.
But wait, there's more.
We're also gonna need Inkscape
to rasterize our SeaGL vector logo
at different resolutions.
And we're gonna need the JetBrains Mono font
to make our source code look snazzy.
We'll also need the Inter font
to make our prose look snazzy as well.
I've helpfully added a bash code block in the README
that you can hit C-c C-c on to install.
This really does lock up Emacs for a few minutes
and it's sort of annoying.
When we export the document and turn off all caching
and it actually builds Emacs for real,
Emacs can be locked up for tens of minutes.
There's a package called ob-async
that I've been meaning to check out that might help here.
But since I wanted this document
to work on bog-standard Emacs setups,
I didn't get around to it.
Before we get into talking about running the document,
let's talk briefly about results caching.
We'll take a look at the section of the document
where we talk about Git tags for an example.
The `num_tags` bash code block determines
how many tags there are in the Emacs Git repo.
And when I hit C-c C-c on that block
several days ago, when I was first creating the document,
that number was 183.
That result has remained cached in the document since then.
And you can see a snippet of the SHA1 hash
of the contents of the source block below.
You can see where I referenced the result
using the `sr` for string raw macro in the prose below,
and how it gets rendered in the exported PDF document.
All the source blocks in the exported sections
of the document include cached results like this.
If I export the document now, it won't take that long to do
because while there are a ton of code blocks
in the exported sections, they're all cached.
Now let's get back to the section of the README
that explains how to execute the code in the document.
Here I explain that if you want to build Emacs
on your computer using this document,
you've got a couple of options.
The first option is to manually invalidate the caches
and take C-c C-c on every code block
in the main document.
This lets you supervise the entire process,
and it also creates new cached result blocks,
but it's time consuming.
There is also an internal link to the main document here,
and you can jump to it with C-c C-o.
This is one of those intra-document links
that is really tricky to get right with LaTeX,
and is why we opted to use the latexmk Perl script
to build the PDF version of the document.
I'm mentioning it specifically here
because it took me forever to figure this out.
The second option you've got
is to change the default header arg
from `:cache yes` to `:cache no` at the top of the document.
If we cruise up to the top of the document,
you can see that this header argument property
basically says that unless a code block
explicitly says otherwise,
it's by default supposed to be cached.
That's how we were able to export the document
before so quickly.
The code block named `no_cache_no_confirm`
uses the `save-excursion` and regex replace trick
that I demonstrated earlier
to munch the default cache header arg
from "cache yes" to "cache no".
And it also turns off confirmations on bash code blocks.
Let's do that now.
Now we'll export the document to PDF,
which will ignore the cache result blocks
and clone the Git repository on Savannah,
create a branch that points
to the most recently tagged version of Emacs 29,
run configure a handful of times,
installing packages to fix missing dependencies
along the way,
build Emacs, install Emacs in our home directory,
verify that it has successfully built a binary,
run it in batch mode with some sample Elisp
and show the file sizes and dates of the generated files.
This is gonna take a while.
And while it's running, we'll pop over to our Fedora box.
All right, now we'll fire up Emacs,
hit `C-c C-c` on the `configure_document` code block
to configure the document for RedHat
since Fedora here is a RedHat based distro.
Then what we'll do is we'll pop down
and hit `C-c C-c`
on the `rh_install_latex` code block
to install the LaTeX prerequisites
for this Fedora virtual machine.
Finally, we'll execute the `no_cache_no_confirm` block
and then kick off the export.
Then we'll go and check back on what's happening
on the Ubuntu box.
Ooh, top looks pretty quiet.
I think the export is complete.
Ooh, those are the words I love to see in the status area,
PDF file produced!
Now I can't use my web browser
to take a look at this PDF file
because I haven't set up a web server
or anything like that on the Ubuntu virtual machine.
I can, however, use TRAMP with the ssh method
to poke around on the ubuntu host
on my personal version of Emacs.
So let's do that.
Okay, so now if we go into the source directory
and then we hop into the orgdemo2 directory
and then we look at the deb version of the PDF,
there she blows.
Now, if we go down to the Building Emacs section,
we can see that it built.
And if we look in the bin directory,
we can see that at 17:01,
that's when all of those files got created.
Also the file creation date on the PDF is 17:01.
So all of this code executed roughly the same time
the PDF was created.
All right, so now let's head back over to the Fedora box
and then we'll navigate to the source directory,
the orgdemo2 directory,
and there is our RedHat version of the built Emacs PDF.
And Bob's your uncle.
And you can see it is the RedHat version of the document
because this is a RedHat box.
And if we go over to the What did we install? section,
you can see that these binaries were built at 17:35.
And now if we pop open dired
and we take a look at the PDF,
we can see it also was created at 17:35.
All right, in the couple minutes remaining,
I thought it would be a good idea
just to take a look at the document
and maybe just go through some of what it actually does
in explaining how to build Emacs from source.
We'll look at the RedHat version since we're here.
And the first thing you do is
you have to get access to the source code.
And before you can do anything,
this is a RedHat-specific section
where you need to install some development tools.
And this development tools group actually has Git.
Now I installed Git earlier, but if you didn't do that,
that would be the first thing that you need to do.
We create a source directory, we cd into it,
we clone the repo from Savannah.
And then we start to take a look at some of the Git tags.
And we showed this before where we check out
how many different tags there are.
And then we run this kind of funky Git command
to sort of list all the tags that begin with 'emacs-29',
and we sort them by when they were tagged.
So we can see that Emacs 29.1.pretest
is the most recent version.
So that's the one we grab
and that's the one we decide to build.
And then we create a branch that is based on this tag.
And this is dynamically generated based on what we saw here.
So that's what we use here.
In this case, we're piping standard error
to where standard out goes.
That's another trick.
If you want to actually see an error get created,
org-mode will capture any errors that code blocks produce,
and it will show you the error message in a buffer.
So if you actually wanna show what it looks like
when something errors out, this is the trick you have to use.
And then what we do is we look for a configure script
and there isn't one.
And then we realize,
uh-oh, we're gonna have to deal with autotools.
So, you know, we run the autogen script and it complains
because we're missing some prerequisites.
So we have to install autoconf,
and then we run it again,
and finally it generates a configure script.
And this is another case where I pull this number
right here into the actual prose.
And I can see it's, oh, it's, you know, this how many bytes.
When was the last time you wrote a shell script
that was this many bytes long?
And then we configure the build process.
And, you know, it's not gonna work right away
because we don't have GNU Texinfo installed.
So we gotta do that, which we do with `dnf install` here.
And then there's this section that is either RedHat-
or Debian-specific that talks about, like,
if you don't know the name of a package
that contains a given file name, how do you query it?
And in the RedHat world, you use `dnf provides makeinfo`.
In the Debian world, you do something entirely different.
And then we have to install the `ncurses` binary.
And finally we get like a minimal configuration
and you can see that there's a whole bunch of nos here.
So, you know, we don't have cairo,
we don't have imagemagick, we don't have dbus,
you know, there's a whole bunch of stuff we don't have.
We don't have X, we don't have libjansson, no tree-sitter.
This is really a bare-bones Emacs
that is strictly terminal mode.
Then we actually build Emacs, which is, you know,
kind of boring, we're just gonna type make
and then make is gonna run successfully.
And make is gonna spew a ton of output, right?
So here's where I do that /dev/null trick,
where I pipe everything to /dev/null
and then I, or I pipe standard output to /dev/null
and then I pipe standard error
to wherever standard output's going.
And then at the end to say that it ran successfully,
I say "Make ran successfully!"
Then we take a look at the Emacs binary
and you know, it's an elf binary.
And, you know, because this is running on my Mac,
this is an ARM-based machine, this virtual machine is.
Oops, and this is a bug.
This really should be a macro call,
but I think I have the wrong number of curly braces
or something in there.
I need to figure out why that's not right.
I'll look into that later.
And then we install Emacs and then we kind of show
like the file sizes of everything in the home directory.
And then we, you know, show the binaries that got installed.
Anyway, so this is the final thoughts section.
And my final thoughts are, is I hope you enjoyed this talk
and I hope you actually learned a thing or two.
All right, thanks everybody.
And I'll see you all next time.