0

I've been a bit stuck getting labels to work properly with org-mode. Preferably, I want to use my own labels over anything that org generates, so I naturally enable this in my personal configuration: (setq org-latex-prefer-user-labels t).

However, I cannot seem to get this to work on a file-local level. E.g., say that I have the org-file and corresponding makefile:

# -*- org-latex-prefer-user-labels:t -*-
#+TITLE: Test Doc

#+STARTUP: org-latex-prefer-user-labels t
#+OPTIONS: org-latex-prefer-user-labels t
#+BIND: org-latex-prefer-user-labels t
#+PROPERTY: org-latex-prefer-user-labels t


* Test

  This is a test: \ref{fig:needed}.

   
#+CAPTION: Expecting to place a figure here.
#+LABEL:   fig:needed
[[./needed.pdf]]

all: test.pdf
%.pdf: %.org
    emacs --batch --visit=$< --eval='(org-latex-export-to-pdf)'

Now, the Emacs invocation that make runs will always report undefined references, so clearly org-latex-prefer-user-labels never gets set properly when the exporter is run despite numerous different tags (and combinations of them).

So, what is the correct way to specify this variable (and other, general variables) such that the exporter picks them up when run in batch-mode from e.g., a makefile?

2 Answers 2

1

This has to do with lexical binding: file local variables are set using the function hack-one-local-variable which uses (set (make-local-variable var) val) to set it. But set and lexical binding don't play well together (apparently - my understanding is rudimentary and incomplete, but see this answer by @phils).

Since you cannot use file local variables to do your bidding, you will have to modify the command line to do explicitly what you want. The following works for me:

%.pdf: %.org
    emacs --batch --visit=$< --eval="(progn (require 'ox-latex) (let ((org-latex-prefer-user-labels t)) (org-latex-export-to-pdf)))"

The require loads the ox-latex library where org-latex-prefer-user-labels is defined as a defcustom (and therefore a special dynamically bound variable). Then you can let-bind the variable around the call to org-latex-export-to-pdf and it will take effect.

Unfortunately, lexical binding seems to make file local variables (and probably the #+BIND: mechanism) ineffective when you use --eval from the command line.

All of this is AFAIK and to the best of my knowledge. I'm sure there's more to it.

1

@NickD's answer above works well and have received my vote, but I did eventually come back to this and found another way to achieve the same thing that is a bit more scalable for more options: Create a configuration section in the document:

#+TITLE: Test Doc

* Export Configuration                                   :noexport:

#+begin_src emacs-lisp :results output :session :exports both
  (setq org-latex-prefer-user-labels t)
#+end_src

* Test

  This is a test: \ref{fig:needed}.

   
#+CAPTION: Expecting to place a figure here.
#+LABEL:   fig:needed
[[./needed.pdf]]
#+end_example

Note the :noexport: tag to avoid exporting that section, while still evaluating the contained configuration blocks.

Then set (setq org-confirm-babel-evaluate nil) in the makefile to avoid having to confirm the block evaluation each time (You control the source, so naturally it is safe to evaluate):

all: test.pdf
%.pdf: %.org
    emacs --batch --visit=$< --eval='(progn (setq org-confirm-babel-evaluate nil)(org-latex-export-to-pdf))'

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.