Source code for dolfin.jit.pybind11jit

# -*- coding: utf-8 -*-
# Copyright (C) 2017 Chris N. Richardson and Garth N. Wells
#
# This file is part of DOLFIN (https://www.fenicsproject.org)
#
# SPDX-License-Identifier:    LGPL-3.0-or-later

import hashlib
import os
import re

import dijitso
from dolfin import cpp, jit
from dolfin.cpp.log import LogLevel, log


def jit_generate(cpp_code, module_name, signature, parameters):

    log(LogLevel.TRACE,
        "Calling dijitso just-in-time (JIT) compiler for pybind11 code.")

    # Split code on reserved word "SIGNATURE" which will be replaced
    # by the module signature
    # This must occur only once in the code
    split_cpp_code = re.split('SIGNATURE', cpp_code)
    if len(split_cpp_code) < 2:
        raise RuntimeError(
            "Cannot find keyword: SIGNATURE in pybind11 C++ code.")
    elif len(split_cpp_code) > 2:
        raise RuntimeError(
            "Found multiple instances of keyword: SIGNATURE in pybind11 C++ code."
        )

    code_c = split_cpp_code[0] + signature + split_cpp_code[1]

    code_h = ""
    depends = []

    return code_h, code_c, depends


[docs]def compile_cpp_code(cpp_code, include_dirs=[], libs=[], lib_dirs=[], cxxflags=[]): """Compile a user C(++) string and expose as a Python object with pybind11. """ # Set compiler/build options # FIXME: need to locate Python libs and pybind11 from distutils import sysconfig params = dijitso.params.default_params() pyversion = "python" + sysconfig.get_config_var("LDVERSION") params['cache']['lib_prefix'] = "" params['cache']['lib_basename'] = "" params['cache']['lib_loader'] = "import" # Include path and library info from DOLFIN (dolfin.pc) params['build']['include_dirs'] = jit.dolfin_pc["include_dirs"] + get_pybind_include() \ + [sysconfig.get_config_var("INCLUDEDIR") + "/" + pyversion] params['build']['libs'] = jit.dolfin_pc["libraries"] + [pyversion] params['build']['lib_dirs'] = jit.dolfin_pc["library_dirs"] + [ sysconfig.get_config_var("LIBDIR") ] params['build']['cxxflags'] += ('-fno-lto', ) # Enable all macros from dolfin.pc dmacros = ['-D' + dm for dm in jit.dolfin_pc['define_macros']] params['build']['cxxflags'] += tuple(dmacros) # Parse argument compilation options params['build']['include_dirs'] += include_dirs params['build']['libs'] += libs params['build']['lib_dirs'] += lib_dirs params['build']['cxxflags'] += tuple(cxxflags) hash_str = cpp_code + cpp.__version__ module_hash = hashlib.md5(hash_str.encode('utf-8')).hexdigest() module_name = "dolfin_cpp_module_" + module_hash module, signature = jit.dijitso_jit( cpp_code, module_name, params, generate=jit_generate) return module
[docs]def get_pybind_include(): """Find the pybind11 include path""" # Look in PYBIND11_DIR pybind_dir = os.getenv('PYBIND11_DIR', None) if pybind_dir: p = os.path.join(pybind_dir, "include") if (_check_pybind_path(p)): return [p] # Try extracting from pybind11 module try: # Get include paths from module import pybind11 return [pybind11.get_include(True), pybind11.get_include()] except Exception: pass # Look in /usr/local/include and /usr/include root = os.path.abspath(os.sep) for p in (os.path.join(root, "usr", "local", "include"), os.path.join(root, "usr", "include")): if (_check_pybind_path(p)): return [p] raise RuntimeError("Unable to locate pybind11 header files")
def _check_pybind_path(root): p = os.path.join(root, "pybind11", "pybind11.h") if os.path.isfile(p): return True else: return False