From 5418a663cb79bbdb30cce90d22cb071e940cff58 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Mon, 25 Jan 2010 14:48:49 +0000 Subject: [PATCH] Support different MS calling conventions, thanks to Nicolas Lelong. Closes #3833. [SVN r59265] --- test/calling_conventions.cpp | 158 +++++++++++++++++++++++++++++++ test/calling_conventions.py | 81 ++++++++++++++++ test/calling_conventions_mf.cpp | 159 ++++++++++++++++++++++++++++++++ test/calling_conventions_mf.py | 84 +++++++++++++++++ 4 files changed, 482 insertions(+) create mode 100644 test/calling_conventions.cpp create mode 100644 test/calling_conventions.py create mode 100644 test/calling_conventions_mf.cpp create mode 100644 test/calling_conventions_mf.py diff --git a/test/calling_conventions.cpp b/test/calling_conventions.cpp new file mode 100644 index 00000000..54f49aeb --- /dev/null +++ b/test/calling_conventions.cpp @@ -0,0 +1,158 @@ +// +// adapted from bind_stdcall_test.cpp - test for bind.hpp + __stdcall (free functions) +// The purpose of this simple test is to determine if a function can be +// called from Python with the various existing calling conventions +// +// Copyright (c) 2001 Peter Dimov and Multi Media Ltd. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// + +#if !defined(TEST_INCLUDE_RECURSION) + +#define TEST_INCLUDE_RECURSION + +//------------------------------------------------------------------------------ +// this section is the main body of the test extension module + +#define BOOST_PYTHON_ENABLE_CDECL +#define BOOST_PYTHON_ENABLE_STDCALL +#define BOOST_PYTHON_ENABLE_FASTCALL +#include +#include +#include +using namespace boost::python; + +// first define test functions for every calling convention + +#define TEST_DECLARE_FUNCTIONS + +#define TESTED_CALLING_CONVENTION __cdecl +#include "calling_conventions.cpp" +#undef TESTED_CALLING_CONVENTION + +#define TESTED_CALLING_CONVENTION __stdcall +#include "calling_conventions.cpp" +#undef TESTED_CALLING_CONVENTION + +#define TESTED_CALLING_CONVENTION __fastcall +#include "calling_conventions.cpp" +#undef TESTED_CALLING_CONVENTION + +#undef TEST_DECLARE_FUNCTIONS + +// then create a module wrapping the defined functions for every calling convention + +BOOST_PYTHON_MODULE( calling_conventions_ext ) +{ + +#define TEST_WRAP_FUNCTIONS + +#define TESTED_CALLING_CONVENTION __cdecl +#include "calling_conventions.cpp" +#undef TESTED_CALLING_CONVENTION + +#define TESTED_CALLING_CONVENTION __stdcall +#include "calling_conventions.cpp" +#undef TESTED_CALLING_CONVENTION + +#define TESTED_CALLING_CONVENTION __fastcall +#include "calling_conventions.cpp" +#undef TESTED_CALLING_CONVENTION + +#undef TEST_WRAP_FUNCTIONS + +} + +#else // !defined(TEST_INCLUDE_RECURSION) + +//------------------------------------------------------------------------------ +// this section defines the functions to be wrapped + +# if defined(TEST_DECLARE_FUNCTIONS) + +# if !defined(TESTED_CALLING_CONVENTION) +# error "One calling convention must be defined" +# endif // !defined(TESTED_CALLING_CONVENTION) + +namespace BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION) { + + long TESTED_CALLING_CONVENTION f_0() + { + return 17041L; + } + + long TESTED_CALLING_CONVENTION f_1(long a) + { + return a; + } + + long TESTED_CALLING_CONVENTION f_2(long a, long b) + { + return a + 10 * b; + } + + long TESTED_CALLING_CONVENTION f_3(long a, long b, long c) + { + return a + 10 * b + 100 * c; + } + + long TESTED_CALLING_CONVENTION f_4(long a, long b, long c, long d) + { + return a + 10 * b + 100 * c + 1000 * d; + } + + long TESTED_CALLING_CONVENTION f_5(long a, long b, long c, long d, long e) + { + return a + 10 * b + 100 * c + 1000 * d + 10000 * e; + } + + long TESTED_CALLING_CONVENTION f_6(long a, long b, long c, long d, long e, long f) + { + return a + 10 * b + 100 * c + 1000 * d + 10000 * e + 100000 * f; + } + + long TESTED_CALLING_CONVENTION f_7(long a, long b, long c, long d, long e, long f, long g) + { + return a + 10 * b + 100 * c + 1000 * d + 10000 * e + 100000 * f + 1000000 * g; + } + + long TESTED_CALLING_CONVENTION f_8(long a, long b, long c, long d, long e, long f, long g, long h) + { + return a + 10 * b + 100 * c + 1000 * d + 10000 * e + 100000 * f + 1000000 * g + 10000000 * h; + } + + long TESTED_CALLING_CONVENTION f_9(long a, long b, long c, long d, long e, long f, long g, long h, long i) + { + return a + 10 * b + 100 * c + 1000 * d + 10000 * e + 100000 * f + 1000000 * g + 10000000 * h + 100000000 * i; + } + +} // namespace test##TESTED_CALLING_CONVENTION + +# endif // defined(TEST_DECLARE_FUNCTIONS) + +//------------------------------------------------------------------------------ +// this section wraps the functions + +# if defined(TEST_WRAP_FUNCTIONS) + +# if !defined(TESTED_CALLING_CONVENTION) +# error "One calling convention must be defined" +# endif // !defined(TESTED_CALLING_CONVENTION) + + def("f_0" BOOST_PP_STRINGIZE(TESTED_CALLING_CONVENTION), &BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION)::f_0); + def("f_1" BOOST_PP_STRINGIZE(TESTED_CALLING_CONVENTION), &BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION)::f_1); + def("f_2" BOOST_PP_STRINGIZE(TESTED_CALLING_CONVENTION), &BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION)::f_2); + def("f_3" BOOST_PP_STRINGIZE(TESTED_CALLING_CONVENTION), &BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION)::f_3); + def("f_4" BOOST_PP_STRINGIZE(TESTED_CALLING_CONVENTION), &BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION)::f_4); + def("f_5" BOOST_PP_STRINGIZE(TESTED_CALLING_CONVENTION), &BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION)::f_5); + def("f_6" BOOST_PP_STRINGIZE(TESTED_CALLING_CONVENTION), &BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION)::f_6); + def("f_7" BOOST_PP_STRINGIZE(TESTED_CALLING_CONVENTION), &BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION)::f_7); + def("f_8" BOOST_PP_STRINGIZE(TESTED_CALLING_CONVENTION), &BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION)::f_8); + def("f_9" BOOST_PP_STRINGIZE(TESTED_CALLING_CONVENTION), &BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION)::f_9); + +# endif // defined(TEST_WRAP_FUNCTIONS) + +#endif // !defined(TEST_INCLUDE_RECURSION) diff --git a/test/calling_conventions.py b/test/calling_conventions.py new file mode 100644 index 00000000..ce74a843 --- /dev/null +++ b/test/calling_conventions.py @@ -0,0 +1,81 @@ +# Copyright Nicolas Lelong, 2010. Distributed under the Boost +# Software License, Version 1.0 (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +""" +>>> from calling_conventions_ext import * +>>> f_0__cdecl() +17041 +>>> f_1__cdecl(1) +1 +>>> f_2__cdecl(1, 2) +21 +>>> f_3__cdecl(1, 2, 3) +321 +>>> f_4__cdecl(1, 2, 3, 4) +4321 +>>> f_5__cdecl(1, 2, 3, 4, 5) +54321 +>>> f_6__cdecl(1, 2, 3, 4, 5, 6) +654321 +>>> f_7__cdecl(1, 2, 3, 4, 5, 6, 7) +7654321 +>>> f_8__cdecl(1, 2, 3, 4, 5, 6, 7, 8) +87654321 +>>> f_9__cdecl(1, 2, 3, 4, 5, 6, 7, 8, 9) +987654321 +>>> f_0__stdcall() +17041 +>>> f_1__stdcall(1) +1 +>>> f_2__stdcall(1, 2) +21 +>>> f_3__stdcall(1, 2, 3) +321 +>>> f_4__stdcall(1, 2, 3, 4) +4321 +>>> f_5__stdcall(1, 2, 3, 4, 5) +54321 +>>> f_6__stdcall(1, 2, 3, 4, 5, 6) +654321 +>>> f_7__stdcall(1, 2, 3, 4, 5, 6, 7) +7654321 +>>> f_8__stdcall(1, 2, 3, 4, 5, 6, 7, 8) +87654321 +>>> f_9__stdcall(1, 2, 3, 4, 5, 6, 7, 8, 9) +987654321 +>>> f_0__fastcall() +17041 +>>> f_1__fastcall(1) +1 +>>> f_2__fastcall(1, 2) +21 +>>> f_3__fastcall(1, 2, 3) +321 +>>> f_4__fastcall(1, 2, 3, 4) +4321 +>>> f_5__fastcall(1, 2, 3, 4, 5) +54321 +>>> f_6__fastcall(1, 2, 3, 4, 5, 6) +654321 +>>> f_7__fastcall(1, 2, 3, 4, 5, 6, 7) +7654321 +>>> f_8__fastcall(1, 2, 3, 4, 5, 6, 7, 8) +87654321 +>>> f_9__fastcall(1, 2, 3, 4, 5, 6, 7, 8, 9) +987654321 +""" + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status) diff --git a/test/calling_conventions_mf.cpp b/test/calling_conventions_mf.cpp new file mode 100644 index 00000000..80ccc406 --- /dev/null +++ b/test/calling_conventions_mf.cpp @@ -0,0 +1,159 @@ +// +// adapted from bind_stdcall_mf_test.cpp - test for bind.hpp + __stdcall (free functions) +// The purpose of this simple test is to determine if a function can be +// called from Python with the various existing calling conventions +// +// Copyright (c) 2001 Peter Dimov and Multi Media Ltd. +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// + +#if !defined(TEST_INCLUDE_RECURSION) + +#define TEST_INCLUDE_RECURSION + +//------------------------------------------------------------------------------ +// this section is the main body of the test extension module + +#define BOOST_PYTHON_ENABLE_CDECL +#define BOOST_PYTHON_ENABLE_STDCALL +#define BOOST_PYTHON_ENABLE_FASTCALL +#include +#include +#include +using namespace boost::python; + +// first define test functions for every calling convention + +#define TEST_DECLARE_FUNCTIONS + +#define TESTED_CALLING_CONVENTION __cdecl +#include "calling_conventions_mf.cpp" +#undef TESTED_CALLING_CONVENTION + +#define TESTED_CALLING_CONVENTION __stdcall +#include "calling_conventions_mf.cpp" +#undef TESTED_CALLING_CONVENTION + +#define TESTED_CALLING_CONVENTION __fastcall +#include "calling_conventions_mf.cpp" +#undef TESTED_CALLING_CONVENTION + +#undef TEST_DECLARE_FUNCTIONS + +// then create a module wrapping the defined functions for every calling convention + +BOOST_PYTHON_MODULE( calling_conventions_mf_ext ) +{ + +#define TEST_WRAP_FUNCTIONS + +#define TESTED_CALLING_CONVENTION __cdecl +#include "calling_conventions_mf.cpp" +#undef TESTED_CALLING_CONVENTION + +#define TESTED_CALLING_CONVENTION __stdcall +#include "calling_conventions_mf.cpp" +#undef TESTED_CALLING_CONVENTION + +#define TESTED_CALLING_CONVENTION __fastcall +#include "calling_conventions_mf.cpp" +#undef TESTED_CALLING_CONVENTION + +#undef TEST_WRAP_FUNCTIONS + +} + +#else // !defined(TEST_INCLUDE_RECURSION) + +//------------------------------------------------------------------------------ +// this section defines the functions to be wrapped + +# if defined(TEST_DECLARE_FUNCTIONS) + +# if !defined(TESTED_CALLING_CONVENTION) +# error "One calling convention must be defined" +# endif // !defined(TESTED_CALLING_CONVENTION) + +namespace BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION) { + +struct X +{ + mutable unsigned int hash; + + X(): hash(0) {} + + void TESTED_CALLING_CONVENTION f0() { f1(17); } + void TESTED_CALLING_CONVENTION g0() const { g1(17); } + + void TESTED_CALLING_CONVENTION f1(int a1) { hash = (hash * 17041 + a1) % 32768; } + void TESTED_CALLING_CONVENTION g1(int a1) const { hash = (hash * 17041 + a1 * 2) % 32768; } + + void TESTED_CALLING_CONVENTION f2(int a1, int a2) { f1(a1); f1(a2); } + void TESTED_CALLING_CONVENTION g2(int a1, int a2) const { g1(a1); g1(a2); } + + void TESTED_CALLING_CONVENTION f3(int a1, int a2, int a3) { f2(a1, a2); f1(a3); } + void TESTED_CALLING_CONVENTION g3(int a1, int a2, int a3) const { g2(a1, a2); g1(a3); } + + void TESTED_CALLING_CONVENTION f4(int a1, int a2, int a3, int a4) { f3(a1, a2, a3); f1(a4); } + void TESTED_CALLING_CONVENTION g4(int a1, int a2, int a3, int a4) const { g3(a1, a2, a3); g1(a4); } + + void TESTED_CALLING_CONVENTION f5(int a1, int a2, int a3, int a4, int a5) { f4(a1, a2, a3, a4); f1(a5); } + void TESTED_CALLING_CONVENTION g5(int a1, int a2, int a3, int a4, int a5) const { g4(a1, a2, a3, a4); g1(a5); } + + void TESTED_CALLING_CONVENTION f6(int a1, int a2, int a3, int a4, int a5, int a6) { f5(a1, a2, a3, a4, a5); f1(a6); } + void TESTED_CALLING_CONVENTION g6(int a1, int a2, int a3, int a4, int a5, int a6) const { g5(a1, a2, a3, a4, a5); g1(a6); } + + void TESTED_CALLING_CONVENTION f7(int a1, int a2, int a3, int a4, int a5, int a6, int a7) { f6(a1, a2, a3, a4, a5, a6); f1(a7); } + void TESTED_CALLING_CONVENTION g7(int a1, int a2, int a3, int a4, int a5, int a6, int a7) const { g6(a1, a2, a3, a4, a5, a6); g1(a7); } + + void TESTED_CALLING_CONVENTION f8(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) { f7(a1, a2, a3, a4, a5, a6, a7); f1(a8); } + void TESTED_CALLING_CONVENTION g8(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8) const { g7(a1, a2, a3, a4, a5, a6, a7); g1(a8); } +}; + +} // namespace BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION) + +# endif // defined(TEST_DECLARE_FUNCTIONS) + +//------------------------------------------------------------------------------ +// this section wraps the functions + +# if defined(TEST_WRAP_FUNCTIONS) + +# if !defined(TESTED_CALLING_CONVENTION) +# error "One calling convention must be defined" +# endif // !defined(TESTED_CALLING_CONVENTION) + +{ + + typedef BOOST_PP_CAT(test, TESTED_CALLING_CONVENTION)::X X; + + class_("X" BOOST_PP_STRINGIZE(TESTED_CALLING_CONVENTION)) + .def("f0", &X::f0) + .def("g0", &X::g0) + .def("f1", &X::f1) + .def("g1", &X::g1) + .def("f2", &X::f2) + .def("g2", &X::g2) + .def("f3", &X::f3) + .def("g3", &X::g3) + .def("f4", &X::f4) + .def("g4", &X::g4) + .def("f5", &X::f5) + .def("g5", &X::g5) + .def("f6", &X::f6) + .def("g6", &X::g6) + .def("f7", &X::f7) + .def("g7", &X::g7) + .def("f8", &X::f8) + .def("g8", &X::g8) + .def_readonly("hash", &X::hash) + ; + +} + +# endif // defined(TEST_WRAP_FUNCTIONS) + +#endif // !defined(TEST_INCLUDE_RECURSION) diff --git a/test/calling_conventions_mf.py b/test/calling_conventions_mf.py new file mode 100644 index 00000000..1ec9c2b6 --- /dev/null +++ b/test/calling_conventions_mf.py @@ -0,0 +1,84 @@ +# Copyright Nicolas Lelong, 2010. Distributed under the Boost +# Software License, Version 1.0 (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +""" +>>> from calling_conventions_mf_ext import * +>>> x = X__cdecl() +>>> x.f0() +>>> x.g0() +>>> x.f1(1) +>>> x.g1(1) +>>> x.f2(1, 2) +>>> x.g2(1, 2) +>>> x.f3(1, 2, 3) +>>> x.g3(1, 2, 3) +>>> x.f4(1, 2, 3, 4) +>>> x.g4(1, 2, 3, 4) +>>> x.f5(1, 2, 3, 4, 5) +>>> x.g5(1, 2, 3, 4, 5) +>>> x.f6(1, 2, 3, 4, 5, 6) +>>> x.g6(1, 2, 3, 4, 5, 6) +>>> x.f7(1, 2, 3, 4, 5, 6, 7) +>>> x.g7(1, 2, 3, 4, 5, 6, 7) +>>> x.f8(1, 2, 3, 4, 5, 6, 7, 8) +>>> x.g8(1, 2, 3, 4, 5, 6, 7, 8) +>>> x.hash +2155 +>>> x = X__stdcall() +>>> x.f0() +>>> x.g0() +>>> x.f1(1) +>>> x.g1(1) +>>> x.f2(1, 2) +>>> x.g2(1, 2) +>>> x.f3(1, 2, 3) +>>> x.g3(1, 2, 3) +>>> x.f4(1, 2, 3, 4) +>>> x.g4(1, 2, 3, 4) +>>> x.f5(1, 2, 3, 4, 5) +>>> x.g5(1, 2, 3, 4, 5) +>>> x.f6(1, 2, 3, 4, 5, 6) +>>> x.g6(1, 2, 3, 4, 5, 6) +>>> x.f7(1, 2, 3, 4, 5, 6, 7) +>>> x.g7(1, 2, 3, 4, 5, 6, 7) +>>> x.f8(1, 2, 3, 4, 5, 6, 7, 8) +>>> x.g8(1, 2, 3, 4, 5, 6, 7, 8) +>>> x.hash +2155 +>>> x = X__fastcall() +>>> x.f0() +>>> x.g0() +>>> x.f1(1) +>>> x.g1(1) +>>> x.f2(1, 2) +>>> x.g2(1, 2) +>>> x.f3(1, 2, 3) +>>> x.g3(1, 2, 3) +>>> x.f4(1, 2, 3, 4) +>>> x.g4(1, 2, 3, 4) +>>> x.f5(1, 2, 3, 4, 5) +>>> x.g5(1, 2, 3, 4, 5) +>>> x.f6(1, 2, 3, 4, 5, 6) +>>> x.g6(1, 2, 3, 4, 5, 6) +>>> x.f7(1, 2, 3, 4, 5, 6, 7) +>>> x.g7(1, 2, 3, 4, 5, 6, 7) +>>> x.f8(1, 2, 3, 4, 5, 6, 7, 8) +>>> x.g8(1, 2, 3, 4, 5, 6, 7, 8) +>>> x.hash +2155 +""" + +def run(args = None): + import sys + import doctest + + if args is not None: + sys.argv = args + return doctest.testmod(sys.modules.get(__name__)) + +if __name__ == '__main__': + print "running..." + import sys + status = run()[0] + if (status == 0): print "Done." + sys.exit(status)