diff --git a/.gitignore b/.gitignore
index 5bd2d8af3276d30225062d5cddfe237c0578176d..d484f6a04277b6d27baea18c96717919acad33b7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,6 +7,7 @@
 /src/assets/docs
 /release
 /build
+/docs/pdf_build
 
 # dependencies
 /node_modules
diff --git a/README.md b/README.md
index 5750c79b6ba0413eaaf5bd25fba416d4790817f8..0fc8a9725a79ebaa03c2684ef07a93917538361a 100644
--- a/README.md
+++ b/README.md
@@ -14,7 +14,7 @@ Requirements for developping Cassiopee can be achieved by manually install the r
  * npm
  * python3
  * pandoc ^2 (optional, for PDF documentation only)
- * texlive (optional, for PDF documentation only)
+ * texlive, texlive-bibtex-extra, texlive-latex-extra, latexmk (optional, for PDF documentation only)
 
 Building the HTML documentation requires MkDocs and some extensions:
 
diff --git a/scripts/mkdocs2pdf.py b/scripts/mkdocs2pdf.py
index 6e3cf68040aa15e43debd48019a955e3e13d9b2a..37deb6a8f52ef1d99b61ccf8f1b618790e3fa4a2 100644
--- a/scripts/mkdocs2pdf.py
+++ b/scripts/mkdocs2pdf.py
@@ -20,6 +20,9 @@ import yaml
 import re
 import shutil
 
+# verbose output
+verbose = False
+
 baseDir = os.getcwd()
 buildDir = os.path.join(baseDir, 'build')
 latexSourceDir = os.path.join(baseDir, 'docs/latex')
@@ -38,6 +41,21 @@ def runCommand(cmd):
     if os.waitstatus_to_exitcode(os.system(cmd)) != 0:
         raise RuntimeError("error executing:",cmd)
 
+# Create a symbolic link
+def createLink(src):
+    # check if destination already exists
+    dest = os.path.basename(src)
+    if os.path.exists(dest):
+        if not os.path.islink(dest):
+            raise Exception('{} exists but is not a symbolic link'.format(dest))
+    else:
+        runCommand('ln -s {}'.format(src))
+
+def createEmptyDir(path):
+    if os.path.exists(path):
+        shutil.rmtree(path)
+    os.makedirs(path)
+
 # Reads an MkDocs configuration file
 def readConfig(sYAML):
     f = open(sYAML, 'r')
@@ -130,9 +148,14 @@ def convertMdToTex(filePath):
 def getLatexModel():
     # Clone Git repository
     os.chdir(pdfBuildDir)
-    runCommand(
-        'git clone {} {}'.format(latexModelRepository, latexModelDir)
-    )
+    if os.path.isdir(latexModelDir):
+        # git directory exists, update it
+        os.chdir(latexModelDir)
+        runCommand('git pull')
+        # platform independent "cd .."
+        os.chdir(os.path.dirname(os.getcwd()))
+    else:
+        runCommand('git clone {} {}'.format(latexModelRepository, latexModelDir))
     # back to original working drectory
     os.chdir(baseDir)
 
@@ -146,35 +169,17 @@ def injectContentIntoModel(mergedDocFilenameTex, lang):
     # Symlink necessary resources
     os.chdir(modelDir)
     relPathToMergedTexDoc = os.path.join('..', mergedDocFilenameTex)
-    runCommand(
-        'ln -s {} .'.format(relPathToMergedTexDoc)
-    )
+    createLink(relPathToMergedTexDoc)
     latexTemplate = filenamePrefix + lang + '.tex'
     relPathToLatexTemplate = os.path.join(latexSourceDir, latexTemplate)
-    runCommand(
-        'ln -s {}'.format(relPathToLatexTemplate)
-    )
-    runCommand(
-        'ln -s {}'.format(os.path.join(latexSourceDir, 'logo_pole.png'))
-    )
-    runCommand(
-        'ln -s {}/schema_rugosite_fond.png'.format(os.path.join(baseDir, 'docs', lang, 'calculators', 'pam'))
-    )
-    runCommand(
-        'ln -s {}/bloc_cylindre.png'.format(os.path.join(baseDir, 'docs', lang, 'calculators', 'pam'))
-    )
-    runCommand(
-        'ln -s {}/bloc_face_arrondie.png'.format(os.path.join(baseDir, 'docs', lang, 'calculators', 'pam'))
-    )
-    runCommand(
-        'ln -s {}/bloc_base_carree.png'.format(os.path.join(baseDir, 'docs', lang, 'calculators', 'pam'))
-    )
-    runCommand(
-        'rm rapport_inrae/logos.tex'
-    )
-    runCommand(
-        'ln -s {} rapport_inrae/'.format(os.path.join(latexSourceDir, 'logos.tex'))
-    )
+    createLink(relPathToLatexTemplate)
+    createLink(os.path.join(latexSourceDir, 'logo_pole.png'))
+    createLink('{}/schema_rugosite_fond.png'.format(os.path.join(baseDir, 'docs', lang, 'calculators', 'pam')))
+    createLink('{}/bloc_cylindre.png'.format(os.path.join(baseDir, 'docs', lang, 'calculators', 'pam')))
+    createLink('{}/bloc_face_arrondie.png'.format(os.path.join(baseDir, 'docs', lang, 'calculators', 'pam')))
+    createLink('{}/bloc_base_carree.png'.format(os.path.join(baseDir, 'docs', lang, 'calculators', 'pam')))
+    runCommand('rm rapport_inrae/logos.tex')
+    createLink('{} rapport_inrae/'.format(os.path.join(latexSourceDir, 'logos.tex')))
     # back to original working drectory
     os.chdir(baseDir)
 
@@ -189,9 +194,11 @@ def buildPDF(lang):
     cvt = os.path.join(buildDir, 'cassiopee_version.tex')
     shutil.copy(cvt, modelDir)
 
-    os.system(
-        'latexmk -f -xelatex -pdf -interaction=nonstopmode {} > /dev/null 2>&1'.format(sourceTexFile)
-    )
+    if verbose:
+        os.system('latexmk -f -xelatex -pdf -interaction=nonstopmode {} > /dev/null'.format(sourceTexFile))
+    else:
+        os.system('latexmk -f -xelatex -pdf -interaction=nonstopmode {} > /dev/null 2>&1'.format(sourceTexFile))
+
     # copy generated PDF to release directory
     shutil.copy(outputPdfFile, outputDir)
     # back to original working drectory
@@ -201,9 +208,9 @@ def buildPDF(lang):
 def buildDocForLang(lang):
 
     # Prepare temporary build directory
-    os.makedirs(pdfBuildDir, exist_ok=True)
+    createEmptyDir(pdfBuildDir)
     # Prepare output directory
-    os.makedirs(outputDir, exist_ok=True)
+    createEmptyDir(outputDir)
 
     # Read config
     yamlPath = 'mkdocs/mkdocs-' + lang + '.yml'