Is it possible to "relocate" my ~/texmf/ directory?

If you issue the shell command

cat $(kpsewhich texmf.cnf)

(bash syntax, adapt to your shell way to do command substitution) you should see

% (Public domain.)
% This texmf.cnf file should contain only your personal changes from the
% original texmf.cnf (for example, as chosen in the installer).
%
% That is, if you need to make changes to texmf.cnf, put your custom
% settings in this file, which is .../texlive/YYYY/texmf.cnf, rather than
% the distributed file (which is .../texlive/YYYY/texmf-dist/web2c/texmf.cnf).
% And include *only* your changed values, not a copy of the whole thing!
%
TEXMFHOME = ~/texmf
TEXMFVAR = ~/texlive/2018/texmf-var
TEXMFCONFIG = ~/texlive/2018/texmf-config

(this is what you get on standard Unix boxes, there is /Library after ~ with the MacTeX version of TeX Live).

If the start of the file you get is different, namely

% original texmf.cnf -- runtime path configuration file for kpathsea.

then your system doesn't have a top level texmf.cnf file. No problem.

All it takes is to launch

sudo nano $(kpsewhich -var-value TEXMFROOT)/texmf.cnf 

(use whatever method you use for getting superuser privileges and whatever editor you prefer). If you are in the no-top-level-texmf.cnf situation, you will see an empty file.

Add or change the TEXMFHOME line to what you wish. Perhaps also the other lines, if you also want to move texlive to a hidden place.

Then rename or move the relevant directories to the correct place.

Explanation. The file resides at the top level of the TeX Live distribution, namely at

/usr/local/texlive/2018/texmf.cnf

and it is the first configuration file read by kpse library linked programs (all those in the TeX family); other files with the same name are read in during initialization, but values of (pseudo)enviroment variables are never overridden by subsequent files. Setting personal preferences in that file is actually the recommended method.


I had written most of this answer more or less a month ago, but I hadn’t found the time to complete it until now.


Shorter Answer

Elaborating on what I’ve already said in a comment, in my humble opinion the best way to achieve literally what the question asks for depends on whether you are a generic, unprivileged user trying to relocate just your own ~/texmf/ directory, or an administrator who wants to set a different location for the ~/texmf/ directory of all users of a given host.

Generic user who wants to relocate only her/his own directory

Add a line to your .profile, .bashrc, or whatever configuration file your shells reads during initialization a line that creates an environment variable (not just a shell variable) named TEXMFHOME and sets its value to the path that should be used instead of ~/texmf. For example, for a Bourne shell you might add to your .bashrc file a line that says

export TEXMFHOME='~/.some/hidden/place/texmf'

(note that quoting has been used to prevent tilde expansion from being applied by the shell itself).

Administrator who wants to relocate all users’ directories

Let’s assume that your TeX Live distribution for 2018 is located in

/some/path/to/texlive/2018

which amounts to saying that the above path is what you get in reply to the command

kpsewhich -var-value TEXMFROOT

(normally, the reply to this command will be

/usr/local/texlive/2018

which amounts to saying that the above path is where TeX Live 2018 is normally installed on Unix-like systems); then, the parent directory

/some/path/to/texlive

is likely to contain other subdirectories, one for each distribution of a previous year you are still retaining, plus one additional subdirectory named texmf-local (for example, on my machine, the directory

/usr/local/texlive

contains the following subdirectories

2014/
2015/
2016/
2017/
2018/
texmf-local/

with old distributions going back to that of 2014). In any case, acquire root privileges and create a (text) file with full pathname

/some/path/to/texlive/texmf-local/web2c/texmf.cnf

also creating, if necessary, any missing directory along the path (for example, on the machine I’m using now I’d create a file with full pathname

/usr/local/texlive/texmf-local/web2c/texmf.cnf

but on some other machine of mine I wouldn’t need to, because I already did so a few years ago). Open that file for editing and write the following line into it:

TEXMFHOME = ~/.some/hidden/place/texmf

Save the file. That’s all: TeX Live will now look inside ~/.some/hidden/place/texmf/ (and the sub-sub-…-directories thereof) for anything it would have previously searched inside ~/texmf/ (and the sub-sub-…-directories thereof). Don’t forget to instruct users to move their personal texmf tree in the new location!

Comments and caveats

Following this strategy, you won’t need to reapply your customization every time you switch to a new distribution—that is, every year—which, as I remarked in a comment, is a small drawback of the other answer. Indeed, you might want to add other lines to your new file

/some/path/to/texlive/texmf-local/web2c/texmf.cnf

in order to specify some other customization you want to apply on a “all-user, all-year” basis; for example, on some machines (not on this one) I keep, as I’ve already said, a file

/usr/local/texlive/texmf-local/web2c/texmf.cnf

which contains the line

file_line_error_style = t

(possibly among others).

This strategy too, however, is not immune from defects, which are discussed in the longer answer that follows.


Longer Answer (and Explanation)

The path to the root of the “personal” texmf tree, or, more precisely, the value of TEXMFHOME, is specified (of course!) in the same way as any other path, that is, as documented in the Kpathsea manual, Section 5.2 Path Sources, by looking it up in the following sources of information:

  1. A user-set environment variable, e.g., TEXINPUTS. Environment variables with an underscore and the program name appended override; for example, TEXINPUTS_latex overrides TEXINPUTS if the program being run is named latex.

  2. A program-specific configuration file, e.g., an S /a:/b line in Dvips’ config.ps (see Config files in Dvips).

  3. A line in a Kpathsea configuration file texmf.cnf, e.g., TEXINPUTS=/c:/d (see below).

  4. The compile-time default (specified in kpathsea/paths.h).

These sources are queried in turn, in the stated order, and earlier definitions override later ones; moreover, a higher-priority source can “import” a lower-priority one via a mechanism known as “Default Expansion”, which we are not going to describe here (interested readers are referred to Subsection 5.3.1 Default Expansion of the above-cited manual)

Given the above information, you may think that the easiest way to achieve what the question asks for is, perhaps, to set (and export) an environment variable named TEXMFHOME in your .profile/.bashrc/etc. file. There are some caveats, though:

  • The configuration files in the TeX Live distribution define a few other path variables that should be kept “in sync” with TEXMFHOME, but that, notwithstanding this, are not defined in terms of the latter; for example, on my machine (a Mac with MacTeX installed), the file located at

    /usr/local/texlive/2018/texmf.cnf
    

    reads as follows:

    % (Public domain.)
    % This texmf.cnf file should contain only your personal changes from the
    % original texmf.cnf (for example, as chosen in the installer).
    %
    % That is, if you need to make changes to texmf.cnf, put your custom
    % settings in this file, which is .../texlive/YYYY/texmf.cnf, rather than
    % the distributed file (which is .../texlive/YYYY/texmf-dist/web2c/texmf.cnf).
    % And include *only* your changed values, not a copy of the whole thing!
    %
    TEXMFHOME = ~/Library/texmf
    TEXMFVAR = ~/Library/texlive/2018/texmf-var
    TEXMFCONFIG = ~/Library/texlive/2018/texmf-config
    

    Obviously, TEXMFVAR and TEXMFCONFIG should be kept “synchronized” with TEXMFHOME. (At this point, the attentive and knowledgeable reader has probably already spotted the source of the trouble…)

  • You might want to consider quoting the values assigned to environmental variables within a shell script in order to prevent premature expansion by the shell itself.

Following this line of thought, the next option is, of course, to have the desired value of the TEXMFHOME (and, one might feel inclined to add, of the other “synchronized” variables, TEXMFVAR and TEXMFCONFIG) specified in a configuration file, which, in this case, can only be one of the several texmf.cnf files. We say “the several” because the Kpathsea library can read more than one such file, and actually does so in typical situations. Quoting from Subsection 5.2.1 Config files of the manual,

[…] Kpathsea reads runtime configuration files named texmf.cnf for search path and other definitions. The search path used to look for these configuration files is named TEXMFCNF, and is constructed in the usual way, as described above [items 1–4], except that configuration files cannot be used to define the path, naturally; also, an ls-R database is not used to search for them.

Kpathsea reads all texmf.cnf files in the search path, not just the first one found; definitions in earlier files override those in later files. […]

In practice, the first of the two paragraphs just quoted means that TEXMFCNF (which, we repeat, is the search path for the configuration files themselves) is defined either in an environmental variable, or by the compile-time default. Let the former alternative alone, and let’s concentrate on the search path specified at compile-time: as the manual says, this is defined in kpathsea/paths.h; inspecting that file, we find that the definition of DEFAULT_TEXMFCNF reads (I’ve broken it up into separate lines for readability):

#ifndef DEFAULT_TEXMFCNF
#define DEFAULT_TEXMFCNF "{$SELFAUTOLOC,\
  $SELFAUTOLOC/share/texmf-local/web2c,\
  $SELFAUTOLOC/share/texmf-dist/web2c,\
  $SELFAUTOLOC/share/texmf/web2c,\
  $SELFAUTOLOC/texmf-local/web2c,\
  $SELFAUTOLOC/texmf-dist/web2c,\
  $SELFAUTOLOC/texmf/web2c,\
  $SELFAUTODIR,\
  $SELFAUTODIR/share/texmf-local/web2c,\
  $SELFAUTODIR/share/texmf-dist/web2c,\
  $SELFAUTODIR/share/texmf/web2c,\
  $SELFAUTODIR/texmf-local/web2c,\
  $SELFAUTODIR/texmf-dist/web2c,\
  $SELFAUTODIR/texmf/web2c,\
  $SELFAUTOGRANDPARENT/texmf-local/web2c,\
  $SELFAUTOPARENT,\
  $SELFAUTOPARENT/share/texmf-local/web2c,\
  $SELFAUTOPARENT/share/texmf-dist/web2c,\
  $SELFAUTOPARENT/share/texmf/web2c,\
  $SELFAUTOPARENT/texmf-local/web2c,\
  $SELFAUTOPARENT/texmf-dist/web2c,\
  $SELFAUTOPARENT/texmf/web2c}"
#endif

Indeed, this corresponds exactly to what I get on my machine if I issue the shell command

kpsewhich -var-value TEXMFCNF

The answer I get is (again, split up into lines for readability):

{/usr/local/texlive/2018/bin/x86_64-darwin,
  /usr/local/texlive/2018/bin/x86_64-darwin/share/texmf-local/web2c,
  /usr/local/texlive/2018/bin/x86_64-darwin/share/texmf-dist/web2c,
  /usr/local/texlive/2018/bin/x86_64-darwin/share/texmf/web2c,
  /usr/local/texlive/2018/bin/x86_64-darwin/texmf-local/web2c,
  /usr/local/texlive/2018/bin/x86_64-darwin/texmf-dist/web2c,
  /usr/local/texlive/2018/bin/x86_64-darwin/texmf/web2c,
  /usr/local/texlive/2018/bin,
  /usr/local/texlive/2018/bin/share/texmf-local/web2c,
  /usr/local/texlive/2018/bin/share/texmf-dist/web2c,
  /usr/local/texlive/2018/bin/share/texmf/web2c,
  /usr/local/texlive/2018/bin/texmf-local/web2c,
  /usr/local/texlive/2018/bin/texmf-dist/web2c,
  /usr/local/texlive/2018/bin/texmf/web2c,
  /usr/local/texlive/texmf-local/web2c,
  /usr/local/texlive/2018,
  /usr/local/texlive/2018/share/texmf-local/web2c,
  /usr/local/texlive/2018/share/texmf-dist/web2c,
  /usr/local/texlive/2018/share/texmf/web2c,
  /usr/local/texlive/2018/texmf-local/web2c,
  /usr/local/texlive/2018/texmf-dist/web2c,
  /usr/local/texlive/2018/texmf/web2c}

Let’s spend a couple of minutes to understand exactly why the above two listings agree, because something important is involved here.

First of all, I haven’t set TEXMFCNF in my environment, so what I’m getting is indeed the compile-time default. (Note: As a matter of fact, this is not true, because the main texmf.cnf file of TeX Live, that is, /usr/local/texlive/2018/texmf-dist/web2c/texmf.cnf, actually redefines the TEXMFCNF variable; but it is a white lie, since this redefinition agrees completely with the compile-time default.) That being said, the key point is to understand how the (pseudo-?) variables SELFAUTOLOC, SELFAUTODIR, SELFAUTOPARENT, and SELFAUTOGRANDPARENT are interpreted; their meaning is always relative to the position of the executable file that has invoked the Kpathsea library (e.g., pdftex, pdflatex, tex, but also kpsewhich); more precisley:

  • SELFAUTOLOC expands to the path to the directory that contains the executable;

  • SELFAUTODIR expands to the parent directory of the directory that contains the executable;

  • SELFAUTOPARENT expands to the parent directory of the parent directory of the directory that contains the executable;

  • SELFAUTOGRANDPARENT expands to the parent directory of the parent directory of the parent directory of the directory that contains the executable.

A bit confusing, isn’t it? It’s better to use an example: let’s say that the executable file resides inside

/usr/local/texlive/2018/bin/x86_64-darwin/

(as it is on my machine); then:

  • SELFAUTOLOC expands to

    /usr/local/texlive/2018/bin/x86_64-darwin
    
  • SELFAUTODIR expands to

    /usr/local/texlive/2018/bin
    
  • SELFAUTOPARENT expands to

    /usr/local/texlive/2018
    
  • SELFAUTOGRANDPARENT expands to

    /usr/local/texlive
    

(Much clearer, I’d say.) You can now return to the two listings given above, and amuse yourself by checking that each line of the first expands precisely to its corresponding line in the second.

Note an important detail: being relative to the location of the executable, the above expansions work correctly even if the whole texmf tree is moved to a different location (perhaps on a removable media, like a USB stick).

Armed with this knowledge, let’s focus on the particular use that the TeX Live distribution makes of all this machinery. Usually, only two items of the compile-time default are exploited by TeX Live, namely

$SELFAUTOPARENT

and

$SELFAUTOPARENT/texmf-dist/web2c

The latter is the “original” texmf.cnf file being distributed; the former (that, remember, takes precedence) is provided to allow host-specific customization. By way of example, the MacTeX distribution uses the $SELFAUTOPARENT entry to customize the location of the personal texmf tree (TEXMFHOME), moving it inside the Library/ subdirectory of the user’s home folder. This may make this file look like the natural place to turn to in order to solve the OP’s problem, as @egreg has already suggested; but there are a couple of issues you should be aware of:

  1. This solution (as any other based on configuration files) applies on a per-host basis, that is, to all users of a given machine.

  2. Because SELFAUTOPARENT expands to a directory name that embodies the year of the distribution, you’ll need to re-apply your customization when you update your distribution: indeed, in a new distribution the location of the executable will change, and, with it, the value of SELFAUTOPARENT.

Point 1 can be a problem or a feature, depending on the circumstances. As for point 2, a remedy is—or seems to be—readily available: if you go back to the listings extracted from kpathsea/paths.h, you’ll notice, among the entries that precede the two ones used by TeX Live, one that looks particularly appealing:

$SELFAUTOGRANDPARENT/texmf-local/web2c

which typically expands to

/usr/local/texlive/texmf-local/web2c

(“Aha!”—you might be thinking); and indeed, this is where, sometimes (that is, on some machines, but not on this particular one), I keep a third texmf.cnf file, containing the patches I want to apply on a “per-host, but all-year” basis. Well, if you create a file in this location, that is, having full pathname

/usr/local/texlive/texmf-local/web2c/texmf.cnf

and whose contents look like this

TEXMFHOME = ~/.SomeHiddenPlace/texmf

you are changing, in the stated way, the location of the personal texmf tree of all users on your machine, and this change will be permanent across distributions. This is exactly what the title of the question asks for; however, an issue remains, that we have already touched upon above, and that proves unexpectedly difficult to solve, in full generality, by similar means.

We already remarked that there are (at least) two other paths into the personal tree that one would reasonably want to keep “synchronized” with TEXMFHOME, those corresponding to the two variables TEXMFVAR and TEXMFCONFIG. Their default definition (i.e., their definition in the “original” texmf.cnf file of TeX Live) is

% TEXMFVAR, where texconfig/updmap/fmtutil store cached runtime data.
TEXMFVAR = ~/.texlive2018/texmf-var

% TEXMFCONFIG, where texconfig/updmap/fmtutil store configuration data.
TEXMFCONFIG = ~/.texlive2018/texmf-config

It seems reasonable that, if one wishes to convert

TEXMFHOME = ~/texmf

into

TEXMFHOME = ~/.SomeHiddenPlace/texmf

in the same way the same person might want to have TEXMFVAR and TEXMFCONFIG moved in parallel, in order to reduce clutter in her/his home directory:

TEXMFVAR = ~/.SomeHiddenPlace/.texlive2018/texmf-var
TEXMFCONFIG = ~/.SomeHiddenPlace/.texlive2018/texmf-config

In the same way, under MacTeX, one might want to pass from

TEXMFHOME = ~/Library/texmf
TEXMFVAR = ~/Library/texlive/2018/texmf-var
TEXMFCONFIG = ~/Library/texlive/2018/texmf-config

to, say,

TEXMFHOME = ~/Library/TeXStuff/texmf
TEXMFVAR = ~/Library/TeXStuff/texlive/2018/texmf-var
TEXMFCONFIG = ~/Library/TeXStuff/texlive/2018/texmf-config

(although the motivation is much weaker in this case). The problem is that the last two directories should be kept separate in passing from one year to the next; for example, both occurences of 2018, above, should be replaced by 2019 when the 2019 distribution of TeX Live becomes available.

A modest proposal

A possible solution would be to define, in the texmf.cnf file distributed with TeX Live, a new variable that holds the year of the distribution. Let’s assume that this variable is called YYYY; then we could write something like

TEXMFHOME = ~/.SomeHiddenPlace/texmf
TEXMFVAR = ~/.SomeHiddenPlace/.texlive${YYYY}/texmf-var
TEXMFCONFIG = ~/.SomeHiddenPlace/.texlive${YYYY}/texmf-config

in the file

$SELFAUTOGRANDPARENT/texmf-local/web2c

(the typical expansion of which is

/usr/local/texlive/texmf-local/web2c

that is, the file you need not modify when you upgrade your TeX Live distribution to that of a new year) to move the specified directories under .SomeHiddenPlace/ for all the users and all the years to come. Note that this works correctly even if the file that defines the YYYY variable is read by the Kpathsea library after the file where that variable is used; indeed, quoting from Section 5.2.1 of the Kpathsea manual:

All definitions are read before anything is expanded, so you can use variables before they are defined (like Make, unlike most other programs).

The TeX Live team might want to give this proposal some thought.

Tags:

Texlive

Texmf