Edit

kc3-lang/freetype/meson.build

Branch :

  • Show log

    Commit

  • Author : Eli Schwartz
    Date : 2021-12-13 23:40:16
    Hash : d6a5c577
    Message : * meson.build: Optimize lookup for `python3` program. The python module's `find_installation` method is intended to provide routines for compiling and installing python modules into the `site-packages` directory. It does a couple of slow things, including run an introspection command to scrape sysconfig info from the detected interpreter, which are not needed for the sole use case of invoking the found installation as an executable. Furthermore, when invoked without the name or path of a python binary, it is hardcoded to always look for `python3` corresponding to the interpreter meson itself uses to run. So using `find_installation` did not even allow detecting `python2` as a fallback. Instead, switch to a simple `find_program` lookup that finishes as soon as the program is found.

  • meson.build
  • #
    # Meson project file for FreeType 2
    #
    
    # Copyright (C) 2020-2021 by
    # David Turner, Robert Wilhelm, and Werner Lemberg.
    #
    # This file is part of the FreeType project, and may only be used, modified,
    # and distributed under the terms of the FreeType project license,
    # LICENSE.TXT.  By continuing to use, modify, or distribute this file you
    # indicate that you have read the license and understand and accept it
    # fully.
    
    #
    # Say
    #
    #   meson configure
    #
    # to see all configuration options and their default values.  For example,
    # to build only a shared version of FreeType, override the default value
    # with
    #
    #   meson setup -Ddefault_library=shared
    #
    
    project('freetype2', 'c',
      meson_version: '>= 0.55.0',
      default_options: ['default_library=both'],
      version: run_command('builds/meson/extract_freetype_version.py',
                           'include/freetype/freetype.h',
                           check: true).stdout().strip(),
    )
    
    
    # Only meson >= 0.57 can read a file and assign its contents to a
    # variable; we thus use an external command to have this functionality
    # with older versions, too.
    
    python_exe = find_program('python3')
    
    ft2_so_version = run_command(python_exe,
      files('builds/meson/extract_libtool_version.py'),
      '--soversion',
      files('builds/unix/configure.raw'),
      check: true).stdout().strip()
    
    ft2_pkgconfig_version = run_command(python_exe,
      files('builds/meson/extract_libtool_version.py'),
      files('builds/unix/configure.raw'),
      check: true).stdout().strip()
    
    ft2_includes = include_directories('include')
    
    freetype_includedir = join_paths(get_option('includedir'), 'freetype2')
    
    # Generate a custom `ftmodule.h` version based on the content of
    # `modules.cfg`.
    
    ftmodule_h = custom_target('ftmodule.h',
      output: 'ftmodule.h',
      input: 'modules.cfg',
      command: [python_exe, files('builds/meson/parse_modules_cfg.py'),
                '--format=ftmodule.h', '@INPUT@', '--output', '@OUTPUT@'],
      install: true,
      install_dir: join_paths(freetype_includedir, 'freetype/config'),
    )
    ft2_sources = [ftmodule_h]
    
    
    # FreeType 2 modules.
    
    ft_main_modules = run_command(python_exe,
      files('builds/meson/parse_modules_cfg.py'),
      '--format=main-modules',
      files('modules.cfg'),
      check: true).stdout().strip().split()
    
    ft2_sources += files([
      'src/base/ftbase.c',
      'src/base/ftinit.c',
    ])
    
    foreach mod: ft_main_modules
      source = mod
      if mod == 'winfonts'
        source = 'winfnt'
      elif mod == 'cid'
        source = 'type1cid'
      endif
      ft2_sources += 'src/@0@/@1@.c'.format(mod, source)
    endforeach
    
    # NOTE: The `bzip2` aux module is handled through options.
    ft_aux_modules = run_command(python_exe,
      files('builds/meson/parse_modules_cfg.py'),
      '--format=aux-modules',
      files('modules.cfg'),
      check: true).stdout().strip().split()
    
    foreach auxmod: ft_aux_modules
      source = auxmod
      # Most sources are named `src/<module>/<module>.c`, but there are a few
      # exceptions handled here.
      if auxmod == 'cache'
        source = 'ftcache'
      elif auxmod == 'lzw'
        source = 'ftlzw'
      elif auxmod == 'gzip'
        source = 'ftgzip'
      elif auxmod == 'bzip2'
        # Handled through options instead, see below.
        continue
      endif
      ft2_sources += 'src/@0@/@1@.c'.format(auxmod, source)
    endforeach
    
    
    # FreeType 2 base extensions.
    # To be configured in `modules.cfg`.
    
    base_extensions = run_command(python_exe,
      files('builds/meson/parse_modules_cfg.py'),
      '--format=base-extensions-list',
      files('modules.cfg'),
      check: true).stdout().split()
    
    foreach ext: base_extensions
      ft2_sources += files('src/base/' + ext)
    endforeach
    
    
    # Header files.
    
    ft2_public_headers = files([
      'include/freetype/freetype.h',
      'include/freetype/ftadvanc.h',
      'include/freetype/ftbbox.h',
      'include/freetype/ftbdf.h',
      'include/freetype/ftbitmap.h',
      'include/freetype/ftbzip2.h',
      'include/freetype/ftcache.h',
      'include/freetype/ftchapters.h',
      'include/freetype/ftcid.h',
      'include/freetype/ftcolor.h',
      'include/freetype/ftdriver.h',
      'include/freetype/fterrdef.h',
      'include/freetype/fterrors.h',
      'include/freetype/ftfntfmt.h',
      'include/freetype/ftgasp.h',
      'include/freetype/ftglyph.h',
      'include/freetype/ftgxval.h',
      'include/freetype/ftgzip.h',
      'include/freetype/ftimage.h',
      'include/freetype/ftincrem.h',
      'include/freetype/ftlcdfil.h',
      'include/freetype/ftlist.h',
      'include/freetype/ftlzw.h',
      'include/freetype/ftmac.h',
      'include/freetype/ftmm.h',
      'include/freetype/ftmodapi.h',
      'include/freetype/ftmoderr.h',
      'include/freetype/ftotval.h',
      'include/freetype/ftoutln.h',
      'include/freetype/ftparams.h',
      'include/freetype/ftpfr.h',
      'include/freetype/ftrender.h',
      'include/freetype/ftsizes.h',
      'include/freetype/ftsnames.h',
      'include/freetype/ftstroke.h',
      'include/freetype/ftsynth.h',
      'include/freetype/ftsystem.h',
      'include/freetype/fttrigon.h',
      'include/freetype/fttypes.h',
      'include/freetype/ftwinfnt.h',
      'include/freetype/t1tables.h',
      'include/freetype/ttnameid.h',
      'include/freetype/tttables.h',
      'include/freetype/tttags.h',
    ])
    
    ft2_config_headers = files([
      'include/freetype/config/ftconfig.h',
      'include/freetype/config/ftheader.h',
      'include/freetype/config/ftstdlib.h',
      'include/freetype/config/integer-types.h',
      'include/freetype/config/mac-support.h',
      'include/freetype/config/public-macros.h',
    ])
    
    ft2_defines = ['-DFT2_BUILD_LIBRARY=1']
    
    
    # System support file.
    
    cc = meson.get_compiler('c')
    
    # NOTE: msys2 on Windows has `unistd.h` and `fcntl.h` but not `sys/mman.h`!
    has_unistd_h = cc.has_header('unistd.h')
    has_fcntl_h = cc.has_header('fcntl.h')
    has_sys_mman_h = cc.has_header('sys/mman.h')
    
    mmap_option = get_option('mmap')
    
    use_unix_ftsystem_c = false
    if mmap_option.disabled()
      ft2_sources += files(['src/base/ftsystem.c',])
    elif host_machine.system() == 'windows'
      ft2_sources += files(['builds/windows/ftsystem.c',])
    else
      if has_unistd_h and has_fcntl_h and has_sys_mman_h
        # This version of `ftsystem.c` uses `mmap` to read input font files.
        ft2_sources += files(['builds/unix/ftsystem.c',])
        use_unix_ftsystem_c = true
      elif mmap_option.enabled()
        error('mmap was enabled via options but is not available,'
              + ' required headers were not found!')
      else
        ft2_sources += files(['src/base/ftsystem.c',])
      endif
    endif
    
    
    # Debug support file
    #
    # NOTE: Some specialized versions exist for other platforms not supported by
    # Meson.  Most implementation differences are extremely minor, i.e., in the
    # implementation of `FT_Message` and `FT_Panic`, and getting the `FT2_DEBUG`
    # value from the environment, when this is supported.  A smaller refactor
    # might make these platform-specific files much smaller, and could be moved
    # into `ftsystem.c` as well.
    #
    if host_machine.system() == 'windows'
      winmod = import('windows')
      ft2_sources += [
        'builds/windows/ftdebug.c',
        winmod.compile_resources('src/base/ftver.rc'),
      ]
    else
      ft2_sources += 'src/base/ftdebug.c'
    endif
    
    
    ft2_deps = []
    common_ldflags = []
    
    
    # Correct compatibility version for OS x.
    #
    # OSX sets the compatibility_version (aka libtools version) differently from
    # the library name.
    #
    if host_machine.system() == 'darwin'
      # maintain compatibility with autotools on macOS
      common_ldflags = [
        '-compatibility_version', ft2_pkgconfig_version.split('.')[0],
        '-current_version', ft2_pkgconfig_version
      ]
    endif
    
    
    # Generate `ftoption.h` based on available dependencies.
    
    process_header_command = [python_exe,
      files('builds/meson/process_ftoption_h.py'),
      '@INPUT@', '--output=@OUTPUT@']
    ftoption_command = process_header_command
    
    
    # external GZip support
    zlib_dep = dependency('zlib',
      required: get_option('zlib'),
      fallback: 'zlib')
    
    if zlib_dep.found()
      ftoption_command += ['--enable=FT_CONFIG_OPTION_SYSTEM_ZLIB']
      ft2_deps += [zlib_dep]
    else
      ftoption_command += ['--disable=FT_CONFIG_OPTION_SYSTEM_ZLIB']
    endif
    
    # BZip2 support
    bzip2_dep = cc.find_library('bz2',
      required: get_option('bzip2'))
    
    if bzip2_dep.found()
      ftoption_command += ['--enable=FT_CONFIG_OPTION_USE_BZIP2']
      ft2_sources += files(['src/bzip2/ftbzip2.c',])
      ft2_deps += [bzip2_dep]
    endif
    
    # PNG support
    libpng_dep = dependency('libpng',
      required: get_option('png'),
      fallback: 'libpng')
    
    if libpng_dep.found()
      ftoption_command += ['--enable=FT_CONFIG_OPTION_USE_PNG']
      ft2_deps += [libpng_dep]
    endif
    
    # Harfbuzz support
    harfbuzz_dep = dependency('harfbuzz',
      version: '>= 2.0.0',
      required: get_option('harfbuzz'))
    
    if harfbuzz_dep.found()
      ftoption_command += ['--enable=FT_CONFIG_OPTION_USE_HARFBUZZ']
      ft2_deps += [harfbuzz_dep]
    endif
    
    # Brotli decompression support
    brotli_dep = dependency('libbrotlidec',
      required: get_option('brotli'))
    
    if brotli_dep.found()
      ftoption_command += ['--enable=FT_CONFIG_OPTION_USE_BROTLI']
      ft2_deps += [brotli_dep]
    endif
    
    # We can now generate `ftoption.h`.
    ftoption_h = custom_target('ftoption.h',
      input: 'include/freetype/config/ftoption.h',
      output: 'ftoption.h',
      command: ftoption_command,
      install: true,
      install_dir: join_paths(freetype_includedir, 'freetype/config'),
    )
    ft2_sources += ftoption_h
    ft2_defines += ['-DFT_CONFIG_OPTIONS_H=<ftoption.h>']
    
    if host_machine.system() == 'windows'
      ft2_defines += ['-DDLL_EXPORT=1']
    endif
    
    
    # Generate `ftconfig.h`.
    
    ftconfig_command = process_header_command
    if has_unistd_h
      ftconfig_command += '--enable=HAVE_UNISTD_H'
    endif
    if has_fcntl_h
      ftconfig_command += '--enable=HAVE_FCNTL_H'
    endif
    
    if use_unix_ftsystem_c
      ftconfig_h_in = files('builds/unix/ftconfig.h.in')
      ftconfig_h = custom_target('ftconfig.h',
        input: ftconfig_h_in,
        output: 'ftconfig.h',
        command: ftconfig_command,
        install: true,
        install_dir: join_paths(freetype_includedir, 'freetype/config'),
      )
      ft2_sources += ftconfig_h
      ft2_defines += ['-DFT_CONFIG_CONFIG_H=<ftconfig.h>']
    endif
    
    
    ft2_lib = library('freetype',
      sources: ft2_sources + [ftmodule_h],
      c_args: ft2_defines,
      gnu_symbol_visibility: 'hidden',
      include_directories: ft2_includes,
      dependencies: ft2_deps,
      install: true,
      version: ft2_so_version,
      link_args: common_ldflags,
    )
    
    
    # To be used by other projects including this one through `subproject`.
    freetype_dep = declare_dependency(
      include_directories: ft2_includes,
      link_with: ft2_lib,
      version: ft2_pkgconfig_version)
    
    meson.override_dependency('freetype2', freetype_dep)
    
    
    # NOTE: Using both `install_dir` and `subdir` doesn't seem to work below,
    # i.e., the subdir value seems to be ignored, contrary to examples in the
    # Meson documentation.
    install_headers('include/ft2build.h',
      install_dir: freetype_includedir)
    install_headers(ft2_public_headers,
      install_dir: join_paths(freetype_includedir, 'freetype'))
    install_headers(ft2_config_headers,
      install_dir: join_paths(freetype_includedir, 'freetype/config'))
    
    
    pkgconfig = import('pkgconfig')
    
    pkgconfig.generate(ft2_lib,
      filebase: 'freetype2',
      name: 'FreeType 2',
      description: 'A free, high-quality, and portable font engine.',
      url: 'https://freetype.org',
      subdirs: 'freetype2',
      version: ft2_pkgconfig_version,
    )
    
    if get_option('tests').enabled()
      subdir('tests')
    endif
    
    # NOTE: Unlike the old `make refdoc` command, this generates the
    # documentation under `$BUILD/docs/` since Meson doesn't support modifying
    # the source root directory (which is a good thing).
    gen_docs = custom_target('freetype2 reference documentation',
      output: 'docs',
      input: ft2_public_headers + ft2_config_headers,
      command: [python_exe,
        files('builds/meson/generate_reference_docs.py'),
        '--version=' + meson.project_version(),
        '--input-dir=' + meson.current_source_dir(),
        '--output-dir=@OUTPUT@'
      ],
    )
    
    
    summary({'OS': host_machine.system(),
            }, section: 'Operating System')
    
    summary({'Zlib': zlib_dep.found() ? 'external' : 'internal',
             'Bzip2': bzip2_dep.found() ? 'yes' : 'no',
             'Png': libpng_dep.found() ? 'yes' : 'no',
             'Harfbuzz': harfbuzz_dep.found() ? 'yes' : 'no',
             'Brotli': brotli_dep.found() ? 'yes' : 'no',
            }, section: 'Used Libraries')
    
    # EOF