自動確定編譯所需的所有 ctan 包

自動確定編譯所需的所有 ctan 包

我保持相對精簡的 texlive,並根據需要透過 tlmgr 安裝單獨的軟體包。有時我開始與同事合作並必須寫一篇新論文。

現在,我的過程是嘗試編譯(通常使用 pdflatex)。如果編譯器抱怨,例如,說File 'cancel.sty' not found,那麼我將透過 tlmgr 安裝必要的套件。然後我嘗試再次編譯,並根據需要重複。

誠然,這還不是最糟糕的事。加快新專案的進度可能需要 5 分鐘。但如果有一個工具可以確定的話那就太好了全部立即需要或缺少包裹。我正在想像一個工具,可以收集所有依賴項並編寫類似於dependencies.txtpython 中常見的內容。

存在這樣的東西嗎?


我還會注意到,我可能正在嘗試優化此問題的錯誤解決方案。如果我應該以完全不同的方式考慮依賴管理,那麼請告訴我。但由於空間原因,我不打算安裝一個巨大的 texlive。

答案1

人們可以編寫一些腳本來在 Lua 中完成合理數量的工作。下面的腳本使用 TeX Live 的--recorder資料工作,所以需要你做類似的事情

pdflatex <name> --recorder

texlua depreader.lua <name>

(假設你呼叫 script depreader.lua,這就是我所擁有的)。然後還有一些限制

  • 只能拾取 TeX 運作讀取的檔案;例如 Biber 或 MakeIndex 所需的東西將被錯過(我懷疑選擇這些需要某種形式的修改kpse,更類似於 MiKTeX)
  • 您需要確保記錄器運行已設定好所有內容(例如條件加載、多次運行等可能會導致問題)
  • 它不會拾取格式建構中使用的文件(連字符模式等)
  • 它非常慢,因為它需要tlmgr調用每一個檔案名稱
  • 它不考慮 TeX Live 資料庫中列出的依賴項(因此每個 TL 套件都會明確列出)

也就是說,我認為這會讓你感動:

local name = arg[1] or "test"

local execute = os.execute
local find = string.find
local gmatch = string.gmatch
local gsub = string.gsub
local insert = table.insert
local match = string.match
local popen = io.popen
local sort = table.sort

local function extract_name(file)
  local path, name = match(file,"^(.*)/([^/]*)$")
  if path then
    return name
  else
    return file
  end
end

local f = io.open(name .. ".fls")
local data = gsub(f:read("*all") .. "\n","\r\n","\n")

local t = {}

for line in gmatch(data,"([^\n]*)\n") do
  if not (line == ""
       or match(line,name .. ".tex$")
       or match(line,"^PWD ")
       or match(line,"^OUTPUT")
       or match(line,"^INPUT %./")
       or match(line,"%.aux$")
       or match(line,"%.cnf$")
       or match(line,"%.fmt$")
       or match(line,"texmf%-var")) then
    local file = extract_name(gsub(line,"^INPUT ",""))
    t[file] = line
  end
end

local pkgs = {}
local unmatched = {}

for name,path in pairs(t) do
  local f = popen("tlmgr search --file /" .. name)
  local data = f:read("*all")
  local _,n = gsub(data,":","")
  if n == 1 then
    pkgs[match(data,"^([^:]*)")] = true
  elseif n == 0 then
    unmatched[name] = true
  else
    local function search(data,path)
      local pkgline = ""
      for line in gmatch(data,"([^\n]*)\n") do
        if match(line,":$") then
          pkgline = line
        else
          -- Find 'plain' - no patterns, also trimming spaces
          if find(path,gsub(line,"%s+",""),0,true) then
            return gsub(pkgline,":$","")
          end
        end
      end
      return false
    end
    local pkg = search(data,path)
    if pkg then
      pkgs[pkg] = true
    else
      unmatched[name] = true
    end
  end
end

local function print_sorted(t)
  local s = {}
  for k,_ in pairs(t) do
    insert(s,k)
  end
  sort(s)
  for _,v in ipairs(s) do
    print(v)
  end
end

print("TeX Live packages")
print_sorted(pkgs)

if next(unmatched) then
  print("\nNo match for")
  print_sorted(unmatched)
end

如果有興趣,我可能會嘗試使其變得更平滑,但不會達到嘗試執行latexmk多次運行等方面的目的的程度。

相關內容