分类
LaTeX

使用bundledoc打包LaTeX宏包依赖

我遇到过由于宏包不够新导致的latex编译失败。那么有没有办法将我们编译当前文档需要的宏包打包呢?

办法就是使用bundledoc. 我用的texlive2017(脚本位置:E:\texlive\2016\texmf-dist\scripts\bundledoc\bundledoc), 看起来这个宏包有点旧了, 需要修复下。

脚本的修复

P.S. 最新版的bundledoc(2018/05/23, Version 3.3)一下两个问题都已经修复。请直接更新。

首先它是一个perl脚本, 其中有个新建临时目录的函数tmpnam已经弃用了, 这个好像不是非常影响。

# Create a bundled file.
my @dependencies = find_dependencies();
if ($keepdirs) {
    # Put absolute pathnames in the tar file.
    # QUESTIONS: Does this work with multiple drive letters in Windows?
    #            What about UNC names?
    chdir rootdir() || die "${progname}: $! (".rootdir().")\n";
    $ENV{"BDINPUTS"} = join (" ", map {s|^/+||; s/\"//g; "\"$_\""} @dependencies);
    executecmd $uservariable{"bundle"};
}
else {
    # Copy each of the dependencies to a temporary directory and tar it up.
    my $tempdir = tmpnam();
    my $tempdir2 = catfile $tempdir, $docdirname;
    print "CREATING $tempdir\n" if $verbose;
    mkdir ($tempdir, 0777)  || die "${progname}: $! ($tempdir)\n";
    print "CREATING $tempdir2\n" if $verbose;
    mkdir ($tempdir2, 0777) || die "${progname}: $! ($tempdir2)\n";
    foreach my $dep (@dependencies) {
        # If the current dependency is in a subdirectory of the
        # original location, create the same subdirectory in the
        # temporary directory and copy the file there.  Otherwise just
        # copy it to the root of the temporary directory.
        my $targetdir = $tempdir2;
        if (my $sd = $subdirs{$dep}) {
            $targetdir = catfile($targetdir, $sd);
            unless (-d $targetdir) {
                print "CREATING $targetdir\n" if $verbose;
                mkpath($targetdir, 0, 0777) || die "${progname}: $! ($targetdir)\n";
            }
        }
        copy ($dep, $targetdir) || die "${progname}: $! ($targetdir)\n";
    }
    if ($manifest ne "") {
        my $manifest = catfile $tempdir2, $manifest;
        my $manifestdir = dirname $manifest;
        unless (-d $manifestdir) {
            print "CREATING $manifestdir\n" if $verbose;
            mkpath($manifestdir, 0, 0777) || die "${progname}: $! ($manifestdir)\n";
        }
        print "WRITING $manifest\n" if $verbose;
        open (MANIFEST, ">$manifest") || die "${progname}: $! ($manifest)\n";
        print MANIFEST join ("\n", @dependencies), "\n";
        close MANIFEST;
    }
    chdir $tempdir || die "${progname}: $! ($tempdir)\n";
    $ENV{"BDINPUTS"} = "\"$docdirname\"";
    executecmd $uservariable{"bundle"};

    # Clean up our mess.
    # NOTE: We rmtree $tempdir2 and rmdir $tempdir because rmtree
    #       complained on WinNT when trying to remove a top-level
    #       directory (e.g., "\s4r.").
    print "REMOVING $tempdir2\n" if $verbose;
    rmtree $tempdir2, 0, 1;
    chdir (updir());
    print "REMOVING $tempdir\n" if $verbose;
    rmdir $tempdir || die "${progname}: $! ($tempdir)\n";
}
print "FINISHED.\n" if $verbose;
exit 0;

其次, 它的正则表达式{([^\}]*)}不正确, 因为根据*.dep的结构, 我们需要将其改成\\{([^}]*)\\}.

# Find all dependencies listed in the input file.
sub find_dependencies ()
{
    open (DEPFILE, "<$depfile") || die "${progname}: $! ($depfile)\n";
    my $braced = "{([^\}]*)}";   # Regular expression for a braced name
    my @dependencies;            # List of fully-qualified filenames
    @dependencies = qualifyname $texfile;
    while (my $oneline=<DEPFILE>) {
        # Parse an input line into its component fields.
        next if !($oneline =~ /^\s*\*$braced\s*$braced\s*$braced\s*$/);
        my $filetype = $1;
        my $filename = $2;
        my $versioninfo = $3;

        # Extract the subdirectory if one exists.
        my $subdir = dirname $filename;
        my $qname = "";

如果我们只需要将2017年以后的宏包打包, 则可以将上述代码片段改为

# Find all dependencies listed in the input file.
sub find_dependencies ()
{
    open (DEPFILE, "<$depfile") || die "${progname}: $! ($depfile)\n";
    my $braced = "\\{([^}]*)\\}";   # Regular expression for a braced name
    my @dependencies;            # List of fully-qualified filenames
    @dependencies = qualifyname $texfile;
    while (my $oneline=<DEPFILE>) {
        # Parse an input line into its component fields.
        next if !($oneline =~ /^\s*\*$braced\s*$braced\s*\{((2017|2018)[^}]*)\}\s*$/);
        my $filetype = $1;
        my $filename = $2;
        my $versioninfo = $3;

        # Extract the subdirectory if one exists.
        my $subdir = dirname $filename;
        my $qname = "";

脚本的使用

新建test.tex文档如下:

\RequirePackage{snapshot}


Hello world!

这里的关键是需要第一行的\RequirePackage{snapshot}产生宏包依赖列表test.dep. 例如上面的代码产生的宏包依赖列表为:

\RequireVersions{
  *{application}{TeX}     {1990/03/25 v3.x}
  *{format} {LaTeX2e}     {2017-04-15 v2.e}
  *{package}{snapshot}    {2002/03/05 v1.14}
  *{class}  {amsart}      {2017/10/31 v2.20.4}
  *{package}{amsmath}     {2017/09/02 v2.17a}
  *{package}{amstext}     {2000/06/29 v2.01}
  *{package}{amsgen}      {1999/11/30 v2.0}
  *{package}{amsbsy}      {1999/11/29 v1.2d}
  *{package}{amsopn}      {2016/03/08 v2.02}
  *{file}   {umsa.fd}     {2013/01/14 v3.01}
  *{package}{amsfonts}    {2013/01/14 v3.01}
  *{file}   {umsa.fd}     {2013/01/14 v3.01}
  *{file}   {umsb.fd}     {2013/01/14 v3.01}
}

接着, 我们需要在test.tex同目录下创建bundledoc配置文件bundledoc.cfg

# basic config file for use of arlatex + bundledoc
bundle: (arlatex --document=$BDBASE.tex $BDINPUTS | tar -cvf - $BDINPUTS | gzip --best > $BDBASE-all.tar.gz )
sink:   > /dev/null 2>&1
find:   kpsewhich -progname=latex $BDINPUTS

最后, 如果你使用修改后的脚本的话, 运行
bundledoc --config=bundledoc.cfg --verbose test.dep
则得到打包后的压缩文件test-all.tar.gz
需要注意的是, 我们需要压缩文件的软件tar与gzip.

发表回复

您的电子邮箱地址不会被公开。

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据