]> git.lyx.org Git - lyx.git/blobdiff - lib/configure.py
Amend b8502a3ea2735c4
[lyx.git] / lib / configure.py
index aad9cca23286e5c2926ad48ece0f2f99c7518429..615d294df1e9a2cd8df91f073e13b2bac0f30a5b 100644 (file)
@@ -318,13 +318,57 @@ def checkProg(description, progs, rc_entry=None, path=None, not_found =''):
                         addToRC(rc_entry[idx].replace('%%', ac_prog))
                     return [ac_dir, ac_word]
         # if not successful
-        logger.info(msg + ' no')
+        logger.info(msg + ' not in path')
     # write rc entries for 'not found'
     if len(rc_entry) > 0:  # the last one.
         addToRC(rc_entry[-1].replace('%%', not_found))
     return ['', not_found]
 
 
+def check_java():
+    """ Check for Java, don't give up as often as checkProg, using platform-dependent techniques """
+    if os.name == 'nt':
+        # Check in the registry.
+        try:  # Python 3.
+            import winreg
+        except ImportError:  # Python 2.
+            import _winreg as winreg
+
+        potential_keys_64b = ["SOFTWARE\\JavaSoft\\Java Runtime Environment", "SOFTWARE\\JavaSoft\\Java Development Kit",
+                              "SOFTWARE\\JavaSoft\\JDK", "SOFTWARE\\JavaSoft\\JRE"]
+        potential_keys_32b = [k.replace('SOFTWARE', 'SOFTWARE\\WOW6432Node') for k in potential_keys_64b]
+        potential_keys = potential_keys_64b + potential_keys_32b
+
+        reg_hive = winreg.HKEY_LOCAL_MACHINE
+        for key in potential_keys:
+            try:
+                with winreg.OpenKey(reg_hive, key) as reg_key:
+                    version = winreg.QueryValueEx(reg_key, "CurrentVersion")[0]
+                with winreg.OpenKey(reg_hive, key + '\\' + version) as reg_key:
+                    java_bin = winreg.QueryValueEx(reg_key, "JavaHome")[0] + '\\bin\\java.exe'
+                    logger.info('+checking for java: found in Windows registry, ' + str(java_bin))
+                    return java_bin
+            except OSError:
+                pass
+
+        # The test failed, no Java found.
+        return ''
+    else:
+        return ''
+
+
+def checkMacOSappInstalled(prog):
+    '''
+        Use metadata lookup to search for an "installed" macOS application bundle.
+    '''
+    if sys.platform == 'darwin' and len(prog) >= 1:
+        command = r'mdfind "kMDItemContentTypeTree == \"com.apple.application\"c && kMDItemFSName == \"%s\""' % prog
+        result = cmdOutput(command)
+        logger.debug(command + ": " + result)
+        return result != ''
+    return False
+
+
 def checkProgAlternatives(description, progs, rc_entry=None,
                           alt_rc_entry=None, path=None, not_found=''):
     '''
@@ -363,6 +407,10 @@ def checkProgAlternatives(description, progs, rc_entry=None,
             continue
         msg = '+checking for "' + ac_word + '"... '
         found_alt = False
+        if len(alt_rc_entry) >= 1 and ac_word.endswith('.app') and checkMacOSappInstalled(ac_word):
+            logger.info('+add alternative app ' + ac_word)
+            addToRC(alt_rc_entry[0].replace('%%', ac_word))
+            found_alt = True
         for ac_dir in path:
             if hasattr(os, "access") and not os.access(ac_dir, os.F_OK):
                 continue
@@ -413,7 +461,7 @@ def checkProgAlternatives(description, progs, rc_entry=None,
                     break
             if found_alt:
                 break
-        if found_alt == False:
+        if not found_alt:
             # if not successful
             logger.info(msg + ' no')
     if found_prime:
@@ -513,7 +561,7 @@ def checkViewerNoRC(description, progs, rc_entry=None, path=None):
 
 
 def checkEditorNoRC(description, progs, rc_entry=None, path=None):
-    ''' The same as checkViewer, but do not add rc entry '''
+    ''' The same as checkEditor, but do not add rc entry '''
     if rc_entry is None:
         rc_entry = []
     if path is None:
@@ -621,7 +669,7 @@ def checkLatex(dtl_tools):
     if dtl_tools:
         # Windows only: DraftDVI
         addToRC(r'''\converter latex      dvi2       "%s"      "latex,hyperref-driver=dvips"
-\converter dvi2       dvi        "python -tt $$s/scripts/clean_dvi.py $$i $$o" ""''' % LATEX)
+\converter dvi2       dvi        "$${python} $$s/scripts/clean_dvi.py $$i $$o" ""''' % LATEX)
     else:
         addToRC(r'\converter latex      dvi        "%s"        "latex,hyperref-driver=dvips"' % LATEX)
     # no latex
@@ -673,7 +721,7 @@ texteditors = ['xemacs', 'gvim', 'kedit', 'kwrite', 'kate',
                'xed', 'notepad', 'WinEdt', 'WinShell', 'PSPad']
 
 def checkFormatEntries(dtl_tools):
-    ''' Check all formats (\Format entries) '''
+    r''' Check all formats (\Format entries) '''
     checkViewerEditor('a Tgif viewer and editor', ['tgif'],
         rc_entry = [r'\Format tgif      "obj, tgo" Tgif                 "" "%%"        "%%"    "vector"        "application/x-tgif"'])
     #
@@ -721,6 +769,7 @@ def checkFormatEntries(dtl_tools):
 \Format docbook5   xml    "DocBook 5"             "" ""        "%%"    "document,menu=export"  "application/docbook+xml"
 \Format dot        dot    "Graphviz Dot"          "" ""        "%%"    "vector"        "text/vnd.graphviz"
 \Format dviluatex  tex    "LaTeX (dviluatex)"     "" "" "%%"   "document,menu=export"  ""
+\Format epub       epub    ePub                   "" "" "%%"    "document,menu=export"  "application/epub+zip"
 \Format platex     tex    "LaTeX (pLaTeX)"        "" "" "%%"   "document,menu=export"  ""
 \Format literate   nw      NoWeb                  N  ""        "%%"    "document,menu=export"  ""
 \Format sweave     Rnw    "Sweave"                S  "" "%%"   "document,menu=export"  ""
@@ -779,7 +828,7 @@ def checkFormatEntries(dtl_tools):
     checkViewer('a PDF previewer',
                 ['pdfview', 'kpdf', 'okular', 'qpdfview --unique',
                  'evince', 'xreader', 'kghostview', 'xpdf', 'SumatraPDF',
-                 'acrobat', 'acroread', 'mupdf',
+                 'acrobat', 'acroread', 'mupdf', 'Skim.app',
                  'gv', 'ghostview', 'AcroRd32', 'gsview64', 'gsview32'],
         rc_entry = [r'''\Format pdf        pdf    "PDF (ps2pdf)"          P  "%%"      ""      "document,vector,menu=export"   ""
 \Format pdf2       pdf    "PDF (pdflatex)"        F  "%%"      ""      "document,vector,menu=export"   ""
@@ -843,7 +892,7 @@ def checkFormatEntries(dtl_tools):
 
 
 def checkConverterEntries():
-    ''' Check all converters (\converter entries) '''
+    r''' Check all converters (\converter entries) '''
     checkProg('the pdflatex program', ['pdflatex $$i'],
         rc_entry = [ r'\converter pdflatex   pdf2       "%%"   "latex=pdflatex,hyperref-driver=pdftex"' ])
 
@@ -868,7 +917,7 @@ def checkConverterEntries():
 
     path, t2l = checkProg('a LaTeX/Noweb -> LyX converter', [quoteIfSpace(in_binary_subdir), quoteIfSpace(in_binary_subdir + version_suffix), quoteIfSpace(in_binary_dir), quoteIfSpace(in_binary_dir + version_suffix), 'tex2lyx' + version_suffix, 'tex2lyx'],
         rc_entry = [r'''\converter latex      lyx        "%% -f $$i $$o"       ""
-\converter latexclipboard lyx        "%% -fixedenc utf8 -f $$i $$o"    ""
+\converter latexclipboard lyx        "%% -fixedenc utf8 -c $$c -m $$m -f $$i $$o"      ""
 \converter literate   lyx        "%% -n -m noweb -f $$i $$o"   ""
 \converter sweave   lyx        "%% -n -m sweave -f $$i $$o"    ""
 \converter knitr   lyx        "%% -n -m knitr -f $$i $$o"      ""'''], not_found = 'tex2lyx')
@@ -910,7 +959,7 @@ def checkConverterEntries():
     checkProg('an HTML -> LaTeX converter', ['html2latex $$i', 'gnuhtml2latex',
         'htmltolatex -input $$i -output $$o', 'htmltolatex.jar -input $$i -output $$o'],
         rc_entry = [ r'\converter html       latex      "%%"   ""',
-                     r'\converter html       latex      "python -tt $$s/scripts/html2latexwrapper.py %% $$i $$o"       ""',
+                     r'\converter html       latex      "$${python} $$s/scripts/html2latexwrapper.py %% $$i $$o"       ""',
                      r'\converter html       latex      "%%"   ""',
                      r'\converter html       latex      "%%"   ""', '' ])
     #
@@ -931,8 +980,8 @@ def checkConverterEntries():
         ['elyxer.py --html --nofooter --unicode --directory $$r $$i $$o', 'elyxer --html --nofooter --unicode --directory $$r $$i $$o'],
         rc_entry = [ r'\converter lyx      word      "%%"      ""' ])
     if elyxer.find('elyxer') >= 0:
-      addToRC(r'''\copier    html       "python -tt $$s/scripts/ext_copy.py -e html,png,jpg,jpeg,css $$i $$o"''')
-      addToRC(r'''\copier    wordhtml       "python -tt $$s/scripts/ext_copy.py -e html,png,jpg,jpeg,css $$i $$o"''')
+      addToRC(r'''\copier    html       "$${python} $$s/scripts/ext_copy.py -e html,png,jpg,jpeg,css $$i $$o"''')
+      addToRC(r'''\copier    wordhtml       "$${python} $$s/scripts/ext_copy.py -e html,png,jpg,jpeg,css $$i $$o"''')
     else:
       # search for HTML converters other than eLyXer
       # On SuSE the scripts have a .sh suffix, and on debian they are in /usr/share/tex4ht/
@@ -941,17 +990,17 @@ def checkConverterEntries():
           'latex2html -no_subdir -split 0 -show_section_numbers $$i', 'hevea -s $$i'],
           rc_entry = [ r'\converter latex      html       "%%" "needaux"' ])
       if htmlconv.find('htlatex') >= 0 or htmlconv == 'latex2html':
-        addToRC(r'''\copier    html       "python -tt $$s/scripts/ext_copy.py -e html,png,css $$i $$o"''')
+        addToRC(r'''\copier    html       "$${python} $$s/scripts/ext_copy.py -e html,png,css $$i $$o"''')
       else:
-        addToRC(r'''\copier    html       "python -tt $$s/scripts/ext_copy.py $$i $$o"''')
+        addToRC(r'''\copier    html       "$${python} $$s/scripts/ext_copy.py $$i $$o"''')
       path, htmlconv = checkProg('a LaTeX -> HTML (MS Word) converter', ["htlatex $$i 'html,word' 'symbol/!' '-cvalidate'",
           "htlatex.sh $$i 'html,word' 'symbol/!' '-cvalidate'",
           "/usr/share/tex4ht/htlatex $$i 'html,word' 'symbol/!' '-cvalidate'"],
           rc_entry = [ r'\converter latex      wordhtml   "%%" "needaux"' ])
       if htmlconv.find('htlatex') >= 0:
-        addToRC(r'''\copier    wordhtml       "python -tt $$s/scripts/ext_copy.py -e html,png,css $$i $$o"''')
+        addToRC(r'''\copier    wordhtml       "$${python} $$s/scripts/ext_copy.py -e html,png,css $$i $$o"''')
       else:
-        addToRC(r'''\copier    wordhtml       "python -tt $$s/scripts/ext_copy.py $$i $$o"''')
+        addToRC(r'''\copier    wordhtml       "$${python} $$s/scripts/ext_copy.py $$i $$o"''')
 
 
     # Check if LyXBlogger is installed
@@ -970,8 +1019,21 @@ def checkConverterEntries():
     checkProg('an Open Document (Pandoc) -> LaTeX converter', ['pandoc -s -f odt -o $$o -t latex $$i'],
         rc_entry = [ r'\converter odt3        latex      "%%"  ""' ])
     #
-    checkProg('DocBook converter -> PDF (docbook)', ['pandoc -f docbook -t latex --latex-engine=lualatex --toc -o $$o $$i'],
-        rc_entry = [ r'\converter docbook5      pdf9      "%%" ""' ])
+    checkProg('DocBook converter -> PDF (docbook)',
+              ['pandoc -f docbook -t latex --pdf-engine=lualatex --toc -o $$o $$i',  # Since Pandoc 2.0
+               'pandoc -f docbook -t latex --latex-engine=lualatex --toc -o $$o $$i'],  # Up to Pandoc 1.19
+              rc_entry = [ r'\converter docbook5      pdf9      "%%"   ""' ])
+    #
+    xpath, xslt_sheet = checkProg('XSLT stylesheets for ePub', ['chunk.xsl'], '', ['/usr/share/xml/docbook/stylesheet/docbook-xsl-ns/epub3'])
+    if xslt_sheet == 'chunk.xsl':
+        xpath = '/usr/share/xml/docbook/stylesheet/docbook-xsl-ns'
+    else:
+        xpath = 'none'
+    global java
+    if xsltproc != '':
+        addToRC(r'\converter docbook5 epub "$${python} $$s/scripts/docbook2epub.py none none \"' + xsltproc + r'\" ' + xpath + ' $$i $$r $$o" ""')
+    elif java != '':
+        addToRC(r'\converter docbook5 epub "$${python} $$s/scripts/docbook2epub.py \"' + java + r'\" none none ' + xpath + ' $$i $$r $$o" ""')
     #
     checkProg('a MS Word Office Open XML converter -> LaTeX', ['pandoc -s -f docx -o $$o -t latex $$i'],
         rc_entry = [ r'\converter word2      latex      "%%"   ""' ])
@@ -1025,13 +1087,15 @@ def checkConverterEntries():
     # Only define a converter from pdf6 for graphics
     checkProg('a PDF to EPS converter', ['pdftops -eps -f 1 -l 1 $$i $$o'],
         rc_entry = [ r'\converter pdf6        eps        "%%"  ""' ])
-    # Define a converter from pdf6 to png for Macs where pdftops is missing.
+    # sips:Define a converter from pdf6 to png for Macs where pdftops is missing.
     # The converter utility sips allows to force the dimensions of the resulting
     # png image. The value of 800 pixel for the width is arbitrary and not
     # related to the current screen resolution or width.
     # There is no converter parameter for this information.
+    #
+    #pdftoppm: Some systems ban IM eps->png conversion. We will offer eps->pdf->png route instead.
     checkProg('a PDF to PNG converter',
-        ['sips --resampleWidth 800 --setProperty format png $$i --out $$o'],
+        ['sips --resampleWidth 800 --setProperty format png $$i --out $$o' , 'pdftoppm -r 72 -png -singlefile $$i >  $$o'],
         rc_entry = [ r'\converter pdf6        png        "%%" ""' ])
     # Create one converter for a PDF produced using TeX fonts and one for a
     # PDF produced using non-TeX fonts. This does not produce non-unique
@@ -1043,8 +1107,8 @@ def checkConverterEntries():
     # PDF produced using non-TeX fonts. This does not produce non-unique
     # conversion paths, since a given document either uses TeX fonts or not.
     checkProg('Ghostscript', ["gswin32c", "gswin64c", "gs"],
-        rc_entry = [ r'''\converter pdf2   pdf8       "python -tt $$s/scripts/convert_pdf.py $$i $$o ebook"    ""
-\converter pdf4   pdf8       "python -tt $$s/scripts/convert_pdf.py $$i $$o ebook"     ""''' ])
+        rc_entry = [ r'''\converter pdf2   pdf8       "$${python} $$s/scripts/convert_pdf.py $$i $$o ebook"    ""
+\converter pdf4   pdf8       "$${python} $$s/scripts/convert_pdf.py $$i $$o ebook"     ""''' ])
     #
     checkProg('a Beamer info extractor', ['makebeamerinfo -p $$i'],
         rc_entry = [ r'\converter pdf2         beamer.info        "%%" ""' ])
@@ -1070,24 +1134,24 @@ def checkConverterEntries():
 \converter fig        ppm        "fig2dev -L ppm $$i $$o"      ""
 \converter fig        svg        "fig2dev -L svg $$i $$o"      ""
 \converter fig        png        "fig2dev -L png $$i $$o"      ""
-\converter fig        pdftex     "python -tt $$s/scripts/fig2pdftex.py $$i $$o"        ""
-\converter fig        pstex      "python -tt $$s/scripts/fig2pstex.py $$i $$o" ""''')
+\converter fig        pdftex     "$${python} $$s/scripts/fig2pdftex.py $$i $$o"        ""
+\converter fig        pstex      "$${python} $$s/scripts/fig2pstex.py $$i $$o" ""''')
     #
     if inkscape_stable:
         checkProg('a SVG -> PDFTeX converter', [inkscape_cl],
-            rc_entry = [ r'\converter svg        pdftex     "python -tt $$s/scripts/svg2pdftex.py %% $$p$$i $$p$$o" ""'],
+            rc_entry = [ r'\converter svg        pdftex     "$${python} $$s/scripts/svg2pdftex.py %% $$p$$i $$p$$o" ""'],
             path = [inkscape_path])
         #
         checkProg('a SVG -> PSTeX converter', [inkscape_cl],
-            rc_entry = [ r'\converter svg        pstex     "python -tt $$s/scripts/svg2pstex.py %% $$p$$i $$p$$o" ""'],
+            rc_entry = [ r'\converter svg        pstex     "$${python} $$s/scripts/svg2pstex.py %% $$p$$i $$p$$o" ""'],
             path = [inkscape_path])
     else:
         checkProg('a SVG -> PDFTeX converter', [inkscape_cl],
-            rc_entry = [ r'\converter svg        pdftex     "python -tt $$s/scripts/svg2pdftex.py --unstable %% $$p$$i $$p$$o" ""'],
+            rc_entry = [ r'\converter svg        pdftex     "$${python} $$s/scripts/svg2pdftex.py --unstable %% $$p$$i $$p$$o" ""'],
             path = [inkscape_path])
         #
         checkProg('a SVG -> PSTeX converter', [inkscape_cl],
-            rc_entry = [ r'\converter svg        pstex     "python -tt $$s/scripts/svg2pstex.py --unstable %% $$p$$i $$p$$o" ""'],
+            rc_entry = [ r'\converter svg        pstex     "$${python} $$s/scripts/svg2pstex.py --unstable %% $$p$$i $$p$$o" ""'],
             path = [inkscape_path])
     #
     checkProg('a TIFF -> PS converter', ['tiff2ps $$i > $$o'],
@@ -1128,8 +1192,23 @@ def checkConverterEntries():
     checkProg('an EPS -> PDF converter', ['epstopdf'],
         rc_entry = [ r'\converter eps        pdf6       "epstopdf --outfile=$$o $$i"   ""'])
     #
-    checkProg('an EPS -> PNG converter', ['magick $$i $$o', 'convert $$i $$o'],
-        rc_entry = [ r'\converter eps        png        "%%"   ""'])
+    # Due to more restrictive policies, it is possible that (image)magick
+    # does not allow conversions from eps to png.
+    # So before setting the converter test it it on a mock file
+    _, cmd = checkProg('an EPS -> PNG converter', ['magick', 'convert'])
+    if cmd:
+        writeToFile('mock.eps', r'%!PS')
+        try:
+            subprocess.check_call([cmd, "mock.eps", "mock.png"])
+            removeFiles(['mock.eps', 'mock.png'])
+            rc_entry = r'\converter eps        png        "%s $$i[0] $$o"      ""'
+            addToRC(rc_entry % cmd)
+        except:
+            removeFiles(['mock.eps'])
+            #needs empty record otherwise default converter will be issued
+            rc_entry = r'\converter eps        png        ""   ""'
+            addToRC(rc_entry)
+            logger.info('ImageMagick seems to ban conversions from EPS. Disabling direct EPS->PNG.')
     #
     # no agr -> pdf6 converter, since the pdf library used by gracebat is not
     # free software and therefore not compiled in in many installations.
@@ -1202,7 +1281,7 @@ def checkConverterEntries():
     #
     checkProg('Gnuplot', ['gnuplot'],
         rc_entry = [ r'''\Format gnuplot     "gp, gnuplot"    "Gnuplot"     "" "" ""  "vector" "text/plain"
-\converter gnuplot      pdf6      "python -tt $$s/scripts/gnuplot2pdf.py $$i $$o"    "needauth"''' ])
+\converter gnuplot      pdf6      "$${python} $$s/scripts/gnuplot2pdf.py $$i $$o"    "needauth"''' ])
     #
     # gnumeric/xls/ods to tex
     checkProg('a spreadsheet -> latex converter', ['ssconvert'],
@@ -1214,16 +1293,16 @@ def checkConverterEntries():
 \converter oocalc html_table "ssconvert --export-type=Gnumeric_html:html40frag $$i $$o" ""
 \converter excel  html_table "ssconvert --export-type=Gnumeric_html:html40frag $$i $$o" ""
 \converter excel2 html_table "ssconvert --export-type=Gnumeric_html:html40frag $$i $$o" ""
-\converter gnumeric xhtml_table "python $$s/scripts/spreadsheet_to_docbook.py $$i $$o" ""
-\converter oocalc xhtml_table "python $$s/scripts/spreadsheet_to_docbook.py $$i $$o" ""
-\converter excel  xhtml_table "python $$s/scripts/spreadsheet_to_docbook.py $$i $$o" ""
-\converter excel2 xhtml_table "python $$s/scripts/spreadsheet_to_docbook.py $$i $$o" ""
+\converter gnumeric xhtml_table "$${python} $$s/scripts/spreadsheet_to_docbook.py $$i $$o" ""
+\converter oocalc xhtml_table "$${python} $$s/scripts/spreadsheet_to_docbook.py $$i $$o" ""
+\converter excel  xhtml_table "$${python} $$s/scripts/spreadsheet_to_docbook.py $$i $$o" ""
+\converter excel2 xhtml_table "$${python} $$s/scripts/spreadsheet_to_docbook.py $$i $$o" ""
 '''])
 
     path, lilypond = checkProg('a LilyPond -> EPS/PDF/PNG converter', ['lilypond'])
     if (lilypond):
         version_string = cmdOutput("lilypond --version")
-        match = re.match('GNU LilyPond (\S+)', version_string)
+        match = re.match(r'GNU LilyPond (\S+)', version_string)
         if match:
             version_number = match.groups()[0]
             version = version_number.split('.')
@@ -1244,30 +1323,53 @@ def checkConverterEntries():
             logger.info('+  found LilyPond, but could not extract version number.')
     #
     path, lilypond_book = checkProg('a LilyPond book (LaTeX) -> LaTeX converter', ['lilypond-book'])
-    if (lilypond_book):
-        version_string = cmdOutput("lilypond-book --version")
-        match = re.match('(\S+)$', version_string)
-        if match:
-            version_number = match.groups()[0]
-            version = version_number.split('.')
-            if int(version[0]) > 2 or (len(version) > 1 and int(version[0]) == 2 and int(version[1]) >= 13):
-                # Note: The --lily-output-dir flag is required because lilypond-book
-                #       does not process input again unless the input has changed,
-                #       even if the output format being requested is different. So
-                #       once a .eps file exists, lilypond-book won't create a .pdf
-                #       even when requested with --pdf. This is a problem if a user
-                #       clicks View PDF after having done a View DVI. To circumvent
-                #       this, use different output folders for eps and pdf outputs.
-                addToRC(r'\converter lilypond-book latex    "lilypond-book --safe --lily-output-dir=ly-eps $$i"                                ""')
-                addToRC(r'\converter lilypond-book pdflatex "lilypond-book --safe --pdf --latex-program=pdflatex --lily-output-dir=ly-pdf $$i" ""')
-                addToRC(r'\converter lilypond-book-ja platex "lilypond-book --safe --pdf --latex-program=platex --lily-output-dir=ly-pdf $$i" ""')
-                addToRC(r'\converter lilypond-book xetex    "lilypond-book --safe --pdf --latex-program=xelatex --lily-output-dir=ly-pdf $$i"  ""')
-                addToRC(r'\converter lilypond-book luatex   "lilypond-book --safe --pdf --latex-program=lualatex --lily-output-dir=ly-pdf $$i" ""')
-                addToRC(r'\converter lilypond-book dviluatex "lilypond-book --safe --latex-program=dvilualatex --lily-output-dir=ly-eps $$i" ""')
-                logger.info('+  found LilyPond-book version %s.' % version_number)
-            else:
-                logger.info('+  found LilyPond-book, but version %s is too old.' % version_number)
-        else:
+    if lilypond_book:
+        found_lilypond_book = False
+        # On Windows, the file lilypond-book is not directly callable, it must be passed as argument to python.
+        for cmd in ["lilypond-book", os.path.basename(sys.executable) + ' "' + path + '/lilypond-book"']:
+            version_string = cmdOutput(cmd + " --version")
+            if len(version_string) == 0:
+                continue
+            found_lilypond_book = True
+
+            match = re.match(r'(\S+)$', version_string)
+            if match:
+                version_number = match.groups()[0]
+                version = version_number.split('.')
+                if int(version[0]) > 2 or (len(version) > 1 and int(version[0]) == 2 and int(version[1]) >= 13):
+                    # Note: The --lily-output-dir flag is required because lilypond-book
+                    #       does not process input again unless the input has changed,
+                    #       even if the output format being requested is different. So
+                    #       once a .eps file exists, lilypond-book won't create a .pdf
+                    #       even when requested with --pdf. This is a problem if a user
+                    #       clicks View PDF after having done a View DVI. To circumvent
+                    #       this, use different output folders for eps and pdf outputs.
+                    cmd = cmd.replace('"', r'\"')
+                    addToRC(r'\converter lilypond-book latex     "' + cmd + ' --safe --lily-output-dir=ly-eps $$i"                                ""')
+                    addToRC(r'\converter lilypond-book pdflatex  "' + cmd + ' --safe --pdf --latex-program=pdflatex --lily-output-dir=ly-pdf $$i" ""')
+                    addToRC(r'\converter lilypond-book-ja platex "' + cmd + ' --safe --pdf --latex-program=platex --lily-output-dir=ly-pdf $$i" ""')
+                    addToRC(r'\converter lilypond-book xetex     "' + cmd + ' --safe --pdf --latex-program=xelatex --lily-output-dir=ly-pdf $$i"  ""')
+                    addToRC(r'\converter lilypond-book luatex    "' + cmd + ' --safe --pdf --latex-program=lualatex --lily-output-dir=ly-pdf $$i" ""')
+                    addToRC(r'\converter lilypond-book dviluatex "' + cmd + ' --safe --latex-program=dvilualatex --lily-output-dir=ly-eps $$i" ""')
+
+                    # Also create the entry to apply LilyPond on DocBook files. However,
+                    # command must be passed as argument, and it might already have
+                    # quoted parts. LyX doesn't yet handle double-quoting of commands.
+                    # Hence, pass as argument either cmd (if it's a simple command) or
+                    # the Python file that should be called (typical on Windows).
+                    docbook_lilypond_cmd = cmd
+                    if "python" in docbook_lilypond_cmd:
+                        docbook_lilypond_cmd = '"' + path + '/lilypond-book"'
+                    addToRC(r'\copier docbook5 "$${python} $$s/scripts/docbook_copy.py ' + docbook_lilypond_cmd.replace('"', r'\"') + r' $$i $$o"')
+
+                    logger.info('+  found LilyPond-book version %s.' % version_number)
+
+                    # early exit on first match, avoid 2nd try with python call
+                    # in case of lilypond-book being an executable or shell script the python call is useless
+                    break
+                else:
+                    logger.info('+  found LilyPond-book, but version %s is too old.' % version_number)
+        if not found_lilypond_book:
             logger.info('+  found LilyPond-book, but could not extract version number.')
     #
     checkProg('a Noteedit -> LilyPond converter', ['noteedit --export-lilypond $$i'],
@@ -1276,7 +1378,7 @@ def checkConverterEntries():
     # Currently, lyxpak outputs a gzip compressed tar archive on *nix
     # and a zip archive on Windows.
     # So, we configure the appropriate version according to the platform.
-    cmd = r'\converter lyx %s "python -tt $$s/scripts/lyxpak.py $$r/$$f" ""'
+    cmd = r'\converter lyx %s "$${python} $$s/scripts/lyxpak.py $$r/$$f" ""'
     if os.name == 'nt':
         addToRC(r'\Format lyxzip     zip    "LyX Archive (zip)"     "" "" ""  "document,menu=export"   ""')
         addToRC(cmd % "lyxzip")
@@ -1290,24 +1392,24 @@ def checkConverterEntries():
     #
     # Entries that do not need checkProg
     addToRC(r'''
-\converter csv        lyx        "python -tt $$s/scripts/csv2lyx.py $$i $$o"   ""
-\converter fen        asciichess "python -tt $$s/scripts/fen2ascii.py $$i $$o" ""
-\converter lyx        lyx13x     "python -tt $$s/lyx2lyx/lyx2lyx -V 1.3 -o $$o $$i"    ""
-\converter lyx        lyx14x     "python -tt $$s/lyx2lyx/lyx2lyx -V 1.4 -o $$o $$i"    ""
-\converter lyx        lyx15x     "python -tt $$s/lyx2lyx/lyx2lyx -V 1.5 -o $$o $$i"    ""
-\converter lyx        lyx16x     "python -tt $$s/lyx2lyx/lyx2lyx -V 1.6 -o $$o $$i"    ""
-\converter lyx        lyx20x     "python -tt $$s/lyx2lyx/lyx2lyx -V 2.0 -o $$o $$i"    ""
-\converter lyx        lyx21x     "python -tt $$s/lyx2lyx/lyx2lyx -V 2.1 -o $$o $$i"    ""
-\converter lyx        lyx22x     "python -tt $$s/lyx2lyx/lyx2lyx -V 2.2 -o $$o $$i"    ""
-\converter lyx        lyx23x     "python -tt $$s/lyx2lyx/lyx2lyx -V 2.3 -o $$o $$i"    ""
-\converter lyx        clyx       "python -tt $$s/lyx2lyx/lyx2lyx -V 1.4 -o $$o -c big5   $$i"  ""
-\converter lyx        jlyx       "python -tt $$s/lyx2lyx/lyx2lyx -V 1.4 -o $$o -c euc_jp $$i"  ""
-\converter lyx        klyx       "python -tt $$s/lyx2lyx/lyx2lyx -V 1.4 -o $$o -c euc_kr $$i"  ""
-\converter clyx       lyx        "python -tt $$s/lyx2lyx/lyx2lyx -c big5   -o $$o $$i" ""
-\converter jlyx       lyx        "python -tt $$s/lyx2lyx/lyx2lyx -c euc_jp -o $$o $$i" ""
-\converter klyx       lyx        "python -tt $$s/lyx2lyx/lyx2lyx -c euc_kr -o $$o $$i" ""
-\converter lyxpreview png        "python -tt $$s/scripts/lyxpreview2bitmap.py --png"   ""
-\converter lyxpreview ppm        "python -tt $$s/scripts/lyxpreview2bitmap.py --ppm"   ""
+\converter csv        lyx        "$${python} $$s/scripts/csv2lyx.py $$i $$o"   ""
+\converter fen        asciichess "$${python} $$s/scripts/fen2ascii.py $$i $$o" ""
+\converter lyx        lyx13x     "$${python} $$s/lyx2lyx/lyx2lyx -V 1.3 -o $$o $$i"    ""
+\converter lyx        lyx14x     "$${python} $$s/lyx2lyx/lyx2lyx -V 1.4 -o $$o $$i"    ""
+\converter lyx        lyx15x     "$${python} $$s/lyx2lyx/lyx2lyx -V 1.5 -o $$o $$i"    ""
+\converter lyx        lyx16x     "$${python} $$s/lyx2lyx/lyx2lyx -V 1.6 -o $$o $$i"    ""
+\converter lyx        lyx20x     "$${python} $$s/lyx2lyx/lyx2lyx -V 2.0 -o $$o $$i"    ""
+\converter lyx        lyx21x     "$${python} $$s/lyx2lyx/lyx2lyx -V 2.1 -o $$o $$i"    ""
+\converter lyx        lyx22x     "$${python} $$s/lyx2lyx/lyx2lyx -V 2.2 -o $$o $$i"    ""
+\converter lyx        lyx23x     "$${python} $$s/lyx2lyx/lyx2lyx -V 2.3 -o $$o $$i"    ""
+\converter lyx        clyx       "$${python} $$s/lyx2lyx/lyx2lyx -V 1.4 -o $$o -c big5   $$i"  ""
+\converter lyx        jlyx       "$${python} $$s/lyx2lyx/lyx2lyx -V 1.4 -o $$o -c euc_jp $$i"  ""
+\converter lyx        klyx       "$${python} $$s/lyx2lyx/lyx2lyx -V 1.4 -o $$o -c euc_kr $$i"  ""
+\converter clyx       lyx        "$${python} $$s/lyx2lyx/lyx2lyx -c big5   -o $$o $$i" ""
+\converter jlyx       lyx        "$${python} $$s/lyx2lyx/lyx2lyx -c euc_jp -o $$o $$i" ""
+\converter klyx       lyx        "$${python} $$s/lyx2lyx/lyx2lyx -c euc_kr -o $$o $$i" ""
+\converter lyxpreview png        "$${python} $$s/scripts/lyxpreview2bitmap.py --png"   ""
+\converter lyxpreview ppm        "$${python} $$s/scripts/lyxpreview2bitmap.py --ppm"   ""
 ''')
 
 
@@ -1341,11 +1443,11 @@ def checkOtherEntries():
     ## FIXME: MAPLE is not used anywhere
     # path, MAPLE = checkProg('Maple', ['maple'])
     # Add the rest of the entries (no checkProg is required)
-    addToRC(r'''\citation_search_view "python -tt $$s/scripts/lyxpaperview.py"''')
-    addToRC(r'''\copier    fig        "python -tt $$s/scripts/fig_copy.py $$i $$o"
-\copier    pstex      "python -tt $$s/scripts/tex_copy.py $$i $$o $$l"
-\copier    pdftex     "python -tt $$s/scripts/tex_copy.py $$i $$o $$l"
-\copier    program    "python -tt $$s/scripts/ext_copy.py $$i $$o"
+    addToRC(r'''\citation_search_view "$${python} $$s/scripts/lyxpaperview.py"''')
+    addToRC(r'''\copier    fig        "$${python} $$s/scripts/fig_copy.py $$i $$o"
+\copier    pstex      "$${python} $$s/scripts/tex_copy.py $$i $$o $$l"
+\copier    pdftex     "$${python} $$s/scripts/tex_copy.py $$i $$o $$l"
+\copier    program    "$${python} $$s/scripts/ext_copy.py $$i $$o"
 ''')
 
 def _checkForClassExtension(x):
@@ -1357,7 +1459,7 @@ def _checkForClassExtension(x):
         return x.strip()
 
 def processLayoutFile(file):
-    """ process layout file and get a line of result
+    r""" process layout file and get a line of result
 
         Declare lines look like this:
 
@@ -1385,8 +1487,8 @@ def processLayoutFile(file):
     """
     classname = file.split(os.sep)[-1].split('.')[0]
     # return ('[a,b]', 'a', ',b,c', 'article') for \DeclareLaTeXClass[a,b,c]{article}
-    p = re.compile('\s*#\s*\\\\DeclareLaTeXClass\s*(\[([^,]*)(,.*)*])*\s*{(.*)}\s*$')
-    q = re.compile('\s*#\s*\\\\DeclareCategory{(.*)}\s*$')
+    p = re.compile('\\s*#\\s*\\\\DeclareLaTeXClass\\s*(\\[([^,]*)(,.*)*])*\\s*{(.*)}\\s*$')
+    q = re.compile('\\s*#\\s*\\\\DeclareCategory{(.*)}\\s*$')
     classdeclaration = ""
     categorydeclaration = '""'
     for line in open(file, 'r', encoding='utf8').readlines():
@@ -1478,7 +1580,7 @@ def checkLatexConfig(check_config):
     # Construct the list of classes to test for.
     # build the list of available layout files and convert it to commands
     # for chkconfig.ltx
-    declare = re.compile('\\s*#\\s*\\\\DeclareLaTeXClass\\s*(\[([^,]*)(,.*)*\])*\\s*{(.*)}\\s*$')
+    declare = re.compile('\\s*#\\s*\\\\DeclareLaTeXClass\\s*(\\[([^,]*)(,.*)*\\])*\\s*{(.*)}\\s*$')
     category = re.compile('\\s*#\\s*\\\\DeclareCategory{(.*)}\\s*$')
     empty = re.compile('\\s*$')
     testclasses = list()
@@ -1494,7 +1596,7 @@ def checkLatexConfig(check_config):
             for line in open(file, 'r', encoding='utf8').readlines():
                 if not empty.match(line) and line[0] != '#'[0]:
                     if decline == "":
-                        logger.warning("Failed to find valid \Declare line "
+                        logger.warning(r"Failed to find valid \Declare line "
                             "for layout file `%s'.\n\t=> Skipping this file!" % file)
                         nodeclaration = True
                     # A class, but no category declaration. Just break.
@@ -1603,7 +1705,7 @@ def checkModulesConfig():
 
 
 def processModuleFile(file, filename):
-    ''' process module file and get a line of result
+    r''' process module file and get a line of result
 
         The top of a module file should look like this:
           #\DeclareLyXModule[LaTeX Packages]{ModuleName}
@@ -1617,12 +1719,12 @@ def processModuleFile(file, filename):
         We expect output:
           "ModuleName" "filename" "Description" "Packages" "Requires" "Excludes" "Category"
     '''
-    remods = re.compile('\s*#\s*\\\\DeclareLyXModule\s*(?:\[([^]]*?)\])?{(.*)}')
-    rereqs = re.compile('\s*#+\s*Requires: (.*)')
-    reexcs = re.compile('\s*#+\s*Excludes: (.*)')
+    remods = re.compile('\\s*#\\s*\\\\DeclareLyXModule\\s*(?:\\[([^]]*?)\\])?{(.*)}')
+    rereqs = re.compile(r'\s*#+\s*Requires: (.*)')
+    reexcs = re.compile(r'\s*#+\s*Excludes: (.*)')
     recaty = re.compile('\\s*#\\s*\\\\DeclareCategory{(.*)}\\s*$')
-    redbeg = re.compile('\s*#+\s*DescriptionBegin\s*$')
-    redend = re.compile('\s*#+\s*DescriptionEnd\s*$')
+    redbeg = re.compile(r'\s*#+\s*DescriptionBegin\s*$')
+    redend = re.compile(r'\s*#+\s*DescriptionEnd\s*$')
 
     modname = desc = pkgs = req = excl = catgy = ""
     readingDescription = False
@@ -1670,7 +1772,7 @@ def processModuleFile(file, filename):
         continue
 
     if modname == "":
-      logger.warning("Module file without \DeclareLyXModule line. ")
+      logger.warning(r"Module file without \DeclareLyXModule line. ")
       return ""
 
     if pkgs:
@@ -1734,7 +1836,7 @@ def checkCiteEnginesConfig():
 
 
 def processCiteEngineFile(file, filename):
-    ''' process cite engines file and get a line of result
+    r''' process cite engines file and get a line of result
 
         The top of a cite engine file should look like this:
           #\DeclareLyXCiteEngine[LaTeX Packages]{CiteEngineName}
@@ -1744,12 +1846,12 @@ def processCiteEngineFile(file, filename):
         We expect output:
           "CiteEngineName" "filename" "CiteEngineType" "CiteFramework" "DefaultBiblio" "Description" "Packages"
     '''
-    remods = re.compile('\s*#\s*\\\\DeclareLyXCiteEngine\s*(?:\[([^]]*?)\])?{(.*)}')
-    redbeg = re.compile('\s*#+\s*DescriptionBegin\s*$')
-    redend = re.compile('\s*#+\s*DescriptionEnd\s*$')
-    recet = re.compile('\s*CiteEngineType\s*(.*)')
-    redb = re.compile('\s*DefaultBiblio\s*(.*)')
-    resfm = re.compile('\s*CiteFramework\s*(.*)')
+    remods = re.compile('\\s*#\\s*\\\\DeclareLyXCiteEngine\\s*(?:\\[([^]]*?)\\])?{(.*)}')
+    redbeg = re.compile(r'\s*#+\s*DescriptionBegin\s*$')
+    redend = re.compile(r'\s*#+\s*DescriptionEnd\s*$')
+    recet = re.compile(r'\s*CiteEngineType\s*(.*)')
+    redb = re.compile(r'\s*DefaultBiblio\s*(.*)')
+    resfm = re.compile(r'\s*CiteFramework\s*(.*)')
 
     modname = desc = pkgs = cet = db = cfm = ""
     readingDescription = False
@@ -1793,7 +1895,7 @@ def processCiteEngineFile(file, filename):
         continue
 
     if modname == "":
-      logger.warning("Cite Engine File file without \DeclareLyXCiteEngine line. ")
+      logger.warning(r"Cite Engine File file without \DeclareLyXCiteEngine line. ")
       return ""
 
     if pkgs:
@@ -1900,7 +2002,7 @@ if __name__ == '__main__':
     lyx_check_config = True
     lyx_kpsewhich = True
     outfile = 'lyxrc.defaults'
-    lyxrc_fileformat = 34
+    lyxrc_fileformat = 37
     rc_entries = ''
     lyx_keep_temps = False
     version_suffix = ''
@@ -1960,7 +2062,10 @@ Format %i
     LATEX = checkLatex(dtl_tools)
     # check java and perl before any checkProg that may require them
     java = checkProg('a java interpreter', ['java'])[1]
+    if java == '':
+        java = check_java()
     perl = checkProg('a perl interpreter', ['perl'])[1]
+    xsltproc = checkProg('xsltproc', ['xsltproc'])[1]
     (inkscape_path, inkscape_gui) = os.path.split(checkInkscape())
     # On Windows, we need to call the "inkscape.com" wrapper
     # for command line purposes. Other OSes do not differentiate.