Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 11 additions & 12 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,24 @@ on:
push:
pull_request:
schedule:
#Every 5 days at midnight
#Every 5 days at midnight
- cron: "0 0 1/5 * *"

jobs:
compilejobFedora:
strategy:
fail-fast: false
fail-fast: false
matrix:
version: [26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40]
version: [29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40]
runs-on: ubuntu-latest
name: Binder_on_Fedora${{ matrix.version }}
container:
image: fedora:${{ matrix.version }}
steps:
- name: Install
- name: Install
run: |
set -x
uname -a
uname -a
cat /etc/issue
yum -y install git zlib zlib-devel ncurses-devel clang clang-devel clang-libs llvm llvm-devel llvm-static \
libcxx-devel cmake make gcc gcc-c++ \
Expand All @@ -34,28 +34,27 @@ jobs:
make install
ldd source/binder
ldd -u -r source/binder || echo "OK"
ctest . --output-on-failure
ctest . --output-on-failure

compilejobOSX:
runs-on: macos-latest
name: Binder_on_OSX
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Install
- name: Install
run: |
set -x
brew install wget coreutils xz pybind11 git
wget --no-verbose https://github.com/llvm/llvm-project/releases/download/llvmorg-11.0.0/clang+llvm-11.0.0-x86_64-apple-darwin.tar.xz
wget --no-verbose https://github.com/llvm/llvm-project/releases/download/llvmorg-14.0.5/clang+llvm-14.0.5-x86_64-apple-darwin.tar.xz
ls
tar -xJf clang+llvm-11.0.0-x86_64-apple-darwin.tar.xz
export PATH=$PATH:clang+llvm-11.0.0-x86_64-apple-darwin/bin
tar -xJf clang+llvm-14.0.5-x86_64-apple-darwin.tar.xz
export PATH=$PATH:clang+llvm-14.0.5-x86_64-apple-darwin/bin
- name: Compile
run: |
export PATH=$PATH:clang+llvm-11.0.0-x86_64-apple-darwin/bin
export PATH=$PATH:clang+llvm-14.0.5-x86_64-apple-darwin/bin
cmake CMakeLists.txt
make
make install
otool -L source/binder
ctest . --output-on-failure

2 changes: 1 addition & 1 deletion documentation/config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ files. Typically the following files will be generated: ``<root-module>.cpp``, `


``--annotate-includes`` [debug] if specified Binder will comment each include with type name which trigger it inclusion.
``--annotate-functions`` [debug] if specified Binder will generate an extra comment for each function/constructor bound containing its C++ type signature.


``--trace`` [debug] if specified instruct Binder to add extra debug output before binding each type. This might be useful when debugging generated code that produce seg-faults during python import.
Expand Down Expand Up @@ -253,4 +254,3 @@ Config file directives:
.. code-block:: bash

+pybind11_include_file pybind11/smart_holder.h

58 changes: 44 additions & 14 deletions source/class.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1032,8 +1032,15 @@ string bind_constructor(ConstructorBindingInfo const &CBI, uint args_to_bind, bo
// string function_qualified_name { F->getQualifiedNameAsString() };

string c;

if( O_annotate_functions ) {
clang::FunctionDecl const *F = CBI.T;
string const include = relevant_include(F);
c += "\t// function-signature: " + function_qualified_name(F, true) + "(" + function_arguments(F) + ") file:" + (include.size() ? include.substr(1, include.size() - 2) : "") + " line:" + line_number(F) + "\n";
}

if( args_to_bind == CBI.T->getNumParams() and not CBI.T->isVariadic() ) {
c = "\tcl.def( pybind11::init<{}>()"_format(function_arguments(CBI.T));
c += "\tcl.def( pybind11::init<{}>()"_format(function_arguments(CBI.T));

for( uint i = 0; i < CBI.T->getNumParams() and i < args_to_bind; ++i ) {
c += ", pybind11::arg(\"{}\")"_format(string(CBI.T->getParamDecl(i)->getName()));
Expand All @@ -1052,14 +1059,14 @@ string bind_constructor(ConstructorBindingInfo const &CBI, uint args_to_bind, bo

for( uint i = 0; i < CBI.T->getNumParams() and i < args_to_bind; ++i ) { args_helper += ", pybind11::arg(\"{}\")"_format(string(CBI.T->getParamDecl(i)->getName())); }

// if( CBI.T->isVariadic() ) c = fmt::format(constructor_lambda_template, params, args.second, constructor_types.first, constructor_types.second);
// else if( constructor_types.first.size() and constructor_types.second.size() ) c = fmt::format(constructor_lambda_template, params, args.second, constructor_types.first,
// constructor_types.second); else if( constructor_types.first.size() ) c = fmt::format(constructor_template, params, args.second, constructor_types.first); else c =
// if( CBI.T->isVariadic() ) c += fmt::format(constructor_lambda_template, params, args.second, constructor_types.first, constructor_types.second);
// else if( constructor_types.first.size() and constructor_types.second.size() ) c += fmt::format(constructor_lambda_template, params, args.second, constructor_types.first,
// constructor_types.second); else if( constructor_types.first.size() ) c += fmt::format(constructor_template, params, args.second, constructor_types.first); else c +=
// fmt::format(constructor_template, params, args.second, constructor_types.second);

if( CBI.C->isAbstract() ) c = fmt::format(constructor_template, params, args.second, CBI.trampoline_qualified_name);
else if( CBI.trampoline ) c = fmt::format(constructor_with_trampoline_template, params, args.second, CBI.class_qualified_name, CBI.trampoline_qualified_name);
else c = fmt::format(constructor_template_with_py_arg, params, args.second, CBI.class_qualified_name, args_helper);
if( CBI.C->isAbstract() ) c += fmt::format(constructor_template, params, args.second, CBI.trampoline_qualified_name);
else if( CBI.trampoline ) c += fmt::format(constructor_with_trampoline_template, params, args.second, CBI.class_qualified_name, CBI.trampoline_qualified_name);
else c += fmt::format(constructor_template_with_py_arg, params, args.second, CBI.class_qualified_name, args_helper);
}

return c;
Expand All @@ -1069,20 +1076,40 @@ string bind_constructor(ConstructorBindingInfo const &CBI, uint args_to_bind, bo
/// Generate code for binding default constructor
string bind_default_constructor(ConstructorBindingInfo const &CBI) // CXXRecordDecl const *, string const & binding_qualified_name)
{
string code;
if( O_annotate_functions ) {
clang::FunctionDecl const *F = CBI.T;
if(F) {
string const include = relevant_include(F);
code += "\t// function-signature: " + function_qualified_name(F, true) + "(" + function_arguments(F) + ") file:" + (include.size() ? include.substr(1, include.size() - 2) : "") + " line:" + line_number(F) + "\n";
}
else {
code += "\t// function-signature: " + CBI.class_qualified_name + "()\n";
}
}

// version before error: chosen constructor is explicit in copy-initialization
// return "\tcl.def(pybind11::init<>());__\n";

// return "\tcl.def( pybind11::init( [](){{ return new {0}(); }} ) );\n"_format(binding_qualified_name);

if( CBI.C->isAbstract() ) return "\tcl.def( pybind11::init( [](){{ return new {0}(); }} ) );\n"_format(CBI.trampoline_qualified_name);
else if( CBI.trampoline ) return "\tcl.def( pybind11::init( [](){{ return new {0}(); }}, [](){{ return new {1}(); }} ) );\n"_format(CBI.class_qualified_name, CBI.trampoline_qualified_name);
else return "\tcl.def( pybind11::init( [](){{ return new {0}(); }} ) );\n"_format(CBI.class_qualified_name);
if( CBI.C->isAbstract() ) code += "\tcl.def( pybind11::init( [](){{ return new {0}(); }} ) );\n"_format(CBI.trampoline_qualified_name);
else if( CBI.trampoline ) code += "\tcl.def( pybind11::init( [](){{ return new {0}(); }}, [](){{ return new {1}(); }} ) );\n"_format(CBI.class_qualified_name, CBI.trampoline_qualified_name);
else code += "\tcl.def( pybind11::init( [](){{ return new {0}(); }} ) );\n"_format(CBI.class_qualified_name);

return code;
}

/// Generate copy constructor in most cases this will be just: "\tcl.def(pybind11::init<{} const &>());\n"_format(binding_qualified_name);
/// but for POD structs with zero data mambers this will be a lambda function. This is done as a workaround for Pybind11 2,2+ bug
string bind_copy_constructor(ConstructorBindingInfo const &CBI) // CXXConstructorDecl const *T, string const & binding_qualified_name)
{
string code;
if( O_annotate_functions ) {
clang::FunctionDecl const *F = CBI.T;
string const include = relevant_include(F);
code += "\t// function-signature: " + function_qualified_name(F, true) + "(" + function_arguments(F) + ") file:" + (include.size() ? include.substr(1, include.size() - 2) : "") + " line:" + line_number(F) + "\n";
}
// CXXRecordDecl const *C = T->getParent();

// C->dump();
Expand Down Expand Up @@ -1111,15 +1138,18 @@ string bind_copy_constructor(ConstructorBindingInfo const &CBI) // CXXConstructo
}

if( CBI.trampoline ) {
if( CBI.C->isAbstract() ) return "\tcl.def(pybind11::init<{}{} &>());\n"_format(CBI.trampoline_qualified_name, const_bit);
if( CBI.C->isAbstract() ) code += "\tcl.def(pybind11::init<{}{} &>());\n"_format(CBI.trampoline_qualified_name, const_bit);
else {
// not yet supported by Pybind11? return "\tcl.def( pybind11::init( []({0} const &o){{ return new {0}(o); }}, []({1} const &o){{ return new {1}(o); }} )
// );\n"_format(CBI.class_qualified_name, CBI.binding_qualified_name);
return "\tcl.def( pybind11::init( []({0}{1} &o){{ return new {0}(o); }} ) );\n"_format(CBI.trampoline_qualified_name, const_bit) +
(CBI.T->getAccess() == AS_public ? "\tcl.def( pybind11::init( []({0}{1} &o){{ return new {0}(o); }} ) );\n"_format(CBI.class_qualified_name, const_bit) : "");
code += \
"\tcl.def( pybind11::init( []({0}{1} &o){{ return new {0}(o); }} ) );\n"_format(CBI.trampoline_qualified_name, const_bit) +
(CBI.T->getAccess() == AS_public ? "\tcl.def( pybind11::init( []({0}{1} &o){{ return new {0}(o); }} ) );\n"_format(CBI.class_qualified_name, const_bit) : "");
}
}
else return "\tcl.def( pybind11::init( []({0}{1} &o){{ return new {0}(o); }} ) );\n"_format(CBI.class_qualified_name, const_bit);
else code += "\tcl.def( pybind11::init( []({0}{1} &o){{ return new {0}(o); }} ) );\n"_format(CBI.class_qualified_name, const_bit);

return code;
}

// Generate binding for given constructor. If constructor have default arguments generate set of bindings by creating separate bindings for each argument with default.
Expand Down
6 changes: 6 additions & 0 deletions source/function.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
/// @author Sergey Lyskov

#include <function.hpp>
#include <options.hpp>

#include <class.hpp>
#include <fmt/format.h>
Expand Down Expand Up @@ -451,6 +452,11 @@ string bind_function(string const &module, FunctionDecl const *F, Context &conte
{
string code;

if( O_annotate_functions ) {
string const include = relevant_include(F);
code += "\t// function-signature: " + function_qualified_name(F) + "(" + function_arguments(F) + ") file:" + (include.size() ? include.substr(1, include.size() - 2) : "") + " line:" + line_number(F) + "\n";
}

int num_params = F->getNumParams();

int args_to_bind = 0;
Expand Down
2 changes: 2 additions & 0 deletions source/options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ llvm::cl::OptionCategory BinderToolCategory("Binder options");

cl::opt<bool> O_annotate_includes("annotate-includes", cl::desc("Annotate each includes in generated code with type name that trigger it inclusion"), cl::init(false), cl::cat(BinderToolCategory));

cl::opt<bool> O_annotate_functions("annotate-functions", cl::desc("Annotate each function bindings with full function signature"), cl::init(false), cl::cat(BinderToolCategory));

cl::opt<bool> O_single_file("single-file", cl::desc("Concatenate all binder output into single file with name: root-module-name + '.cpp'. Use this for a small projects and for testing."),
cl::init(false), cl::cat(BinderToolCategory));

Expand Down
1 change: 1 addition & 0 deletions source/options.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
extern llvm::cl::OptionCategory BinderToolCategory;

extern llvm::cl::opt<bool> O_annotate_includes;
extern llvm::cl::opt<bool> O_annotate_functions;
extern llvm::cl::opt<bool> O_single_file;
extern llvm::cl::opt<bool> O_trace;
extern llvm::cl::opt<bool> O_verbose;
Expand Down
1 change: 1 addition & 0 deletions test/T07.class.hpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

// -*- mode:c++;tab-width:2;indent-tabs-mode:t;show-trailing-whitespace:t;rm-trailing-spaces:t -*-
// vi: set ts=2 noet:
//
Expand Down
7 changes: 5 additions & 2 deletions test/self-test.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,11 @@ def run_test(test_path, build_dir, pyenv):
python = pyenv.python
python_includes = '-I'+pyenv.python_include_dir #'-I/usr/include/python2.7'

command_line = '{binder} --bind "" --skip-line-number --root-module {root_module} --prefix {build_dir} --single-file --annotate-includes {config}{cli} {source} -- -x c++ -std=c++11 -I {source_dir} -I {source_dir}/.. -isystem {pybind11} {python_includes}' \
extras = '--annotate-functions' if Options.annotate else ''

command_line = '{binder} --bind "" --skip-line-number --root-module {root_module} --prefix {build_dir} --single-file --annotate-includes {extras} {config}{cli} {source} -- -x c++ -std=c++11 -I {source_dir} -I {source_dir}/.. -isystem {pybind11} {python_includes}' \
.format(binder=Options.binder, root_module=root_module, build_dir=build_dir, source_dir=source_dir, cli=cli, source=source_include,
config='--config {}'.format(config) if config else '', pybind11=Options.pybind11, python_includes=python_includes)
config='--config {}'.format(config) if config else '', pybind11=Options.pybind11, python_includes=python_includes, extras=extras)

execute('{} Running test...'.format(test), command_line);

Expand Down Expand Up @@ -150,6 +152,7 @@ def main():
parser.add_argument('--pybind11', default='', help='Path to pybind11 source tree')

parser.add_argument("--accept", action="store_true", help="Run tests and accept new tests results as reference")
parser.add_argument("--annotate", action="store_true", help="Run Binder with extra annotation options")

parser.add_argument('args', nargs=argparse.REMAINDER, help='Optional: list of tests to run')

Expand Down
Loading