Skip to content

Create PDF version of the OSCAR manual#5627

Draft
varuntrehan7 wants to merge 16 commits intooscar-system:masterfrom
varuntrehan7:vt/pdf-docs
Draft

Create PDF version of the OSCAR manual#5627
varuntrehan7 wants to merge 16 commits intooscar-system:masterfrom
varuntrehan7:vt/pdf-docs

Conversation

@varuntrehan7
Copy link
Contributor

@varuntrehan7 varuntrehan7 commented Dec 8, 2025

This PR adds PDF documentation generation using Documenter’s built-in
LaTeX backend. The HTML build is unchanged, the PDF is generated in
parallel using the docker LaTeX platform to avoid external toolchain
dependencies.

Resolves #5362.

Documenter.LaTeX(platform = "docker"),
],
sitename = "Oscar.jl",
authors = ["OSCAR Team"],
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please keep the changes as minimal as possible. In particular, you do not need to reformat this whole thing. And the line about authors was not present before

@lgoettgens lgoettgens added the documentation Improvements or additions to documentation label Dec 8, 2025
canonical = "https://docs.oscar-system.org/stable/",
),
# Add PDF generation via LaTeX
Documenter.LaTeX(platform = "docker"),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer if there was some argument to choose between html and pdf output. When just locally working on the documentation, I want to rebuild the html over and over again. But also generating and compiling latex all the time just wastes my time and resources

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also think that it would be good to have this behind an option. We could run this on our github CI for master and provide the pdf as an artifact.
But I would prefer not to run this locally by default. I think that it is more likely that Oscar developers have latex installed than docker, so this should probably be behind a check that docker is in the path?

plugins = [bib],
)
end
format = if get(ENV, "OSCAR_BUILD_PDF", "false") == "true" &&
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure if this place is the best one to check the condition. I would find it more natural to have this type of format as an input to this doit function. That way the parameter could be (with a bit more work) be exposed as an argument to Oscar.build_doc, so that any user can directly when building the documentation decide which versions to build (and not have to fiddle around with env variables)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay got it, thank you

plugins=[bib],
)
end
format = if build_pdf && success(`docker --version`)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

similarly, the docker check should IMO not be here. If I request a pdf, it should be built or throw an error

@lgoettgens
Copy link
Member

I am not quite sure that we are at the same point of understanding here.
What I suggeste to have:
The function build_docs gets two kwargs: formats::Vector{Symbol} which may contain :html and/or :pdf (default is [:html]), as well as a variable pdf_method that has the options :pdf_via_docker and :pdf_via_latex (default).
These options should be passed around todoit, which should then populate the format field based on these variables. In particular, none of the functions should perform any calls to the operating system to check for available software (instead, we want the errors from Documenter.jl).

These new options should also be added to the docstring of build_docs.

Please also remove all formatting changes to lines that you didn't change at all. This makes it easier to review the diff in the github UI.

@varuntrehan7
Copy link
Contributor Author

I am not quite sure that we are at the same point of understanding here. What I suggeste to have: The function build_docs gets two kwargs: formats::Vector{Symbol} which may contain :html and/or :pdf (default is [:html]), as well as a variable pdf_method that has the options :pdf_via_docker and :pdf_via_latex (default). These options should be passed around todoit, which should then populate the format field based on these variables. In particular, none of the functions should perform any calls to the operating system to check for available software (instead, we want the errors from Documenter.jl).

These new options should also be added to the docstring of build_docs.

Please also remove all formatting changes to lines that you didn't change at all. This makes it easier to review the diff in the github UI.

thank you for explaining that, that's helpful and before I do anything I had one question - I want to confirm that
you mentioned adding formats::Vector{Symbol} and pdf_method as keyword arguments to build_docs.
I found the existing function build_doc in src/utils/docs.jl, which internally calls BuildDoc.doit.
Should I extend this existing build_doc function to accept the new keywords (formats, pdf_method) and pass them into doit?

@lgoettgens
Copy link
Member

Should I extend this existing build_doc function to accept the new keywords (formats, pdf_method) and pass them into doit?

Yes, exactly. build_doc (https://docs.oscar-system.org/dev/DeveloperDocumentation/documentation/#build_doc) is the user-facing function for everything related to building the docs

@varuntrehan7
Copy link
Contributor Author

Should I extend this existing build_doc function to accept the new keywords (formats, pdf_method) and pass them into doit?

Yes, exactly. build_doc (https://docs.oscar-system.org/dev/DeveloperDocumentation/documentation/#build_doc) is the user-facing function for everything related to building the docs

Thankyou for clarifying, I'll make the changes and push shortly ( maybe tonight since I have a class right now).

@varuntrehan7
Copy link
Contributor Author

Thankyou for the changes, should I ready for review it?

@lgoettgens
Copy link
Member

The one thing that IMO is still missing is adding a pdf build to the CI job that builds the documentation. The resulting pdf should then be made available as an action artifact

@varuntrehan7
Copy link
Contributor Author

The one thing that IMO is still missing is adding a pdf build to the CI job that builds the documentation. The resulting pdf should then be made available as an action artifact

got it, I will add and push shortly. Thankyou!

@lgoettgens
Copy link
Member

The respective CI job does not run, possibly due to some syntax error in the yml file. BUt looking at you changes in general, it would be better to just adapt the script that gets called in the action file. In fact, the only use-case of docs/make.jl is to get called from the action script to build and deploy documentation

@varuntrehan7
Copy link
Contributor Author

I’ve now adapted BuildDoc.doit to support formats and pdf_method, and changed docs/make.jl to request [:html, :pdf] with pdf_via_latex.

Locally, the PDF is not produced because the docs build aborts early due to existing @docs errors , but the HTML build starts.
Before pushing further, could you please confirm that adapting docs/make.jl is sufficient or do i need to do something else?thanks!

@lgoettgens
Copy link
Member

From a pure code perspective, this looks good. The build failure is due to latex not being available on the CI runner.

@benlorenz @fingolfin do you have any preference if we install docker or latex on the CI runners to be able to produce the pdf documentation? (Depending on the answers, @varuntrehan7 could change the pdf_method used in docs/make.jl.)

@benlorenz
Copy link
Member

From a pure code perspective, this looks good. The build failure is due to latex not being available on the CI runner.

@benlorenz @fingolfin do you have any preference if we install docker or latex on the CI runners to be able to produce the pdf documentation? (Depending on the answers, @varuntrehan7 could change the pdf_method used in docs/make.jl.)

I think docker would be easier for our CI, since I think docker is already installed on the runner images (at least the github-hosted runners).
Running locally I would prefer latex directly as the default.

@benlorenz
Copy link
Member

benlorenz commented Dec 20, 2025

latexmk is unhappy:

...
------------
Run number 3 of rule 'pdflatex'
------------
------------
Running 'lualatex  -interaction=batchmode -halt-on-error -shell-escape -recorder  "Oscar.jl.tex"'
------------
Latexmk: applying rule 'pdflatex'...
This is LuaTeX, Version 1.0.4 (TeX Live 2017/Debian) 
 system commands enabled.
tput: No value for $TERM and no -T specified
luaotfload | main : initialization completed in 0.083 seconds/usr/bin/pygmentize
Latexmk: Missing input file: 'Oscar.jl.toc' from line
  'No file Oscar.jl.toc.'
Latexmk: List of undefined refs and citations:
  Label `10051290786723033841' multiply defined
  Label `10979499249110312737' multiply defined
  Label `13202649218045799579' multiply defined
  Label `13672098208301162927' multiply defined
  Label `14644122405856279089' multiply defined
  Label `14729179461903857169' multiply defined
  Label `15006912158171622068' multiply defined
  Label `15110382712247013745' multiply defined
  Label `16449533676332156424' multiply defined
  Label `16722491028088630393' multiply defined
  Label `16879307210612674453' multiply defined
  Label `16985367299622158104' multiply defined
  Label `17139417440091107597' multiply defined
  Label `17486127170697257492' multiply defined
  Label `18436683344473831779' multiply defined
  Label `1884029577258034648' multiply defined
  Label `1949164512217459377' multiply defined
  Label `2073659105529905161' multiply defined
  Label `323256303896486797' multiply defined
  Label `3456431557027766564' multiply defined
  Label `4250268531802119509' multiply defined
  Label `5363436185578144927' multiply defined
  Label `5504793881854483654' multiply defined
  Label `6822023193845507898' multiply defined
  Label `7328998503939343043' multiply defined
  Label `7341319293784296869' multiply defined
  Label `7481204796310077727' multiply defined
  Label `841302357412519072' multiply defined
  Label `8928132420117073301' multiply defined
  Label `9108156241743617419' multiply defined
  Label `9314838813112426257' multiply defined
Latexmk: Summary of warnings:
  Latex found 62 multiply defined reference(s)
Failure to make 'Oscar.jl.pdf'
Collected error summary (may duplicate other messages):
Latexmk: Errors, in force_mode: so I tried finishing targets
  pdflatex: Command for 'pdflatex' gave return code 256
┌ Error: LaTeXWriter: failed to compile tex with docker. Logs and partial output can be found in ../../../../../../tmp/jl_OLqz6P
│   exception =
│    failed process: Process(`docker exec -u zeptodoctor latex-container bash -c 'mkdir /home/zeptodoctor/build
│    cd /home/zeptodoctor/build
│    cp -r /mnt/. .
│    latexmk -f -interaction=batchmode -halt-on-error -view=none -lualatex -shell-escape Oscar.jl.tex
│    '`, ProcessExited(12)) [12]
│    
└ @ Documenter.LaTeXWriter ~/.julia/packages/Documenter/xvqbW/src/latex/LaTeXWriter.jl:230
latex-container
ERROR: LoadError: Compiling the .tex file failed. See logs for more information.

That docker image seems quite old: https://hub.docker.com/r/juliadocs/documenter-latex/

Last updated about 7 years ago

@lgoettgens
Copy link
Member

That docker image seems quite old: hub.docker.com/r/juliadocs/documenter-latex

Last updated about 7 years ago

It seems that the corresponding Dockerfile is not even in the Documenter.jl repo, but still in the predecessor DocumenterLatex.jl. See JuliaDocs/Documenter.jl#2073 and JuliaDocs/Documenter.jl#2092

@fingolfin
Copy link
Member

I don't understand in how far docker would be better in CI: it still has to download the container images, right? OTOH installing latex via apt is routine and also matches more closely how we plan to use it locally. So I'd suggest to try that instead?

@benlorenz
Copy link
Member

benlorenz commented Dec 20, 2025

I don't understand in how far docker would be better in CI: it still has to download the container images, right? OTOH installing latex via apt is routine and also matches more closely how we plan to use it locally. So I'd suggest to try that instead?

I thought the docker image would make sure that we have all relevant latex packages for documenter installed and less prone to new updates causing problems. It was also just a one-word change since it docker is pre-installed. But I didn't expect a 7 year old image.

So yeah let's try installing the packages directly.

@varuntrehan7
Copy link
Contributor Author

@lgoettgens Should i make any changes from my side?

docs/make.jl Outdated
include("make_work.jl")

Base.invokelatest(BuildDoc.doit, Oscar; warnonly=false, local_build=false, doctest=false)
Base.invokelatest(BuildDoc.doit, Oscar; warnonly=false, local_build=false, doctest=false, formats = [:html, :pdf], pdf_method = :pdf_via_docker)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Base.invokelatest(BuildDoc.doit, Oscar; warnonly=false, local_build=false, doctest=false, formats = [:html, :pdf], pdf_method = :pdf_via_docker)
Base.invokelatest(BuildDoc.doit, Oscar; warnonly=false, local_build=false, doctest=false, formats = [:html, :pdf], pdf_method = :pdf_via_latex)

@varuntrehan7 this was suggested by @fingolfin and @benlorenz. Please apply this change and then tinker with apt install statements in the action yaml file tot try to get it running

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay got it, thanks!

@varuntrehan7
Copy link
Contributor Author

I’ve added LaTeX installation via apt (latexmk + texlive), I also tried building the docs locally after installing LaTeX. The build still errors, but the remaining failures come from existing Documenter @docs blocks (missing docstrings in Nemo), not from the PDF/LaTeX toolchain itself.

@varuntrehan7
Copy link
Contributor Author

@lgoettgens can you also look into this? thanks!

@fingolfin fingolfin changed the title Add PDF build via Documenter.LaTeX Create PDF version of the OSCAR manual Jan 14, 2026
@fingolfin fingolfin added enhancement New feature or request release notes: use title For PRs: the title of this PR is suitable for direct use in the release notes labels Jan 14, 2026
@fingolfin
Copy link
Member

The actual error is not shown in the logs. I did run it locally and had a look at the Oscar.jl.log it produced in a temp dir. This is the actual error:

]
! Undefined control sequence.
<inserted text> ...f)} & & \\ \(\mathbb {Q}(\alpha ) \subseteq \R 
                                                  \) & \texttt {embedded\_nu...
l.42533 \end{tabulary}

So, something is using invalid TeX syntax. Using git grep in the Oscar.jl repository we can find more uses of \R and \RR:

$ git grep -n -F '\R'
docs/src/CommutativeAlgebra/localizations.md:12:1 \in U  \;\text{ and }\;  u, v \in U \;\Rightarrow \; u\cdot v \in U.
experimental/InjectiveResolutions/src/MonoidAlgebra.jl:303:Let kQ be a monoid algebra over some semigroup $Q$. Given a face $F$ of the cone $C = \RR_{\geq 0}Q$ of the monoid algebra kQ,
experimental/InjectiveResolutions/src/MonoidAlgebra.jl:325:# OUTPUT:   polyhedral cone \RR_{\geq 0}Q
experimental/IntersectionTheory/src/Main.jl:1288:Compute all the Chern numbers of `X` as a list of pairs $\lambda\Rightarrow
src/Groups/schur_index.jl:300:  # Determine m_\R(chi) and use Theorem 2.2 to find a bound u \in \N
src/Groups/schur_index.jl:442:  # Set u to be the LCM of m_\R(chi) and the u_p’s.
src/Groups/schur_index.jl:626:  # Return m_\R(\chi) and the sequence of pairs `p => u_p` where u_p \not= 1.

We can edit each of these, but the result will be less nice to read interactively... so perhaps we should just define macros. According to https://documenter.juliadocs.org/stable/man/latex/#Set-math-engine-and-define-macros-for-LaTeX something like this might work (to be adapted to our needs)

mathengine = Documenter.MathJax(Dict(:TeX => Dict(
    :Macros => Dict(
        :R => "\\mathbb{R}",
        :RR => "\\mathbb{R}",
    ),
)))

Though I think it would actually be better to agree one (say, \RR), and replace the occurrences of \R by that. And then also define this similarly for F, K, N, Q, Z

It is very likely that more errors of this kind will pop up. If you can't figure out a solution, post the error here or on slack and we can figure it out.

@varuntrehan7
Copy link
Contributor Author

The actual error is not shown in the logs. I did run it locally and had a look at the Oscar.jl.log it produced in a temp dir. This is the actual error:

]
! Undefined control sequence.
<inserted text> ...f)} & & \\ \(\mathbb {Q}(\alpha ) \subseteq \R 
                                                  \) & \texttt {embedded\_nu...
l.42533 \end{tabulary}

So, something is using invalid TeX syntax. Using git grep in the Oscar.jl repository we can find more uses of \R and \RR:

$ git grep -n -F '\R'
docs/src/CommutativeAlgebra/localizations.md:12:1 \in U  \;\text{ and }\;  u, v \in U \;\Rightarrow \; u\cdot v \in U.
experimental/InjectiveResolutions/src/MonoidAlgebra.jl:303:Let kQ be a monoid algebra over some semigroup $Q$. Given a face $F$ of the cone $C = \RR_{\geq 0}Q$ of the monoid algebra kQ,
experimental/InjectiveResolutions/src/MonoidAlgebra.jl:325:# OUTPUT:   polyhedral cone \RR_{\geq 0}Q
experimental/IntersectionTheory/src/Main.jl:1288:Compute all the Chern numbers of `X` as a list of pairs $\lambda\Rightarrow
src/Groups/schur_index.jl:300:  # Determine m_\R(chi) and use Theorem 2.2 to find a bound u \in \N
src/Groups/schur_index.jl:442:  # Set u to be the LCM of m_\R(chi) and the u_p’s.
src/Groups/schur_index.jl:626:  # Return m_\R(\chi) and the sequence of pairs `p => u_p` where u_p \not= 1.

We can edit each of these, but the result will be less nice to read interactively... so perhaps we should just define macros. According to https://documenter.juliadocs.org/stable/man/latex/#Set-math-engine-and-define-macros-for-LaTeX something like this might work (to be adapted to our needs)

mathengine = Documenter.MathJax(Dict(:TeX => Dict(
    :Macros => Dict(
        :R => "\\mathbb{R}",
        :RR => "\\mathbb{R}",
    ),
)))

Though I think it would actually be better to agree one (say, \RR), and replace the occurrences of \R by that. And then also define this similarly for F, K, N, Q, Z

It is very likely that more errors of this kind will pop up. If you can't figure out a solution, post the error here or on slack and we can figure it out.

okay got it, thanks!

@fingolfin
Copy link
Member

The new plan is now to add PDF output to AA; then Nemo; etc. until we have resolved all the math TeX errors in each, then we can return to this one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation enhancement New feature or request release notes: use title For PRs: the title of this PR is suitable for direct use in the release notes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Provide PDF version of OSCAR manual

4 participants