diff options
Diffstat (limited to '')
-rw-r--r-- | mesonbuild/scripts/gtkdochelper.py | 296 |
1 files changed, 296 insertions, 0 deletions
diff --git a/mesonbuild/scripts/gtkdochelper.py b/mesonbuild/scripts/gtkdochelper.py new file mode 100644 index 0000000..ded952d --- /dev/null +++ b/mesonbuild/scripts/gtkdochelper.py @@ -0,0 +1,296 @@ +# Copyright 2015-2016 The Meson development team + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from __future__ import annotations + +import sys, os +import subprocess +import shutil +import argparse +from ..mesonlib import MesonException, Popen_safe, is_windows, is_cygwin, split_args +from . import destdir_join +import typing as T + +parser = argparse.ArgumentParser() + +parser.add_argument('--sourcedir', dest='sourcedir') +parser.add_argument('--builddir', dest='builddir') +parser.add_argument('--subdir', dest='subdir') +parser.add_argument('--headerdirs', dest='headerdirs') +parser.add_argument('--mainfile', dest='mainfile') +parser.add_argument('--modulename', dest='modulename') +parser.add_argument('--moduleversion', dest='moduleversion') +parser.add_argument('--htmlargs', dest='htmlargs', default='') +parser.add_argument('--scanargs', dest='scanargs', default='') +parser.add_argument('--scanobjsargs', dest='scanobjsargs', default='') +parser.add_argument('--gobjects-types-file', dest='gobject_typesfile', default='') +parser.add_argument('--fixxrefargs', dest='fixxrefargs', default='') +parser.add_argument('--mkdbargs', dest='mkdbargs', default='') +parser.add_argument('--ld', dest='ld', default='') +parser.add_argument('--cc', dest='cc', default='') +parser.add_argument('--ldflags', dest='ldflags', default='') +parser.add_argument('--cflags', dest='cflags', default='') +parser.add_argument('--content-files', dest='content_files', default='') +parser.add_argument('--expand-content-files', dest='expand_content_files', default='') +parser.add_argument('--html-assets', dest='html_assets', default='') +parser.add_argument('--ignore-headers', dest='ignore_headers', default='') +parser.add_argument('--namespace', dest='namespace', default='') +parser.add_argument('--mode', dest='mode', default='') +parser.add_argument('--installdir', dest='install_dir') +parser.add_argument('--run', dest='run', default='') +for tool in ['scan', 'scangobj', 'mkdb', 'mkhtml', 'fixxref']: + program_name = 'gtkdoc-' + tool + parser.add_argument('--' + program_name, dest=program_name.replace('-', '_')) + +def gtkdoc_run_check(cmd: T.List[str], cwd: str, library_paths: T.Optional[T.List[str]] = None) -> None: + if library_paths is None: + library_paths = [] + + env = dict(os.environ) + if is_windows() or is_cygwin(): + if 'PATH' in env: + library_paths.extend(env['PATH'].split(os.pathsep)) + env['PATH'] = os.pathsep.join(library_paths) + else: + if 'LD_LIBRARY_PATH' in env: + library_paths.extend(env['LD_LIBRARY_PATH'].split(os.pathsep)) + env['LD_LIBRARY_PATH'] = os.pathsep.join(library_paths) + + if is_windows(): + cmd.insert(0, sys.executable) + + # Put stderr into stdout since we want to print it out anyway. + # This preserves the order of messages. + p, out = Popen_safe(cmd, cwd=cwd, env=env, stderr=subprocess.STDOUT)[0:2] + if p.returncode != 0: + err_msg = [f"{cmd!r} failed with status {p.returncode:d}"] + if out: + err_msg.append(out) + raise MesonException('\n'.join(err_msg)) + elif out: + # Unfortunately Windows cmd.exe consoles may be using a codepage + # that might choke print() with a UnicodeEncodeError, so let's + # ignore such errors for now, as a compromise as we are outputting + # console output here... + try: + print(out) + except UnicodeEncodeError: + pass + +def build_gtkdoc(source_root: str, build_root: str, doc_subdir: str, src_subdirs: T.List[str], + main_file: str, module: str, module_version: str, + html_args: T.List[str], scan_args: T.List[str], fixxref_args: T.List[str], mkdb_args: T.List[str], + gobject_typesfile: str, scanobjs_args: T.List[str], run: str, ld: str, cc: str, ldflags: str, cflags: str, + html_assets: T.List[str], content_files: T.List[str], ignore_headers: T.List[str], namespace: str, + expand_content_files: T.List[str], mode: str, options: argparse.Namespace) -> None: + print("Building documentation for %s" % module) + + src_dir_args = [] + for src_dir in src_subdirs: + if not os.path.isabs(src_dir): + dirs = [os.path.join(source_root, src_dir), + os.path.join(build_root, src_dir)] + else: + dirs = [src_dir] + src_dir_args += ['--source-dir=' + d for d in dirs] + + doc_src = os.path.join(source_root, doc_subdir) + abs_out = os.path.join(build_root, doc_subdir) + htmldir = os.path.join(abs_out, 'html') + + content_files += [main_file] + sections = os.path.join(doc_src, module + "-sections.txt") + if os.path.exists(sections): + content_files.append(sections) + + overrides = os.path.join(doc_src, module + "-overrides.txt") + if os.path.exists(overrides): + content_files.append(overrides) + + # Copy files to build directory + for f in content_files: + # FIXME: Use mesonlib.File objects so we don't need to do this + if not os.path.isabs(f): + f = os.path.join(doc_src, f) + elif os.path.commonpath([f, build_root]) == build_root: + continue + shutil.copyfile(f, os.path.join(abs_out, os.path.basename(f))) + + shutil.rmtree(htmldir, ignore_errors=True) + try: + os.mkdir(htmldir) + except Exception: + pass + + for f in html_assets: + f_abs = os.path.join(doc_src, f) + shutil.copyfile(f_abs, os.path.join(htmldir, os.path.basename(f_abs))) + + scan_cmd = [options.gtkdoc_scan, '--module=' + module] + src_dir_args + if ignore_headers: + scan_cmd.append('--ignore-headers=' + ' '.join(ignore_headers)) + # Add user-specified arguments + scan_cmd += scan_args + gtkdoc_run_check(scan_cmd, abs_out) + + # Use the generated types file when available, otherwise gobject_typesfile + # would often be a path to source dir instead of build dir. + if '--rebuild-types' in scan_args: + gobject_typesfile = os.path.join(abs_out, module + '.types') + + if gobject_typesfile: + scanobjs_cmd = [options.gtkdoc_scangobj] + scanobjs_args + scanobjs_cmd += ['--types=' + gobject_typesfile, + '--module=' + module, + '--run=' + run, + '--cflags=' + cflags, + '--ldflags=' + ldflags, + '--cc=' + cc, + '--ld=' + ld, + '--output-dir=' + abs_out] + + library_paths = [] + for ldflag in split_args(ldflags): + if ldflag.startswith('-Wl,-rpath,'): + library_paths.append(ldflag[11:]) + + gtkdoc_run_check(scanobjs_cmd, build_root, library_paths) + + # Make docbook files + if mode == 'auto': + # Guessing is probably a poor idea but these keeps compat + # with previous behavior + if main_file.endswith('sgml'): + modeflag = '--sgml-mode' + else: + modeflag = '--xml-mode' + elif mode == 'xml': + modeflag = '--xml-mode' + elif mode == 'sgml': + modeflag = '--sgml-mode' + else: # none + modeflag = None + + mkdb_cmd = [options.gtkdoc_mkdb, + '--module=' + module, + '--output-format=xml', + '--expand-content-files=' + ' '.join(expand_content_files), + ] + src_dir_args + if namespace: + mkdb_cmd.append('--name-space=' + namespace) + if modeflag: + mkdb_cmd.append(modeflag) + if main_file: + # Yes, this is the flag even if the file is in xml. + mkdb_cmd.append('--main-sgml-file=' + main_file) + # Add user-specified arguments + mkdb_cmd += mkdb_args + gtkdoc_run_check(mkdb_cmd, abs_out) + + # Make HTML documentation + mkhtml_cmd = [options.gtkdoc_mkhtml, + '--path=' + os.pathsep.join((doc_src, abs_out)), + module, + ] + html_args + if main_file: + mkhtml_cmd.append('../' + main_file) + else: + mkhtml_cmd.append('%s-docs.xml' % module) + # html gen must be run in the HTML dir + gtkdoc_run_check(mkhtml_cmd, htmldir) + + # Fix cross-references in HTML files + fixref_cmd = [options.gtkdoc_fixxref, + '--module=' + module, + '--module-dir=html'] + fixxref_args + gtkdoc_run_check(fixref_cmd, abs_out) + + if module_version: + shutil.move(os.path.join(htmldir, f'{module}.devhelp2'), + os.path.join(htmldir, f'{module}-{module_version}.devhelp2')) + +def install_gtkdoc(build_root: str, doc_subdir: str, install_prefix: str, datadir: str, module: str) -> None: + source = os.path.join(build_root, doc_subdir, 'html') + final_destination = os.path.join(install_prefix, datadir, module) + shutil.rmtree(final_destination, ignore_errors=True) + shutil.copytree(source, final_destination) + +def run(args: T.List[str]) -> int: + options = parser.parse_args(args) + if options.htmlargs: + htmlargs = options.htmlargs.split('@@') + else: + htmlargs = [] + if options.scanargs: + scanargs = options.scanargs.split('@@') + else: + scanargs = [] + if options.scanobjsargs: + scanobjsargs = options.scanobjsargs.split('@@') + else: + scanobjsargs = [] + if options.fixxrefargs: + fixxrefargs = options.fixxrefargs.split('@@') + else: + fixxrefargs = [] + if options.mkdbargs: + mkdbargs = options.mkdbargs.split('@@') + else: + mkdbargs = [] + build_gtkdoc( + options.sourcedir, + options.builddir, + options.subdir, + options.headerdirs.split('@@'), + options.mainfile, + options.modulename, + options.moduleversion, + htmlargs, + scanargs, + fixxrefargs, + mkdbargs, + options.gobject_typesfile, + scanobjsargs, + options.run, + options.ld, + options.cc, + options.ldflags, + options.cflags, + options.html_assets.split('@@') if options.html_assets else [], + options.content_files.split('@@') if options.content_files else [], + options.ignore_headers.split('@@') if options.ignore_headers else [], + options.namespace, + options.expand_content_files.split('@@') if options.expand_content_files else [], + options.mode, + options) + + if 'MESON_INSTALL_PREFIX' in os.environ: + destdir = os.environ.get('DESTDIR', '') + install_prefix = destdir_join(destdir, os.environ['MESON_INSTALL_PREFIX']) + if options.install_dir: + install_dir = options.install_dir + else: + install_dir = options.modulename + if options.moduleversion: + install_dir += '-' + options.moduleversion + if os.path.isabs(install_dir): + install_dir = destdir_join(destdir, install_dir) + install_gtkdoc(options.builddir, + options.subdir, + install_prefix, + 'share/gtk-doc/html', + install_dir) + return 0 + +if __name__ == '__main__': + sys.exit(run(sys.argv[1:])) |