diff options
73 files changed, 9774 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..fa13dcc58 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +build +.kdev4 +*.log +*.pyc +*.o +*.so +.preprocessed.tmp +.*.swp +*.kdev4 +doc/_build diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 000000000..6e802fb53 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,8 @@ +Anderson Lizardo <anderson.lizardo@openbossa.org> +Bruno Araujo <bruno.araujo@openbossa.org> +Hugo Parente Lima <hugo.lima@openbossa.org> +Lauro Moura <lauro.neto@openbossa.org> +Luciano Wolf <luciano.wolf@openbossa.org> +Marcelo Lira <marcelo.lira@openbossa.org> +Renato Araujo Oliveira Filho <renato.filho@openbossa.org> + diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..6c9c3098e --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,54 @@ +project(boostpythongenerator) + +cmake_minimum_required(VERSION 2.6) + +find_package(Qt4 4.5.0 REQUIRED) +find_package(ApiExtractor REQUIRED) + +add_definitions(${QT_DEFINITIONS}) + +set(boostpythongenerator_VERSION 0.1) +configure_file(boostpythongeneratorversion.h.in ${CMAKE_CURRENT_BINARY_DIR}/boostpythongeneratorversion.h @ONLY) +set(CMAKE_BUILD_TYPE Debug) + +set(boostpythongenerator_SRC +boostpythongenerator.cpp +convertergenerator.cpp +docgenerator.cpp +hppgenerator.cpp +cppgenerator.cpp +) + +include_directories(${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} + ${APIEXTRACTOR_INCLUDE_DIR} + ${APIEXTRACTOR_INCLUDE_DIR}/.. + ${QT_INCLUDE_DIR} + ${QT_QTCORE_INCLUDE_DIR}) + +add_library(libboostpythongenerator STATIC ${boostpythongenerator_SRC}) +target_link_libraries(libboostpythongenerator + ${APIEXTRACTOR_LIBRARY} + ${QT_QTCORE_LIBRARY} + ${QT_QTXML_LIBRARY}) +add_executable(boostpythongenerator main.cpp) +target_link_libraries(boostpythongenerator libboostpythongenerator) + +# uninstall target +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" + IMMEDIATE @ONLY) +add_custom_target(uninstall "${CMAKE_COMMAND}" + -P "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake") + + +# "make dist", in fact "make package_source" +set(CPACK_SOURCE_PACKAGE_FILE_NAME "boostpythongenerator-${boostpythongenerator_VERSION}") +set(CPACK_SOURCE_GENERATOR TGZ) +set(CPACK_SOURCE_IGNORE_FILES "~$" ".svn" "debian/" "build/" ".swp$" "*.kdev4") +include(CPack) + +install(TARGETS boostpythongenerator DESTINATION bin) + +enable_testing() +add_subdirectory(tests) diff --git a/COPYING b/COPYING new file mode 100644 index 000000000..4ccd71466 --- /dev/null +++ b/COPYING @@ -0,0 +1,342 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. + +------------------------------------------------------------------------- diff --git a/Doxyfile b/Doxyfile new file mode 100644 index 000000000..f5e8d73fe --- /dev/null +++ b/Doxyfile @@ -0,0 +1,311 @@ +# Doxyfile 1.5.7.1 + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = "Boost Python Generator Backend" +PROJECT_NUMBER = 0.1 +OUTPUT_DIRECTORY = doc +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = /tmp/src/boostbackend/ +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = YES +QT_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 8 +ALIASES = +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = NO +OPTIMIZE_FOR_FORTRAN = NO +OPTIMIZE_OUTPUT_VHDL = NO +BUILTIN_STL_SUPPORT = NO +CPP_CLI_SUPPORT = NO +SIP_SUPPORT = NO +IDL_PROPERTY_SUPPORT = YES +DISTRIBUTE_GROUP_DOC = NO +SUBGROUPING = YES +TYPEDEF_HIDES_STRUCT = NO +SYMBOL_CACHE_SIZE = 0 +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- +EXTRACT_ALL = YES +EXTRACT_PRIVATE = YES +EXTRACT_STATIC = YES +EXTRACT_LOCAL_CLASSES = YES +EXTRACT_LOCAL_METHODS = NO +EXTRACT_ANON_NSPACES = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_GROUP_NAMES = NO +SORT_BY_SCOPE_NAME = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_DIRECTORIES = NO +SHOW_FILES = YES +SHOW_NAMESPACES = YES +FILE_VERSION_FILTER = +LAYOUT_FILE = +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = /tmp/src/boostbackend +INPUT_ENCODING = UTF-8 +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.d \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.idl \ + *.odl \ + *.cs \ + *.php \ + *.php3 \ + *.inc \ + *.m \ + *.mm \ + *.dox \ + *.py \ + *.f90 \ + *.f \ + *.vhd \ + *.vhdl \ + *.C \ + *.CC \ + *.C++ \ + *.II \ + *.I++ \ + *.H \ + *.HH \ + *.H++ \ + *.CS \ + *.PHP \ + *.PHP3 \ + *.M \ + *.MM \ + *.PY \ + *.F90 \ + *.F \ + *.VHD \ + *.VHDL +RECURSIVE = YES +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXCLUDE_SYMBOLS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = * +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_PATTERNS = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = NO +REFERENCES_RELATION = NO +REFERENCES_LINK_SOURCE = YES +USE_HTAGS = NO +VERBATIM_HEADERS = NO +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = YES +COLS_IN_ALPHA_INDEX = 3 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_ALIGN_MEMBERS = YES +HTML_DYNAMIC_SECTIONS = NO +GENERATE_DOCSET = NO +DOCSET_FEEDNAME = "Doxygen generated docs" +DOCSET_BUNDLE_ID = org.doxygen.Project +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +CHM_INDEX_ENCODING = +BINARY_TOC = NO +TOC_EXPAND = NO +GENERATE_QHP = NO +QCH_FILE = +QHP_NAMESPACE = org.doxygen.Project +QHP_VIRTUAL_FOLDER = doc +QHG_LOCATION = +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NONE +TREEVIEW_WIDTH = 250 +FORMULA_FONTSIZE = 10 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = YES +USE_PDFLATEX = YES +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = NO +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = YES +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- +TAGFILES = ../libgenerator/libgenerator.tag=../libgenerator +GENERATE_TAGFILE = boostbackend.tag +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +MSCGEN_PATH = +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = YES +DOT_FONTNAME = FreeSans +DOT_FONTSIZE = 10 +DOT_FONTPATH = +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = NO +UML_LOOK = NO +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = NO +INCLUDED_BY_GRAPH = NO +CALL_GRAPH = NO +CALLER_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = NO +DOT_IMAGE_FORMAT = png +DOT_PATH = +DOTFILE_DIRS = +DOT_GRAPH_MAX_NODES = 50 +MAX_DOT_GRAPH_DEPTH = 1000 +DOT_TRANSPARENT = NO +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO diff --git a/boostpythongenerator.cpp b/boostpythongenerator.cpp new file mode 100644 index 000000000..70ce4a5ed --- /dev/null +++ b/boostpythongenerator.cpp @@ -0,0 +1,494 @@ +/* + * This file is part of the Boost Python Generator project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * + * Contact: PySide team <contact@pyside.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "boostpythongenerator.h" +#include <reporthandler.h> + +#include <QtCore/QDir> +#include <QtCore/QTextStream> +#include <QtCore/QVariant> +#include <QtCore/QRegExp> +#include <QtCore/QDebug> + +#define NULL_VALUE "NULL" +#define COMMENT_LINE_WIDTH 77 + +static Indentor INDENT; +static void dump_function(AbstractMetaFunctionList lst); + +FunctionModificationList BoostPythonGenerator::functionModifications(const AbstractMetaFunction *metaFunction) +{ + FunctionModificationList mods; + const AbstractMetaClass *cls = metaFunction->implementingClass(); + while (cls) { + mods += metaFunction->modifications(cls); + + if (cls == cls->baseClass()) + break; + cls = cls->baseClass(); + } + return mods; +} + +QString BoostPythonGenerator::translateType(const AbstractMetaType *cType, + const AbstractMetaClass *context, + int option) const +{ + QString s; + + if (context && cType && + context->typeEntry()->isGenericClass() && + cType->originalTemplateType()) { + qDebug() << "set original templateType" << cType->name(); + cType = cType->originalTemplateType(); + } + + if (!cType) { + s = "void"; + } else if (cType->isArray()) { + s = translateType(cType->arrayElementType(), context) + "[]"; + } else if (cType->isEnum() || cType->isFlags()) { + if (option & Generator::EnumAsInts) + s = "int"; + else + s = cType->cppSignature(); +#if 0 + } else if (c_type->isContainer()) { + qDebug() << "is container" << c_type->cppSignature(); + s = c_type->name(); + if (!(option & SkipTemplateParameters)) { + s += " < "; + QList<AbstractMetaType *> args = c_type->instantiations(); + for (int i = 0; i < args.size(); ++i) { + if (i) + s += ", "; + qDebug() << "container type: " << args.at(i)->cppSignature() << " / " << args.at(i)->instantiations().count(); + s += translateType(args.at(i), context, option); + } + s += " > "; + } +#endif + } else { + s = cType->cppSignature(); + if (cType->isConstant() && (option & Generator::ExcludeConst)) + s.replace("const", ""); + if (cType->isReference() && (option & Generator::ExcludeReference)) + s.replace("&", ""); + } + + return s; +} + +QString BoostPythonGenerator::getWrapperName(const AbstractMetaClass* clazz) +{ + QString result = clazz->name().toLower(); + result.replace("::", "_"); + result += "_wrapper"; + return result; +} + +QString BoostPythonGenerator::argumentString(const AbstractMetaFunction *cppFunction, + const AbstractMetaArgument *cppArgument, + uint options) const +{ + QString modifiedType = cppFunction->typeReplaced(cppArgument->argumentIndex() + 1); + QString arg; + + if (modifiedType.isEmpty()) + arg = translateType(cppArgument->type(), cppFunction->implementingClass(), (Generator::Option) options); + else + arg = modifiedType.replace('$', '.'); + + if (!(options & Generator::SkipName)) { + arg += " "; + arg += cppArgument->argumentName(); + } + + QList<ReferenceCount> referenceCounts; + referenceCounts = cppFunction->referenceCounts(cppFunction->implementingClass(), cppArgument->argumentIndex() + 1); + if ((options & Generator::SkipDefaultValues) != Generator::SkipDefaultValues && + !cppArgument->defaultValueExpression().isEmpty()) { + QString defaultValue = cppArgument->defaultValueExpression(); + if (defaultValue == "NULL") + defaultValue = NULL_VALUE; + + //WORKAROUND: fix this please + if (defaultValue.startsWith("new ")) + defaultValue.remove(0, 4); + + arg += " = " + defaultValue; + } + + return arg; +} + +void BoostPythonGenerator::writeArgument(QTextStream &s, + const AbstractMetaFunction *func, + const AbstractMetaArgument *cppArgument, + uint options) const +{ + s << argumentString(func, cppArgument, options); +} + +void BoostPythonGenerator::writeFunctionArguments(QTextStream &s, + const AbstractMetaFunction *func, + uint options) const +{ + AbstractMetaArgumentList arguments = func->arguments(); + + if (options & Generator::WriteSelf) { + s << func->implementingClass()->name() << '&'; + if (!(options & SkipName)) + s << " self"; + } + + int argUsed = 0; + for (int i = 0; i < arguments.size(); ++i) { + if ((options & Generator::SkipRemovedArguments) && func->argumentRemoved(i + 1)) + continue; + + if ((options & Generator::WriteSelf) || argUsed) + s << ", "; + + writeArgument(s, func, arguments[i], options); + argUsed++; + } +} + +QString BoostPythonGenerator::functionReturnType(const AbstractMetaFunction* func, int option) +{ + QString modifiedReturnType = QString(func->typeReplaced(0)); + if (!modifiedReturnType.isNull() && (!(option & OriginalTypeDescription))) + return modifiedReturnType; + else + return translateType(func->type(), func->implementingClass(), option); +} + +QString BoostPythonGenerator::functionSignature(const AbstractMetaFunction *func, + QString prepend, + QString append, + int option, + int argCount) +{ + AbstractMetaArgumentList arguments = func->arguments(); + int argument_count = argCount < 0 ? arguments.size() : argCount; + + + QString result; + QTextStream s(&result); + // The actual function + if (!(func->isEmptyFunction() || + func->isNormal() || + func->isSignal())) { + option = Option(option | Generator::SkipReturnType); + } else { + s << functionReturnType(func, option) << ' '; + } + + // name + QString name(func->originalName()); + if (func->isConstructor()) + name = getWrapperName(func->ownerClass()); + + s << prepend << name << append << "("; + writeFunctionArguments(s, func, option); + s << ")"; + + if (func->isConstant() && (!(option & Generator::ExcludeMethodConst))) + s << " const"; + + return result; +} + +QString BoostPythonGenerator::signatureForDefaultVirtualMethod(const AbstractMetaFunction *cppFunction, + QString prepend, + QString append, + int option, + int arg_count) +{ + QString defaultMethodSignature = functionSignature(cppFunction, prepend, append, option, arg_count); + QString staticSelf("("); + if (cppFunction->isConstant()) + staticSelf += "const "; + + staticSelf += cppFunction->ownerClass()->qualifiedCppName() + "& "; + if (!(option & SkipName)) + staticSelf += " self"; + + if (cppFunction->arguments().size() > 0) + staticSelf += ", "; + + defaultMethodSignature.replace(defaultMethodSignature.lastIndexOf(") const"), 7, ")"); + defaultMethodSignature.replace(defaultMethodSignature.indexOf('('), 1, staticSelf); + return defaultMethodSignature; +} + +void BoostPythonGenerator::writeArgumentNames(QTextStream &s, + const AbstractMetaFunction *func, + uint options) const +{ + AbstractMetaArgumentList arguments = func->arguments(); + int argCount = 0; + for (int j = 0, max = arguments.size(); j < max; j++) { + + if ((options & Generator::SkipRemovedArguments) && + (func->argumentRemoved(arguments.at(j)->argumentIndex() + 1))) { + continue; + } + + if (argCount > 0) + s << ", "; + + if ((options & Generator::BoxedPrimitive) && + !arguments.at(j)->type()->isReference() && + (arguments.at(j)->type()->isQObject() || + arguments.at(j)->type()->isObject())) { + s << "PySide::ptr( " << arguments.at(j)->argumentName() << ")"; + } else { + s << arguments.at(j)->argumentName(); + } + argCount++; + } +} + +AbstractMetaFunctionList BoostPythonGenerator::queryGlobalOperators(const AbstractMetaClass *cppClass) +{ + AbstractMetaFunctionList result; + + foreach (AbstractMetaFunction *func, cppClass->functions()) { + if (func->isInGlobalScope() && func->isOperatorOverload()) + result.append(func); + } + return result; +} + +AbstractMetaFunctionList BoostPythonGenerator::sortContructor(AbstractMetaFunctionList list) +{ + AbstractMetaFunctionList result; + + foreach (AbstractMetaFunction *func, list) { + bool inserted = false; + foreach (AbstractMetaArgument *arg, func->arguments()) { + if (arg->type()->isFlags() || arg->type()->isEnum()) { + result.push_back(func); + inserted = true; + break; + } + } + if (!inserted) + result.push_front(func); + } + + return result; +} + +AbstractMetaFunctionList BoostPythonGenerator::queryFunctions(const AbstractMetaClass *cppClass, bool allFunctions) +{ + AbstractMetaFunctionList result; + + if (allFunctions) { + int default_flags = AbstractMetaClass::NormalFunctions | AbstractMetaClass::Visible; + default_flags |= cppClass->isInterface() ? 0 : AbstractMetaClass::ClassImplements; + + // Constructors + result = cppClass->queryFunctions(AbstractMetaClass::Constructors | + default_flags); + + // put enum constructor first to avoid conflict with int contructor + result = sortContructor(result); + + // Final functions + result += cppClass->queryFunctions(AbstractMetaClass::FinalInTargetLangFunctions | + AbstractMetaClass::NonStaticFunctions | + default_flags); + + //virtual + result += cppClass->queryFunctions(AbstractMetaClass::VirtualInTargetLangFunctions | + AbstractMetaClass::NonStaticFunctions | + default_flags); + + // Static functions + result += cppClass->queryFunctions(AbstractMetaClass::StaticFunctions | default_flags); + + // Empty, private functions, since they aren't caught by the other ones + result += cppClass->queryFunctions(AbstractMetaClass::Empty | + AbstractMetaClass::Invisible | default_flags); + // Signals + result += cppClass->queryFunctions(AbstractMetaClass::Signals | default_flags); + } else { + result = cppClass->functionsInTargetLang(); + } + + return result; +} + +void BoostPythonGenerator::writeFunctionCall(QTextStream &s, + const AbstractMetaFunction* func, + uint options) + +{ + if (!(options & Generator::SkipName)) + s << (func->isConstructor() ? func->ownerClass()->qualifiedCppName() : func->originalName()); + + s << '('; + writeArgumentNames(s, func, options); + s << ')'; +} + +AbstractMetaFunctionList BoostPythonGenerator::filterFunctions(const AbstractMetaClass *cppClass) +{ + AbstractMetaFunctionList lst = queryFunctions(cppClass, true); + foreach (AbstractMetaFunction *func, lst) { + //skip signals + if (func->isSignal() || + func->isDestructor() || + (func->isModifiedRemoved() && !func->isAbstract())) { + lst.removeOne(func); + } + } + + //virtual not implemented in current class + AbstractMetaFunctionList virtual_lst = cppClass->queryFunctions(AbstractMetaClass::VirtualFunctions); + foreach (AbstractMetaFunction *func, virtual_lst) { + if ((func->implementingClass() != cppClass) && + !lst.contains(func)) { + lst.append(func); + } + } + + //append global operators + foreach (AbstractMetaFunction *func , queryGlobalOperators(cppClass)) { + if (!lst.contains(func)) + lst.append(func); + } + + return lst; + //return cpp_class->functions(); +} + +CodeSnipList BoostPythonGenerator::getCodeSnips(const AbstractMetaFunction *func) +{ + CodeSnipList result; + const AbstractMetaClass *cppClass = func->implementingClass(); + while (cppClass) { + foreach (FunctionModification mod, func->modifications(cppClass)) { + if (mod.isCodeInjection()) + result << mod.snips; + } + + if (cppClass == cppClass->baseClass()) + break; + cppClass = cppClass->baseClass(); + } + + return result; +} + +void BoostPythonGenerator::writeCodeSnips(QTextStream &s, + const CodeSnipList &codeSnips, + CodeSnip::Position position, + TypeSystem::Language language, + const AbstractMetaFunction *func) +{ + Indentation indentation(INDENT); + foreach (CodeSnip snip, codeSnips) { + if ((snip.position != position) || + !(snip.language & language)) { + continue; + } + + QString code; + QTextStream tmpStream(&code); + snip.formattedCode(tmpStream, INDENT); + + if (func) + replaceTemplateVariables(code, func); + + s << code << endl; + } +} + +bool BoostPythonGenerator::canCreateWrapperFor(const AbstractMetaClass* cppClass) +{ + return !cppClass->hasPrivateDestructor() && !cppClass->isNamespace(); +} + + + +QStringList BoostPythonGenerator::getBaseClasses(const AbstractMetaClass *cppClass) +{ + QStringList baseClass; + + if (!cppClass->baseClassName().isEmpty() && + (cppClass->name() != cppClass->baseClassName())) { + baseClass.append(cppClass->baseClassName()); + } + + foreach (AbstractMetaClass *interface, cppClass->interfaces()) { + AbstractMetaClass *aux = interface->primaryInterfaceImplementor(); + if (!aux) + continue; + + //skip templates + if (aux->templateArguments().size() > 0) + continue; + + if (!aux->name().isEmpty() && (cppClass->qualifiedCppName() != aux->qualifiedCppName())) + baseClass.append(aux->qualifiedCppName()); + } + + return baseClass; +} + + +bool BoostPythonGenerator::isCopyable(const AbstractMetaClass *cppClass) +{ + if (cppClass->typeEntry()->copyable() == ComplexTypeEntry::Unknown) + return cppClass->hasCloneOperator(); + else + return (cppClass->typeEntry()->copyable() == ComplexTypeEntry::CopyableSet); + + return false; +} + +static void dump_function(AbstractMetaFunctionList lst) +{ + qDebug() << "DUMP FUNCTIONS: "; + foreach (AbstractMetaFunction *func, lst) { + qDebug() << "*" << func->ownerClass()->name() + << func->signature() + << "Private: " << func->isPrivate() + << "Empty: " << func->isEmptyFunction() + << "Static:" << func->isStatic() + << "Signal:" << func->isSignal() + << "ClassImplements: " << (func->ownerClass() != func->implementingClass()) + << "is operator:" << func->isOperatorOverload() + << "is global:" << func->isInGlobalScope(); + } +} + + +bool BoostPythonGenerator::prepareGeneration(const QMap<QString, QString>&) +{ + return true; +} diff --git a/boostpythongenerator.h b/boostpythongenerator.h new file mode 100644 index 000000000..4ad191b50 --- /dev/null +++ b/boostpythongenerator.h @@ -0,0 +1,147 @@ +/* + * This file is part of the Boost Python Generator project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * + * Contact: PySide team <contact@pyside.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef BOOSTPYTHONGENERATOR_H +#define BOOSTPYTHONGENERATOR_H + +#include <apiextractor/generator.h> +#include <QtCore/QTextStream> + +class DocParser; + +/** +* Abstract generator that contains common methods used in CppGenerator and HppGenerator. +*/ +class BoostPythonGenerator : public Generator +{ +public: + /** + * Translate metatypes to boost::python format. + * \param boost_type a pointer to metatype + * \param context the current meta class + * \param option some extra options + * \return the metatype translated to boost::python format + */ + virtual QString translateType(const AbstractMetaType *boost_type, + const AbstractMetaClass *context, + int option = NoOption) const; + /** + * Write a function argument in the boost::python format in the text stream \p s. + * This function just call \code s << argumentString(); \endcode + * \param s text stream used to write the output. + * \param boost_fuction the current metafunction. + * \param boost_argument metaargument information to be parsed. + * \param options some extra options. + */ + void writeArgument(QTextStream &s, + const AbstractMetaFunction *boost_function, + const AbstractMetaArgument *boost_argument, + uint options = 0) const; + /** + * Create a QString in the boost::python format to an function argument. + * \param boost_fuction the current metafunction. + * \param boost_argument metaargument information to be parsed. + * \param options some extra options. + */ + QString argumentString(const AbstractMetaFunction *boost_function, + const AbstractMetaArgument *boost_argument, + uint options = 0) const; + + void writeArgumentNames(QTextStream &s, + const AbstractMetaFunction *cpp_function, + uint options = 0) const; + + /** + * Function used to write the fucntion arguments on the class buffer. + * \param s the class output buffer + * \param boost_function the pointer to metafunction information + * \param count the number of function arguments + * \param options some extra options used during the parser + */ + void writeFunctionArguments(QTextStream &s, + const AbstractMetaFunction *boost_function, + uint options = 0) const; + QString functionReturnType(const AbstractMetaFunction* func, int option = NoOption); + /** + * Write a code snip into the buffer \p s. + * CodeSnip are codes inside inject-code tags. + * \param s the buffer + * \param cpp_function the cpp function + * \param code_snips a list of code snips + * \param position the position to insert the code snip + * \param language the kind of code snip + */ + void writeCodeSnips(QTextStream &s, + const CodeSnipList &code_snips, + CodeSnip::Position position, + TypeSystem::Language language, + const AbstractMetaFunction *cpp_function = 0); + /// returns the code snips of a function + CodeSnipList getCodeSnips(const AbstractMetaFunction *func); + static bool canCreateWrapperFor(const AbstractMetaClass* cppClass); + /** + * Function witch parse the metafunction information + * \param cpp_function the function witch will be parserd + * \param option some extra options + * \param arg_count the number of function arguments + */ + QString functionSignature(const AbstractMetaFunction *boost_function, + QString prepend = "", + QString append = "", + int option = NoOption, + int arg_count = -1); + + QString signatureForDefaultVirtualMethod(const AbstractMetaFunction *cpp_function, + QString prepend = "", + QString append = "_default", + int option = NoOption, + int arg_count = -1); + + virtual QString subDirectoryForClass(const AbstractMetaClass* metaClass) const + { + return subDirectoryForPackage(metaClass->package()); + } + + QStringList getBaseClasses(const AbstractMetaClass* cppClass); + + static QString getWrapperName(const AbstractMetaClass* clazz); + + + virtual bool prepareGeneration(const QMap<QString, QString>& args); + +protected: + // verify if the class is copyalbe + bool isCopyable(const AbstractMetaClass *cpp_class); + + static FunctionModificationList functionModifications(const AbstractMetaFunction *meta_function); + AbstractMetaFunctionList queryFunctions(const AbstractMetaClass *cpp_class, bool all_function = false); + void writeFunctionCall(QTextStream &s, const AbstractMetaFunction *cpp_func, uint options = 0); + + AbstractMetaFunctionList filterFunctions(const AbstractMetaClass *cpp_class); + AbstractMetaFunctionList queryGlobalOperators(const AbstractMetaClass *cpp_class); + AbstractMetaFunctionList sortContructor(AbstractMetaFunctionList list); +}; + + +#endif // BOOSTPYTHONGENERATOR_H + diff --git a/boostpythongeneratorversion.h.in b/boostpythongeneratorversion.h.in new file mode 100644 index 000000000..9d7d2b60d --- /dev/null +++ b/boostpythongeneratorversion.h.in @@ -0,0 +1,4 @@ +#ifndef BOOSTPYTHONGENERATORVERSION_H +#define BOOSTPYTHONGENERATORVERSION_H +#define BOOSTPYTHONGENERATOR_VERSION "@boostpythongenerator_VERSION@" +#endif diff --git a/cmake_uninstall.cmake b/cmake_uninstall.cmake new file mode 100644 index 000000000..df95fb9d8 --- /dev/null +++ b/cmake_uninstall.cmake @@ -0,0 +1,21 @@ +IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + MESSAGE(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"") +ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + +FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) +STRING(REGEX REPLACE "\n" ";" files "${files}") +FOREACH(file ${files}) + MESSAGE(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"") + IF(EXISTS "$ENV{DESTDIR}${file}") + EXEC_PROGRAM( + "@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\"" + OUTPUT_VARIABLE rm_out + RETURN_VALUE rm_retval + ) + IF(NOT "${rm_retval}" STREQUAL 0) + MESSAGE(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"") + ENDIF(NOT "${rm_retval}" STREQUAL 0) + ELSE(EXISTS "$ENV{DESTDIR}${file}") + MESSAGE(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.") + ENDIF(EXISTS "$ENV{DESTDIR}${file}") +ENDFOREACH(file) diff --git a/convertergenerator.cpp b/convertergenerator.cpp new file mode 100644 index 000000000..ea52b9193 --- /dev/null +++ b/convertergenerator.cpp @@ -0,0 +1,180 @@ +/* + * This file is part of the Boost Python Generator project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * + * Contact: PySide team <contact@pyside.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include <QtCore/QDebug> +#include <fileout.h> +#include "convertergenerator.h" + +static Indentor INDENT; + +ConverterGenerator::ConverterGenerator() +{ + // QPair + m_conversions << qMakePair(QString("QPair<"), &m_qpairTypes); + // QList + m_conversions << qMakePair(QString("QList<"), &m_qlistTypes); + // QVector + m_conversions << qMakePair(QString("QVector<"), &m_qvectorTypes); + // QMap + m_conversions << qMakePair(QString("QMap<"), &m_qmapTypes); + // QHash + m_conversions << qMakePair(QString("QHash<"), &m_qhashTypes); + // QMultiMap + m_conversions << qMakePair(QString("QMultiMap<"), &m_qmultiMapTypes); + +} + +void ConverterGenerator::finishGeneration() +{ + if (!classes().size()) + return; + + QString fileOutPath; + + foreach (AbstractMetaClass *cls, classes()) { + if (!shouldGenerate(cls)) + continue; + + if (fileOutPath.isNull()) { + m_packageName = cls->package(); + fileOutPath = outputDirectory() + '/' + subDirectoryForClass(cls) + + "/converter_register_" + moduleName().toLower() + ".hpp"; + } + + foreach (AbstractMetaFunction* func, filterFunctions(cls)) + checkFunctionMetaTypes(func); + } + + FileOut fileOut(fileOutPath); + QTextStream& s = fileOut.stream; + + // write license comment + s << licenseComment() << endl; + + s << "#ifndef CONVERTERREGISTER_" << moduleName().toUpper() << "_HPP\n"; + s << "#define CONVERTERREGISTER_" << moduleName().toUpper() << "_HPP\n\n"; + + //Includes + QStringList includes; + foreach (AbstractMetaClass *cls, classes()) { + if (cls->typeEntry()->include().isValid()) { + QString include_file = cls->typeEntry()->include().toString(); + if (!includes.contains(include_file)) { + s << include_file << endl; + includes << include_file; + } + } + + if (cls->typeEntry()->generateCode()) { + QList<Include> extra_includes = cls->typeEntry()->extraIncludes(); + foreach (Include include, extra_includes) { + if (!includes.contains(include.toString())) { + s << include.toString() << endl; + includes << include.toString(); + } + } + } + } + + s << "#include \"type_converter.hpp\"\n\n"; + + s << "void register_type_converters_" << moduleName().toLower() << "()\n{\n"; + Indentation indent(INDENT); + writeConverterRegistration(s, "register_qpair_converter", "QPair", m_qpairTypes); + writeConverterRegistration(s, "register_container_converter", "QList", m_qlistTypes); + writeConverterRegistration(s, "register_container_converter", "QVector", m_qvectorTypes); + writeConverterRegistration(s, "register_dict_converter", "QMap", m_qmapTypes); + writeConverterRegistration(s, "register_dict_converter", "QHash", m_qhashTypes); + writeConverterRegistration(s, "register_multimap_converter", "QMultiMap", m_qmultiMapTypes); + s << "}\n\n"; + s << "#endif\n\n"; + + m_numGeneratedWritten = m_qpairTypes.size() + m_qlistTypes.size() + + m_qvectorTypes.size() + m_qmapTypes.size() + + m_qhashTypes.size(); +} + +void ConverterGenerator::writeConverterRegistration(QTextStream& out, + const QString& funcName, + const QString& type, + const QSet<QString>& params) +{ + foreach (QString param, params) { + QString completeType(QMetaObject::normalizedType( + (type + '<' + param + " >").toLatin1().data())); + out << INDENT << "PySide::" << funcName; + out << '<' << completeType << " >(\""; + out << completeType << "\");" << endl; + } +} + +void ConverterGenerator::checkFunctionMetaTypes(AbstractMetaFunction* func) +{ + if (func->type()) + checkMetaType(functionReturnType(func)); + + foreach (AbstractMetaArgument* arg, func->arguments()) { + if (arg->type()) { + checkMetaType(argumentString(func, arg, + (Generator::SkipName | Generator::SkipDefaultValues))); + } + } +} + +// FIXME Use some AbstracyMetaAnything info instead of parse the cpp signature? +void ConverterGenerator::checkMetaType(const QString& cppSignature) +{ + QRegExp typeRegex("Q\\w+"); + + foreach (Conversion conv, m_conversions) { + int index = cppSignature.indexOf(conv.first); + if (index >= 0) { + QString templateArg = extractTemplateArgument(cppSignature.right(cppSignature.length() - index - conv.first.length())); + conv.second->insert(templateArg); + // detect types to generate includes + int offset = 0; + while ((offset = typeRegex.indexIn(templateArg, offset)) != -1) { + const QString cap(typeRegex.cap(0)); + offset += cap.length(); + } + } + } +} + +QString ConverterGenerator::extractTemplateArgument(const QString& templateParams) +{ + int stack = 0; + for (int i = 0; i < templateParams.length(); ++i) { + QChar c = templateParams[i]; + if (c == '<') { + stack++; + } else if (c == '>') { + stack--; + if (stack < 0) + return templateParams.left(i).trimmed(); + } + } + Q_ASSERT(false); + return QString(); +} + diff --git a/convertergenerator.h b/convertergenerator.h new file mode 100644 index 000000000..8f91377c0 --- /dev/null +++ b/convertergenerator.h @@ -0,0 +1,77 @@ +/* + * This file is part of the Boost Python Generator project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * + * Contact: PySide team <contact@pyside.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef CONVERTERGENERATOR_H +#define CONVERTERGENERATOR_H + +// #include <QRegExp> +#include <QtCore/QSet> +#include "boostpythongenerator.h" + +/** +* Generator for convertions between python collections and Qt collections. +* +* It generates a file called converter_register_MODULENAME.hpp with only one +* function called register_type_converters_MODULENAME, where MODULENAME is the current module name. +* QPair are converted to python tuples, QList, QVector and QLinkedList to python lists, QHash and QMap to python dicts. +*/ +class ConverterGenerator : public BoostPythonGenerator +{ +public: + ConverterGenerator(); + + const char* name() const + { + return "ConverterGenerator"; + } + +protected: + void generateClass(QTextStream& s, const AbstractMetaClass* clazz) + { + } + + void finishGeneration(); + QString fileNameForClass(const AbstractMetaClass* cppClass) const + { + return QString(); + } +private: + void checkFunctionMetaTypes(AbstractMetaFunction* func); + void checkMetaType(const QString& cppSignature); + QString extractTemplateArgument(const QString& templateParams); + + void writeConverterRegistration(QTextStream& out, const QString& func_name, const QString& type, const QSet<QString>& params); + + typedef QPair<QString, QSet<QString>* > Conversion; + typedef QList<Conversion> ConversionList; + ConversionList m_conversions; + QSet<QString> m_qpairTypes; + QSet<QString> m_qlistTypes; + QSet<QString> m_qvectorTypes; + QSet<QString> m_qmapTypes; + QSet<QString> m_qhashTypes; + QSet<QString> m_qmultiMapTypes; +}; + +#endif // CONVERSIONGENERATOR_H + diff --git a/cppgenerator.cpp b/cppgenerator.cpp new file mode 100644 index 000000000..ae1f625a8 --- /dev/null +++ b/cppgenerator.cpp @@ -0,0 +1,1421 @@ +/* + * This file is part of the Boost Python Generator project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * + * Contact: PySide team <contact@pyside.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ +#include "cppgenerator.h" +#include <apiextractor/reporthandler.h> +#include <apiextractor/fileout.h> +#include <apiextractor/abstractmetalang.h> + +#include <QtCore/QDir> +#include <QtCore/QTextStream> +#include <QtCore/QVariant> +#include <QtCore/QRegExp> +#include <QtCore/QDebug> +#include <QtCore/QListIterator> + +static Indentor INDENT; + +// utiliy functions +inline QString getMethodPointerString(const AbstractMetaFunction* func) +{ + QString className; + if (!func->declaringClass()->isAbstract()) + className = func->declaringClass()->qualifiedCppName(); + else + className = func->ownerClass()->qualifiedCppName(); + + return '&' + className + "::" + func->originalName(); +} + +static QString nameForModifiedCtorFunction(const AbstractMetaFunction* func) { + QString res = func->ownerClass()->name().toLower().replace("::", "_"); + res += "_constructor"; + foreach (AbstractMetaArgument* arg, func->arguments()) { + res += '_'; + res += arg->type()->name().toLower(); + } + return res; +} + +static QString createStaticFunctionName(const AbstractMetaFunction* func) +{ + QString funcName; + QString originalName(func->name()); + + + funcName = func->ownerClass()->name().toLower(); + + //remove initial 'Q' + if (funcName.startsWith('q')) + funcName = funcName.remove(0, 1); + + //upercase first letter + funcName += originalName[0].toUpper() + originalName.mid(1); + + return funcName; +} + +QString CppGenerator::fileNameForClass(const AbstractMetaClass* cppClass) const +{ + return getWrapperName(cppClass) + QLatin1String(".cpp"); +} + +QString CppGenerator::getFuncTypedefName(const AbstractMetaFunction* func) const +{ + return func->name() + QLatin1String("_type"); +} + +void CppGenerator::writeConstructorInitialization(QTextStream &s, const AbstractMetaFunction *function) +{ + QStringList nonOpts; + QStringList opts; + + foreach (AbstractMetaArgument *arg, function->arguments()) { + uint options = SkipName | SkipDefaultValues; + QString argType = argumentString(function, arg, options); + if (arg->defaultValueExpression().isEmpty()) + nonOpts << argType; + else + opts << argType; + } + + bool hasModifications = function->allowThread() || function->hasInjectedCode(); + + if (hasModifications) { + s << "\"__init__\", python::make_constructor(" + << nameForModifiedCtorFunction(function); + } else { + s << "python::init< "; + + if (nonOpts.size() > 0) + s << nonOpts.join(", "); + + if (opts.size() > 0) { + if (nonOpts.size() > 0) + s << ", "; + + s << "python::optional< " << opts.join(",") << " > "; + } + + s << " > ()"; + } + + QString callPolicy = getFunctionCallPolicy(function); + QString parentType; + const AbstractMetaClass *cppClass = function->ownerClass(); + uint closePolicy = 0; + bool hasPolicy = false; + + if ( + !hasModifications && + (!cppClass->isPolymorphic() || cppClass->hasPrivateDestructor() || cppClass->isNamespace()) + ) { + closePolicy++; + hasPolicy = true; + s << "[ PySide::register_wrapper_object< " + << function->ownerClass()->qualifiedCppName(); + } + + if (callPolicy.isEmpty()) { + int parentIndex = -1; + //try find for parent arg to create callPolicy + foreach (AbstractMetaArgument *arg, function->arguments()) { + if (arg->argumentName() == "parent") { + parentIndex = arg->argumentIndex(); + parentType = translateType(arg->type(), function->ownerClass(), + Generator::ExcludeConst | Generator::ExcludeReference).replace("*", ""); + break; + } + } + if (parentIndex != -1) { + if (!closePolicy) + s << (hasModifications ? ", " : "[ "); + else + s << ", "; + + s << "parent_policy_add< " << parentIndex + 2 << ", 1, " + << parentType << " , " << function->ownerClass()->qualifiedCppName(); + + hasPolicy = true; + closePolicy++; + } + } else { + if (!closePolicy) + s << (hasModifications ? ", " : "[ "); + else + s << ", "; + + if (callPolicy.endsWith("()")) + callPolicy = callPolicy.remove(callPolicy.size() - 2, 2); + + s << callPolicy; + hasPolicy = true; + } + + while(closePolicy) { + s << " > "; + closePolicy--; + } + + if (hasModifications) + s << ')'; + else if (hasPolicy) + s << "() ]"; +} + +QString CppGenerator::getFunctionReturnType(const AbstractMetaFunction* func) +{ + QString modifiedReturnType = QString(func->typeReplaced(0)); + + return modifiedReturnType.isNull() ? translateType(func->type(), func->implementingClass()) : modifiedReturnType; +} + +QString CppGenerator::writeFunctionCast(QTextStream &s, + const AbstractMetaFunction* func, + const QString& castNameSuffix, + const QString& className) +{ + QString castName = getFuncTypedefName(func) + castNameSuffix; + const AbstractMetaClass* cppClass = func->ownerClass(); + bool isWrapped = !func->isVirtual() && + (func->hasInjectedCode() || func->isThread() || func->allowThread()); + bool isVirtualMethodDefault = castNameSuffix == "_default"; + + s << INDENT << "typedef "; + s << getFunctionReturnType(func); + s << " ("; + if (cppClass && !func->isStatic() && func->ownerClass() && !isVirtualMethodDefault) { + if (!isWrapped) { + // pointer to a class method + if (!className.isEmpty()) + s << className; + else if (func->isVirtual() && !func->declaringClass()->isAbstract()) + s << func->declaringClass()->qualifiedCppName(); + else + s << cppClass->qualifiedCppName(); + + s << "::"; + } + } + + s << '*' << castName << ") ("; + if (isVirtualMethodDefault) { + if (func->isConstant()) + s << "const "; + + s << func->implementingClass()->qualifiedCppName() << "&"; + if (func->arguments().size() > 0) + s << ", "; + } + int options = SkipName | SkipDefaultValues | SkipRemovedArguments; + if (isWrapped && !func->isStatic()) + options |= WriteSelf; + + writeFunctionArguments(s, func, options); + s << ')'; + + if (func->isConstant() && !isWrapped && !isVirtualMethodDefault) + s << " const"; + + s << ';' << endl; + + return castName; +} + +QString CppGenerator::verifyDefaultReturnPolicy(const AbstractMetaFunction *cppFunction, const QString& callPolicy) +{ + AbstractMetaType *type = cppFunction->type(); + QString returnPolicy; + + if (type && type->isReference() && type->isConstant()) { + returnPolicy = "python::return_value_policy<python::copy_const_reference"; + if (!callPolicy.isEmpty()) + returnPolicy += ", " + callPolicy; + returnPolicy += " >()"; + } else if (type && (type->isReference() || type->isQObject() || type->isObject())) { + bool cppOwnership = type->isConstant(); + if (cppFunction->isStatic() || cppOwnership) { + returnPolicy = "python::return_value_policy<PySide::return_ptr_object< " + + (cppOwnership ? QString("true") : QString("false")) + "> >()"; + } else if (type->isQObject() || type->isObject()) { + returnPolicy = QString("PySide::return_object<1, 0, %1, %2 %3 %4 >()") + .arg(getArgumentType(cppFunction->ownerClass(), cppFunction, -1)) + .arg(getArgumentType(cppFunction->ownerClass(), cppFunction, 0)) + .arg(callPolicy.isEmpty() ? "" : ",") + .arg(callPolicy); + } else { + returnPolicy = QString("python::return_internal_reference<%1 %2>()") + .arg(callPolicy.isEmpty() ? "" : ",") + .arg(callPolicy); + } + } else if (!callPolicy.isEmpty()) { + returnPolicy = callPolicy + "()"; + } + + return returnPolicy; +} + +static int boost_parent_policy_index(int i, const AbstractMetaFunction* func = 0) +{ + if (func && func->isStatic()) + return i; + + if (i == -1) + return 1; + else if (i > 0) + return i + 1; + else + return i; +} + +QString CppGenerator::getArgumentType(const AbstractMetaClass *cppClass, const AbstractMetaFunction *func, int idx) +{ + QString retval; + if (idx == -1) { + retval = cppClass->qualifiedCppName(); + } else if (idx == 0 && func->type()) { + retval = translateType(func->type(), cppClass, + Generator::ExcludeConst | Generator::ExcludeReference); + } else if (idx > 0) { + retval = argumentString(func, func->arguments()[idx-1], + Generator::SkipDefaultValues | Generator::ExcludeConst | + Generator::ExcludeReference | Generator::SkipName); + } + + retval = retval.trimmed(); + if (retval.endsWith('*')) + retval.chop(1); + return retval; +} + +QString CppGenerator::getFunctionCallPolicy(const AbstractMetaFunction *func) +{ + QString callPolicy; + QStringList callPolicies; + bool returnChild = false; + const AbstractMetaClass* cppClass = func->implementingClass(); + + const int numArgs = func->arguments().count(); + + for (int i = -1; i <= numArgs; ++i) { + ArgumentOwner ao = func->argumentOwner(cppClass, i); + //Parent Policy + if ((ao.index != -2) && (ao.index != i)) { + switch (ao.action) { + case ArgumentOwner::Add: + if (!i) { + callPolicy = "return_object<"; + returnChild = true; + } else { + callPolicy = "parent_policy_add<"; + } + break; + case ArgumentOwner::Remove: + callPolicy = "parent_policy_remove<"; + break; + default: + continue; + } + + callPolicy += QString("%1, %2, %3, %4") + .arg(boost_parent_policy_index(ao.index, func)) + .arg(boost_parent_policy_index(i, func)) + .arg(getArgumentType(cppClass, func, ao.index)) + .arg(getArgumentType(cppClass, func, i)); + + callPolicies << callPolicy; + } else if (i) { //only function args ignore return value + //Ownership policy + bool changeOwnership = false; + bool releaseOwnership = false; + TypeSystem::Ownership owner = func->ownership(cppClass, + TypeSystem::TargetLangCode, i); + + switch(owner) + { + case TypeSystem::CppOwnership: + releaseOwnership = true; + case TypeSystem::TargetLangOwnership: + changeOwnership = true; + break; + default: + changeOwnership = false; + } + + if (changeOwnership) + { + QString ownershipPolicy = QString("transfer_ownership<%1, %2, %3") + .arg(boost_parent_policy_index(i, func)) + .arg(releaseOwnership ? "true" : "false") + .arg(getArgumentType(cppClass, func, i)); + callPolicies << ownershipPolicy; + } + } + } + + if (callPolicies.size() > 0) { + callPolicy = callPolicies.join(", "); + for (int i = 0; i < callPolicies.count(); ++i) + callPolicy += " >"; + } + + QString returnPolicy; + + //return value + bool cppOwnership = false; + + if (!returnChild) { + switch (func->ownership(cppClass, TypeSystem::TargetLangCode, 0)) + { + case TypeSystem::CppOwnership: + cppOwnership = true; + case TypeSystem::TargetLangOwnership: + { + QString cppOwnershipFlag = (cppOwnership ? "true" : "false"); + returnPolicy = "python::return_value_policy< PySide::return_ptr_object<" + cppOwnershipFlag + "> "; + if (!callPolicy.isEmpty()) + returnPolicy += ", " + callPolicy; + returnPolicy += " >()"; + break; + } + default: + returnPolicy = verifyDefaultReturnPolicy(func, callPolicy); + break; + } + } + + //return policy + if (func->shouldReturnThisObject()) + return "python::return_self< " + callPolicy + " >()"; + else if (!returnPolicy.isEmpty()) + return returnPolicy; + else if (!callPolicy.isEmpty()) + return callPolicy + "()"; + + return QString(); +} + +/*!\internal + Function used to write the enum boost code on the buffer + \param s the output buffer + \param cpp_enum the pointer to metaenum information to be translated to boost +*/ +void CppGenerator::writeEnum(QTextStream &s, + const AbstractMetaEnum *cppEnum, + const QString &nameSpace) +{ + s << INDENT << "python::enum_<" << nameSpace << cppEnum->name(); + s << ">(\"" << cppEnum->name() << "\")" << endl; + const AbstractMetaEnumValueList &values = cppEnum->values(); + EnumTypeEntry *ete = cppEnum->typeEntry(); + + foreach (const AbstractMetaEnumValue* enumValue, values) { + Indentation indent(INDENT); + if (ete->isEnumValueRejected(enumValue->name())) + continue; + + s << INDENT << ".value(\"" << enumValue->name() << "\", "; + s << nameSpace << enumValue->name() << ")" << endl; + } + + //Export values to current scope + s << INDENT << INDENT << ".export_values()" << endl; + s << INDENT << ";" << endl << endl; + + FlagsTypeEntry* flagsEntry = cppEnum->typeEntry()->flags(); + + if (flagsEntry) { + s << INDENT << "PySide::declare_" << (cppEnum->typeEntry()->forceInteger() ? "int_" : "") << "qflags< " + << flagsEntry->originalName() << " >(\"" << flagsEntry->flagsName() << "\");" << endl; + } + + //register enum in typemanager + s << INDENT + << "type_manager::instance().register_native_type<int>(\"" + << cppEnum->qualifier() << "::" << cppEnum->name() << "\");\n\n"; +} + +void CppGenerator::writeEnums(QTextStream &s, const AbstractMetaClass *cppClass, bool useNamespace) +{ + AbstractMetaEnumList enums = cppClass->enums(); + if (!enums.size()) + return; + + s << INDENT << "// Enums" << endl; + QString name_space; + if (useNamespace || !cppClass->isPolymorphic() || cppClass->hasPrivateDestructor()) + name_space = cppClass->qualifiedCppName() + "::"; + + foreach (AbstractMetaEnum *cpp_enum, enums) + writeEnum(s, cpp_enum, name_space); +} + +void CppGenerator::writeImplicitlyConversion(QTextStream &s, const AbstractMetaClass *cppClass) +{ +#if 0 + if (cppClass->isNamespace()) + return; + s << endl << "// Implicitly conversions" << endl; + QStringList interfaces = getBaseClasses(cppClass); + + if (!interfaces.size()) { + s << INDENT << "python::implicitly_convertible< " << endl; + s << INDENT << INDENT << "std::auto_ptr< " << getWrapperName(cppClass->name()) << " >," << endl; + s << INDENT << INDENT << "std::auto_ptr< " << cppClass->name() << " > >();" << endl; + } else { + foreach (QString base_class, interfaces) { + s << INDENT << "python::implicitly_convertible< " << endl; + s << INDENT << INDENT << "std::auto_ptr< " << cppClass->name() << " >," << endl; + s << INDENT << INDENT << "std::auto_ptr< " << base_class << " > >();" << endl; + } + } +#endif +} + + +void CppGenerator::writeDestructor(QTextStream &s, const AbstractMetaClass *cppClass) +{ + Indentation indentation(INDENT); + QString wrapperName = getWrapperName(cppClass); + s << wrapperName << "::~" << wrapperName << "()" << endl << "{" << endl + << INDENT << "PySide::qptr_base::invalidate(this);" << endl << "}" << endl; +} + +/*! + Function used to write the class generated boost code on the buffer + \param s the output buffer + \param cppClass the pointer to metaclass information +*/ +void CppGenerator::generateClass(QTextStream &s, const AbstractMetaClass *cppClass) +{ + ReportHandler::debugSparse("Generating wrapper implementation for " + cppClass->fullName()); + + // write license comment + s << licenseComment() << endl; + + QString localStr, globalStr; + QTextStream includesLocal(&localStr); + QTextStream includesGlobal(&globalStr); + + bool canCreateWrapper = canCreateWrapperFor(cppClass); + + QList<Include> includes = cppClass->typeEntry()->extraIncludes(); + qSort(includes.begin(), includes.end()); + + foreach (Include inc, includes) { + if (inc.type == Include::IncludePath) + includesGlobal << inc.toString() << endl; + else + includesLocal << inc.toString() << endl; + } + + //workaround to access protected functions + s << "//workaround to access protected functions" << endl; + s << "#define protected public" << endl; + + s << "//Base Class" << endl; + if (cppClass->typeEntry()->include().isValid()) + s << cppClass->typeEntry()->include().toString() << endl << endl; + + s << "//Extra includes [global]" << endl; + s << globalStr << endl; + + s << "#undef protected" << endl; + s << "//Base include" << endl; + s << "#include \"pyside.hpp\"" << endl; + s << "#include \"" << getWrapperName(cppClass) << ".hpp\"" << endl; + foreach (AbstractMetaClass* innerClass, cppClass->innerClasses()) { + if (shouldGenerate(innerClass)) + s << "#include \"" << getWrapperName(innerClass) << ".hpp\"" << endl; + } + s << endl << "//Extra includes [local]" << endl; + s << localStr << endl; + + s << endl << "using namespace boost;" << endl; + s << "using namespace PySide;" << endl; + s << endl; + + if (cppClass->typeEntry()->typeFlags() & ComplexTypeEntry::Deprecated) + s << "#Deprecated" << endl; + + if (canCreateWrapper) { + writePrelude(s, cppClass); + if (cppClass->isPolymorphic() && !cppClass->hasPrivateDestructor()) + writeDestructor(s, cppClass); + } + writeBoostDeclaration(s, cppClass); +} + +void CppGenerator::writePrelude(QTextStream& s, const AbstractMetaClass* cppClass) +{ + //inject code native beginner + writeCodeSnips(s, cppClass->typeEntry()->codeSnips(), + CodeSnip::Beginning, TypeSystem::NativeCode); + + foreach (AbstractMetaFunction *func, filterFunctions(cppClass)) { + if ((func->isPrivate() || func->isModifiedRemoved()) && !func->isAbstract()) + continue; + + if (func->isConstructor() && (func->allowThread() || func->hasInjectedCode())) { + writeModifiedConstructorImpl(s, func); + } else if (cppClass->isPolymorphic() && !cppClass->hasPrivateDestructor() && + func->isConstructor() && !func->isCopyConstructor()) { + writeConstructorImpl(s, func); + } else if (func->isVirtual() || func->isAbstract()) { + writeVirtualMethodImpl(s, func); + } else if (func->hasInjectedCode() || func->isThread() || func->allowThread()) { + writeNonVirtualModifiedFunctionImpl(s, func); + } else if (func->isInGlobalScope() && func->isOperatorOverload()) { + writeGlobalOperatorOverloadImpl(s, func); + } + } + + //inject code native end + writeCodeSnips(s, cppClass->typeEntry()->codeSnips(), + CodeSnip::End, TypeSystem::NativeCode); +} + + +void CppGenerator::writeModifiedConstructorImpl ( QTextStream& s, const AbstractMetaFunction* func ) +{ + Indentation indentation(INDENT); + const AbstractMetaClass* clazz = func->ownerClass(); + s << "static " << clazz->name() << "* " << nameForModifiedCtorFunction(func) << '('; + writeFunctionArguments(s, func, SkipDefaultValues); + s << ")\n{" << endl; + + s << INDENT << clazz->name() << "* _self = 0;" << endl; + s << INDENT << '{' << endl; + { + Indentation indentation(INDENT); + if (func->allowThread()) + s << INDENT << "py_allow_threads allow_threads;" << endl; + + s << INDENT << "_self = new "; + writeFunctionCall(s, func); + s << ';' << endl; + } + s << INDENT << '}' << endl; + writeCodeSnips(s, getCodeSnips(func), CodeSnip::Beginning, TypeSystem::All, func); + writeCodeSnips(s, getCodeSnips(func), CodeSnip::End, TypeSystem::All, func); + s << INDENT << "python::object _obj(PySide::ptr(_self));" << endl; + s << INDENT << "return _self;" << endl; + s << '}' << endl; +} + +void CppGenerator::writeConstructorImpl(QTextStream& s, const AbstractMetaFunction* func) +{ + s << functionSignature(func, getWrapperName(func->ownerClass()) + "::", "", + (Option)(OriginalTypeDescription | SkipDefaultValues)); + s << " : "; + writeFunctionCall(s, func); + s << " {" << endl; + writeCodeSnips(s, getCodeSnips(func), CodeSnip::Beginning, TypeSystem::All, func); + writeCodeSnips(s, getCodeSnips(func), CodeSnip::End, TypeSystem::All, func); + s << '}' << endl << endl; +} + +void CppGenerator::writeVirtualMethodImplHead(QTextStream& s, const AbstractMetaFunction* func) +{ + Indentation indentation(INDENT); + s << INDENT << "thread_locker lock;" << endl; + + if (func->hasInjectedCode()) { + writeCodeSnips(s, getCodeSnips(func), + CodeSnip::Beginning, TypeSystem::NativeCode, func); + } + + s << INDENT << "python::object method = PySide::detail::get_override(this, \"" << func->implementingClass()->name(); + if (func->implementingClass()->typeEntry()->isObject() || func->implementingClass()->typeEntry()->isQObject()) + s << '*'; + + s << "\", \"" << func->name() << "\");" << endl + << INDENT << "if (method)" << endl << INDENT << "{" << endl; + + { + Indentation indentation(INDENT); + s << INDENT; + if (func->type()) + s << "python::object __result = "; + + s << "method("; + writeArgumentNames(s, func, BoxedPrimitive); + s << ");" << endl; + + QString typeName = getFunctionReturnType(func); + if (!typeName.isEmpty()) { + + CodeSnipList codeSnips = getCodeSnips(func); + bool hasVirtualBeginningCode = false; + foreach(CodeSnip cs, codeSnips) { + if ((cs.position == CodeSnip::Beginning) && (cs.language == TypeSystem::TargetLangCode)) { + hasVirtualBeginningCode = true; + break; + } + } + + if (hasVirtualBeginningCode) { + writeCodeSnips(s, codeSnips, CodeSnip::Beginning, TypeSystem::TargetLangCode, func); + } else if (func->type()) { + s << INDENT << typeName << " __return_value = " << "python::extract<" << typeName << " >(__result);" << endl; + bool boxedPointer = false; + if (func->type() && !func->type()->isConstant() && + (func->type()->isObject() || func->type()->isQObject())) { + + s << INDENT << "PySide::qptr<" << QString(typeName).replace("*", "") << " > __ptr(__result.ptr());" << endl + << INDENT << "if (__ptr.is_wrapper()) {" << endl + << INDENT << INDENT << "python::incref(__result.ptr());" << endl + << INDENT << "}" << endl + << INDENT << "__ptr.release_ownership();" << endl; + } + + s << INDENT << "return __return_value;" << endl; + } + } + } + s << INDENT << "}" << endl; +} + +void CppGenerator::writeVirtualMethodImpl(QTextStream& s, const AbstractMetaFunction* func) +{ + if (func->isModifiedRemoved()) + return; + + if (!func->isAbstract() && !func->ownerClass()->hasPrivateDestructor() && + func->implementingClass() == func->ownerClass()) { + writeVirtualDefaultFunction(s, func); + } + + + QString prefix = getWrapperName(func->ownerClass()) + "::"; + s << functionSignature(func, prefix, "", + Generator::OriginalTypeDescription | Generator::SkipDefaultValues) + << endl << "{" << endl; + + writeVirtualMethodImplHead(s, func); + + if (func->isAbstract()) + writePureVirtualMethodImplFoot(s, func); + else + writeVirtualMethodImplFoot(s, func); + + s << '}' << endl << endl; +} + + +void CppGenerator::writePureVirtualMethodImplFoot(QTextStream& s, const AbstractMetaFunction* func) +{ + Indentation indentation(INDENT); + s << INDENT << "else" << endl + << INDENT << "{" << endl; + { + Indentation indentation(INDENT); + s << INDENT << "PyErr_SetString(PyExc_NotImplementedError, \"" + << func->ownerClass()->name() << "." << func->name() << " : " + << "You need to implement pure virtual functions in python\");" << endl + << INDENT << "throw python::error_already_set();" << endl; + } + s << INDENT << "}" << endl; +} + +void CppGenerator::writeVirtualMethodImplFoot(QTextStream& s, const AbstractMetaFunction* func) +{ + Indentation indentation(INDENT); + s << INDENT << "else" << endl << INDENT << "{" << endl; + { + Indentation indentation(INDENT); + QString returnKeyword = func->type() ? QLatin1String("return ") : QString(); + + if (func->allowThread()) + s << INDENT << "py_allow_threads allow_threads;" << endl; + + s << INDENT << returnKeyword << func->implementingClass()->qualifiedCppName() << "::"; + writeFunctionCall(s, func); + s << ';' << endl; + } + s << INDENT << '}' << endl; +} + +void CppGenerator::writeVirtualDefaultFunction(QTextStream &s, const AbstractMetaFunction *func) +{ + Indentation indentation(INDENT); + QString returnKeyword = func->type() ? QLatin1String("return ") : QString(); + QString defaultMethodSignature = signatureForDefaultVirtualMethod(func, getWrapperName(func->ownerClass()) + "::", "_default", Generator::SkipDefaultValues); + s << defaultMethodSignature << endl << '{' << endl; + + if (func->allowThread()) + s << INDENT << "py_allow_threads allow_threads;" << endl; + + CodeSnipList codeSnips = getCodeSnips(func); + bool hasVirtualEndCode = false; + foreach(CodeSnip cs, codeSnips) { + if ((cs.position == CodeSnip::End) && (cs.language == TypeSystem::TargetLangCode)) { + hasVirtualEndCode = true; + break; + } + } + + if (!hasVirtualEndCode) { + s << INDENT << returnKeyword << "self." << func->implementingClass()->qualifiedCppName() << "::"; + writeFunctionCall(s, func); + s << ";" << endl; + } else { + writeCodeSnips(s, getCodeSnips(func), + CodeSnip::End, TypeSystem::TargetLangCode, func); + } + s << '}' << endl << endl; + +} + + + +void CppGenerator::writeNonVirtualModifiedFunctionImpl(QTextStream& s, const AbstractMetaFunction* func) +{ + Indentation indentation(INDENT); + + s << "static " << getFunctionReturnType(func) << ' '; + s << func->ownerClass()->name() << '_' << func->originalName() << "_modified("; + + uint options = SkipRemovedArguments | SkipDefaultValues; + if (!func->isStatic()) + options |= WriteSelf; + + writeFunctionArguments(s, func, options); + s << ")" << endl << "{" << endl; + + if (func->isThread()) + s << INDENT << "thread_locker lock;" << endl; + + if (func->allowThread()) + s << INDENT << "py_allow_threads allow_threads;" << endl; + + if (getCodeSnips(func).size() > 0) { + writeCodeSnips(s, getCodeSnips(func), CodeSnip::Beginning, TypeSystem::All, func); + writeCodeSnips(s, getCodeSnips(func), CodeSnip::End, TypeSystem::All, func); + } else { + s << INDENT; + if (func->type()) + s << "return "; + + if (func->isStatic()) + s << func->declaringClass()->name() << "::"; + else + s << "self."; + + writeFunctionCall(s, func); + s << ";" << endl; + } + + s << '}' << endl << endl; +} + +AbstractMetaFunction* CppGenerator::findMainConstructor(const AbstractMetaClass* clazz) +{ + foreach (AbstractMetaFunction* func, clazz->functions()) { + if (func->isConstructor() && + func->isPublic() && + !func->isModifiedRemoved() && + !func->isPrivate()) { + return func; + } + } + return 0; +} + +void CppGenerator::writeHashFunction(QTextStream& s, const AbstractMetaClass* cppClass) +{ + QString argType; + + //WORKAROUND: diferent way to QChar + if (cppClass->name() == "QChar") + argType = "QChar"; + else + argType = "const " + cppClass->name() + "&"; + + s << "// Hash function" << endl + << "{" << endl + << INDENT << INDENT << "typedef uint (*hash_type) ( " << argType << " );" + << INDENT << INDENT << "python_cls.def(\"__hash__\", hash_type(&" + << cppClass->typeEntry()->hashFunction() << "));" << endl + << "}" << endl; +} + +QString CppGenerator::baseClassName(const QString& name) +{ + QStringList lst = name.split("::"); + return lst.last(); +} + +void CppGenerator::writeBoostDeclaration(QTextStream& s, const AbstractMetaClass* cppClass) +{ + Indentation indent(INDENT); + QString wrapperName = getWrapperName(cppClass); + + s << "void " << wrapperName << "::define_python_class() throw() {" << endl; + + const AbstractMetaFunction* mainCtor = 0; + bool mainCtorHasModifications = false; + if (!cppClass->isNamespace()) { + // python_cls declaration + mainCtor = findMainConstructor(cppClass); + if (mainCtor) + mainCtorHasModifications = mainCtor->allowThread() || mainCtor->hasInjectedCode(); + + s << INDENT; + if (!cppClass->isPolymorphic() || cppClass->hasPrivateDestructor()) + s << wrapperName << "::"; + + s << "class_type python_cls(\"" + << baseClassName(cppClass->name()) << "\", "; + + if (!mainCtor || mainCtorHasModifications) + s << "python::no_init"; + else + writeConstructorInitialization(s, mainCtor); + + s << ");" << endl << endl; + } else { + QRegExp reg("(?:\\w+::)*(\\w+)"); + reg.indexIn(cppClass->name()); + s << INDENT << "python::class_<Namespace> python_cls(\"" << reg.cap(1) << "\");" << endl; + } + // scope declaration + s << INDENT << "python::scope " << wrapperName << "_scope(python_cls);" << endl; + + if (cppClass->templateBaseClass() && cppClass->templateBaseClass()->typeEntry()->isContainer()) { + //const ContainerTypeEntry *type = static_cast<const ContainerTypeEntry*>(cppClass->templateBaseClass()->typeEntry()); + //if (type->type() == ContainerTypeEntry::ListContainer) { + s << endl << INDENT << "//Index suite for QContainer" << endl + << INDENT << "python_cls.def(qcontainer_indexing_suite< " << cppClass->qualifiedCppName() << " >());" << endl << endl; + //} + } + + if (isCopyable(cppClass) && !cppClass->isNamespace()) { + s << INDENT << "python_cls.def(python::init<const "; + s << cppClass->qualifiedCppName() << "&>());" << endl; + } + + if (cppClass->isPolymorphic() && !cppClass->hasPrivateDestructor() && canCreateWrapperFor(cppClass)) { + QString heldType = cppClass->typeEntry()->heldTypeValue(); + if (heldType.isEmpty()) + heldType = "PySide::qptr"; + + s << INDENT << "python::implicitly_convertible< " + << heldType << "<" << wrapperName << ">, " + << heldType << "<" << cppClass->qualifiedCppName() << "> >();" << endl; + } + + //Enums + writeEnums(s, cppClass, cppClass->hasPrivateDestructor() || cppClass->isNamespace()); + + if (cppClass->innerClasses().count()) { + s << endl << INDENT << "// Inner classes" << endl; + foreach (AbstractMetaClass* innerClass, cppClass->innerClasses()) { + if (!innerClass->typeEntry()->generateCode()) + continue; + s << INDENT << getWrapperName(innerClass) << "::define_python_class();" << endl; + } + } + + //Fields + foreach (AbstractMetaField *field, cppClass->fields()) { + QString strAccess; + + if (field->isPublic()) { + if (field->type()->isConstant()) + strAccess = "def_readonly"; + else + strAccess = "def_readwrite"; + + s << INDENT << "python_cls." + << strAccess + << "(\"" << field->name() << "\", &" + << field->enclosingClass()->name() << "::" << field->name() << ");" << endl; + } + } + + writeCodeSnips(s, cppClass->typeEntry()->codeSnips(), + CodeSnip::Beginning, TypeSystem::TargetLangCode); + + QSet<QString> staticMethods; + + if (!cppClass->isNamespace()) { + //search for all static methods to match with normal functions + //to rename when match with one member function + foreach (AbstractMetaFunction *func, filterFunctions(cppClass)) { + if (func->isStatic() && !func->isOperatorOverload()) + staticMethods << func->name(); + } + } + + foreach (AbstractMetaFunction *func, filterFunctions(cppClass)) { + if (func->isModifiedRemoved() || func->isPrivate() || func->isSignal()) + continue; + + //rename static function when is the same name as member function + if (!cppClass->isNamespace() && func->isStatic()) { + QString staticName(createStaticFunctionName(func)); + QSet<QString>::iterator staticFuncInter = staticMethods.find(staticName); + if (staticFuncInter != staticMethods.end()) + func->setName(staticName); + } else { + QSet<QString>::iterator staticFuncInter = staticMethods.find(func->name()); + if (staticFuncInter != staticMethods.end()) { + staticMethods.erase(staticFuncInter); + staticMethods << createStaticFunctionName(func); + } + } + + if (func->isOperatorOverload()) { + // Do not join the ifs -- isOperatorOverload must be checked alone + if (func->originalName() == func->name()) + writeOperatorOverload(s, func); + } else if (func->isConstructor()) { + if (mainCtorHasModifications || func != mainCtor) + writeConstructor(s, func); + } else if (!func->isVirtual() && + (func->hasInjectedCode() || + func->isThread() || func->allowThread())) { + writeModifiedMethodDef(s, func); + } else if (func->implementingClass() == func->ownerClass()) { + writeNormalMethodDef(s, func); + } + + //if is namespace all methothds is stattic + if (cppClass->isNamespace()) + s << INDENT << "python_cls.staticmethod(\"" << func->name() << "\");" << endl; + } + + writeCodeSnips(s, cppClass->typeEntry()->codeSnips(), + CodeSnip::End, TypeSystem::TargetLangCode); + + if (!cppClass->isNamespace()) { + // Static methods + if (!staticMethods.isEmpty()) + s << INDENT << "// Static methods" << endl; + + foreach (QString funcName, staticMethods) + s << INDENT << "python_cls.staticmethod(\"" << funcName << "\");" << endl; + } + + // qHash usage + if (!cppClass->typeEntry()->hashFunction().isEmpty()) + writeHashFunction(s, cppClass); + + // implicity conversions + writeImplicitlyConversion(s, cppClass); + + // register object/value type + if (!cppClass->isNamespace()) { + QString className = cppClass->qualifiedCppName(); + const char* funcName = (cppClass->typeEntry()->isObject() || !isCopyable(cppClass)) ? "object" : "value"; + s << INDENT + << "type_manager::instance().register_" + << funcName + << "_type<" << className << " >(\"" + << cppClass->qualifiedCppName() << (cppClass->typeEntry()->isObject() ? "*" : "") << "\");\n"; + } + s << '}' << endl; +} + +void CppGenerator::writeConstructor(QTextStream& s, const AbstractMetaFunction* func) +{ + s << INDENT << "python_cls.def("; + writeConstructorInitialization(s, func); + s << ");" << endl; +} + +void CppGenerator::writeFunctionArgsDef(QTextStream &sOut, + const AbstractMetaFunction *cppFunction) +{ + bool hasDefaultValue = false; + int argUsed = 0; + QString aux; + QTextStream s(&aux); + + foreach (const AbstractMetaArgument *arg, cppFunction->arguments()) { + if (cppFunction->argumentRemoved(arg->argumentIndex() + 1)) + continue; + + if (argUsed > 0) + s << ", "; + + if (!m_disableNamedArgs) + s << "python::arg(\"" << arg->argumentName() << "\")"; + else + s << "python::arg(0)"; + + if (!arg->defaultValueExpression().isEmpty()) { + QString defaultValue = arg->defaultValueExpression(); + bool isPointer = arg->type()->isObject() || + arg->type()->isQObject() || + arg->type()->isNativePointer(); + + if (isPointer && defaultValue == "0") { + defaultValue = "python::object()"; + } else if (arg->type()->isFlags()) { + defaultValue = " (int) " + defaultValue; + } else if (arg->type()->isEnum()) { + QString enumName = arg->type()->minimalSignature(); + QRegExp reg("(.*::)"); + reg.indexIn(enumName); + if (!defaultValue.startsWith(reg.cap(1))) + defaultValue = reg.cap(1) + defaultValue; + } + + s << "=" << defaultValue; + hasDefaultValue = true; + } + argUsed++; + } + + if (hasDefaultValue || ((argUsed > 0) && !m_disableNamedArgs)) + sOut << "," << endl << INDENT << INDENT << "(" << aux << ")"; +} + +void CppGenerator::writeNormalMethodDef(QTextStream& s, const AbstractMetaFunction* func) +{ + s << INDENT << '{' << endl; + { + Indentation indentation(INDENT); + QString wrapperClassName = getWrapperName(func->ownerClass()); + bool needDefaultFunction = func->isVirtual() && !func->isAbstract() && !func->ownerClass()->hasPrivateDestructor(); + QString castName; + + if (needDefaultFunction) + castName = writeFunctionCast(s, func, "_default", func->implementingClass()->qualifiedCppName()); + else + castName = writeFunctionCast(s, func); + + s << INDENT << "python_cls.def(\"" << func->name() << "\", "; + + if (needDefaultFunction) { // add the default function + s << castName << "(&" << wrapperClassName << "::" << func->originalName() << "_default)"; + } else { + if (func->isAbstract()) + s << "python::pure_virtual"; + s << '(' << castName << '(' << getMethodPointerString(func) << "))"; + } + + QString functionPolicy = getFunctionCallPolicy(func); + if (!functionPolicy.isEmpty()) + s << ", " << functionPolicy; + + writeFunctionArgsDef(s, func); + s << ");" << endl; + } + s << INDENT << '}' << endl; +} + +void CppGenerator::writeModifiedMethodDef(QTextStream& s, const AbstractMetaFunction* func) +{ + s << INDENT << '{' << endl; + { + Indentation indentation(INDENT); + QString castName = writeFunctionCast(s, func); + s << INDENT + << "python_cls.def(\"" + << func->name() << "\", " + << castName + << "(&" << func->implementingClass()->name() + << "_" << func->originalName() + << "_modified)"; + QString functionPolicy = getFunctionCallPolicy(func); + if (!functionPolicy.isEmpty()) + s << ", " << functionPolicy; + + writeFunctionArgsDef(s, func); + s << ");" << endl; + } + s << INDENT << '}' << endl; +} + +QString CppGenerator::operatorFunctionName(const AbstractMetaFunction *cppFunction) +{ + QString funcName = QString("%1_operator_%2_") + .arg(cppFunction->arguments()[0]->type()->name()) + .arg(cppFunction->arguments()[1]->type()->name()); + + if (cppFunction->name().contains(">>")) { + funcName += "rshift"; + } else if (cppFunction->name().contains("<<")) { + funcName += "lshift"; + } else { + //TODO: implemente support to others operators + return QString(); + } + + return funcName; +} + +void CppGenerator::writeGlobalOperatorOverloadImpl(QTextStream& s, const AbstractMetaFunction* cppFunction) +{ + Indentation indent(INDENT); + QString operatorStr; + + if (cppFunction->name().contains(">>")) { + operatorStr = " >> "; + } else if (cppFunction->name().contains("<<")) { + operatorStr = " << "; + } else { + //TODO: implemente support to others operators + return; + } + + QString funcName = operatorFunctionName(cppFunction); + bool reverse = cppFunction->isReverseOperator(); + + const AbstractMetaClass *klass = cppFunction->ownerClass(); + s << "python::object " << funcName << "("; + writeFunctionArguments(s, cppFunction, SkipDefaultValues | SkipRemovedArguments); + s << ")" << endl << "{" << endl + << INDENT << cppFunction->arguments()[reverse]->argumentName() + << operatorStr << cppFunction->arguments()[!reverse]->argumentName() << ";" << endl + << INDENT << "return python::object(PySide::ptr(&" + << cppFunction->arguments()[reverse]->argumentName() << "));" << endl + << "}" << endl; +} + +void CppGenerator::writeGlobalOperatorOverload(QTextStream &s, const AbstractMetaFunction *cppFunction) +{ + QString funcName = operatorFunctionName(cppFunction); + if (funcName.isEmpty()) + return; + + bool reverse = cppFunction->isReverseOperator(); + QString operatorStr; + if (cppFunction->name().contains(">>")) { + operatorStr = QString("__%1rshift__").arg(reverse ? "r" : ""); + } else if (cppFunction->name().contains("<<")) { + operatorStr = QString("__%1lshift__").arg(reverse ? "r" : ""); + } else { + //TODO: implemente support to others operators + return; + } + + s << INDENT << "python_cls.def(\"" << operatorStr << "\", " << funcName << ");\n"; +} + +QString CppGenerator::getOperatorArgumentTypeName(const AbstractMetaFunction *cppFunction, int argumentIndex) +{ + AbstractMetaType* type = cppFunction->arguments()[argumentIndex]->type(); + if (type->name() == cppFunction->implementingClass()->name()) + return QLatin1String("python::self"); + + QString typeName = translateType(type, cppFunction->implementingClass(), + (Option)(ExcludeReference)); + return type->isPrimitive() ? "(" + typeName + ")(0)" : "python::other<" + typeName + " >()"; +} + +void CppGenerator::writeOperatorOverload(QTextStream& s, const AbstractMetaFunction* cppFunction) +{ + static QRegExp operatorRegex("operator(.+)"); + + if (!operatorRegex.exactMatch(cppFunction->originalName())) { + qWarning("What kind of operator is that!? %s", + cppFunction->originalName().toLocal8Bit().data()); + return; + } + + QString op(operatorRegex.cap(1)); + if (op == "=" || op == "[]") { + // = is handled by type boost and type conversions, [] by someone... + return; + } + + // no args == member unary operator + if (!cppFunction->arguments().count()) { + // check if it is a name instead of an operator symbol + // this means it is a conversion operator that will be ignored for now + static QRegExp ConversionOperatorRegex("[A-Za-z]+"); + if (ConversionOperatorRegex.indexIn(op) < 0) + s << INDENT << "python_cls.def(" << op << "python::self);" << endl; + return; + } + + //this because global operators use first arg with current class + if (cppFunction->isInGlobalScope()) { + writeGlobalOperatorOverload(s, cppFunction); + return; + } + + QString operand1, operand2; + if (cppFunction->arguments().count() == 1) { + operand1 = "python::self"; + operand2 = getOperatorArgumentTypeName(cppFunction, 0); + } else { + operand1 = getOperatorArgumentTypeName(cppFunction, 0); + operand2 = getOperatorArgumentTypeName(cppFunction, 1); + } + s << INDENT << "python_cls.def(" << operand1 << ' ' << op << ' ' << operand2 << ");\n"; +} + +void CppGenerator::finishGeneration() +{ + //Generate boost wrapper file + QString classFiles; + QTextStream sClassFiles(&classFiles); + QString classPythonDefines; + QTextStream sClassPythonDefines(&classPythonDefines); + + Indentation indent(INDENT); + + foreach (AbstractMetaClass *cls, classes()) { + if (!shouldGenerate(cls) || cls->enclosingClass()) + continue; + + if (m_packageName.isEmpty()) + m_packageName = cls->package(); + + QString wrapperName = getWrapperName(cls); + QString boostFilename; + boostFilename += wrapperName + ".hpp"; + sClassFiles << "#include \"" << boostFilename << "\"" << endl; + + QString define_str = wrapperName + "::"; + define_str += "define_python_class();"; + + sClassPythonDefines << INDENT << define_str << endl; + } + + QString moduleFileName(outputDirectory() + "/" + subDirectoryForPackage(m_packageName)); + moduleFileName += "/" + moduleName().toLower() + "_module_wrapper.cpp"; + + QFile file(moduleFileName); + if (file.open(QFile::WriteOnly)) { + QTextStream s(&file); + + // write license comment + s << licenseComment() << endl; + + s << "#include \"converter_register_" << moduleName().toLower(); + s << ".hpp\"" << endl << endl; + + s << classFiles << endl; + + s << "using namespace boost;" << endl << endl; + s << "using namespace PySide;" << endl << endl; + + s << "// forward decl. for global func. register\n"; + s << "void register_global_functions_" << moduleName().toLower() << "();\n\n"; + + s << "BOOST_PYTHON_MODULE(" << moduleName() << ")" << endl; + s << "{" << endl; + + foreach (QString requiredModule, TypeDatabase::instance()->requiredTargetImports()) { + s << INDENT << "if ("; + s << "PyImport_ImportModule(\"" << requiredModule << "\") == NULL) {" << endl; + s << INDENT << INDENT << "PyErr_SetString(PyExc_ImportError,"; + s << "\"could not import " << requiredModule << "\");" << endl; + s << INDENT << INDENT << "return;" << endl; + s << INDENT << "}" << endl; + } + s << endl; + + s << INDENT << "register_type_converters_" << moduleName().toLower() << "();" << endl << endl + << classPythonDefines << endl + << INDENT << "register_global_functions_" << moduleName().toLower() << "();" << endl + << INDENT << "//Namespaces" << endl; + + + s << "}" << endl << endl; + } + + writeGlobalFunctions(); +} + +void CppGenerator::writeGlobalFunctions() +{ + QString fileName = moduleName().toLower() + "_globals_wrapper.cpp"; + + FileOut fileOut(outputDirectory() + "/" + subDirectoryForPackage(m_packageName) + "/" + fileName); + + QSet<QString> includes; + QString defsStr; + QTextStream defsStream(&defsStr); + + foreach (AbstractMetaFunction* func, globalFunctions()) { + QString incFile = func->includeFile(); + QRegExp regex("\\b" + moduleName() + "\\b"); + //FIXME: this regex doesn't work with all cases, e.g.: + // moduleName() = local + // incFile = /usr/local/include/local + if (regex.indexIn(incFile) == -1) + continue; + + int idx = incFile.indexOf(moduleName()); + QString cleanPath = QDir::cleanPath(incFile.mid(idx)); + if (!cleanPath.startsWith(moduleName())) + continue; + + includes << cleanPath; + defsStream << INDENT << "{\n" << INDENT; + QString castName = writeFunctionCast(defsStream, func); + defsStream << INDENT << INDENT << "python::def(\"" << func->name(); + defsStream << "\", " << castName << '(' << func->name() << ')'; + if (func->type() && func->type()->isReference()) + defsStream << ", python::return_internal_reference<>()"; + defsStream << ");\n"; + defsStream << INDENT << "}\n"; + } + + QTextStream& s = fileOut.stream; + + // write license comment + s << licenseComment() << endl; + + s << "#include \"pyside.hpp\"" << endl; + + foreach (QString include, includes) + s << "#include <" << include << ">\n"; + + s << "using namespace boost;\n\n"; + s << "using namespace PySide;\n\n"; + + // Add module level code snippets to 'Global' class + TypeSystemTypeEntry *moduleEntry = dynamic_cast<TypeSystemTypeEntry *>( + TypeDatabase::instance()->findType(m_packageName)); + QString sEnd; + QTextStream snipEnd(&sEnd); + if (moduleEntry && moduleEntry->codeSnips().size() > 0) { + foreach (CodeSnip snip, moduleEntry->codeSnips()) { + if (snip.position == CodeSnip().Beginning) + snip.formattedCode(s, INDENT); + else + snip.formattedCode(snipEnd, INDENT); + } + } + + s << "\nvoid register_global_functions_" << moduleName().toLower() << "() {\n"; + { //global enums + QString name_space; + + foreach (AbstractMetaEnum *cppEnum, globalEnums()) { + if (cppEnum) + writeEnum(s, cppEnum, name_space); + } + } + s << sEnd; + s << defsStr; + s << "}\n"; +} + diff --git a/cppgenerator.h b/cppgenerator.h new file mode 100644 index 000000000..03d37438a --- /dev/null +++ b/cppgenerator.h @@ -0,0 +1,102 @@ +/* + * This file is part of the Boost Python Generator project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * + * Contact: PySide team <contact@pyside.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef CPPGENERATOR_H +#define CPPGENERATOR_H + +#include "boostpythongenerator.h" + +/** +* The CppGenerator generate the implementation of boost::python bindings classes. +*/ +class CppGenerator : public BoostPythonGenerator +{ +public: + void setDisableNamedArgs(bool disable) + { + m_disableNamedArgs = disable; + } + + const char* name() const + { + return "CppGenerator"; + } + +protected: + QString fileNameForClass(const AbstractMetaClass *cppClass) const; + void generateClass(QTextStream &s, const AbstractMetaClass *cppClass); + void finishGeneration(); + +private: + void writePrelude(QTextStream &s, const AbstractMetaClass *cppClass); + void writeBoostDeclaration(QTextStream &s, const AbstractMetaClass *cppClass); + + // method declaration writers + void writeConstructor(QTextStream &s, const AbstractMetaFunction *func); + void writeConstructorInitialization(QTextStream &s, const AbstractMetaFunction *func); + void writeNormalMethodDef(QTextStream &s, const AbstractMetaFunction *func); + void writeModifiedMethodDef(QTextStream &s, const AbstractMetaFunction *func); + void writeOperatorOverload(QTextStream &s, const AbstractMetaFunction *func); + void writeGlobalOperatorOverload(QTextStream &s, const AbstractMetaFunction *func); + void writeFunctionArgsDef(QTextStream &s_out, const AbstractMetaFunction *func); + void writeGlobalFunctions(); + void writeDestructor(QTextStream &s, const AbstractMetaClass *cppClass); + + // method implementation writers + void writeModifiedConstructorImpl(QTextStream &s, const AbstractMetaFunction *func); + void writeConstructorImpl(QTextStream &s, const AbstractMetaFunction *func); + void writeVirtualMethodImpl(QTextStream &s, const AbstractMetaFunction *func); + void writeVirtualMethodImplHead(QTextStream &s, const AbstractMetaFunction *func); + void writeVirtualMethodImplFoot(QTextStream &s, const AbstractMetaFunction *func); + void writePureVirtualMethodImplFoot(QTextStream &s, const AbstractMetaFunction *func); + void writeNonVirtualModifiedFunctionImpl(QTextStream &s, const AbstractMetaFunction *func); + void writeGlobalOperatorOverloadImpl(QTextStream& s, const AbstractMetaFunction* func); + + // helper functions + QString writeFunctionCast(QTextStream& s, const AbstractMetaFunction* func, const QString& castNameSuffix = QString(), const QString& className = QString()); + QString getFuncTypedefName(const AbstractMetaFunction *func) const; + QString getFunctionReturnType(const AbstractMetaFunction *func); + AbstractMetaFunction* findMainConstructor(const AbstractMetaClass *clazz); + QString getArgumentType(const AbstractMetaClass *cppClass, const AbstractMetaFunction *func, int idx); + QString operatorFunctionName(const AbstractMetaFunction *func); + QString getOperatorArgumentTypeName(const AbstractMetaFunction *func, int argumentIndex); + + // call policy related + QString verifyDefaultReturnPolicy(const AbstractMetaFunction *func, const QString &callPolicy); + QString getFunctionCallPolicy(const AbstractMetaFunction *func); + + // enum related + void writeEnums(QTextStream &s, const AbstractMetaClass *cppClass, bool useNamespace); + void writeEnum(QTextStream &s, const AbstractMetaEnum *cppEnum, const QString &nameSpace); + // write implicitly conversions + void writeImplicitlyConversion(QTextStream &s, const AbstractMetaClass *cppClass); + void writeVirtualDefaultFunction(QTextStream &s, const AbstractMetaFunction *arg2); + + void writeHashFunction(QTextStream &s, const AbstractMetaClass *cppClass); + QString baseClassName(const QString &name); + + bool m_disableNamedArgs; +}; + +#endif // CPPGENERATOR_H + diff --git a/doc/Makefile b/doc/Makefile new file mode 100644 index 000000000..f9fe2f01c --- /dev/null +++ b/doc/Makefile @@ -0,0 +1,88 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d _build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest + +help: + @echo "Please use \`make <target>' where <target> is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + -rm -rf _build/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) _build/html + @echo + @echo "Build finished. The HTML pages are in _build/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) _build/dirhtml + @echo + @echo "Build finished. The HTML pages are in _build/dirhtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) _build/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) _build/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) _build/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in _build/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) _build/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in _build/qthelp, like this:" + @echo "# qcollectiongenerator _build/qthelp/BoostPythonGenerator.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile _build/qthelp/BoostPythonGenerator.qhc" + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) _build/latex + @echo + @echo "Build finished; the LaTeX files are in _build/latex." + @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ + "run these through (pdf)latex." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) _build/changes + @echo + @echo "The overview file is in _build/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) _build/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in _build/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) _build/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in _build/doctest/output.txt." diff --git a/doc/_static/basic.css b/doc/_static/basic.css new file mode 100644 index 000000000..2509c227f --- /dev/null +++ b/doc/_static/basic.css @@ -0,0 +1,417 @@ +/** + * Sphinx stylesheet -- basic theme + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +/* -- main layout ----------------------------------------------------------- */ + +div.documentwrapper { + float: left; + width: 100%; +} + +div.bodywrapper { + margin: 0 0 0 230px; +} + +div.clearer { + clear: both; +} + +/* -- relbar ---------------------------------------------------------------- */ + +div.related { + width: 100%; + font-size: 90%; +} + +div.related h3 { + display: none; +} + +div.related ul { + margin: 0; + padding: 0 0 0 0px; + list-style: none; +} + +div.related li { + float: left; + display: inline; + padding-right:17px; + padding-left:10px; + background-image:url(images/bread_crumb.png); + background-position:right; + background-repeat:no-repeat; +} + +div.related li.right { + float: right; + margin-right: 5px; + padding: 0 0 0 0px; + background-image:none; +} + +/* -- sidebar --------------------------------------------------------------- */ + +div.sphinxsidebarwrapper { + padding: 10px 5px 0 10px; +} + +div.sphinxsidebar { + float: left; + width: 230px; + margin-left: -100%; + font-size: 90%; +} + +div.sphinxsidebar ul { + list-style: none; +} + +div.sphinxsidebar ul ul, +div.sphinxsidebar ul.want-points { + margin-left: 20px; + list-style: square; +} + +div.sphinxsidebar ul ul { + margin-top: 0; + margin-bottom: 0; +} + +div.sphinxsidebar form { + margin-top: 10px; +} + +img { + border: 0; +} + +/* -- search page ----------------------------------------------------------- */ + +ul.search { + margin: 10px 0 0 20px; + padding: 0; +} + +ul.search li { + padding: 5px 0 5px 20px; + background-image: url(file.png); + background-repeat: no-repeat; + background-position: 0 7px; +} + +ul.search li a { + font-weight: bold; +} + +ul.search li div.context { + color: #888; + margin: 2px 0 0 30px; + text-align: left; +} + +ul.keywordmatches li.goodmatch a { + font-weight: bold; +} + +/* -- index page ------------------------------------------------------------ */ + +table.contentstable { + text-align: left; + width: 90%; +} + +table.contentstable p.biglink { + line-height: 150%; +} + +a.biglink { + font-size: 1.3em; +} + +span.linkdescr { + text-align: left; + padding-top: 5px; + font-size: 90%; +} + +/* -- general index --------------------------------------------------------- */ + +table.indextable td { + text-align: left; + vertical-align: top; +} + +table.indextable dl, table.indextable dd { + margin-top: 0; + margin-bottom: 0; +} + +table.indextable tr.pcap { + height: 10px; +} + +table.indextable tr.cap { + margin-top: 10px; + background-color: #f2f2f2; +} + +img.toggler { + margin-right: 3px; + margin-top: 3px; + cursor: pointer; +} + +/* -- general body styles --------------------------------------------------- */ + +a.headerlink { + visibility: hidden; +} + +h1:hover > a.headerlink, +h2:hover > a.headerlink, +h3:hover > a.headerlink, +h4:hover > a.headerlink, +h5:hover > a.headerlink, +h6:hover > a.headerlink, +dt:hover > a.headerlink { + visibility: visible; +} + +div.body p.caption { + text-align: inherit; +} + +div.body td { + text-align: left; +} + +.field-list ul { + padding-left: 1em; +} + +.first { + margin-top: 0 !important; +} + +p.rubric { + margin-top: 30px; + font-weight: bold; +} + +/* -- sidebars -------------------------------------------------------------- */ + +div.sidebar { + margin: 0 0 0.5em 1em; + border: 1px solid #ddb; + padding: 7px 7px 0 7px; + background-color: #ffe; + width: 40%; + float: right; +} + +p.sidebar-title { + font-weight: bold; +} + +/* -- topics ---------------------------------------------------------------- */ + +div.topic { + border: 1px solid #ccc; + padding: 7px 7px 0 7px; + margin: 10px 0 10px 0; +} + +p.topic-title { + font-size: 1.1em; + font-weight: bold; + margin-top: 10px; +} + +/* -- admonitions ----------------------------------------------------------- */ + +div.admonition { + margin-top: 10px; + margin-bottom: 10px; + padding: 7px; +} + +div.admonition dt { + font-weight: bold; +} + +div.admonition dl { + margin-bottom: 0; +} + +p.admonition-title { + margin: 0px 10px 5px 0px; + font-weight: bold; +} + +div.body p.centered { + text-align: center; + margin-top: 25px; +} + +/* -- tables ---------------------------------------------------------------- */ + +table.docutils { + border: 0; + border-collapse: collapse; +} + +table.docutils td, table.docutils th { + padding: 2px 8px 2px 8px; + border-top: 0; + border-left: 0; + border-right: 0; + border-bottom: 1px solid #aaa; +} + +table.field-list td, table.field-list th { + border: 0 !important; +} + +table.footnote td, table.footnote th { + border: 0 !important; +} + +th { + text-align: left; + padding-right: 5px; +} + +/* -- other body styles ----------------------------------------------------- */ + +dl { + margin-bottom: 15px; +} + +dd p { + margin-top: 0px; +} + +dd ul, dd table { + margin-bottom: 10px; +} + +dd { + margin-top: 3px; + margin-bottom: 10px; + margin-left: 30px; +} + +dt:target, .highlight { + background-color: #fbe54e; +} + +dl.glossary dt { + font-weight: bold; + font-size: 1.1em; +} + +.field-list ul { + margin: 0; + padding-left: 1em; +} + +.field-list p { + margin: 0; +} + +.refcount { + color: #060; +} + +.optional { + font-size: 1.3em; +} + +.versionmodified { + font-style: italic; +} + +.system-message { + background-color: #fda; + padding: 5px; + border: 3px solid red; +} + +.footnote:target { + background-color: #ffa +} + +/* -- code displays --------------------------------------------------------- */ + +pre { + overflow: auto; +} + +td.linenos pre { + padding: 5px 0px; + border: 0; + background-color: transparent; + color: #aaa; +} + +table.highlighttable { + margin-left: 0.5em; +} + +table.highlighttable td { + padding: 0 0.5em 0 0.5em; +} + +tt.descname { + background-color: transparent; + font-weight: bold; + font-size: 1.2em; +} + +tt.descclassname { + background-color: transparent; +} + +tt.xref, a tt { + background-color: transparent; + font-weight: bold; +} + +h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt { + background-color: transparent; +} + +/* -- math display ---------------------------------------------------------- */ + +img.math { + vertical-align: middle; +} + +div.math p { + text-align: center; +} + +span.eqno { + float: right; +} + +/* -- printout stylesheet --------------------------------------------------- */ + +@media print { + div.document, + div.documentwrapper, + div.bodywrapper { + margin: 0; + width: 100%; + } + + div.sphinxsidebar, + div.related, + div.footer, + #top-link { + display: none; + } +} diff --git a/doc/_static/bindingexample.tar.bz2 b/doc/_static/bindingexample.tar.bz2 Binary files differnew file mode 100644 index 000000000..bf1fdea66 --- /dev/null +++ b/doc/_static/bindingexample.tar.bz2 diff --git a/doc/_static/default.css b/doc/_static/default.css new file mode 100644 index 000000000..721ceb71b --- /dev/null +++ b/doc/_static/default.css @@ -0,0 +1,248 @@ +/** + * Sphinx stylesheet -- default theme + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + */ + +@import url("basic.css"); + +/* -- page layout ----------------------------------------------------------- */ + +body { + font-family: sans-serif; + font-size: 100%; + background-color: #000000; + color: #000; + margin: 0; + padding: 0; +} + +div.document { + background-image:url(images/side_background.jpg); + background-repeat:repeat-y; + background-color:#ffd800; +} + +div.body { + position:relative; + background-color:#fff; + color: #000000; + padding: 0 20px 30px 20px; +} + +div.footer { + color: #ffffff; + width: 100%; + padding: 9px 0 9px 0; + text-align: center; + font-size: 75%; +} + +div.footer a { + color: #ffffff; + text-decoration: underline; +} + +div.related { + background-image:url(images/top_background.jpg); + background-repeat:repeat-x; + background-color: #d7aa00; + line-height:33px; + height:33px; + color: #000000; +} + +div.related a { + color: #000000; +} + +div.related img { + padding-top:3px; +} + +div.sphinxsidebar { +} + +div.sphinxsidebar h3 { + font-family: Arial, Verdana, sans-serif; + color: #000000; + font-size: 1.4em; + font-weight: normal; + margin: 0; + padding: 0; +} + +div.sphinxsidebar h3 a { + color: #000000; +} + +div.sphinxsidebar h4 { + font-family: Arial, Verdana, sans-serif; + color: #000000; + font-size: 1.3em; + font-weight: normal; + margin: 5px 0 0 0; + padding: 0; +} + +div.sphinxsidebar p { + color: #ffffff; +} + +div.sphinxsidebar p.topless { + margin: 5px 10px 10px 10px; +} + +div.sphinxsidebar ul { + margin: 10px; + padding: 0; + color: #ffffff; +} + +div#searchbox p.searchtip { + color:#000000; + font-size:90%; + padding-top:50px; +} + +div#searchbox { + background-image:url(images/background_search.jpg); + background-repeat:no-repeat; + background-position:center; + border:none; +} + +div.sphinxsidebar a { + color: #009491; +} + + +/* -- body styles ----------------------------------------------------------- */ + +a { + color: #009491; + text-decoration: underline; +} + +a:hover { + text-decoration: underline; +} + +div.body p, div.body dd, div.body li { + text-align: left; + line-height: 130%; +} + +div.body h1 { + font-family: Arial, Verdana, sans-serif; + background-color: #f2f2f2; + font-weight: normal; + color: #20435c; + border-bottom: 1px solid #ccc; + margin: 20px -20px 10px -20px; + padding: 3px 0 3px 10px; +} + +div.body h2, +div.body h3, +div.body h4, +div.body h5, +div.body h6 { + font-family: Arial, Verdana, Helvetica, sans-serif; + font-size:12px; + font-weight:normal; + border-left-width: 1px; + border-right-width: 1px; + border-top-width: 1px; + border-bottom-width: 2px; + border-style: solid; + border-left-color: #b1b1b1; + border-right-color: #b1b1b1; + border-top-color: #b1b1b1; + border-bottom-color: #009491; + background-color: #e0e0e0; + padding-left:5px; +} + +div.body h1 { margin-top: 0; font-size: 200%; } +div.body h2 { font-size: 120%; } +div.body h3 { font-size: 115%; } +div.body h4 { font-size: 110%; } +div.body h5 { font-size: 105%; } +div.body h6 { font-size: 100%; } + +a.headerlink { + color: #c60f0f; + font-size: 0.8em; + padding: 0 4px 0 4px; + text-decoration: none; +} + +a.headerlink:hover { + background-color: #c60f0f; + color: white; +} + +div.body p, div.body dd, div.body li { + text-align: left; + line-height: 130%; +} + +div.admonition p.admonition-title + p { + display: inline; +} + +div.note { + background-color: #eee; + border: 1px solid #ccc; +} + +div.seealso { + background-color: #ffc; + border: 1px solid #ff6; +} + +div.topic { + background-color: #eee; +} + +div.warning { + background-color: #ffe4e4; + border: 1px solid #f66; +} + +p.admonition-title { + display: inline; +} + +p.admonition-title:after { + content: ":"; +} + +input[type=text]{ + background-color: #009491; + font: 11px verdana, arial, helvetica, sans-serif; + color:#FFFFFF; + width: 150px; + height: 18px; + border: 1px solid #009491; + margin-left:13px; + margin-top:15px; + margin-bottom:4px; + border:none; +} + +pre { + padding: 5px; + background-color: #eeffcc; + color: #333333; + line-height: 120%; + border: 1px solid #ac9; + border-left: none; + border-right: none; +} + +tt { + background-color: #ecf0f3; + padding: 0 1px 0 1px; + font-size: 0.95em; +} diff --git a/doc/_static/images/._background_search.jpg b/doc/_static/images/._background_search.jpg Binary files differnew file mode 100755 index 000000000..d5c689c31 --- /dev/null +++ b/doc/_static/images/._background_search.jpg diff --git a/doc/_static/images/._bread_crumb.png b/doc/_static/images/._bread_crumb.png Binary files differnew file mode 100755 index 000000000..46b8591c6 --- /dev/null +++ b/doc/_static/images/._bread_crumb.png diff --git a/doc/_static/images/._button_search.jpg b/doc/_static/images/._button_search.jpg Binary files differnew file mode 100755 index 000000000..d5c689c31 --- /dev/null +++ b/doc/_static/images/._button_search.jpg diff --git a/doc/_static/images/._side_background.jpg b/doc/_static/images/._side_background.jpg Binary files differnew file mode 100755 index 000000000..a79b91c97 --- /dev/null +++ b/doc/_static/images/._side_background.jpg diff --git a/doc/_static/images/._top_background.jpg b/doc/_static/images/._top_background.jpg Binary files differnew file mode 100755 index 000000000..d5c689c31 --- /dev/null +++ b/doc/_static/images/._top_background.jpg diff --git a/doc/_static/images/background_search.jpg b/doc/_static/images/background_search.jpg Binary files differnew file mode 100644 index 000000000..c0481c561 --- /dev/null +++ b/doc/_static/images/background_search.jpg diff --git a/doc/_static/images/bg.jpg b/doc/_static/images/bg.jpg Binary files differnew file mode 100644 index 000000000..2ceb19583 --- /dev/null +++ b/doc/_static/images/bg.jpg diff --git a/doc/_static/images/bread_crumb.png b/doc/_static/images/bread_crumb.png Binary files differnew file mode 100644 index 000000000..f7ebd20e4 --- /dev/null +++ b/doc/_static/images/bread_crumb.png diff --git a/doc/_static/images/button_search.png b/doc/_static/images/button_search.png Binary files differnew file mode 100644 index 000000000..0160b81ab --- /dev/null +++ b/doc/_static/images/button_search.png diff --git a/doc/_static/images/side_background.jpg b/doc/_static/images/side_background.jpg Binary files differnew file mode 100644 index 000000000..6e6667542 --- /dev/null +++ b/doc/_static/images/side_background.jpg diff --git a/doc/_static/images/top_background.jpg b/doc/_static/images/top_background.jpg Binary files differnew file mode 100644 index 000000000..aafe1f72e --- /dev/null +++ b/doc/_static/images/top_background.jpg diff --git a/doc/_templates/index.html b/doc/_templates/index.html new file mode 100644 index 000000000..296aae27d --- /dev/null +++ b/doc/_templates/index.html @@ -0,0 +1,32 @@ +{% extends "layout.html" %} +{% set title = 'Overview' %} +{% block body %} + <h1>BoostPythonGenerator {{ version }}</h1> + + <p>BoostPythonGenerator is a tool that eases the development of Python bindings for Qt-based + libraries by automating most of the process. It relies heavily on the ApiExtractor library + to parse the header files and manipulate the classes information while generating the code. + This generated code uses the + <a href="http://www.boost.org/doc/libs/1_39_0/libs/python/doc/index.html">Boost::Python library</a> + in order to bridge the C++ library and Python.</p> + + <p>BoostPythonGenerator is based on the + <a href="http://labs.trolltech.com/page/Projects/QtScript/Generator">QtScriptGenerator</a> project.</p> + + <h2>Documentation</h2> + <table class="contentstable" align="center" style="margin-left: 30px"><tr> + <td width="50%"> + <p class="biglink"><a class="biglink" href="{{ pathto("overview") }}">Overview</a><br/> + <span class="linkdescr">how generator works</span></p> + <p class="biglink"><a class="biglink" href="{{ pathto("tutorial/introduction") }}">Tutorial</a><br/> + <span class="linkdescr">start here</span></p> + </td> + <td width="50%"> + <p class="biglink"><a class="biglink" href="{{ pathto("compiling/compiling") }}">Compiling/Installing</a><br/> + <span class="linkdescr">how to compile and install BoostPythonGenerator</span></p> + <p class="biglink"><a class="biglink" href="{{ pathto("contents") }}">Contents</a><br/> + <span class="linkdescr">for a complete overview</span></p> + </td></tr> + </table> + +{% endblock %} diff --git a/doc/_templates/layout.html b/doc/_templates/layout.html new file mode 100644 index 000000000..12fed4d0f --- /dev/null +++ b/doc/_templates/layout.html @@ -0,0 +1,34 @@ +{% extends "!layout.html" %} +{% block rootrellink %} + <!--<li><img src="{{ pathto('_static/py.png', 1) }}" alt="" + style="vertical-align: middle; margin-top: -1px"/></li>--> + <li><a href="{{ pathto('index') }}">{{ shorttitle }}</a>{{ reldelim1 }}</li> +{% endblock %} +{% set reldelim1 = '' %} +{% block extrahead %} + <!--<link rel="shortcut icon" type="image/png" href="{{ pathto('_static/py.png', 1) }}" />--> +{{ super() }} +{% endblock %} + +{% block sidebarsearch %} + <div id="searchbox" style="display: none"> + <h3>Quick search</h3> + <form class="search" action="search.html" method="get"> + <div style="width:195px;"> + <div style="float:left;"> + <input type="text" name="q" size="18" /> + </div> + <div style="float:right; padding-top:14px; "> + <input type="image" src="{{ pathto('_static/images/button_search.png', 1) }}"/> + </div> + </div> + <input type="hidden" name="check_keywords" value="yes" /> + <input type="hidden" name="area" value="default" /> + </form> + <p class="searchtip" style="font-size: 90%"> + Enter search terms or a module, class or function name. + </p> + </div> + <script type="text/javascript">$('#searchbox').show(0);</script> +{% endblock %} + diff --git a/doc/compiling/cmake-primer.rst b/doc/compiling/cmake-primer.rst new file mode 100644 index 000000000..7769005be --- /dev/null +++ b/doc/compiling/cmake-primer.rst @@ -0,0 +1,72 @@ + +.. _cmake-primer: + +************ +CMake primer +************ + +This chapter is a basic introduction to CMake, the build system used by PySide +and the boost binding generator. + +The practical steps will focus on how to use cmake on a Unix-like (GNU/Linux) +environment. + + +Configuring +=========== + +Project file - CMakeLists.txt +----------------------------- + +CMake parses the file CMakeLists.txt for information about the project, +like project name, dependencies, what should be compiled, what should be +shipped. + + +CMake variables +--------------- + +CMake can have its default behavior modified by providing some + +* ``CMAKE_INSTALL_PREFIX=<some path here>`` sets the install prefix to + the specified path. +* ``CMAKE_MODULE_PATH=<some path here>`` sets the extra directories + where CMake will try to find its modules. +* ``CMAKE_TOOLCHAIN_FILE=<file path>`` sets the path to the file that + describes the toolchain used to compile this project. It is very useful + when using CMake with icecc to speedup compilation. + +You can define a variable using the ``-D<VARIABLE>`` switch like the example +below. + +* ``-DCMAKE_BUILD_TYPE=Release|Debug`` sets the building behavior. Default + value is *Release*. + +Invoking CMake +-------------- + +After writing the CMakeLists.txt and deciding which flags will be used, +you can invoke CMake using:: + + cmake <CMake flags> <path to toplevel CMakeLists.txt file> + +For example, if you use the ``build/`` folder to build the project and +want it to be installed into ``/opt/sandbox/``, use the following lines:: + + cd build/ + cmake -DCMAKE_INSTALL_PREFIX=/opt/sandbox .. + +CMake will process the project file and write the output files in the +current directory + +Building +======== + +After the configuration process, the Makefiles are written and you can build +the project using :program:`make`. + +Installing +========== + +As in the building process, ``make install`` will install the files into +the target directory. diff --git a/doc/compiling/compiling.rst b/doc/compiling/compiling.rst new file mode 100644 index 000000000..638efa91a --- /dev/null +++ b/doc/compiling/compiling.rst @@ -0,0 +1,9 @@ +Compiling +********* + +.. toctree:: + :maxdepth: 3 + + cmake-primer + setup-apiextractor + setup-generator diff --git a/doc/compiling/setup-apiextractor.rst b/doc/compiling/setup-apiextractor.rst new file mode 100644 index 000000000..5443f46ea --- /dev/null +++ b/doc/compiling/setup-apiextractor.rst @@ -0,0 +1,48 @@ + +.. _api-extractor: + +************** +API Extractor +************** + +Overview +======== + +The **API Extractor** library is used by the binding generator to +parse the header and typesystem files to create an internal +representation of the API. It is based on the QtScriptGenerator +codebase. + +Getting the sources +=================== + +* Download URL: http://www.pyside.org/downloads/ + +Build requirements +================== + +* Qt4.5 development headers and libraries >= 4.5.0 +* libboost-graph >= 1.38.0 +* cmake >= 2.6.0 + +Building and installing +======================= + +To build and install just follow the generic cmake instructions in section +:ref:`cmake-primer`. + +Debian packaging +================ + +In order to compile this package in a debian environment, make sure the +following packages are installed: + +* debhelper (>= 5) +* cdbs +* cmake (>= 2.6.0) +* libboost-graph1.38-dev (>= 1.38.0) +* libqt4-dev (>= 4.5) + +And then you can build the package using:: + + $ dpkg-buildpackage -rfakeroot diff --git a/doc/compiling/setup-generator.rst b/doc/compiling/setup-generator.rst new file mode 100644 index 000000000..d58f98368 --- /dev/null +++ b/doc/compiling/setup-generator.rst @@ -0,0 +1,49 @@ + +.. _boost-python-generator: + +*********************** +Boost::Python Generator +*********************** + +Overview +========================================= + +The **Boost::Python Generator** (A.K.A. :program:`boostpythongenerator`) is +the program that creates the bindings source files from Qt headers and +auxiliary files (typesystems, ``global.h`` and glue files). It makes +heavy use of the :ref:`api-extractor` library. + + +Getting the sources +=================== + +* Download URL: http://www.pyside.org/downloads/ + +Build requirements +================== + ++ CMake >= 2.6.0 ++ Qt4.5 libraries and development headers >= 4.5.0 ++ :ref:`api-extractor` + development headers + +Building and installing +======================= + +To build and install just follow the generic cmake instructions in +section :ref:`cmake-primer`. + +Debian packaging +================ + +In order to compile this package in a debian environment, make sure the +following packages are installed: + +* debhelper (>= 5) +* cdbs +* cmake (>= 2.6.0) +* libqt4-dev (>= 4.5) +* libapiextractor-dev (>= 0.1) + +And then you can build the package using:: + + $ dpkg-buildpackage -rfakeroot diff --git a/doc/conf.py b/doc/conf.py new file mode 100644 index 000000000..8d196e455 --- /dev/null +++ b/doc/conf.py @@ -0,0 +1,188 @@ +# -*- coding: utf-8 -*- +# +# BoostPythonGenerator documentation build configuration file, created by +# sphinx-quickstart on Wed Apr 22 15:04:20 2009. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.append(os.path.abspath('.')) + +# -- General configuration ----------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.ifconfig', 'sphinx.ext.refcounting', 'sphinx.ext.coverage'] + +rst_epilog = """ +.. |project| replace:: BoostPythonGenerator +""" + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +source_encoding = 'utf-8' + +# The master toctree document. +#master_doc = 'contents' + +# General information about the project. +project = u'BoostPythonGenerator' +copyright = u'2009, Nokia Corporation' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '0.1' +# The full version, including alpha/beta/rc tags. +release = '0.1' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of documents that shouldn't be included in the build. +#unused_docs = [] + +# List of directories, relative to source directory, that shouldn't be searched +# for source files. +exclude_trees = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. Major themes that come with +# Sphinx are currently 'default' and 'sphinxdoc'. +html_theme = 'default' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = { +#} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# "<project> v<release> documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = { '' : ''} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +html_additional_pages = { 'index' : 'index.html'} + +# If false, no module index is generated. +#html_use_modindex = True + +# If false, no index is generated. +html_use_index = True + +# If true, the index is split into individual pages for each letter. +html_split_index = False + +# If true, links to the reST sources are added to the pages. +html_show_sourcelink = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a <link> tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = '' + +# -- Options for LaTeX output -------------------------------------------------- + +# The paper size ('letter' or 'a4'). +#latex_paper_size = 'letter' + +# The font size ('10pt', '11pt' or '12pt'). +#latex_font_size = '10pt' + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# Additional stuff for the LaTeX preamble. +#latex_preamble = '' + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_use_modindex = True diff --git a/doc/contents.rst b/doc/contents.rst new file mode 100644 index 000000000..5574c7ac1 --- /dev/null +++ b/doc/contents.rst @@ -0,0 +1,9 @@ +Table of contents +***************** +.. toctree:: + :numbered: + :maxdepth: 3 + + overview.rst + tutorial/introduction.rst + compiling/compiling.rst diff --git a/doc/dependency-pyside.svg b/doc/dependency-pyside.svg new file mode 100644 index 000000000..786bdb8a6 --- /dev/null +++ b/doc/dependency-pyside.svg @@ -0,0 +1,527 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="900" + height="560" + id="svg2" + sodipodi:version="0.32" + inkscape:version="0.46" + version="1.0" + sodipodi:docname="dependency-pyside.svg" + inkscape:output_extension="org.inkscape.output.svg.inkscape" + inkscape:export-filename="/tmp/dependency-pyside.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90"> + <defs + id="defs4"> + <marker + inkscape:stockid="Arrow1Lstart" + orient="auto" + refY="0" + refX="0" + id="Arrow1Lstart" + style="overflow:visible"> + <path + id="path3270" + d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z" + style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" + transform="matrix(0.8,0,0,0.8,10,0)" /> + </marker> + <marker + inkscape:stockid="Arrow1Lend" + orient="auto" + refY="0" + refX="0" + id="Arrow1Lend" + style="overflow:visible"> + <path + id="path3679" + d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z" + style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" + transform="matrix(-0.8,0,0,-0.8,-10,0)" /> + </marker> + <inkscape:perspective + sodipodi:type="inkscape:persp3d" + inkscape:vp_x="0 : 526.18109 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_z="744.09448 : 526.18109 : 1" + inkscape:persp3d-origin="372.04724 : 350.78739 : 1" + id="perspective10" /> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + gridtolerance="10000" + guidetolerance="10" + objecttolerance="10" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="0.79440331" + inkscape:cx="-36.66006" + inkscape:cy="372.04724" + inkscape:document-units="px" + inkscape:current-layer="svg2" + showgrid="false" + showguides="true" + inkscape:guide-bbox="true" + inkscape:window-width="1278" + inkscape:window-height="949" + inkscape:window-x="0" + inkscape:window-y="0"> + <sodipodi:guide + orientation="1,0" + position="384.28571,590" + id="guide2601" /> + <sodipodi:guide + orientation="1,0" + position="678.57143,491.42857" + id="guide2603" /> + <sodipodi:guide + orientation="1,0" + position="78.571429,257.14286" + id="guide2605" /> + <sodipodi:guide + orientation="1,0" + position="93.571429,280.71429" + id="guide7565" /> + <sodipodi:guide + orientation="1,0" + position="148.57143,216.42857" + id="guide7567" /> + </sodipodi:namedview> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(-78.088635,-190.95252)" /> + <g + id="g5394" + transform="translate(6.1314759,14.304617)"> + <g + transform="translate(-65.84289,-190.95252)" + id="g5205"> + <g + id="g5171"> + <rect + rx="9.3643799" + y="338.7739" + x="678.57141" + height="73.281754" + width="274.54263" + id="rect2393" + style="fill:#aaeeff;fill-rule:evenodd;stroke:#006078;stroke-width:0.96620417px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + ry="13.104657" /> + <text + id="text2395" + y="355.93701" + x="683.46539" + style="font-size:16.27989578px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + xml:space="preserve"><tspan + y="355.93701" + x="683.46539" + id="tspan2397" + sodipodi:role="line">boost::python</tspan></text> + <text + id="text2399" + y="371.60172" + x="683.46539" + style="font-size:8.40044498px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + xml:space="preserve"><tspan + y="371.60172" + x="683.46539" + id="tspan2401" + sodipodi:role="line">1.38.0</tspan></text> + <text + id="text2403" + y="387.14166" + x="683.46539" + style="font-size:9.33067703px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + xml:space="preserve"><tspan + id="tspan2435" + y="387.14166" + x="683.46539" + sodipodi:role="line">headers and libraries - compile-time and run-time</tspan></text> + <text + id="text2413" + y="402.4646" + x="683.46539" + style="font-size:8.26250458px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + xml:space="preserve"><tspan + y="402.4646" + x="683.46539" + id="tspan2415" + sodipodi:role="line">Boost Software License 1.0</tspan></text> + </g> + <g + id="g5193"> + <rect + rx="8.3239012" + y="342.86383" + x="78.571426" + height="73.282379" + width="274.18781" + id="rect2417" + style="fill:#b3ff80;fill-rule:evenodd;stroke:#2a7800;stroke-width:0.96558368px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + ry="9.2689295" /> + <text + id="text2419" + y="359.67014" + x="88.822823" + style="font-size:16.27989578px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + xml:space="preserve"><tspan + y="359.67014" + x="88.822823" + id="tspan2421" + sodipodi:role="line">Qt 4.5</tspan></text> + <text + id="text2423" + y="375.33484" + x="88.822823" + style="font-size:8.40044498px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + xml:space="preserve"><tspan + y="375.33484" + x="88.822823" + id="tspan2425" + sodipodi:role="line">4.5</tspan></text> + <text + id="text2427" + y="390.87479" + x="88.822823" + style="font-size:9.33067703px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + xml:space="preserve"><tspan + y="390.87479" + x="88.822823" + id="tspan2429" + sodipodi:role="line">headers and libraries - compile-time and run-time</tspan></text> + <text + id="text2431" + y="400.84058" + x="88.822823" + style="font-size:8.26250458px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + xml:space="preserve"><tspan + y="400.84058" + x="88.822823" + id="tspan2433" + sodipodi:role="line">GNU General Public License v3 /</tspan><tspan + y="411.1687" + x="88.822823" + sodipodi:role="line" + id="tspan2472">GNU Lesser General Public Licence v2.1</tspan></text> + </g> + <g + id="g5120"> + <rect + y="496.43558" + x="384.28571" + height="73.281754" + width="274.54263" + id="rect2441" + style="fill:#e9ddaf;fill-rule:evenodd;stroke:#5f5019;stroke-width:0.96620417px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + ry="13.104635" + rx="10.404889" /> + <text + id="text2443" + y="513.59869" + x="389.17969" + style="font-size:16.27989578px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + xml:space="preserve"><tspan + y="513.59869" + x="389.17969" + id="tspan2445" + sodipodi:role="line">libapiextractor</tspan></text> + <text + id="text2447" + y="529.26337" + x="389.17969" + style="font-size:8.40044498px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + xml:space="preserve"><tspan + y="529.26337" + x="389.17969" + id="tspan2449" + sodipodi:role="line">0.1</tspan></text> + <text + id="text2451" + y="544.80334" + x="389.17969" + style="font-size:9.33067703px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + xml:space="preserve"><tspan + id="tspan2453" + y="544.80334" + x="389.17969" + sodipodi:role="line">headers and libraries - compile-time and run-time</tspan></text> + <text + id="text2455" + y="560.12628" + x="389.17969" + style="font-size:8.26250458px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + xml:space="preserve"><tspan + y="560.12628" + x="389.17969" + id="tspan2457" + sodipodi:role="line">LGPL version 2.1</tspan></text> + </g> + <g + id="g5131"> + <rect + y="340.72134" + x="384.28571" + height="73.281754" + width="274.54263" + id="rect2459" + style="fill:#e9ddaf;fill-rule:evenodd;stroke:#5f5019;stroke-width:0.96620417px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + ry="10.309408" + rx="9.3644047" /> + <text + id="text2461" + y="357.88449" + x="389.17969" + style="font-size:16.27989578px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + xml:space="preserve"><tspan + y="357.88449" + x="389.17969" + id="tspan2463" + sodipodi:role="line">BoostPythonGenerator</tspan></text> + <text + id="text2465" + y="373.54916" + x="389.17969" + style="font-size:8.40044498px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + xml:space="preserve"><tspan + y="373.54916" + x="389.17969" + id="tspan2467" + sodipodi:role="line">0.1</tspan></text> + <text + id="text2469" + y="389.08914" + x="389.17969" + style="font-size:9.33067703px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + xml:space="preserve"><tspan + id="tspan2471" + y="389.08914" + x="389.17969" + sodipodi:role="line">Binary executable - compile-time</tspan></text> + <text + id="text2473" + y="404.41208" + x="389.17969" + style="font-size:8.26250458px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + xml:space="preserve"><tspan + y="404.41208" + x="389.17969" + id="tspan2475" + sodipodi:role="line">LGPL version 2.1</tspan></text> + </g> + <g + id="g5142"> + <rect + y="191.43562" + x="384.28571" + height="73.281754" + width="274.54263" + id="rect2523" + style="fill:#e9ddaf;fill-opacity:1;fill-rule:evenodd;stroke:#5f5019;stroke-width:0.96620417px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + ry="14.285714" /> + <text + id="text2525" + y="208.59874" + x="389.17966" + style="font-size:16.27989578px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + xml:space="preserve"><tspan + y="208.59874" + x="389.17966" + id="tspan2527" + sodipodi:role="line">Qt Python bindings</tspan></text> + <text + id="text2529" + y="224.26344" + x="389.17966" + style="font-size:8.40044498px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + xml:space="preserve"><tspan + y="224.26344" + x="389.17966" + id="tspan2531" + sodipodi:role="line">0.1</tspan></text> + <text + id="text2533" + y="239.80339" + x="389.17966" + style="font-size:9.33067703px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + xml:space="preserve"><tspan + id="tspan2535" + y="239.80339" + x="389.17966" + sodipodi:role="line">Target</tspan></text> + <text + id="text2537" + y="255.12633" + x="389.17966" + style="font-size:8.26250458px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + xml:space="preserve"><tspan + y="255.12633" + x="389.17966" + id="tspan2539" + sodipodi:role="line">LGPL version 2.1</tspan></text> + </g> + <g + id="g5182"> + <rect + rx="10.404877" + y="648.57843" + x="384.28571" + height="73.281754" + width="274.54263" + id="rect2563" + style="fill:#aaeeff;fill-rule:evenodd;stroke:#006078;stroke-width:0.96620417px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + ry="11.287985" /> + <text + id="text2565" + y="665.74158" + x="389.17969" + style="font-size:16.27989578px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + xml:space="preserve"><tspan + y="665.74158" + x="389.17969" + id="tspan2567" + sodipodi:role="line">boost::graph</tspan></text> + <text + id="text2569" + y="681.40625" + x="389.17969" + style="font-size:8.40044498px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + xml:space="preserve"><tspan + y="681.40625" + x="389.17969" + id="tspan2571" + sodipodi:role="line">1.38.0</tspan></text> + <text + id="text2573" + y="696.94623" + x="389.17969" + style="font-size:9.33067703px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + xml:space="preserve"><tspan + id="tspan2575" + y="696.94623" + x="389.17969" + sodipodi:role="line">headers and libraries - compile-time and run-time</tspan></text> + <text + id="text2577" + y="712.26917" + x="389.17969" + style="font-size:8.26250458px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + xml:space="preserve"><tspan + y="712.26917" + x="389.17969" + id="tspan2579" + sodipodi:role="line">Boost Software License 1.0</tspan></text> + </g> + </g> + <path + inkscape:connector-type="polyline" + id="path2869" + d="M 212.85114,151.42852 L 368.56822,74.247959" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Arrow1Lstart);marker-end:none;stroke-opacity:1" /> + <path + inkscape:connector-type="polyline" + id="path2871" + d="M 663.60462,147.33826 L 517.61788,74.247959" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Arrow1Lstart);marker-end:none;stroke-opacity:1" /> + <path + inkscape:connector-type="polyline" + id="path2877" + d="M 443.4684,149.28571 L 443.46839,74.247959" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Arrow1Lstart);marker-end:none;stroke-opacity:1" /> + <path + inkscape:connector-type="polyline" + id="path2879" + d="M 443.4684,304.99994 L 443.4684,223.53367" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Arrow1Lstart);marker-end:none;stroke-opacity:1" /> + <path + inkscape:connector-type="polyline" + id="path2881" + d="M 443.4684,457.14279 L 443.4684,379.2479" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Arrow1Lstart);marker-mid:none;marker-end:none;stroke-opacity:1" /> + <rect + ry="17.142857" + y="293.85626" + x="0.48279184" + height="124.28571" + width="211.42857" + id="rect7541" + style="fill:#e3e2db;stroke:#000000;stroke-opacity:1" /> + <text + id="text7543" + y="325.44049" + x="70.482788" + style="font-size:20.61732101px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + xml:space="preserve"><tspan + y="325.44049" + x="70.482788" + id="tspan7545" + sodipodi:role="line">Boost</tspan></text> + <text + id="text7547" + y="358.37042" + x="70.482788" + style="font-size:20.61732101px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + xml:space="preserve"><tspan + y="358.37042" + x="70.482788" + id="tspan7549" + sodipodi:role="line">Qt Software</tspan></text> + <text + id="text7551" + y="394.07593" + x="70.482788" + style="font-size:20.61732101px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + xml:space="preserve"><tspan + y="394.07593" + x="70.482788" + id="tspan7553" + sodipodi:role="line">INdT/Nokia</tspan></text> + <rect + ry="6.4285707" + y="307.24911" + x="15.482792" + height="22.5" + width="43.163269" + id="rect7555" + style="fill:#aaeeff;fill-opacity:1;stroke:#000000;stroke-width:0.64285713;stroke-opacity:1" /> + <rect + ry="6.4285707" + y="341.17767" + x="15.482792" + height="22.5" + width="43.163269" + id="rect7561" + style="fill:#b3ff80;fill-opacity:1;stroke:#000000;stroke-width:0.64285713;stroke-opacity:1" /> + <rect + ry="6.4285707" + y="376.17767" + x="15.482792" + height="22.5" + width="43.163269" + id="rect7563" + style="fill:#e9ddaf;fill-opacity:1;stroke:#000000;stroke-width:0.64285713;stroke-opacity:1" /> + </g> +</svg> diff --git a/doc/images/.directory b/doc/images/.directory new file mode 100644 index 000000000..e65475f65 --- /dev/null +++ b/doc/images/.directory @@ -0,0 +1,3 @@ +[Dolphin] +ShowPreview=true +Timestamp=2009,5,5,17,43,26 diff --git a/doc/images/bindinggen-development.png b/doc/images/bindinggen-development.png Binary files differnew file mode 100644 index 000000000..3d64e7641 --- /dev/null +++ b/doc/images/bindinggen-development.png diff --git a/doc/images/bindinggen-development.svg b/doc/images/bindinggen-development.svg new file mode 100644 index 000000000..3b6b3a26e --- /dev/null +++ b/doc/images/bindinggen-development.svg @@ -0,0 +1,543 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="640" + height="200" + id="svg2" + sodipodi:version="0.32" + inkscape:version="0.46" + version="1.0" + sodipodi:docname="bindgen-development.svg" + inkscape:output_extension="org.inkscape.output.svg.inkscape" + inkscape:export-filename="bindinggen-development.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90"> + <defs + id="defs4"> + <marker + inkscape:stockid="EmptyDiamondL" + orient="auto" + refY="0" + refX="0" + id="EmptyDiamondL" + style="overflow:visible"> + <path + id="path3930" + d="M 0,-7.0710768 L -7.0710894,0 L 0,7.0710589 L 7.0710462,0 L 0,-7.0710768 z" + style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" + transform="scale(0.8,0.8)" /> + </marker> + <marker + inkscape:stockid="EmptyTriangleInL" + orient="auto" + refY="0" + refX="0" + id="EmptyTriangleInL" + style="overflow:visible"> + <path + id="path3975" + d="M 5.77,0 L -2.88,5 L -2.88,-5 L 5.77,0 z" + style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" + transform="matrix(-0.8,0,0,-0.8,4.8,0)" /> + </marker> + <marker + inkscape:stockid="Arrow1Sstart" + orient="auto" + refY="0" + refX="0" + id="Arrow1Sstart" + style="overflow:visible"> + <path + id="path3835" + d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z" + style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" + transform="matrix(0.2,0,0,0.2,1.2,0)" /> + </marker> + <marker + inkscape:stockid="Arrow1Mend" + orient="auto" + refY="0" + refX="0" + id="Arrow1Mend" + style="overflow:visible"> + <path + id="path3832" + d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z" + style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" + transform="matrix(-0.4,0,0,-0.4,-4,0)" /> + </marker> + <marker + inkscape:stockid="Tail" + orient="auto" + refY="0" + refX="0" + id="Tail" + style="overflow:visible"> + <g + id="g3859" + transform="scale(-1.2,-1.2)"> + <path + id="path3861" + d="M -3.8048674,-3.9585227 L 0.54352094,0" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;marker-start:none;marker-end:none" /> + <path + id="path3863" + d="M -1.2866832,-3.9585227 L 3.0617053,0" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;marker-start:none;marker-end:none" /> + <path + id="path3865" + d="M 1.3053582,-3.9585227 L 5.6537466,0" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;marker-start:none;marker-end:none" /> + <path + id="path3867" + d="M -3.8048674,4.1775838 L 0.54352094,0.21974226" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;marker-start:none;marker-end:none" /> + <path + id="path3869" + d="M -1.2866832,4.1775838 L 3.0617053,0.21974226" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;marker-start:none;marker-end:none" /> + <path + id="path3871" + d="M 1.3053582,4.1775838 L 5.6537466,0.21974226" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;marker-start:none;marker-end:none" /> + </g> + </marker> + <marker + inkscape:stockid="Arrow2Lend" + orient="auto" + refY="0" + refX="0" + id="Arrow2Lend" + style="overflow:visible"> + <path + id="path3636" + style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z" + transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> + </marker> + <inkscape:perspective + sodipodi:type="inkscape:persp3d" + inkscape:vp_x="0 : 526.18109 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_z="744.09448 : 526.18109 : 1" + inkscape:persp3d-origin="372.04724 : 350.78739 : 1" + id="perspective10" /> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + gridtolerance="10000" + guidetolerance="10" + objecttolerance="10" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="1.0859375" + inkscape:cx="320" + inkscape:cy="136.17463" + inkscape:document-units="px" + inkscape:current-layer="g5658" + showgrid="false" + inkscape:window-width="1156" + inkscape:window-height="883" + inkscape:window-x="1396" + inkscape:window-y="35" + showguides="true" + inkscape:guide-bbox="true"> + <sodipodi:guide + orientation="1,0" + position="-557.55608,678.10875" + id="guide7299" /> + </sodipodi:namedview> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(-1758.7331,-2056.8567)"> + <flowRoot + xml:space="preserve" + id="flowRoot3229" + style="font-size:40px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + transform="translate(4.1137413,-2.3429609)"><flowRegion + id="flowRegion3231"><rect + id="rect3233" + width="125.74072" + height="40.5849" + x="388.45547" + y="279.5423" /></flowRegion><flowPara + id="flowPara3235" /></flowRoot> <g + id="g5658" + transform="translate(6.5767925,7.0112479)"> + <g + id="g5634"> + <g + id="g6271" + transform="translate(1086.3689,746.93837)"> + <g + transform="matrix(0,-1,1,0,-294.81158,2953.0504)" + id="g6252"> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" + d="M 1586.5317,1300.2858 L 1586.6222,1389.8124" + id="path11089" + inkscape:connector-type="polyline" + sodipodi:nodetypes="cc" /> + <path + sodipodi:nodetypes="cc" + inkscape:connector-type="polyline" + id="path2758" + d="M 1586.7489,1389.4756 L 1594.7468,1380.3688" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" /> + <path + sodipodi:nodetypes="cc" + inkscape:connector-type="polyline" + id="path2760" + d="M 1586.6031,1389.5063 L 1578.6052,1380.3994" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" /> + </g> + </g> + </g> + <g + transform="translate(134.35978,44.472131)" + id="g2777"> + <rect + style="fill:#addc52;fill-opacity:1;stroke:#6ca400;stroke-width:0.82399696;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect5172" + width="185.49777" + height="75.08918" + x="2047.775" + y="2029.4594" + ry="3.0323718" + rx="2.6724329" /> + <text + xml:space="preserve" + style="font-size:40px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + x="2140.5562" + y="2062.9375" + id="text5174"><tspan + sodipodi:role="line" + x="2140.5562" + y="2062.9375" + style="font-size:22px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#050800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans Bold" + id="tspan5176">Qt bindings</tspan><tspan + id="tspan6109" + sodipodi:role="line" + x="2140.5562" + y="2084.457" + style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#050800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">(generated code)</tspan></text> + </g> + <g + transform="translate(141.86951,-31.391207)" + id="g3216"> + <rect + style="fill:#bff3bc;fill-opacity:1;stroke:#0af400;stroke-width:0.64492828;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect3625" + width="185.67708" + height="75.268074" + x="1829.1727" + y="2105.2332" + ry="2.3353095" + rx="2.1257713" /> + <text + xml:space="preserve" + style="font-size:38.71272278px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + x="1921.9705" + y="2136.9409" + id="text3627" + transform="scale(1.0000266,0.9999734)"><tspan + id="tspan3697" + sodipodi:role="line" + x="1921.9705" + y="2136.9409" + style="font-size:21.29199791px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans Bold">generator</tspan><tspan + sodipodi:role="line" + x="1921.9705" + y="2163.5559" + style="font-size:21.29199791px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans Bold" + id="tspan2464">front-end</tspan></text> + </g> + <g + id="g5641"> + <g + id="g5465" + transform="translate(874.42628,746.93837)"> + <g + transform="matrix(0,-1,1,0,-294.81158,2953.0504)" + id="g5467"> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" + d="M 1586.5317,1300.2858 L 1586.6222,1389.8124" + id="path5469" + inkscape:connector-type="polyline" + sodipodi:nodetypes="cc" /> + <path + sodipodi:nodetypes="cc" + inkscape:connector-type="polyline" + id="path5471" + d="M 1586.7489,1389.4756 L 1594.7468,1380.3688" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" /> + <path + sodipodi:nodetypes="cc" + inkscape:connector-type="polyline" + id="path5473" + d="M 1586.6031,1389.5063 L 1578.6052,1380.3994" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" /> + </g> + </g> + </g> + <g + transform="translate(-194.79968,-212.08495)" + id="g5440"> + <rect + rx="1.2158648" + ry="2.9911308" + y="2285.8806" + x="1953.809" + height="75.360634" + width="185.76964" + id="rect3166" + style="fill:#dfe994;fill-opacity:1;stroke:#d5f400;stroke-width:0.55236381;stroke-opacity:1" /> + <text + id="text3168" + y="2328.8809" + x="2046.646" + style="font-size:27.94354057px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#4c5800;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + xml:space="preserve"><tspan + style="font-size:19.56047821px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#4c5800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans" + y="2328.8809" + x="2046.646" + sodipodi:role="line" + id="tspan5424">API Extractor</tspan></text> + </g> + <g + transform="translate(-102.30216,-279.71223)" + id="g5541"> + <path + sodipodi:type="arc" + style="fill:#f28888;fill-opacity:1;stroke:#d5f400;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:3, 3;stroke-dashoffset:0;stroke-opacity:1" + id="path5535" + sodipodi:cx="255.10791" + sodipodi:cy="326.69064" + sodipodi:rx="38.848923" + sodipodi:ry="38.848923" + d="M 293.95683,326.69064 A 38.848923,38.848923 0 1 1 216.25899,326.69064 A 38.848923,38.848923 0 1 1 293.95683,326.69064 z" + transform="matrix(0.4405339,0,0,0.4405339,1842.2283,2282.9708)" /> + <text + xml:space="preserve" + style="font-size:27.62000275px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + x="1946.3259" + y="2435.7" + id="text5537"><tspan + sodipodi:role="line" + id="tspan5539" + x="1946.3259" + y="2435.7" + style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:FreeMono;-inkscape-font-specification:FreeMono Bold">1</tspan></text> + </g> + <g + transform="translate(52.589867,-352.69787)" + id="g5546"> + <path + sodipodi:type="arc" + style="fill:#f28888;fill-opacity:1;stroke:#d5f400;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:3, 3;stroke-dashoffset:0;stroke-opacity:1" + id="path5548" + sodipodi:cx="255.10791" + sodipodi:cy="326.69064" + sodipodi:rx="38.848923" + sodipodi:ry="38.848923" + d="M 293.95683,326.69064 A 38.848923,38.848923 0 1 1 216.25899,326.69064 A 38.848923,38.848923 0 1 1 293.95683,326.69064 z" + transform="matrix(0.4405339,0,0,0.4405339,1842.2283,2282.9708)" /> + <text + xml:space="preserve" + style="font-size:27.62000275px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + x="1946.3259" + y="2435.7" + id="text5550"><tspan + sodipodi:role="line" + id="tspan5552" + x="1946.3259" + y="2435.7" + style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:FreeMono;-inkscape-font-specification:FreeMono Bold">2</tspan></text> + </g> + <g + transform="matrix(0,-1,1,0,697.50638,3244.256)" + id="g5624"> + <g + id="g5626" + transform="matrix(0,-1,1,0,-294.81158,2953.0504)"> + <path + sodipodi:nodetypes="cc" + inkscape:connector-type="polyline" + id="path5628" + d="M 1586.5317,1348.2858 L 1586.6222,1389.8124" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" + d="M 1586.7489,1389.4756 L 1594.7468,1380.3688" + id="path5630" + inkscape:connector-type="polyline" + sodipodi:nodetypes="cc" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" + d="M 1586.6031,1389.5063 L 1578.6052,1380.3994" + id="path5632" + inkscape:connector-type="polyline" + sodipodi:nodetypes="cc" /> + </g> + </g> + <g + transform="translate(5.3442137,15.993306)" + id="g5459"> + <rect + rx="2.4652832" + ry="2.9818845" + y="2151.3206" + x="1965.7682" + height="75.127686" + width="185.53668" + id="rect3485" + style="fill:#b2e994;fill-opacity:1;stroke:#56f400;stroke-width:0.78531456;stroke-opacity:1" /> + <text + id="text3487" + y="2184.2461" + x="2059.1909" + style="font-size:27.94354057px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#1f5800;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + xml:space="preserve"><tspan + id="tspan2509" + style="font-size:19.56047821px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#1f5800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans" + y="2184.2461" + x="2059.1909" + sodipodi:role="line">typesystem</tspan><tspan + style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#1f5800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans" + y="2205.1477" + x="2059.1909" + sodipodi:role="line" + id="tspan5432">(handwritten)</tspan></text> + </g> + <g + transform="matrix(0,-1,1,0,908.50929,3242.9612)" + id="g5648"> + <g + id="g5650" + transform="matrix(0,-1,1,0,-294.81158,2953.0504)"> + <path + sodipodi:nodetypes="cc" + inkscape:connector-type="polyline" + id="path5652" + d="M 1586.5317,1348.2858 L 1586.6222,1389.8124" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" + d="M 1586.7489,1389.4756 L 1594.7468,1380.3688" + id="path5654" + inkscape:connector-type="polyline" + sodipodi:nodetypes="cc" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" + d="M 1586.6031,1389.5063 L 1578.6052,1380.3994" + id="path5656" + inkscape:connector-type="polyline" + sodipodi:nodetypes="cc" /> + </g> + </g> + <g + transform="translate(299.78191,21.148391)" + id="g2771"> + <rect + style="fill:#cce994;fill-opacity:1;stroke:#a1f400;stroke-width:0.62429351;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect2733" + width="185.69771" + height="75.288704" + x="1882.2529" + y="2146.085" + ry="2.2607138" + rx="2.0576432" /> + <text + xml:space="preserve" + style="font-size:40px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#3a5800;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + x="1975.134" + y="2180.2722" + id="text2735"><tspan + sodipodi:role="line" + x="1975.134" + y="2180.2722" + style="font-size:22px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#3a5800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans Bold" + id="tspan2737">injected code</tspan><tspan + id="tspan2743" + sodipodi:role="line" + x="1975.134" + y="2201.7917" + style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#3a5800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">(handwritten)</tspan></text> + </g> + <g + transform="translate(200.4676,-222.96766)" + id="g5554"> + <path + sodipodi:type="arc" + style="fill:#f28888;fill-opacity:1;stroke:#d5f400;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:3, 3;stroke-dashoffset:0;stroke-opacity:1" + id="path5556" + sodipodi:cx="255.10791" + sodipodi:cy="326.69064" + sodipodi:rx="38.848923" + sodipodi:ry="38.848923" + d="M 293.95683,326.69064 A 38.848923,38.848923 0 1 1 216.25899,326.69064 A 38.848923,38.848923 0 1 1 293.95683,326.69064 z" + transform="matrix(0.4405339,0,0,0.4405339,1842.2283,2282.9708)" /> + <text + xml:space="preserve" + style="font-size:27.62000275px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + x="1946.3259" + y="2435.7" + id="text5558"><tspan + sodipodi:role="line" + id="tspan5560" + x="1946.3259" + y="2435.7" + style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:FreeMono;-inkscape-font-specification:FreeMono Bold">3</tspan></text> + </g> + <g + transform="translate(413.633,-206.84535)" + id="g5562"> + <path + sodipodi:type="arc" + style="fill:#f28888;fill-opacity:1;stroke:#d5f400;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:3, 3;stroke-dashoffset:0;stroke-opacity:1" + id="path5564" + sodipodi:cx="255.10791" + sodipodi:cy="326.69064" + sodipodi:rx="38.848923" + sodipodi:ry="38.848923" + d="M 293.95683,326.69064 A 38.848923,38.848923 0 1 1 216.25899,326.69064 A 38.848923,38.848923 0 1 1 293.95683,326.69064 z" + transform="matrix(0.4405339,0,0,0.4405339,1842.2283,2282.9708)" /> + <text + xml:space="preserve" + style="font-size:27.62000275px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + x="1946.3259" + y="2435.7" + id="text5566"><tspan + sodipodi:role="line" + id="tspan5568" + x="1946.3259" + y="2435.7" + style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-family:FreeMono;-inkscape-font-specification:FreeMono Bold">4</tspan></text> + </g> + </g> + </g> +</svg> diff --git a/doc/images/boostgenarch.png b/doc/images/boostgenarch.png Binary files differnew file mode 100644 index 000000000..001b84435 --- /dev/null +++ b/doc/images/boostgenarch.png diff --git a/doc/images/boostgenarch.svg b/doc/images/boostgenarch.svg new file mode 100644 index 000000000..8a5f74b0b --- /dev/null +++ b/doc/images/boostgenarch.svg @@ -0,0 +1,711 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="1050.42" + height="397.94467" + id="svg2" + sodipodi:version="0.32" + inkscape:version="0.46" + version="1.0" + sodipodi:docname="boostgenarch.svg" + inkscape:output_extension="org.inkscape.output.svg.inkscape" + inkscape:export-filename="boostgenarch.png" + inkscape:export-xdpi="56.549999" + inkscape:export-ydpi="56.549999"> + <defs + id="defs4"> + <marker + inkscape:stockid="EmptyDiamondL" + orient="auto" + refY="0" + refX="0" + id="EmptyDiamondL" + style="overflow:visible"> + <path + id="path3930" + d="M 0,-7.0710768 L -7.0710894,0 L 0,7.0710589 L 7.0710462,0 L 0,-7.0710768 z" + style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" + transform="scale(0.8,0.8)" /> + </marker> + <marker + inkscape:stockid="EmptyTriangleInL" + orient="auto" + refY="0" + refX="0" + id="EmptyTriangleInL" + style="overflow:visible"> + <path + id="path3975" + d="M 5.77,0 L -2.88,5 L -2.88,-5 L 5.77,0 z" + style="fill:#ffffff;fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" + transform="matrix(-0.8,0,0,-0.8,4.8,0)" /> + </marker> + <marker + inkscape:stockid="Arrow1Sstart" + orient="auto" + refY="0" + refX="0" + id="Arrow1Sstart" + style="overflow:visible"> + <path + id="path3835" + d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z" + style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" + transform="matrix(0.2,0,0,0.2,1.2,0)" /> + </marker> + <marker + inkscape:stockid="Arrow1Mend" + orient="auto" + refY="0" + refX="0" + id="Arrow1Mend" + style="overflow:visible"> + <path + id="path3832" + d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z" + style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" + transform="matrix(-0.4,0,0,-0.4,-4,0)" /> + </marker> + <marker + inkscape:stockid="Tail" + orient="auto" + refY="0" + refX="0" + id="Tail" + style="overflow:visible"> + <g + id="g3859" + transform="scale(-1.2,-1.2)"> + <path + id="path3861" + d="M -3.8048674,-3.9585227 L 0.54352094,0" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;marker-start:none;marker-end:none" /> + <path + id="path3863" + d="M -1.2866832,-3.9585227 L 3.0617053,0" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;marker-start:none;marker-end:none" /> + <path + id="path3865" + d="M 1.3053582,-3.9585227 L 5.6537466,0" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;marker-start:none;marker-end:none" /> + <path + id="path3867" + d="M -3.8048674,4.1775838 L 0.54352094,0.21974226" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;marker-start:none;marker-end:none" /> + <path + id="path3869" + d="M -1.2866832,4.1775838 L 3.0617053,0.21974226" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;marker-start:none;marker-end:none" /> + <path + id="path3871" + d="M 1.3053582,4.1775838 L 5.6537466,0.21974226" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.80000001;stroke-linecap:round;marker-start:none;marker-end:none" /> + </g> + </marker> + <marker + inkscape:stockid="Arrow2Lend" + orient="auto" + refY="0" + refX="0" + id="Arrow2Lend" + style="overflow:visible"> + <path + id="path3636" + style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z" + transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> + </marker> + <inkscape:perspective + sodipodi:type="inkscape:persp3d" + inkscape:vp_x="0 : 526.18109 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_z="744.09448 : 526.18109 : 1" + inkscape:persp3d-origin="372.04724 : 350.78739 : 1" + id="perspective10" /> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + gridtolerance="10000" + guidetolerance="10" + objecttolerance="10" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="1.5155842" + inkscape:cx="525.21002" + inkscape:cy="198.97234" + inkscape:document-units="px" + inkscape:current-layer="layer1" + showgrid="false" + inkscape:window-width="1680" + inkscape:window-height="973" + inkscape:window-x="1280" + inkscape:window-y="25" + showguides="true" + inkscape:guide-bbox="true" /> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(-109.91989,-748.26874)"> + <flowRoot + xml:space="preserve" + id="flowRoot3229" + style="font-size:40px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + transform="translate(2.0918751e-6,-6.0000008)"><flowRegion + id="flowRegion3231"><rect + id="rect3233" + width="125.74072" + height="40.5849" + x="388.45547" + y="279.5423" /></flowRegion><flowPara + id="flowPara3235" /></flowRoot> <g + id="g3406" + transform="translate(-2.6095003,-1.3051758e-5)"> + <rect + rx="4.1757755" + ry="5.4922562" + y="756.909" + x="123.11251" + height="380.66443" + width="470.24225" + id="rect3609" + style="fill:#e4fae3;fill-opacity:0.65882353;stroke:#8eff89;stroke-width:0.87503546;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + <text + transform="scale(1.0000266,0.9999734)" + id="text3601" + y="785.98743" + x="354.32269" + style="font-size:38.71272278px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + xml:space="preserve"><tspan + id="tspan3605" + style="font-size:27.09890556px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans" + y="785.98743" + x="354.32269" + sodipodi:role="line"><tspan + id="tspan2508" + style="font-weight:bold">API Extractor</tspan><tspan + id="tspan2510" + style="font-size:22px"> (Generator Back-End)</tspan></tspan></text> + <g + transform="matrix(0.9678438,0,0,0.9677923,-160.77317,253.92619)" + id="g3709"> + <rect + style="fill:#bff3bc;fill-opacity:1;stroke:#0af400;stroke-width:0.69825613;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect2821" + width="198.90968" + height="93.892342" + x="305.2475" + y="807.38849" + ry="2.6812849" + rx="2.1703238" /> + <text + xml:space="preserve" + style="font-size:40px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + x="405.17499" + y="831.81903" + id="text3611"><tspan + id="tspan3687" + sodipodi:role="line" + x="405.17499" + y="831.81903" + style="font-size:22px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans Bold">TypeDatabase</tspan><tspan + id="tspan5641" + sodipodi:role="line" + x="405.17499" + y="853.33856" + style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">parses typesystem</tspan><tspan + id="tspan3689" + sodipodi:role="line" + x="405.17499" + y="873.33856" + style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">and stores information</tspan></text> + </g> + <g + transform="matrix(0.9678438,0,0,0.9677923,33.530997,29.623658)" + id="g3728"> + <rect + style="fill:#bff3bc;fill-opacity:1;stroke:#0af400;stroke-width:0.54871088;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect3625" + width="117.15066" + height="86.355225" + x="133.25664" + y="809.36938" + ry="2.6793056" + rx="1.3412292" /> + <text + xml:space="preserve" + style="font-size:40px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + x="191.58197" + y="838.75159" + id="text3627"><tspan + sodipodi:role="line" + x="191.58197" + y="838.75159" + style="font-size:22px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans Bold" + id="tspan3631">Parser</tspan><tspan + id="tspan3695" + sodipodi:role="line" + x="191.58197" + y="860.27112" + style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">parses the</tspan><tspan + id="tspan3697" + sodipodi:role="line" + x="191.58197" + y="880.27112" + style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">lib headers</tspan></text> + </g> + <g + transform="matrix(0.9678438,0,0,0.9677923,67.17479,-62.939246)" + id="g3763"> + <rect + style="fill:#bff3bc;fill-opacity:1;stroke:#0af400;stroke-width:0.79775763;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect3737" + width="244.82956" + height="101.59812" + x="267.06232" + y="905.13727" + ry="3.1522403" + rx="2.4096873" /> + <text + xml:space="preserve" + style="font-size:40px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + x="389.39117" + y="931.86993" + id="text3739"><tspan + sodipodi:role="line" + x="389.39117" + y="931.86993" + style="font-size:22px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans Bold" + id="tspan3741">ApiExtractor</tspan><tspan + id="tspan2523" + sodipodi:role="line" + x="389.39117" + y="953.38947" + style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">commands the parsing and</tspan><tspan + id="tspan2517" + sodipodi:role="line" + x="389.39117" + y="973.38947" + style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">building of the data model</tspan><tspan + id="tspan2519" + sodipodi:role="line" + x="389.39117" + y="993.38947" + style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">and calls the user generators</tspan></text> + </g> + <g + transform="matrix(0.9678438,0,0,0.9677923,-18.729241,25.76123)" + id="g9183"> + <rect + style="fill:#bff3bc;fill-opacity:1;stroke:#0af400;stroke-width:0.70975834;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect9158" + width="202.60791" + height="83.543121" + x="398.08612" + y="1051.0632" + ry="2.5920558" + rx="2.3196087" /> + <text + xml:space="preserve" + style="font-size:40px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + x="499.39008" + y="1078.575" + id="text9160"><tspan + sodipodi:role="line" + x="499.39008" + y="1078.575" + style="font-size:22px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans Bold" + id="tspan9162">Generator</tspan><tspan + id="tspan9168" + sodipodi:role="line" + x="499.39008" + y="1100.0945" + style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">base class for front-end</tspan><tspan + id="tspan9176" + sodipodi:role="line" + x="499.39008" + y="1120.0945" + style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">output classes</tspan></text> + </g> + <rect + rx="4.3700728" + ry="5.4919772" + y="756.91852" + x="603.24152" + height="380.64514" + width="549.11475" + id="rect9190" + style="fill:#cbe990;fill-opacity:0.51184836;stroke:#6ca400;stroke-width:0.89513886;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + <text + transform="scale(1.0000266,0.9999734)" + id="text9192" + y="785.98743" + x="907.21234" + style="font-size:38.71272278px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#050800;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + xml:space="preserve"><tspan + id="tspan9194" + style="font-size:27.09890556px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#050800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans" + y="785.98743" + x="907.21234" + sodipodi:role="line"><tspan + id="tspan2512" + style="font-weight:bold">boostpythongenerator</tspan><tspan + id="tspan2514" + style="font-size:22px"> (Front-End)</tspan></tspan></text> + <path + sodipodi:nodetypes="cc" + inkscape:connector-type="polyline" + id="path9241" + d="M 563.24815,1086.3017 L 756.17483,1086.2141" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#EmptyTriangleInL);stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" /> + <g + transform="matrix(0.9678438,0,0,0.9677923,-53.053078,32.316629)" + id="g9234"> + <rect + style="fill:#addc52;fill-opacity:1;stroke:#6ca400;stroke-width:0.73640609;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect9206" + width="218.17299" + height="83.517967" + x="694.6994" + y="1044.8701" + ry="2.5912752" + rx="2.4978092" /> + <text + xml:space="preserve" + style="font-size:40px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + x="803.78589" + y="1072.3693" + id="text9208"><tspan + sodipodi:role="line" + x="803.78589" + y="1072.3693" + style="font-size:22px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#050800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans Bold" + id="tspan9210">BoostGenerator</tspan><tspan + id="tspan9218" + sodipodi:role="line" + x="803.78589" + y="1093.8888" + style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#050800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">common functionality</tspan><tspan + id="tspan9222" + sodipodi:role="line" + x="803.78589" + y="1113.8888" + style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#050800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">for all generators</tspan></text> + </g> + <path + sodipodi:nodetypes="cc" + inkscape:connector-type="polyline" + id="path9873" + d="M 520.90636,976.05583 L 540.21434,975.96825" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" /> + <path + sodipodi:nodetypes="cc" + inkscape:connector-type="polyline" + id="path9875" + d="M 540.21912,918.88309 L 540.30671,975.90002" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#EmptyDiamondL);stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" /> + <g + transform="matrix(0.9678438,0,0,0.9677923,-69.696202,32.316631)" + id="g11669"> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.03325212;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" + d="M 1238.687,822.30296 L 1238.7775,1044.4792" + id="path11089" + inkscape:connector-type="polyline" + sodipodi:nodetypes="cc" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.03325212;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" + d="M 654.1163,822.6964 L 1238.9792,822.6059" + id="path11656" + inkscape:connector-type="polyline" + sodipodi:nodetypes="cc" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.97947711;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" + d="M 1204.3853,823.2094 L 1204.359,950.47279" + id="path11658" + inkscape:connector-type="polyline" + sodipodi:nodetypes="cc" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.97947711;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" + d="M 1057.8933,822.98518 L 1057.867,857.1068" + id="path11660" + inkscape:connector-type="polyline" + sodipodi:nodetypes="cc" /> + </g> + <g + transform="matrix(0.9678438,0,0,0.9677923,-69.696202,32.316631)" + id="g11664"> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.03325212;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#EmptyTriangleInL);stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" + d="M 927.80296,1086.6352 L 998.0099,1086.5447" + id="path11083" + inkscape:connector-type="polyline" + sodipodi:nodetypes="cc" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.03325212;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" + d="M 948.33557,992.88246 L 977.67216,992.79196" + id="path11654" + inkscape:connector-type="polyline" + sodipodi:nodetypes="cc" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99674439;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" + d="M 947.88456,937.33484 L 948.0104,1086.0336" + id="path11662" + inkscape:connector-type="polyline" + sodipodi:nodetypes="cc" /> + </g> + <g + transform="matrix(0.9678438,0,0,0.9677923,-94.860111,47.801308)" + id="g10490"> + <rect + style="fill:#addc52;fill-opacity:1;stroke:#6ca400;stroke-width:0.79788101;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect10463" + width="256.302" + height="83.458473" + x="991.64471" + y="935.10797" + ry="2.5894294" + rx="2.9343388" /> + <text + xml:space="preserve" + style="font-size:40px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + x="1119.7955" + y="962.57739" + id="text10465"><tspan + sodipodi:role="line" + x="1119.7955" + y="962.57739" + style="font-size:22px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#050800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans Bold" + id="tspan10467">CppGenerator</tspan><tspan + id="tspan10469" + sodipodi:role="line" + x="1119.7955" + y="984.09692" + style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#050800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">writes main body of code</tspan><tspan + id="tspan10471" + sodipodi:role="line" + x="1119.7955" + y="1004.0969" + style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#050800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">for the binding classes</tspan></text> + </g> + <g + transform="matrix(0.9678438,0,0,0.9677923,-70.620184,48.023961)" + id="g10483"> + <rect + style="fill:#addc52;fill-opacity:1;stroke:#6ca400;stroke-width:0.79788101;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect10473" + width="256.302" + height="83.458473" + x="992.59943" + y="1028.6698" + ry="2.5894294" + rx="2.9343388" /> + <text + xml:space="preserve" + style="font-size:40px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + x="1120.7501" + y="1056.1392" + id="text10475"><tspan + sodipodi:role="line" + x="1120.7501" + y="1056.1392" + style="font-size:22px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#050800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans Bold" + id="tspan10477">ConverterGenerator</tspan><tspan + id="tspan10481" + sodipodi:role="line" + x="1120.7501" + y="1077.6587" + style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#050800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">writes converters for classes</tspan><tspan + id="tspan10508" + sodipodi:role="line" + x="1120.7501" + y="1097.6587" + style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#050800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">with Python equivalents</tspan></text> + </g> + <g + transform="matrix(0.9678438,0,0,0.9677923,-128.77856,45.865724)" + id="g10497"> + <rect + style="fill:#addc52;fill-opacity:1;stroke:#6ca400;stroke-width:0.79788101;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect10444" + width="256.302" + height="83.458473" + x="990.69006" + y="843.45557" + ry="2.5894294" + rx="2.9343388" /> + <text + xml:space="preserve" + style="font-size:40px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + x="1118.8409" + y="870.92499" + id="text10446"><tspan + sodipodi:role="line" + x="1118.8409" + y="870.92499" + style="font-size:22px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#050800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans Bold" + id="tspan10448">HppGenerator</tspan><tspan + id="tspan10452" + sodipodi:role="line" + x="1118.8409" + y="892.44452" + style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#050800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">writes headers for the</tspan><tspan + id="tspan10456" + sodipodi:role="line" + x="1118.8409" + y="912.44452" + style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#050800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">binding classes</tspan></text> + </g> + <g + transform="matrix(0.7300473,0,0,0.7300085,224.93105,280.6603)" + id="g2762"> + <path + sodipodi:nodetypes="cc" + inkscape:connector-type="polyline" + id="path2758" + d="M 1238.8766,1044.0556 L 1249.4796,1031.9824" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.36981082;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" /> + <path + sodipodi:nodetypes="cc" + inkscape:connector-type="polyline" + id="path2760" + d="M 1238.6833,1044.0962 L 1228.0803,1032.023" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.36981082;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" /> + </g> + <g + transform="matrix(0.7300473,0,0,0.7300085,191.62705,189.94594)" + id="g2766"> + <path + sodipodi:nodetypes="cc" + inkscape:connector-type="polyline" + id="path2768" + d="M 1238.8766,1044.0556 L 1249.4796,1031.9824" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.36981082;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" /> + <path + sodipodi:nodetypes="cc" + inkscape:connector-type="polyline" + id="path2770" + d="M 1238.6833,1044.0962 L 1228.0803,1032.023" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.36981082;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" /> + </g> + <g + transform="matrix(0.7300473,0,0,0.7300085,49.80626,99.273761)" + id="g2772"> + <path + sodipodi:nodetypes="cc" + inkscape:connector-type="polyline" + id="path2774" + d="M 1238.8766,1044.0556 L 1249.4796,1031.9824" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.36981082;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" /> + <path + sodipodi:nodetypes="cc" + inkscape:connector-type="polyline" + id="path2776" + d="M 1238.6833,1044.0962 L 1228.0803,1032.023" + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.36981082;stroke-linecap:butt;stroke-linejoin:miter;marker-start:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" /> + </g> + <g + transform="translate(-5.7111906,0)" + id="g3397"> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:0.99999994px;stroke-linecap:round;stroke-linejoin:round;marker-start:none;stroke-opacity:1;display:inline" + d="M 234.14728,897.65591 L 234.08039,1034.5389" + id="path3685" + inkscape:connector-type="polyline" + sodipodi:nodetypes="cc" /> + <g + id="g3385" + transform="translate(-19.531521,268.55504)"> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;marker-start:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" + d="M 253.61706,628.77816 L 249.34863,640.58185" + id="path2799" + inkscape:connector-type="polyline" + sodipodi:nodetypes="cc" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;marker-start:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" + d="M 253.67366,628.77816 L 257.94209,640.58185" + id="path2559" + inkscape:connector-type="polyline" + sodipodi:nodetypes="cc" /> + </g> + <g + id="g3391" + transform="matrix(1,0,0,-1,-19.531521,1663.0776)"> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;marker-start:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" + d="M 253.61706,628.77816 L 249.34863,640.58185" + id="path3393" + inkscape:connector-type="polyline" + sodipodi:nodetypes="cc" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000012;stroke-linecap:round;stroke-linejoin:round;marker-start:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;display:inline" + d="M 253.67366,628.77816 L 257.94209,640.58185" + id="path3395" + inkscape:connector-type="polyline" + sodipodi:nodetypes="cc" /> + </g> + </g> + <g + transform="matrix(0.9678438,0,0,0.9677923,-92.060029,-109.98534)" + id="g3809"> + <rect + style="fill:#bff3bc;fill-opacity:1;stroke:#0af400;stroke-width:1.00168562;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect3785" + width="332.48172" + height="82.830231" + x="302.83319" + y="1068.9153" + ry="3.1461167" + rx="3.8065021" /> + <text + xml:space="preserve" + style="font-size:40px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + x="469.03497" + y="1095.5493" + id="text3787"><tspan + id="tspan3791" + sodipodi:role="line" + x="469.03497" + y="1095.5493" + style="font-size:22px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans Bold">AbstractMetaBuilder</tspan><tspan + sodipodi:role="line" + x="469.03497" + y="1117.0688" + style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans" + id="tspan3807">builds the data model with information</tspan><tspan + id="tspan2545" + sodipodi:role="line" + x="469.03497" + y="1137.0688" + style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">from headers and binding directives</tspan><tspan + id="tspan3795" + sodipodi:role="line" + x="469.03497" + y="1157.0688" + style="font-size:16px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans" /></text> + </g> + </g> + </g> +</svg> diff --git a/doc/images/boostqtarch.png b/doc/images/boostqtarch.png Binary files differnew file mode 100644 index 000000000..a82f97088 --- /dev/null +++ b/doc/images/boostqtarch.png diff --git a/doc/images/boostqtarch.svg b/doc/images/boostqtarch.svg new file mode 100644 index 000000000..9fbb38271 --- /dev/null +++ b/doc/images/boostqtarch.svg @@ -0,0 +1,226 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="350" + height="220" + id="svg2" + sodipodi:version="0.32" + inkscape:version="0.46" + version="1.0" + sodipodi:docname="boostqtarch.svg" + inkscape:output_extension="org.inkscape.output.svg.inkscape" + inkscape:export-filename="boostqtarch.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90"> + <defs + id="defs4"> + <marker + inkscape:stockid="Arrow2Lend" + orient="auto" + refY="0" + refX="0" + id="Arrow2Lend" + style="overflow:visible"> + <path + id="path3636" + style="font-size:12px;fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round" + d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.97309,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z" + transform="matrix(-1.1,0,0,-1.1,-1.1,0)" /> + </marker> + <inkscape:perspective + sodipodi:type="inkscape:persp3d" + inkscape:vp_x="0 : 526.18109 : 1" + inkscape:vp_y="0 : 1000 : 0" + inkscape:vp_z="744.09448 : 526.18109 : 1" + inkscape:persp3d-origin="372.04724 : 350.78739 : 1" + id="perspective10" /> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + gridtolerance="10000" + guidetolerance="10" + objecttolerance="10" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="1.4812981" + inkscape:cx="145.70936" + inkscape:cy="94.089827" + inkscape:document-units="px" + inkscape:current-layer="layer1" + showgrid="false" + inkscape:window-width="1278" + inkscape:window-height="951" + inkscape:window-x="1592" + inkscape:window-y="29" + showguides="true" + inkscape:guide-bbox="true" /> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(-61.076804,-301.50489)"> + <flowRoot + xml:space="preserve" + id="flowRoot3229" + style="font-size:40px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + transform="translate(2.0918751e-6,-6.0000008)"><flowRegion + id="flowRegion3231"><rect + id="rect3233" + width="125.74072" + height="40.5849" + x="388.45547" + y="279.5423" /></flowRegion><flowPara + id="flowPara3235" /></flowRoot> <g + id="g3010" + transform="matrix(0.9508755,0,0,0.9508755,11.317746,20.273572)"> + <g + transform="translate(0,-9.7919846e-6)" + id="g2952"> + <rect + style="fill:#dfe994;fill-opacity:1;stroke:#d5f400;stroke-width:0.7162478;stroke-opacity:1" + id="rect3166" + width="349.23203" + height="67.403336" + x="61.417336" + y="377.74161" + ry="2.6752985" + rx="2.285728" /> + <text + xml:space="preserve" + style="font-size:29.38717079px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#4c5800;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + x="236.08904" + y="397.98755" + id="text3168"><tspan + sodipodi:role="line" + x="236.08904" + y="397.98755" + style="font-size:20.57102013px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#4c5800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans" + id="tspan3176">Boost::Python</tspan><tspan + sodipodi:role="line" + x="236.08904" + y="418.35535" + style="font-size:15.20761585px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#4c5800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans" + id="tspan2880">helper library to interface with CPython API</tspan><tspan + id="tspan2922" + sodipodi:role="line" + x="236.08904" + y="437.36487" + style="font-size:15.20761585px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#4c5800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">and expose C++ entities to Python</tspan></text> + </g> + <g + transform="translate(0,-9.7025776e-6)" + id="g2959"> + <rect + style="fill:#addc52;fill-opacity:1;stroke:#6ca400;stroke-width:0.71624762;stroke-opacity:1" + id="rect3542" + width="349.23203" + height="67.403351" + x="61.417336" + y="301.84543" + ry="2.675298" + rx="2.285728" /> + <text + xml:space="preserve" + style="font-size:29.38717079px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#050800;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + x="236.5123" + y="322.09137" + id="text3544"><tspan + id="tspan3596" + sodipodi:role="line" + x="236.5123" + y="322.09137" + style="font-size:20.57102013px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#050800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans">Qt-Python Bindings</tspan><tspan + sodipodi:role="line" + x="236.5123" + y="342.45917" + style="font-size:15.20761585px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#050800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans" + id="tspan12937">Qt classes and functions</tspan><tspan + sodipodi:role="line" + x="236.5123" + y="361.46869" + style="font-size:15.20761585px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;fill:#050800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans" + id="tspan2411">exported to Python</tspan></text> + </g> + <g + id="g2998"> + <g + id="g2986"> + <rect + rx="2.285728" + ry="2.675298" + y="453.63776" + x="61.417336" + height="67.403336" + width="172.02341" + id="rect3485" + style="fill:#b2e994;fill-opacity:1;stroke:#56f400;stroke-width:0.71624762;stroke-opacity:1" /> + <text + id="text3487" + y="482.29712" + x="147.73038" + style="font-size:29.38717079px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#1f5800;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + xml:space="preserve"><tspan + style="font-size:20.57102013px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#1f5800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans" + y="482.29712" + x="147.73038" + sodipodi:role="line" + id="tspan3499">CPython</tspan><tspan + id="tspan2509" + style="font-size:20.57102013px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#1f5800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans" + y="508.01089" + x="147.73038" + sodipodi:role="line">API</tspan></text> + </g> + <g + id="g2992"> + <rect + rx="2.285728" + ry="2.675298" + y="453.63776" + x="239.30101" + height="67.403351" + width="172.02295" + id="rect2459" + style="fill:#cce994;fill-opacity:1;stroke:#a1f400;stroke-width:0.71624762;stroke-opacity:1" /> + <text + id="text2461" + y="481.97067" + x="324.86047" + style="font-size:29.38717079px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#3a5800;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + xml:space="preserve"><tspan + style="font-size:20.57102013px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#3a5800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans" + y="481.97067" + x="324.86047" + sodipodi:role="line" + id="tspan2467">Qt4</tspan><tspan + id="tspan2490" + style="font-size:20.57102013px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#3a5800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans" + y="507.68445" + x="324.86047" + sodipodi:role="line">Libraries</tspan></text> + </g> + </g> + </g> + </g> +</svg> diff --git a/doc/overview.rst b/doc/overview.rst new file mode 100644 index 000000000..122019760 --- /dev/null +++ b/doc/overview.rst @@ -0,0 +1,46 @@ +.. _gen-overview: + +****************** +Generator Overview +****************** + +In a few words, the Generator is a utility that parses a collecion of header and +typesystem files, generating other files (code, documentation, etc.) as result. + +Creating new bindings +===================== + +.. figure:: images/bindinggen-development.png + :scale: 80 + :align: center + + Creating new bindings + +Each module of the generator system has an specific role. + +1. Provide enough data about the classes and functions. +2. Generate valid code, with modifications from typesystems and injected codes. +3. Modify the API to expose the objects in a Python-friendly way. +4. Insert customizations where handwritten code is needed. + +.. figure:: images/boostqtarch.png + :scale: 80 + :align: center + + Runtime architecture + +The newly created binding will run on top of Boost.Python library which takes +care of interfacing Python and the underlying C++ library. + +Handwritten inputs +================== + +Creating new bindings involves creating two pieces of "code": the typesystem and +the inject code. + +:typesystem: XML files that provides the developer with a tool to customize the + way that the generators will see the classes and functions. For + example, functions can be renamed, have its signature changed and + many other actions. +:inject code: allows the developer to insert handwritten code where the generated + code is not suitable or needs some customization. diff --git a/doc/tutorial/bindinglibfoo.rst b/doc/tutorial/bindinglibfoo.rst new file mode 100644 index 000000000..87b7e482a --- /dev/null +++ b/doc/tutorial/bindinglibfoo.rst @@ -0,0 +1,77 @@ +.. highlight:: xml + +.. _gentut-bindinglibfoo: + +Binding libfoo with the Generator +================================= + +In order to create bindings for a library based on Qt4 a number of components +must be available on the system. + + + Qt4 library (with headers and pkg-config .pc files for development -- the + ``-dev`` packages in a Debian distribution). + + Qt4 Python bindings made with :program:`boostpythongenerator`. + + Typesystems for the Qt4 Python bindings. + + Headers for the library to be bound. + +With the items listed above the developer must write the components from +where the generator will gather information to create the binding source code. + + + Typesystem file describing the way the binding must be done. + + **global.h** including all the **libfoo** headers and defining required macros. + + A build system to direct the process of generating, compiling and linking the + binding. + +The directory structure for the binding project could be something like the tree +shown below: + +:: + + foobinding/ + |-- data/ + `-- module_dir/ + `-- glue/ + + +The **data** directory should contain the **global.h** and the typesystem +file. This typesystem need to refer to the ones used to create the Qt4 bindings, +commonly located on **/usr/share/PySide/typesystem**, the exact location +can be checked with pkg-config: + +:: + + $ pkg-config pyside --variable=typesystemdir + + +The **module_dir** directory is the place where the sources generated should +be placed. It starts empty except for the build instructions file (Makefile, +Makefile.am, CMakeLists.txt, etc). The realname of this directory must be the +same written in the typesystem file: + +:: + + <typesystem package="module_dir"> + + +If there is any need for handwritten source code longer than a couple of lines, +making them unconfortable to be put on the typesystem xml file, the sources +could be orderly placed in a **glue** directory, also referred in the +new binding typesystem. + +When writing the typesystem file (more on this later) there is no need to refer +to the other required typesystem files with absolute paths, the locations where +they can be found could be passed to the generator through a command line +option (``--typesystem-paths=PATH1:PATH2:[...]``) or the environment variable +**TYPESYSTEMPATH**. + +For **libfoo** no glue code will be needed so this directory is not used, +the other directories are created with proper names. + +:: + + foobinding/ + |-- data/global.h + | `-- typesystem_foo.xml + `-- foo/ + `-- Makefile + diff --git a/doc/tutorial/buildingthebinding.rst b/doc/tutorial/buildingthebinding.rst new file mode 100644 index 000000000..b5bec28e3 --- /dev/null +++ b/doc/tutorial/buildingthebinding.rst @@ -0,0 +1,132 @@ +.. _gentut-buildingthebinding: + +Building The Binding +==================== + +As mentioned before the build system used must perform the following tasks +in the correct order: + + + Gather data about locations of headers and external needed typesystems. + + Run the generator with the correct parameters. + + Compile and link the binding. + +The first and last are the usual, being the second the only novelty in the +process. + +Running the Generator +--------------------- + +The generator is called with the following parameters and options: + +:: + + $ boostpythongenerator global_headers.h \ + --include-paths=$(PATHS_TO_HEADERS)) \ + --typesystem-paths=$(PATHS_TO_TYPESYSTEMS) \ + --output-directory=. \ + typesystem.xml + +Notice that the variables for include and typesystem paths could be determined +at build time with the pkg-config tool. + +Collecting information with pkg-config +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The Qt4 bindings include compile and build information through the pkg-config +mechanism. The pkg-config name for Qt4 Python bindings is **pyside** and a +simple ``pkg-config pyside --cflags --libs`` will retrieve the information +needed to build the new binding. + +The Qt4 bindings file ``pyside.pc`` for the use of pkg-config requires +the ``.pc`` files from Qt4 to be installed. If the library is in an unusual +location, e.g. ``/opt/qt45``, remember to export it to the ``PKG_CONFIG_PATH`` +environment variable. +For example: ``export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/opt/qt45/lib/pkgconfig`` + +There is a vital information also available through pkg-config: +the **typesystemdir** variable. It is used like this: +``pkg-config pyside --variable=typesystemdir`` This provides information +where to find the typesystem files used to create the Qt4 bindings, and as said +before the binding being created needs this to complement its own binding +information for the generation proccess. + +Makefile +-------- + +Below is a plain Makefile for the binding project. + +**foobinding/foo/Makefile** +:: + + LIBFOO_DIR = ../../libfoo + LIBS = -lboost_python `python-config --libs` \ + `pkg-config pyside --libs` \ + -lfoo -L$(LIBFOO_DIR) \ + -lpthread -ldl -lutil + CXXFLAGS = -I/usr/share/qt4/mkspecs/linux-g++ -I. \ + -I$(LIBFOO_DIR) \ + `pkg-config pyside --cflags` \ + -I`python-config --includes` \ + -I/usr/include/boost/python + QT4TYPESYSTEM_DIR = `pkg-config --variable=typesystemdir pyside` + QT4HEADER_DIRS = `pkg-config --variable=includedir QtCore`:`pkg-config --variable=includedir QtCore`/.. + + SOURCES = foo_globals_wrapper.cpp foo_module_wrapper.cpp math_wrapper.cpp + OBJECTS = foo_globals_wrapper.o foo_module_wrapper.o math_wrapper.o + + all: generate compile link + + generate: + boostpythongenerator ../data/global.h \ + --include-paths=$(LIBFOO_DIR):$(QT4HEADER_DIRS):/usr/include \ + --typesystem-paths=../data:$(QT4TYPESYSTEM_DIR) \ + --output-directory=.. \ + ../data/typesystem_foo.xml + + compile: $(SOURCES) + g++ -Wall -fPIC -DPIC $(CXXFLAGS) -c foo_globals_wrapper.cpp + g++ -Wall -fPIC -DPIC $(CXXFLAGS) -c foo_module_wrapper.cpp + g++ -Wall -fPIC -DPIC $(CXXFLAGS) -c math_wrapper.cpp + + link: + g++ -shared -Wl,-soname,foo.so -o foo.so $(LIBS) $(OBJECTS) + + test: + LD_LIBRARY_PATH=$(LIBFOO_DIR):$LD_LIBRARY_PATH python -c \ + "import PySide.QtCore; import foo; print dir(foo); m = foo.Math(); print \"5 squared is %d\" % m.squared(5)" + + clean: + rm -rf *.o *.so *.?pp *.log + + +Keep in mind that the Makefile above expects the ``libfoo`` and +``foobinding`` directories to be in the same level in the directory +hierarchy, remember to change any path references accordingly if +you choose to change things. + +**Warning:** + The order in which the link flags are passed matters. + **libboost_python** must come first, otherwise weeping + and gnashing of teeth will follow. + +Testing the Binding +------------------- +Now compile the binding with ``make``: + +:: + + $ cd foobinding/foo + $ make + +To test if the new binding is working (it can pass the build phase but still +blow up at runtime) start up a Python terminal and import it by the name. + +:: + + $ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/path/to/libfoo/shared/object/dir + $ export PYTHONPATH=$PYTHONPATH:/path/to/foo/python/module/file/dir + $ python + >> import foo + >> print dir(foo) + >> m = foo.Math() + >> print m.squared(5) diff --git a/doc/tutorial/globalheader.rst b/doc/tutorial/globalheader.rst new file mode 100644 index 000000000..d1ac2392e --- /dev/null +++ b/doc/tutorial/globalheader.rst @@ -0,0 +1,36 @@ +.. highlight:: cpp + +.. _gentut-globalheader: + +The Global Header +================= + +Besides the information provided by the typesystem, the generator needs to +gather more data from the library headers containing the classes to be exposed +in Python. If there is a header that include all the others (or just one, as is +the case of **libfoo**) this could be passed directly to the generator. + +If such a file is not available, or only a subset of the library is desired, or +if some flags must be defined before parsing the library headers, then a +``global.h`` file must be provided. + +The use of a ``global.h`` file is preferred if some macros must be defined +before the parser gather data from the headers. For example, if ``NULL`` is not +defined and it is used as a default paramater for some constructor or method, +the parser will not recognize it. + +The solve this create a ``global.h`` including all the desired headers and the +defined (and undefined) flags as follows: + +**foobinding/data/global.h** +:: + + #undef QT_NO_STL + #undef QT_NO_STL_WCHAR + + #ifndef NULL + #define NULL 0 + #endif + + #include <foo.h> + diff --git a/doc/tutorial/images/generatorworkings.png b/doc/tutorial/images/generatorworkings.png Binary files differnew file mode 100644 index 000000000..d35a565ff --- /dev/null +++ b/doc/tutorial/images/generatorworkings.png diff --git a/doc/tutorial/images/generatorworkings.svg b/doc/tutorial/images/generatorworkings.svg new file mode 100644 index 000000000..85a7782af --- /dev/null +++ b/doc/tutorial/images/generatorworkings.svg @@ -0,0 +1,392 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="680" + height="280" + id="svg2" + sodipodi:version="0.32" + inkscape:version="0.46" + sodipodi:docname="generatorworkings.svg" + inkscape:output_extension="org.inkscape.output.svg.inkscape" + inkscape:export-filename="generatorworkings.png" + inkscape:export-xdpi="86.970001" + inkscape:export-ydpi="86.970001" + version="1.0"> + <defs + id="defs4"> + <marker + inkscape:stockid="Arrow1Lstart" + orient="auto" + refY="0" + refX="0" + id="Arrow1Lstart" + style="overflow:visible"> + <path + id="path4293" + d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z" + style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" + transform="matrix(0.8,0,0,0.8,10,0)" /> + </marker> + <linearGradient + inkscape:collect="always" + id="linearGradient3235"> + <stop + style="stop-color:#000000;stop-opacity:1;" + offset="0" + id="stop3237" /> + <stop + style="stop-color:#000000;stop-opacity:0;" + offset="1" + id="stop3239" /> + </linearGradient> + <marker + inkscape:stockid="Arrow1Lend" + orient="auto" + refY="0" + refX="0" + id="Arrow1Lend" + style="overflow:visible"> + <path + id="path3282" + d="M 0,0 L 5,-5 L -12.5,0 L 5,5 L 0,0 z" + style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none" + transform="matrix(-0.8,0,0,-0.8,-10,0)" /> + </marker> + <inkscape:perspective + sodipodi:type="inkscape:persp3d" + inkscape:vp_x="0 : 526.18109 : 1" + inkscape:vp_y="6.1230318e-14 : 1000 : 0" + inkscape:vp_z="744.09448 : 526.18109 : 1" + inkscape:persp3d-origin="372.04724 : 350.78739 : 1" + id="perspective10" /> + <linearGradient + inkscape:collect="always" + xlink:href="#linearGradient3235" + id="linearGradient3241" + x1="-29.816929" + y1="320.97046" + x2="191.17912" + y2="322.7244" + gradientUnits="userSpaceOnUse" /> + </defs> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + gridtolerance="10000" + guidetolerance="10" + objecttolerance="10" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="1.4420481" + inkscape:cx="361.95624" + inkscape:cy="122.34225" + inkscape:document-units="px" + inkscape:current-layer="g3297" + showgrid="false" + inkscape:window-width="1279" + inkscape:window-height="944" + inkscape:window-x="391" + inkscape:window-y="38" + showguides="true" + inkscape:guide-bbox="true"> + <sodipodi:guide + orientation="1,0" + position="-228.99296,-21.575354" + id="guide3165" /> + </sodipodi:namedview> + <metadata + id="metadata7"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(291.86879,-366.35864)"> + <text + xml:space="preserve" + style="font-size:40px;font-style:normal;font-weight:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + x="324.86121" + y="308.08389" + id="text3395" + transform="translate(-28.960129,110.67739)"><tspan + sodipodi:role="line" + id="tspan3397" + x="324.86121" + y="308.08389" /></text> + <g + id="g3254"> + <g + id="g3297" + transform="translate(15,11.795533)"> + <rect + style="fill:#e4fae3;fill-opacity:0.65882353;stroke:#8eff89;stroke-width:0.52055138;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect3609" + width="323.15158" + height="216.66933" + x="-151.9006" + y="364.42294" + ry="7.354454" + rx="5.3701153" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Arrow1Lstart);marker-end:none;stroke-opacity:1;display:inline" + d="M 195.16416,473.16835 L 149.88745,473.08346" + id="path3285" + inkscape:connector-type="polyline" + sodipodi:nodetypes="cc" + inkscape:connection-start="#g3276" /> + <g + id="g3276" + transform="translate(-47.379381,-25.682818)"> + <rect + ry="11.816782" + rx="12.0209" + y="462.87637" + x="242.78513" + height="72.257683" + width="163.85461" + id="rect2461" + style="fill:#9dcdf9;fill-opacity:1;stroke:#0084ff;stroke-width:0.48317167;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + <text + id="text2463" + y="494.80786" + x="324.45514" + style="font-size:144px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + xml:space="preserve"><tspan + style="font-size:22px;text-align:center;text-anchor:middle" + y="494.80786" + x="324.45514" + id="tspan2465" + sodipodi:role="line">binding</tspan><tspan + style="font-size:22px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;font-family:FreeMono;-inkscape-font-specification:FreeMono" + y="519.56543" + x="324.45514" + sodipodi:role="line" + id="tspan3018">source code</tspan></text> + </g> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Arrow1Lstart);marker-end:none;stroke-opacity:1;display:inline" + d="M -130.41272,567.21015 L -180.20217,584.91297" + id="path3054" + inkscape:connector-type="polyline" + sodipodi:nodetypes="cc" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Arrow1Lstart);marker-end:none;stroke-opacity:1;display:inline" + d="M -129.57075,528.12072 L -181.18287,504.96225" + id="path3056" + inkscape:connector-type="polyline" + sodipodi:nodetypes="cc" /> + <g + id="g3147" + transform="translate(74.301071,9.8268847)"> + <g + transform="translate(62.764666,-13.729771)" + id="g2986"> + <rect + style="fill:#fafcc5;fill-opacity:1;stroke:#f9ff00;stroke-width:0.3511245;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect2970" + width="115.38314" + height="55.650036" + x="-430.1297" + y="481.9653" + rx="11.184198" + ry="13.895926" /> + <text + xml:space="preserve" + style="font-size:144px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + x="-371.96939" + y="505.29422" + id="text2972"><tspan + id="tspan2976" + sodipodi:role="line" + x="-371.96939" + y="505.29422" + style="font-size:16px;text-align:center;text-anchor:middle">typesystem</tspan><tspan + id="tspan2980" + sodipodi:role="line" + x="-371.96939" + y="525.29419" + style="font-size:16px;text-align:center;text-anchor:middle">descriptions</tspan></text> + </g> + <g + transform="translate(74.533053,61.297656)" + id="g3020"> + <rect + style="fill:#fafcc5;fill-opacity:1;stroke:#f9ff00;stroke-width:0.36426121;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" + id="rect3022" + width="91.833252" + height="75.250854" + x="-418.35477" + y="472.16489" + rx="9.1466599" + ry="12.17058" /> + <text + xml:space="preserve" + style="font-size:144px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + x="-372.64865" + y="494.13867" + id="text3024"><tspan + id="tspan3026" + sodipodi:role="line" + x="-372.64865" + y="494.13867" + style="font-size:16px;text-align:center;text-anchor:middle">custom</tspan><tspan + id="tspan3028" + sodipodi:role="line" + x="-372.64865" + y="513.88837" + style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;font-family:FreeMono;-inkscape-font-specification:FreeMono">source</tspan><tspan + id="tspan3030" + sodipodi:role="line" + x="-372.64865" + y="536.38837" + style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;text-anchor:middle;font-family:FreeMono;-inkscape-font-specification:FreeMono">code</tspan></text> + </g> + </g> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Arrow1Lstart);marker-end:none;stroke-opacity:1;display:inline" + d="M -40.946515,396.85213 L -179.16818,396.16834" + id="path3098" + inkscape:connector-type="polyline" + sodipodi:nodetypes="cc" /> + <g + id="g3141" + transform="translate(66.255107,-6.2939423)"> + <rect + ry="11.897643" + rx="9.5758715" + y="381.30014" + x="-342.70132" + height="47.647366" + width="98.790642" + id="rect2415" + style="fill:#fafcc5;fill-opacity:1;stroke:#f9ff00;stroke-width:0.30063155;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + <text + id="text2417" + y="401.08865" + x="-293.63803" + style="font-size:144px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + xml:space="preserve"><tspan + style="font-size:16px;text-align:center;text-anchor:middle" + y="401.08865" + x="-293.63803" + id="tspan2419" + sodipodi:role="line">library</tspan><tspan + style="font-size:16px;text-align:center;text-anchor:middle" + y="421.08865" + x="-293.63803" + sodipodi:role="line" + id="tspan2949">headers</tspan></text> + </g> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Arrow1Lstart);marker-end:none;stroke-opacity:1;display:inline" + d="M 33.165609,503.00316 L 32.819729,546.19947" + id="path3167" + inkscape:connector-type="polyline" + sodipodi:nodetypes="cc" /> + <path + style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;marker-start:url(#Arrow1Lstart);marker-end:none;stroke-opacity:1;display:inline" + d="M 33.145722,443.9261 L 32.799842,391.41316" + id="path3169" + inkscape:connector-type="polyline" + sodipodi:nodetypes="cc" /> + <g + id="g2944" + transform="translate(85.554958,3.1233551)"> + <rect + rx="6.8840375" + ry="10.365664" + y="371.05527" + x="-125.40932" + height="44.903805" + width="101.06483" + id="rect3625" + style="fill:#bff3bc;fill-opacity:1;stroke:#0af400;stroke-width:0.36750945;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + <text + transform="scale(1.0000266,0.9999734)" + id="text3627" + y="401.12787" + x="-75.810593" + style="font-size:38.71272278px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + xml:space="preserve"><tspan + style="font-size:21.29199791px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans Bold" + y="401.12787" + x="-75.810593" + sodipodi:role="line" + id="tspan3697">Parser</tspan></text> + </g> + <g + id="g3093" + transform="translate(-22.960524,10.08797)"> + <rect + ry="8.5151205" + rx="9.4630651" + y="433.92093" + x="9.3588104" + height="58.626995" + width="163.91852" + id="rect2446" + style="fill:#b2d7b5;fill-opacity:1;stroke:#34ff34;stroke-width:0.20534486;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.69008268" /> + <text + id="text2448" + y="457.49274" + x="90.813187" + style="font-size:144px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + xml:space="preserve"><tspan + style="font-size:22px;font-weight:bold;text-align:center;text-anchor:middle" + y="457.49274" + x="90.813187" + id="tspan2450" + sodipodi:role="line">Generator</tspan><tspan + style="font-size:22px;font-weight:bold;text-align:center;text-anchor:middle" + y="484.99274" + x="90.813187" + sodipodi:role="line" + id="tspan3340">Backend</tspan></text> + </g> + <g + id="g3160" + transform="translate(94.301071,19.633862)"> + <rect + rx="5.7330456" + ry="8.3964748" + y="506.2883" + x="-225.62247" + height="44.764942" + width="192.46243" + id="rect2933" + style="fill:#bff3bc;fill-opacity:1;stroke:#0af400;stroke-width:0.50637114;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> + <text + transform="scale(1.0000266,0.9999734)" + id="text2935" + y="534.47565" + x="-128.93036" + style="font-size:38.71272278px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Bitstream Vera Sans" + xml:space="preserve"><tspan + style="font-size:21.29199791px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#035800;fill-opacity:1;font-family:Bitstream Vera Sans;-inkscape-font-specification:Bitstream Vera Sans Bold" + y="534.47565" + x="-128.93036" + sodipodi:role="line" + id="tspan2937">TypeDatabase</tspan></text> + </g> + </g> + </g> + </g> +</svg> diff --git a/doc/tutorial/introduction.rst b/doc/tutorial/introduction.rst new file mode 100644 index 000000000..62372af1b --- /dev/null +++ b/doc/tutorial/introduction.rst @@ -0,0 +1,32 @@ +Binding Generation Tutorial +*************************** + +This tutorial intends to describe the process of binding creation with +BoostPythonGenerator and using a very simple Qt4 based library will be used as an +example. + +The image below shows the inputs needed to generate the binding source code. + +.. image:: images/generatorworkings.png + +Putting in words, the user provides the headers for the library along with a +typesystem file describing how the classes will be exposed in the target +language, as well as any needed custom source code to be merged with +the generated source code. + +This tutorial will go through the steps needed to have the binding +being able to be imported and used from a Python program. The tutorial +source code is available as a tar ball `here <../_static/bindingexample.tar.bz2>`_. + +**NOTE:** the binding generator is intended to be used with Qt4 based libraries +only, at least for the time being. + +.. toctree:: + :maxdepth: 3 + + libfoo + bindinglibfoo + typesystemcreation + globalheader + buildingthebinding + diff --git a/doc/tutorial/libfoo.rst b/doc/tutorial/libfoo.rst new file mode 100644 index 000000000..76246570d --- /dev/null +++ b/doc/tutorial/libfoo.rst @@ -0,0 +1,68 @@ +.. highlight:: cpp + +.. _gentut-libfoo: + +Creating the foo library +========================= + +In this section it will be presented the code and the build instructions for a +very simple Qt4 based library. It will be used as the subject for this tutorial. + +The Source Code +--------------- + +There is only one class on this foo library plus a ``.pro`` file which means +that the build system used will be Trolltech's **qmake**. + +Put the files below in a directory called **libfoo**. Be aware that this +directory will be refered by the binding Makefile presented in a next section +of this tutorial. If you want to use other names or paths change the binding +Makefile accordingly. Blind copy'n'paste shortens your life. + +**libfoo/foo.h** +:: + + #ifndef FOO_H + #define FOO_H + + #include <QtCore/QtCore> + + class Math : public QObject + { + Q_OBJECT + public: + Math() {} + virtual ~Math() {} + int squared(int x); + }; + #endif // FOO_H + + +**libfoo/foo.cpp** +:: + + #include "foo.h" + + int Math::squared(int x) + { + return x * x; + } + + +**libfoo/foo.pro** +:: + + TEMPLATE = lib + TARGET = foo + DEPENDPATH += . + INCLUDEPATH += . + HEADERS += foo.h + SOURCES += foo.cpp + +To build the lib: + +:: + + $ cd libfoo + $ qmake + $ make diff --git a/doc/tutorial/typesystemcreation.rst b/doc/tutorial/typesystemcreation.rst new file mode 100644 index 000000000..ae33ccb9e --- /dev/null +++ b/doc/tutorial/typesystemcreation.rst @@ -0,0 +1,135 @@ +.. highlight:: xml + +.. _gentut-typesystem: + +Creating the Typesystem Description +=================================== + +The typesystem is an specification used when mapping a C++ based library onto a +corresponding Python module. The specification is a handwritten XML document +listing the types that will be available in the generated binding, alterations +to classes and function signatures to better suit the target language, +and listing the components that should be rejected for the binding. + +**PySide** uses a typesystem format similar to the ones used by **QtJambi** and +**QtScript**, thoroughly described in the page *"The Qt Jambi Type System"*. [#]_ + +The divergences between **PySide** and QtScript/QtJambi typesystems will be +highlighted whenever they appear. Things to be aware of when writing +a typesystem will be also mentioned. + +Describing **libfoo** for Python Audiences +------------------------------------------ + +All typesystem files start with the root ``typesystem`` tag. The +``package`` attribute carries the name of the package as it will be seen +from Python. + +Right after that, all the typesystem files providing information required for +the generation process are included in the same fashion as header files in C. + +**foobinding/data/typesystem_foo.xml** +:: + + <?xml version="1.0"?> + <typesystem package="foo"> + <load-typesystem name="typesystem_core.xml" generate="no"/> + <object-type name="Math"/> + </typesystem> + + +The inclusion of other typesystem files is achieved with the +``load-typesystem`` tag. The ``generate`` attribute must be set to ``"no"`` +otherwise the generator will try to create more source code for the already +existing bindings included for reference. + +The C++ classes derived from **QObject** intended to be exposed in the target +language are described with ``object-type`` tags. + + +For this example binding just specifying the name of the class does the trick, +since the generator system will automatically catch the methods with arguments +and return value of types known. These types can be described in the same +typesystem file or in the ones referenced with the ``load-typesystem`` tag. + +In more complex situations method signatures can be changed or rejected with +other tags that can be checked out in the typesystem reference. + + +Other Common Cases and Differences +---------------------------------- + +What follows now is some common uses of the typesystem capabilities. All of them +can be seen in the Qt4 typesystem files. They are not used for this binding +tutorial example, so if you just want to have things working ASAP, move along. + +Templates +~~~~~~~~~ + +To ease the process of writing custom code for the binding, recurring pieces of +code can be turned generic with the typesystem template mechanism. +They are declared in a way similar to this snippet: + +:: + + <template name="only_bool*_fix"> + bool ok; + %RETURN_TYPE retval = self.%FUNCTION_NAME(&ok); + </template> + +And is used as in this example: + +:: + + <inject-code class="native" position="beginning"> + <insert-template name="only_bool*_fix"/> + </inject-code> + + +The ``typesystem_template.xml`` file from the Qt4 bindings can be used as a +good resource for examples of this. Check also the QtJambi documentation on +typesystem templates. [#]_ + +Non-QObject Derived Classes +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Even in a Qt4 based library it is common to find classes that doesn't +pertain to the QObject hierarchy, these must be declared as ``value-type``: + +:: + + <value-type name="RectOrSomethingLikeThat"/> + + +Unused Tags +~~~~~~~~~~~ + +Some tags defined in the QtScript/QtJambi typesystem has no effect in **PySide** +typesystem, they are: + + + conversion-rule + + argument-map + +Changes to ``"inject-code"`` Tag +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can pass a file name to the **inject-code** tag so the file contents will +be injected in the generated code. + +The ``class`` attribute value ``java`` was changed to ``target``, while +``native`` remained the same. + +Global Functions +~~~~~~~~~~~~~~~~ + +The BoostPythonGenerator supports global functions, you can also reject these functions using +the **rejection** tag like is done to reject classes. Just pass an empty string to +the class attribute. + +:: + + <rejection class="" function-name="qt_noop"/> + + +.. [#] http://doc.trolltech.com/qtjambi-4.4/html/com/trolltech/qt/qtjambi-typesystem.html +.. [#] http://doc.trolltech.com/qtjambi-4.4/html/com/trolltech/qt/qtjambi-typesystem.html#using-code-templates diff --git a/docgenerator.cpp b/docgenerator.cpp new file mode 100644 index 000000000..fd80ac51f --- /dev/null +++ b/docgenerator.cpp @@ -0,0 +1,1371 @@ +/* + * This file is part of the Boost Python Generator project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * + * Contact: PySide team <contact@pyside.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include "docgenerator.h" +#include <reporthandler.h> +#include <qtdocparser.h> +#include <algorithm> +#include <QtCore/QStack> +#include <QtCore/QTextStream> +#include <QtCore/QXmlStreamReader> +#include <QtCore/QFile> +#include <QtCore/QDir> +#include <boost/graph/graph_concepts.hpp> + +static Indentor INDENT; + +namespace +{ + +static bool functionSort(const AbstractMetaFunction *func1, const AbstractMetaFunction *func2) +{ + return func1->name() < func2->name(); +} + +QString createRepeatedChar(int i, char c) +{ + QString out; + for (int j = 0; j < i; ++j) + out += c; + + return out; +} + +QString escape(QString& str) +{ + return str + .replace("*", "\\*") + .replace("_", "\\_"); +} + +QString escape(const QStringRef& strref) +{ + QString str = strref.toString(); + return escape(str); +} + +} + +QtXmlToSphinx::QtXmlToSphinx(DocGenerator* generator, const QString& doc, const QString& context) + : m_context(context), m_generator(generator), m_insideBold(false), m_insideItalic(false) +{ + m_handlerMap.insert("heading", &QtXmlToSphinx::handleHeadingTag); + m_handlerMap.insert("brief", &QtXmlToSphinx::handleParaTag); + m_handlerMap.insert("para", &QtXmlToSphinx::handleParaTag); + m_handlerMap.insert("italic", &QtXmlToSphinx::handleItalicTag); + m_handlerMap.insert("bold", &QtXmlToSphinx::handleBoldTag); + m_handlerMap.insert("see-also", &QtXmlToSphinx::handleSeeAlsoTag); + m_handlerMap.insert("snippet", &QtXmlToSphinx::handleSnippetTag); + m_handlerMap.insert("dots", &QtXmlToSphinx::handleDotsTag); + m_handlerMap.insert("codeline", &QtXmlToSphinx::handleDotsTag); + m_handlerMap.insert("table", &QtXmlToSphinx::handleTableTag); + m_handlerMap.insert("header", &QtXmlToSphinx::handleRowTag); + m_handlerMap.insert("row", &QtXmlToSphinx::handleRowTag); + m_handlerMap.insert("item", &QtXmlToSphinx::handleItemTag); + m_handlerMap.insert("argument", &QtXmlToSphinx::handleArgumentTag); + m_handlerMap.insert("teletype", &QtXmlToSphinx::handleArgumentTag); + m_handlerMap.insert("link", &QtXmlToSphinx::handleLinkTag); + m_handlerMap.insert("inlineimage", &QtXmlToSphinx::handleImageTag); + m_handlerMap.insert("image", &QtXmlToSphinx::handleImageTag); + m_handlerMap.insert("list", &QtXmlToSphinx::handleListTag); + m_handlerMap.insert("term", &QtXmlToSphinx::handleTermTag); + m_handlerMap.insert("raw", &QtXmlToSphinx::handleRawTag); + m_handlerMap.insert("underline", &QtXmlToSphinx::handleItalicTag); + m_handlerMap.insert("superscript", &QtXmlToSphinx::handleSuperScriptTag); + m_handlerMap.insert("code", &QtXmlToSphinx::handleCodeTag); + m_handlerMap.insert("legalese", &QtXmlToSphinx::handleCodeTag); + m_handlerMap.insert("section", &QtXmlToSphinx::handleAnchorTag); + m_handlerMap.insert("quotefile", &QtXmlToSphinx::handleQuoteFileTag); + + // ignored tags + m_handlerMap.insert("generatedlist", &QtXmlToSphinx::handleIgnoredTag); + m_handlerMap.insert("tableofcontents", &QtXmlToSphinx::handleIgnoredTag); + m_handlerMap.insert("quotefromfile", &QtXmlToSphinx::handleIgnoredTag); + m_handlerMap.insert("skipto", &QtXmlToSphinx::handleIgnoredTag); + m_handlerMap.insert("target", &QtXmlToSphinx::handleIgnoredTag); + + // useless tags + m_handlerMap.insert("description", &QtXmlToSphinx::handleUselessTag); + m_handlerMap.insert("definition", &QtXmlToSphinx::handleUselessTag); + m_handlerMap.insert("printuntil", &QtXmlToSphinx::handleUselessTag); + m_handlerMap.insert("relation", &QtXmlToSphinx::handleUselessTag); + + m_result = transform(doc); +} + +void QtXmlToSphinx::pushOutputBuffer() +{ + QString* buffer = new QString(); + m_buffers << buffer; + m_output.setString(buffer); +} + +QString QtXmlToSphinx::popOutputBuffer() +{ + Q_ASSERT(!m_buffers.isEmpty()); + QString* str = m_buffers.pop(); + QString strcpy(*str); + delete str; + m_output.setString(m_buffers.isEmpty() ? 0 : m_buffers.top()); + return strcpy; +} + + +QString QtXmlToSphinx::transform(const QString& doc) +{ + Q_ASSERT(m_buffers.isEmpty()); + Indentation indentation(INDENT); + if (doc.trimmed().isEmpty()) + return doc; + + pushOutputBuffer(); + + QXmlStreamReader reader(doc); + + while (!reader.atEnd()) { + QXmlStreamReader::TokenType token = reader.readNext(); + if (reader.hasError()) { + m_output << INDENT << "XML Error: " + reader.errorString() + "\n" + doc; + ReportHandler::warning("XML Error: " + reader.errorString() + "\n" + doc); + break; + } + + if (token == QXmlStreamReader::StartElement) { + QStringRef tagName = reader.name(); + TagHandler handler = m_handlerMap.value(tagName.toString(), &QtXmlToSphinx::handleUnknownTag); + if (!m_handlers.isEmpty() && ( (m_handlers.top() == &QtXmlToSphinx::handleIgnoredTag) || + (m_handlers.top() == &QtXmlToSphinx::handleRawTag)) ) + handler = &QtXmlToSphinx::handleIgnoredTag; + + m_handlers.push(handler); + } + if (!m_handlers.isEmpty()) + (this->*(m_handlers.top()))(reader); + + if (token == QXmlStreamReader::EndElement) { + m_handlers.pop(); + m_lastTagName = reader.name().toString(); + } + } + m_output.flush(); + QString retval = popOutputBuffer(); + Q_ASSERT(m_buffers.isEmpty()); + return retval; +} + +QString QtXmlToSphinx::readFromLocation(QString& location, QString& identifier) +{ + QFile inputFile; + inputFile.setFileName(location); + if (!inputFile.open(QIODevice::ReadOnly)) { + ReportHandler::warning("Couldn't read code snippet file: "+inputFile.fileName()); + return QString(); + } + + QRegExp searchString("//!\\s*\\[" + identifier + "\\]"); + QRegExp codeSnippetCode("//!\\s*\\[[\\w\\d\\s]+\\]"); + QString code; + QString line; + bool identifierIsEmpty = identifier.isEmpty(); + bool getCode = false; + + while (!inputFile.atEnd()) { + line = inputFile.readLine(); + if (identifierIsEmpty) + code += line; + else if (getCode && !line.contains(searchString)) + code += line.replace(codeSnippetCode, ""); + else if (line.contains(searchString)) + if (getCode) + break; + else + getCode = true; + } + + if (code.isEmpty()) + ReportHandler::warning("Code snippet file found ("+location+"), but snippet "+ identifier +" not found."); + + return code; +} + +void QtXmlToSphinx::handleHeadingTag(QXmlStreamReader& reader) +{ + static QString heading; + static char type; + static char types[] = { '-', '^' }; + QXmlStreamReader::TokenType token = reader.tokenType(); + if (token == QXmlStreamReader::StartElement) { + int typeIdx = reader.attributes().value("level").toString().toInt(); + if (typeIdx >= sizeof(types)) + type = types[sizeof(types)-1]; + else + type = types[typeIdx]; + } else if (token == QXmlStreamReader::EndElement) { + m_output << createRepeatedChar(heading.length(), type) << endl << endl; + } else if (token == QXmlStreamReader::Characters) { + heading = escape(reader.text()).trimmed(); + m_output << endl << endl << heading << endl; + } +} + +void QtXmlToSphinx::handleParaTag(QXmlStreamReader& reader) +{ + QXmlStreamReader::TokenType token = reader.tokenType(); + if (token == QXmlStreamReader::StartElement) { + pushOutputBuffer(); + } else if (token == QXmlStreamReader::EndElement) { + QString result = popOutputBuffer().simplified(); + if (result.startsWith("**Warning:**")) + result.replace(0, 12, ".. warning:: "); + else if (result.startsWith("**Note:**")) + result.replace(0, 9, ".. note:: "); + + m_output << INDENT << result << endl << endl; + } else if (token == QXmlStreamReader::Characters) { + QString text = escape(reader.text()); + if (!m_output.string()->isEmpty()) { + QChar start = text[0]; + QChar end = m_output.string()->at(m_output.string()->length() - 1); + if ((end == '*' || end == '`') && start != ' ' && !start.isPunct()) + m_output << '\\'; + } + m_output << INDENT << text; + } +} + +void QtXmlToSphinx::handleItalicTag(QXmlStreamReader& reader) +{ + QXmlStreamReader::TokenType token = reader.tokenType(); + if (token == QXmlStreamReader::StartElement || token == QXmlStreamReader::EndElement) { + m_insideItalic = !m_insideItalic; + m_output << '*'; + } else if (token == QXmlStreamReader::Characters) { + m_output << escape(reader.text()).trimmed(); + } +} + +void QtXmlToSphinx::handleBoldTag(QXmlStreamReader& reader) +{ + QXmlStreamReader::TokenType token = reader.tokenType(); + if (token == QXmlStreamReader::StartElement || token == QXmlStreamReader::EndElement) { + m_insideBold = !m_insideBold; + m_output << "**"; + } else if (token == QXmlStreamReader::Characters) { + m_output << escape(reader.text()).trimmed(); + } +} + +void QtXmlToSphinx::handleArgumentTag(QXmlStreamReader& reader) +{ + QXmlStreamReader::TokenType token = reader.tokenType(); + if (token == QXmlStreamReader::StartElement || token == QXmlStreamReader::EndElement) + m_output << "``"; + else if (token == QXmlStreamReader::Characters) + m_output << reader.text().toString().trimmed(); +} + +void QtXmlToSphinx::handleSeeAlsoTag(QXmlStreamReader& reader) +{ + QXmlStreamReader::TokenType token = reader.tokenType(); + if (token == QXmlStreamReader::StartElement) + m_output << INDENT << ".. seealso:: "; + else if (token == QXmlStreamReader::EndElement) + m_output << endl; +} + +void QtXmlToSphinx::handleSnippetTag(QXmlStreamReader& reader) +{ + QXmlStreamReader::TokenType token = reader.tokenType(); + if (token == QXmlStreamReader::StartElement) { + bool consecutiveSnippet = m_lastTagName == "snippet" || m_lastTagName == "dots" || m_lastTagName == "codeline"; + if (consecutiveSnippet) { + m_output.flush(); + m_output.string()->chop(2); + } + QString location = reader.attributes().value("location").toString(); + QString identifier = reader.attributes().value("identifier").toString(); + location.prepend(m_generator->codeSnippetDir() + '/'); + QString code = readFromLocation(location, identifier); + if (!consecutiveSnippet) + m_output << INDENT << "::\n\n"; + + Indentation indentation(INDENT); + if (code.isEmpty()) { + m_output << INDENT << "<Code snippet \"" << location << ':' << identifier << "\" not found>" << endl; + } else { + foreach (QString line, code.split("\n")) { + if (!QString(line).trimmed().isEmpty()) + m_output << INDENT << line; + + m_output << endl; + } + } + m_output << endl; + } +} +void QtXmlToSphinx::handleDotsTag(QXmlStreamReader& reader) +{ + QXmlStreamReader::TokenType token = reader.tokenType(); + if (token == QXmlStreamReader::StartElement) { + bool consecutiveSnippet = m_lastTagName == "snippet" || m_lastTagName == "dots" || m_lastTagName == "codeline"; + if (consecutiveSnippet) { + m_output.flush(); + m_output.string()->chop(2); + } + Indentation indentation(INDENT); + pushOutputBuffer(); + m_output << INDENT; + int indent = reader.attributes().value("indent").toString().toInt(); + for (int i = 0; i < indent; ++i) + m_output << ' '; + } else if (token == QXmlStreamReader::Characters) { + m_output << reader.text().toString(); + } else if (token == QXmlStreamReader::EndElement) { + m_output << popOutputBuffer() << "\n\n\n"; + } +} + +void QtXmlToSphinx::handleTableTag(QXmlStreamReader& reader) +{ + QXmlStreamReader::TokenType token = reader.tokenType(); + if (token == QXmlStreamReader::StartElement) { + m_currentTable.clear(); + m_tableHasHeader = false; + } else if (token == QXmlStreamReader::EndElement) { + // write the table on m_output + m_currentTable.enableHeader(m_tableHasHeader); + m_currentTable.normalize(); + m_output << m_currentTable; + m_currentTable.clear(); + } +} + +void QtXmlToSphinx::handleTermTag(QXmlStreamReader& reader) +{ + QXmlStreamReader::TokenType token = reader.tokenType(); + if (token == QXmlStreamReader::StartElement) { + pushOutputBuffer(); + } else if (token == QXmlStreamReader::Characters) { + m_output << reader.text().toString().replace("::", "."); + } else if (token == QXmlStreamReader::EndElement) { + TableCell cell; + cell.data = popOutputBuffer().trimmed(); + m_currentTable << (TableRow() << cell); + } +} + + +void QtXmlToSphinx::handleItemTag(QXmlStreamReader& reader) +{ + QXmlStreamReader::TokenType token = reader.tokenType(); + if (token == QXmlStreamReader::StartElement) { + if (m_currentTable.isEmpty()) + m_currentTable << TableRow(); + TableRow& row = m_currentTable.last(); + TableCell cell; + cell.colSpan = reader.attributes().value("colspan").toString().toShort(); + cell.rowSpan = reader.attributes().value("rowspan").toString().toShort(); + row << cell; + pushOutputBuffer(); + } else if (token == QXmlStreamReader::EndElement) { + QString data = popOutputBuffer().trimmed(); + if (!m_currentTable.isEmpty()) { + TableRow& row = m_currentTable.last(); + if (!row.isEmpty()) + row.last().data = data; + } + } +} + +void QtXmlToSphinx::handleRowTag(QXmlStreamReader& reader) +{ + QXmlStreamReader::TokenType token = reader.tokenType(); + if (token == QXmlStreamReader::StartElement) { + m_tableHasHeader = reader.name() == "header"; + m_currentTable << TableRow(); + } +} + +void QtXmlToSphinx::handleListTag(QXmlStreamReader& reader) +{ + // BUG We do not support a list inside a table cell + static QString listType; + QXmlStreamReader::TokenType token = reader.tokenType(); + if (token == QXmlStreamReader::StartElement) { + listType = reader.attributes().value("type").toString(); + if (listType == "enum") { + m_currentTable << (TableRow() << "Constant" << "Description"); + m_tableHasHeader = true; + } + INDENT.indent--; + } else if (token == QXmlStreamReader::EndElement) { + INDENT.indent++; + if (!m_currentTable.isEmpty()) { + if (listType == "bullet") { + m_output << endl; + foreach (TableCell cell, m_currentTable.first()) { + QStringList itemLines = cell.data.split('\n'); + m_output << INDENT << "* " << itemLines.first() << endl; + for (int i = 1, max = itemLines.count(); i < max; ++i) + m_output << INDENT << " " << itemLines[i] << endl; + } + m_output << endl; + } else if (listType == "enum") { + m_currentTable.enableHeader(m_tableHasHeader); + m_currentTable.normalize(); + m_output << m_currentTable; + } + } + m_currentTable.clear(); + } +} + +void QtXmlToSphinx::handleLinkTag(QXmlStreamReader& reader) +{ + static QString l_linktag; + static QString l_linkref; + static QString l_linktext; + static QString l_linktagending; + static QString l_type; + QXmlStreamReader::TokenType token = reader.tokenType(); + if (token == QXmlStreamReader::StartElement) { + l_linktagending = "` "; + if (m_insideBold) { + l_linktag.prepend("**"); + l_linktagending.append("**"); + } else if (m_insideItalic) { + l_linktag.prepend('*'); + l_linktagending.append('*'); + } + l_type = reader.attributes().value("type").toString(); + + // TODO: create a flag PROPERTY-AS-FUNCTION to ask if the properties + // are recognized as such or not in the binding + if (l_type == "property") + l_type = "function"; + + if (l_type == "typedef") + l_type = "class"; + + QString linkSource; + if (l_type == "function" || l_type == "class") { + linkSource = "raw"; + } else if (l_type == "enum") { + linkSource = "enum"; + } else if (l_type == "page") { + linkSource = "page"; + } else { + linkSource = "href"; + } + + l_linkref = reader.attributes().value(linkSource).toString(); + l_linkref.replace("::", "."); + l_linkref.remove("()"); + + if (l_type == "function" && !m_context.isEmpty()) { + l_linktag = " :meth:`"; + QStringList rawlinklist = l_linkref.split("."); + if (rawlinklist.size() == 1 || rawlinklist[0] == m_context) + l_linkref.prepend("~" + m_context + '.'); + } else if (l_type == "function" && m_context.isEmpty()) { + l_linktag = " :func:`"; + } else if (l_type == "class") { + l_linktag = " :class:`"; + } else if (l_type == "enum") { + l_linktag = " :attr:`"; + } else if (l_type == "page" && l_linkref == m_generator->moduleName()) { + l_linktag = " :mod:`"; + } else { + l_linktag = " :ref:`"; + } + + } else if (token == QXmlStreamReader::Characters) { + QString linktext = reader.text().toString(); + linktext.replace("::", "."); + QString item = l_linkref.split(".").last(); + if (l_linkref == linktext + || (l_linkref + "()") == linktext + || item == linktext + || (item + "()") == linktext) + l_linktext.clear(); + else + l_linktext = linktext + QLatin1String("<"); + } else if (token == QXmlStreamReader::EndElement) { + if (!l_linktext.isEmpty()) + l_linktagending.prepend('>'); + m_output << l_linktag << l_linktext << escape(l_linkref) << l_linktagending; + } +} + +void QtXmlToSphinx::handleImageTag(QXmlStreamReader& reader) +{ + QXmlStreamReader::TokenType token = reader.tokenType(); + if (token == QXmlStreamReader::StartElement) { + QString href = reader.attributes().value("href").toString(); + QDir dir(m_generator->outputDirectory() + '/' + m_generator->packageName().replace(".", "/")); + QString imgPath = dir.relativeFilePath(m_generator->libSourceDir() + "/doc/src/") + '/' + href; + + if (reader.name() == "image") + m_output << INDENT << ".. image:: " << imgPath << endl << endl; + else + m_output << ".. image:: " << imgPath << ' '; + } +} + +void QtXmlToSphinx::handleRawTag(QXmlStreamReader& reader) +{ + QXmlStreamReader::TokenType token = reader.tokenType(); + if (token == QXmlStreamReader::StartElement) { + QString format = reader.attributes().value("format").toString(); + m_output << INDENT << ".. raw:: " << format.toLower() << endl << endl; + } else if (token == QXmlStreamReader::Characters) { + QStringList lst(reader.text().toString().split("\n")); + foreach(QString row, lst) + m_output << INDENT << INDENT << row << endl; + } else if (token == QXmlStreamReader::EndElement) { + m_output << endl << endl; + } +} + +void QtXmlToSphinx::handleCodeTag(QXmlStreamReader& reader) +{ + QXmlStreamReader::TokenType token = reader.tokenType(); + if (token == QXmlStreamReader::StartElement) { + QString format = reader.attributes().value("format").toString(); + m_output << INDENT << "::" << endl << endl; + INDENT.indent++; + } else if (token == QXmlStreamReader::Characters) { + QStringList lst(reader.text().toString().split("\n")); + foreach(QString row, lst) + m_output << INDENT << INDENT << row << endl; + } else if (token == QXmlStreamReader::EndElement) { + m_output << endl << endl; + INDENT.indent--; + } +} + +void QtXmlToSphinx::handleUnknownTag(QXmlStreamReader& reader) +{ + QXmlStreamReader::TokenType token = reader.tokenType(); + if (token == QXmlStreamReader::StartElement) + ReportHandler::warning("Unknow QtDoc tag: \"" + reader.name().toString() + "\"."); +} + +void QtXmlToSphinx::handleSuperScriptTag(QXmlStreamReader& reader) +{ + QXmlStreamReader::TokenType token = reader.tokenType(); + if (token == QXmlStreamReader::StartElement) { + m_output << " :sup:`"; + pushOutputBuffer(); + } else if (token == QXmlStreamReader::Characters) { + m_output << reader.text().toString(); + } else if (token == QXmlStreamReader::EndElement) { + m_output << popOutputBuffer(); + m_output << '`'; + } +} + +void QtXmlToSphinx::handleIgnoredTag(QXmlStreamReader&) +{ +} + +void QtXmlToSphinx::handleUselessTag(QXmlStreamReader&) +{ + // Tag "description" just marks the init of "Detailed description" title. + // Tag "definition" just marks enums. We have a different way to process them. +} + +void QtXmlToSphinx::handleAnchorTag(QXmlStreamReader& reader) +{ + QXmlStreamReader::TokenType token = reader.tokenType(); + if (token == QXmlStreamReader::StartElement) { + QString anchor; + if (reader.attributes().hasAttribute("id")) + anchor = reader.attributes().value("id").toString(); + else if (reader.attributes().hasAttribute("name")) + anchor = reader.attributes().value("name").toString(); + if (!anchor.isEmpty() && m_opened_anchor != anchor) { + m_opened_anchor = anchor; + m_output << INDENT << ".. _" << m_context << "_" << anchor.toLower() << ":" << endl << endl; + } + } else if (token == QXmlStreamReader::EndElement) { + m_opened_anchor = ""; + } +} + +void QtXmlToSphinx::handleQuoteFileTag(QXmlStreamReader& reader) +{ + QXmlStreamReader::TokenType token = reader.tokenType(); + if (token == QXmlStreamReader::Characters) { + QString location = reader.text().toString(); + QString identifier = ""; + location.prepend(m_generator->libSourceDir() + '/'); + QString code = readFromLocation(location, identifier); + + m_output << INDENT << "::\n\n"; + Indentation indentation(INDENT); + if (code.isEmpty()) { + m_output << INDENT << "<Code snippet \"" << location << "\" not found>" << endl; + } else { + foreach (QString line, code.split("\n")) { + if (!QString(line).trimmed().isEmpty()) + m_output << INDENT << line; + + m_output << endl; + } + } + m_output << endl; + } +} + +void QtXmlToSphinx::Table::normalize() +{ + if (m_normalized || isEmpty()) + return; + + int row; + int col; + QtXmlToSphinx::Table& self = *this; + + // add col spans + for (row = 0; row < count(); ++row) { + for (col = 0; col < at(row).count(); ++col) { + QtXmlToSphinx::TableCell& cell = self[row][col]; + if (cell.colSpan > 0) { + QtXmlToSphinx::TableCell newCell; + newCell.colSpan = -1; + for (int i = 0, max = cell.colSpan-1; i < max; ++i) { + self[row].insert(col+1, newCell); + } + cell.colSpan = 0; + col++; + } + } + } + + // row spans + const int numCols = first().count(); + for (col = 0; col < numCols; ++col) { + for (row = 0; row < count(); ++row) { + if (col < self[row].count()) { + QtXmlToSphinx::TableCell& cell = self[row][col]; + if (cell.rowSpan > 0) { + QtXmlToSphinx::TableCell newCell; + newCell.rowSpan = -1; + int max = std::min(cell.rowSpan - 1, count()); + cell.rowSpan = 0; + for (int i = 0; i < max; ++i) { + self[row+i+1].insert(col, newCell); + } + row++; + } + } + } + } + m_normalized = true; +} + +QTextStream& operator<<(QTextStream& s, const QtXmlToSphinx::Table &table) +{ + if (table.isEmpty()) + return s; + + if (!table.isNormalized()) { + ReportHandler::warning("Attempt to print an unnormalized table!"); + return s; + } + + // calc width and height of each column and row + QVector<int> colWidths(table.first().count()); + QVector<int> rowHeights(table.count()); + for (int i = 0, maxI = table.count(); i < maxI; ++i) { + const QtXmlToSphinx::TableRow& row = table[i]; + for (int j = 0, maxJ = row.count(); j < maxJ; ++j) { + QStringList rowLines = row[j].data.split('\n'); // cache this would be a good idea + foreach (QString str, rowLines) + colWidths[j] = std::max(colWidths[j], str.count()); + rowHeights[i] = std::max(rowHeights[i], row[j].data.count('\n') + 1); + } + } + + if (!*std::max_element(colWidths.begin(), colWidths.end())) + return s; // empty table (table with empty cells) + + // create a horizontal line to be used later. + QString horizontalLine("+"); + for (int i = 0, max = colWidths.count(); i < max; ++i) { + horizontalLine += createRepeatedChar(colWidths[i], '-'); + horizontalLine += '+'; + } + + // write table rows + for (int i = 0, maxI = table.count(); i < maxI; ++i) { // for each row + const QtXmlToSphinx::TableRow& row = table[i]; + + // print line + s << INDENT << '+'; + char c = (!i && table.hasHeader()) ? '=' : '-'; + for (int col = 0, max = colWidths.count(); col < max; ++col) { + char c; + if (row[col].rowSpan == -1) + c = ' '; + else if (i == 1 && table.hasHeader()) + c = '='; + else + c = '-'; + s << createRepeatedChar(colWidths[col], c) << '+'; + } + s << endl; + + + // Print the table cells + for (int rowLine = 0; rowLine < rowHeights[i]; ++rowLine) { // for each line in a row + for (int j = 0, maxJ = row.count(); j < maxJ; ++j) { // for each column + const QtXmlToSphinx::TableCell& cell = row[j]; + QStringList rowLines = cell.data.split('\n'); // FIXME: Cache this!!! + if (!j) // First column, so we need print the identation + s << INDENT; + + if (!j || !cell.colSpan) + s << '|'; + else + s << ' '; + s << qSetFieldWidth(colWidths[j]) << left; + s << (rowLine < rowLines.count() ? rowLines[rowLine] : ""); + s << qSetFieldWidth(0); + } + s << '|' << endl; + } + } + s << INDENT << horizontalLine << endl; + s << endl; + return s; +} + +static QString getClassName(const AbstractMetaClass *cppClass) { + return cppClass->name().replace("::", "."); +} + +static QString getFuncName(const AbstractMetaFunction *cppFunc) { + static bool hashInitialized = false; + static QHash<QString, QString> operatorsHash; + if (!hashInitialized) { + operatorsHash.insert("operator+", "__add__"); + operatorsHash.insert("operator+=", "__iadd__"); + operatorsHash.insert("operator-", "__sub__"); + operatorsHash.insert("operator-=", "__isub__"); + operatorsHash.insert("operator*", "__mul__"); + operatorsHash.insert("operator*=", "__imul__"); + operatorsHash.insert("operator/", "__div__"); + operatorsHash.insert("operator/=", "__idiv__"); + operatorsHash.insert("operator%", "__mod__"); + operatorsHash.insert("operator%=", "__imod__"); + operatorsHash.insert("operator<<", "__lshift__"); + operatorsHash.insert("operator<<=", "__ilshift__"); + operatorsHash.insert("operator>>", "__rshift__"); + operatorsHash.insert("operator>>=", "__irshift__"); + operatorsHash.insert("operator&", "__and__"); + operatorsHash.insert("operator&=", "__iand__"); + operatorsHash.insert("operator|", "__or__"); + operatorsHash.insert("operator|=", "__ior__"); + operatorsHash.insert("operator^", "__xor__"); + operatorsHash.insert("operator^=", "__ixor__"); + operatorsHash.insert("operator==", "__eq__"); + operatorsHash.insert("operator!=", "__ne__"); + operatorsHash.insert("operator<", "__lt__"); + operatorsHash.insert("operator<=", "__le__"); + operatorsHash.insert("operator>", "__gt__"); + operatorsHash.insert("operator>=", "__ge__"); + hashInitialized = true; + } + + QHash<QString, QString>::const_iterator it = operatorsHash.find(cppFunc->name()); + QString result = it != operatorsHash.end() ? it.value() : cppFunc->name(); + return result.replace("::", "."); +} + +QString DocGenerator::fileNameForClass(const AbstractMetaClass *cppClass) const +{ + return QString("%1.rst").arg(getClassName(cppClass)); +} + +void DocGenerator::writeFormatedText(QTextStream& s, const Documentation& doc, const AbstractMetaClass* metaClass) +{ + QString metaClassName; + + if (metaClass) + metaClassName = getClassName(metaClass); + + if (doc.format() == Documentation::Native) { + QtXmlToSphinx x(this, doc.value(), metaClassName); + s << x; + } else { + s << doc.value(); + } + + s << endl; +} + +void DocGenerator::writeFunctionBrief(QTextStream &s, + const AbstractMetaClass *cppClass, + const AbstractMetaFunction *cppFunction) +{ + s << INDENT << "def :meth:`" + << cppFunction->name() << "<"; + if (cppClass && cppClass->name() != cppFunction->name()) + s << getClassName(cppClass) << '.'; + + s << cppFunction->name() << ">`" + << " (" << parseArgDocStyle(cppClass, cppFunction) << "):"; +} + +void DocGenerator::generateClass(QTextStream &s, const AbstractMetaClass *cppClass) +{ + QString doc; + QTextStream doc_s(&doc); + + ReportHandler::debugSparse("Generating Documentation for " + cppClass->fullName()); + s << ".. module:: " << packageName() << endl; + QString className = getClassName(cppClass); + s << ".. _" << className << ":" << endl << endl; + + s << className << endl; + s << createRepeatedChar(className.count(), '*') << endl << endl; + + s << ".. inheritance-diagram:: " << className << endl + << " :parts: 2" << endl << endl; // TODO: This would be a parameter in the future... + + //Function list + AbstractMetaFunctionList functionList = filterFunctions(cppClass); + qSort(functionList.begin(), functionList.end(), functionSort); + +#if 0 + if (functionList.size() > 0) + { + QtXmlToSphinx::Table functionTable; + QtXmlToSphinx::TableRow row; + + s << "Functions\n" + "---------\n\n"; + + + foreach (AbstractMetaFunction *func, functionList) { + if ((func->isConstructor() || func->isModifiedRemoved()) || + (func->declaringClass() != cppClass)) + continue; + + QString rowString; + QTextStream rowStream(&rowString); + + writeFunctionBrief(rowStream, cppClass, func); + row << rowString; + functionTable << row; + row.clear(); + } + functionTable.normalize(); + s << functionTable; + } + +#endif + + doc_s << "Detailed Description\n" + "--------------------\n\n"; + + writeInjectDocumentation(doc_s, DocModification::Prepend, cppClass, 0); + writeFormatedText(doc_s, cppClass->documentation(), cppClass); + + + if (!cppClass->isNamespace()) { + + writeConstructors(doc_s, cppClass); + writeEnums(doc_s, cppClass); + writeFields(doc_s, cppClass); + + foreach (AbstractMetaFunction *func, functionList) { + if ((func->isConstructor() || func->isModifiedRemoved()) || + (func->declaringClass() != cppClass)) + continue; + + if (func->isStatic()) + doc_s << ".. staticmethod:: "; + else + doc_s << ".. method:: "; + + writeFunction(doc_s, true, cppClass, func); + } + } + + writeInjectDocumentation(doc_s, DocModification::Append, cppClass, 0); + + writeFunctionList(s, doc, cppClass); + + s << doc; +} + +QString DocGenerator::parseFunctionDeclaration(const QString &doc, const AbstractMetaClass *cppClass) +{ + //.. method:: QObject.childEvent(arg__1) + //def :meth:`removeEventFilter<QObject.removeEventFilter>` (arg__1): + + QString data = doc; + QString markup; + + if (data.startsWith(".. method::")) + markup = ".. method::"; + else if (data.startsWith(".. staticmethod::")) + markup = ".. staticmethod::"; + else + return QString(); + + data = data.mid(markup.size()); //remove .. method:: + data = data.mid(data.indexOf(".") + 1); //remove class name + + QString methName = data.mid(0, data.indexOf("(")); + QString methArgs = data.mid(data.indexOf("(")); + + data = QString("def :meth:`%1<%2.%3>` %4") + .arg(methName) + .arg(cppClass->name()) + .arg(methName) + .arg(methArgs); + + return data; +} + + +void DocGenerator::writeFunctionList(QTextStream &s, const QString &content, const AbstractMetaClass *cppClass) +{ + QStringList functionList; + QStringList staticFunctionList; + + QStringList lst = content.split("\n"); + foreach(QString row, lst) { + QString data = row.trimmed(); + if (data.startsWith(".. method::")) { + functionList << parseFunctionDeclaration(data, cppClass); + } + else if (data.startsWith(".. staticmethod::")) { + staticFunctionList << parseFunctionDeclaration(data, cppClass); + } + } + + if ((functionList.size() > 0) || (staticFunctionList.size() > 0)) + { + QtXmlToSphinx::Table functionTable; + QtXmlToSphinx::TableRow row; + + s << "Synopsis" << endl + << "--------" << endl << endl; + + if (functionList.size() > 0) { + s << "Functions" << endl + << "^^^^^^^^^" << endl << endl; + + qSort(functionList); + foreach (QString func, functionList) { + row << func; + functionTable << row; + row.clear(); + } + + functionTable.normalize(); + s << functionTable << endl; + functionTable.clear(); + } + + if (staticFunctionList.size() > 0) { + s << "Static functions" << endl + << "^^^^^^^^^^^^^^^^" << endl; + + qSort(staticFunctionList); + foreach (QString func, staticFunctionList) { + row << func; + functionTable << row; + row.clear(); + } + + functionTable.normalize(); + s << functionTable << endl; + } + } +} + +void DocGenerator::writeEnums(QTextStream& s, const AbstractMetaClass* cppClass) +{ + static const QString section_title(".. attribute:: "); + + foreach (AbstractMetaEnum *en, cppClass->enums()) { + s << section_title << getClassName(cppClass) << "." << en->name() << endl << endl; + writeFormatedText(s, en->documentation(), cppClass); + } +} + +void DocGenerator::writeFields(QTextStream &s, const AbstractMetaClass *cppClass) +{ + static const QString section_title(".. attribute:: "); + + foreach (AbstractMetaField *field, cppClass->fields()) { + s << section_title << getClassName(cppClass) << "." << field->name() << endl << endl; + //TODO: request for member ‘documentation’ is ambiguous + writeFormatedText(s, field->AbstractMetaAttributes::documentation(), cppClass); + } +} + +void DocGenerator::writeConstructors(QTextStream &s, const AbstractMetaClass *cppClass) +{ + static const QString sectionTitle = ".. class:: "; + static const QString sectionTitleSpace = QString(sectionTitle.size(), ' '); + + AbstractMetaFunctionList lst = cppClass->queryFunctions(AbstractMetaClass::Constructors | AbstractMetaClass::Visible); + + bool first = true; + QHash<QString, AbstractMetaArgument *> arg_map; + + foreach(AbstractMetaFunction *func, lst) { + if (func->isModifiedRemoved()) + continue; + + if (first) { + first = false; + s << sectionTitle; + } else { + s << sectionTitleSpace; + } + writeFunction(s, false, cppClass, func); + foreach(AbstractMetaArgument *arg, func->arguments()) + { + if (!arg_map.contains(arg->argumentName())) { + arg_map.insert(arg->argumentName(), arg); + } + } + } + + s << endl; + + foreach (AbstractMetaArgument *arg, arg_map.values()) { + Indentation indentation(INDENT); + writeParamerteType(s, cppClass, arg); + } + + s << endl; + + foreach (AbstractMetaFunction *func, lst) { + writeFormatedText(s, func->documentation(), cppClass); + } +} + +QString DocGenerator::parseArgDocStyle(const AbstractMetaClass *cppClass, const AbstractMetaFunction *func) +{ + QString ret; + bool optional = false; + + foreach (AbstractMetaArgument *arg, func->arguments()) { + + if (func->argumentRemoved(arg->argumentIndex() + 1)) + continue; + + if (arg->argumentIndex() > 0) + ret += ","; + + if (!arg->defaultValueExpression().isEmpty() && (!optional)) { + ret += "["; + optional = true; + } + + ret += arg->argumentName(); + + if (optional) + ret += "=" + arg->defaultValueExpression(); + } + + if (optional) + ret += "]"; + + return ret; +} + +void DocGenerator::writeDocSnips(QTextStream &s, + const CodeSnipList &codeSnips, + CodeSnip::Position position, + TypeSystem::Language language) +{ + Indentation indentation(INDENT); + QStringList invalidStrings; + const static QString startMarkup("[sphinx-begin]"); + const static QString endMarkup("[sphinx-end]"); + + invalidStrings << "*" << "//" << "/*" << "*/"; + + foreach (CodeSnip snip, codeSnips) { + if ((snip.position != position) || + !(snip.language & language)) + continue; + + QString code = snip.code(); + while (code.contains(startMarkup) && code.contains(endMarkup)) { + int startBlock = code.indexOf(startMarkup) + startMarkup.size(); + int endBlock = code.indexOf(endMarkup); + + if ((startBlock == -1) || (endBlock == -1)) + break; + + QString codeBlock = code.mid(startBlock, endBlock - startBlock); + QStringList rows = codeBlock.split("\n"); + int currenRow = 0; + int offset = 0; + + foreach(QString row, rows) { + foreach(QString invalidString, invalidStrings) { + row = row.remove(invalidString); + } + + if (row.trimmed().size() == 0) { + if (currenRow == 0) + continue; + else + s << endl; + } + + if (currenRow == 0) { + //find offset + for (int i=0, i_max = row.size(); i < i_max; i++) { + if (row[i] == ' ') + offset++; + else if (row[i] == '\n') + offset = 0; + else + break; + } + } + row = row.mid(offset); + s << row << endl; + currenRow++; + } + + code = code.mid(endBlock+endMarkup.size()); + } + } +} + +void DocGenerator::writeInjectDocumentation(QTextStream &s, + DocModification::Mode mode, + const AbstractMetaClass *cppClass, + const AbstractMetaFunction *func) +{ + Indentation indentation(INDENT); + + foreach (DocModification mod, cppClass->typeEntry()->docModifications()) { + if (mod.mode() == mode) { + bool modOk = func ? mod.signature() == func->minimalSignature() : mod.signature().isEmpty(); + + if (modOk) { + Documentation doc; + Documentation::Format fmt; + + if (mod.format == TypeSystem::NativeCode) + fmt = Documentation::Native; + else if (mod.format == TypeSystem::TargetLangCode) + fmt = Documentation::Target; + else + continue; + + doc.setValue(mod.code() , fmt); + s << INDENT; + writeFormatedText(s, doc, cppClass); + } + } + } + + s << endl; + + if (func) { + writeDocSnips(s, getCodeSnips(func), + (mode == DocModification::Prepend ? CodeSnip::Beginning : CodeSnip::End), + TypeSystem::TargetLangCode); + } else { + writeDocSnips(s, cppClass->typeEntry()->codeSnips(), + (mode == DocModification::Prepend ? CodeSnip::Beginning : CodeSnip::End), + TypeSystem::TargetLangCode); + } +} + +void DocGenerator::writeFunctionSignature(QTextStream& s, const AbstractMetaClass* cppClass, const AbstractMetaFunction* func) +{ + if (!func->isConstructor()) + s << getClassName(cppClass) << '.'; + s << getFuncName(func) << "(" << parseArgDocStyle(cppClass, func) << ")"; +} + +QString DocGenerator::translateToPythonType(const AbstractMetaType *type, const AbstractMetaClass *cppClass) +{ + QString originalType = translateType(type, cppClass, Generator::ExcludeConst | Generator::ExcludeReference); + QString strType = originalType; + + //remove "*" + strType.remove("*"); + TypeEntry *te = TypeDatabase::instance()->findType(originalType.trimmed()); + if (te) { + return te->targetLangName(); + } else { + //remove <, > + strType.remove(">"); + strType.remove("<"); + + //replace :: + strType.replace("::", "."); + + //Translate ContainerType + if (strType.contains("QList") || strType.contains("QVector")) { + strType.replace("QList", "List of "); + strType.replace("QVector", "List of "); + } else if (strType.contains("QHash") || strType.contains("QMap")) { + strType.remove("QHash"); + strType.remove("QMap"); + QStringList types = strType.split(","); + strType = QString("Dictionary with keys of type %1 and values of type %2.") + .arg(types[0]).arg(types[1]); + } + return strType; + } +} + +void DocGenerator::writeParamerteType(QTextStream &s, const AbstractMetaClass *cppClass, const AbstractMetaArgument *arg) +{ + s << INDENT << ":param " << arg->argumentName() << ": " + << translateToPythonType(arg->type(), cppClass) << endl; +} + +void DocGenerator::writeFunctionParametersType(QTextStream &s, const AbstractMetaClass *cppClass, const AbstractMetaFunction* func) +{ + Indentation indentation(INDENT); + + s << endl; + foreach (AbstractMetaArgument *arg, func->arguments()) { + + if (func->argumentRemoved(arg->argumentIndex() + 1)) + continue; + + writeParamerteType(s, cppClass, arg); + } + + if (!func->isConstructor() && func->type()) { + s << INDENT << ":rtype: " << translateToPythonType(func->type(), cppClass) << endl; + } + s << endl; +} + +void DocGenerator::writeFunction(QTextStream &s, bool writeDoc, const AbstractMetaClass *cppClass, const AbstractMetaFunction* func) +{ + writeFunctionSignature(s, cppClass, func); + s << endl; + + if (writeDoc) { + s << endl; + writeFunctionParametersType(s, cppClass, func); + s << endl; + writeInjectDocumentation(s, DocModification::Prepend, cppClass, func); + writeFormatedText(s, func->documentation(), cppClass); + writeInjectDocumentation(s, DocModification::Append, cppClass, func); + } +} + +void DocGenerator::finishGeneration() +{ + if (classes().isEmpty()) + return; + + QFile input(outputDirectory() + '/' + subDirectoryForPackage(packageName()) + "/index.rst"); + input.open(QIODevice::WriteOnly); + QTextStream s(&input); + + s << ".. module:: " << packageName() << endl << endl; + + QString title = packageName() + " contents"; + s << title << endl; + s << createRepeatedChar(title.length(), '*') << endl << endl; + s << ".. toctree::" << endl; + + /* Avoid showing "Detailed Description for *every* class in toc tree */ + Indentation indentation(INDENT); + s << INDENT << ":maxdepth: 1" << endl << endl; + + QStringList classList; + foreach (AbstractMetaClass *cls, classes()) { + if (!shouldGenerate(cls)) + continue; + classList << getClassName(cls); + } + classList.sort(); + + foreach (QString clazz, classList) + s << INDENT << clazz << endl; + + s << endl << endl; + + s << "Detailed Description" << endl; + s << "--------------------" << endl << endl; + + if (m_moduleDoc.format() == Documentation::Native) { + QtXmlToSphinx x(this, m_moduleDoc.value(), moduleName()); + s << x; + } else { + s << m_moduleDoc.value(); + } +} + +bool DocGenerator::prepareGeneration(const QMap<QString, QString>& args) +{ + BoostPythonGenerator::prepareGeneration(args); + m_libSourceDir = args.value("library-source-dir"); + setOutputDirectory(args.value("documentation-out-dir")); + m_docDataDir = args.value("documentation-data-dir"); + m_codeSnippetDir = args.value("documentation-code-snippets-dir", m_libSourceDir); + + if (m_libSourceDir.isEmpty() || m_docDataDir.isEmpty()) { + ReportHandler::warning("Documentation data dir and/or Qt source dir not informed, " + "documentation will not be extracted from Qt sources."); + return false; + } else { + QtDocParser docParser; + docParser.setPackageName(packageName()); + docParser.setDocumentationDataDirectory(m_docDataDir); + docParser.setLibrarySourceDirectory(m_libSourceDir); + foreach(AbstractMetaClass* cppClass, classes()) { + docParser.fillDocumentation(cppClass); + } + m_moduleDoc = docParser.retrieveModuleDocumentation(); + return true; + } +} + + +QMap<QString, QString> DocGenerator::options() const +{ + QMap<QString, QString> options; + options.insert("library-source-dir", "Directory where library source code is located"); + options.insert("documentation-out-dir", "The directory where the generated documentation files will be written"); + options.insert("documentation-data-dir", "Directory with XML files generated by documentation tool (qdoc3 or Doxygen)"); + options.insert("documentation-code-snippets-dir", "Directory used to search code snippets used by the documentation"); + return options; +} + diff --git a/docgenerator.h b/docgenerator.h new file mode 100644 index 000000000..cef7fa7a3 --- /dev/null +++ b/docgenerator.h @@ -0,0 +1,212 @@ +/* + * This file is part of the Boost Python Generator project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * + * Contact: PySide team <contact@pyside.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ +#ifndef DOCGENERATOR_H +#define DOCGENERATOR_H + +#include "boostpythongenerator.h" +#include <QtCore/QStack> + +class QXmlStreamReader; +class DocGenerator; + +class QtXmlToSphinx +{ +public: + struct TableCell + { + short rowSpan; + short colSpan; + QString data; + + TableCell(const QString& text = QString()) : rowSpan(0), colSpan(0), data(text) {} + TableCell(const char* text) : rowSpan(0), colSpan(0), data(text) {} + }; + + typedef QList<TableCell> TableRow; + class Table : public QList<TableRow> + { + public: + Table() : m_hasHeader(false), m_normalized(false) + { + } + + void enableHeader(bool enable) + { + m_hasHeader = enable; + } + + bool hasHeader() const + { + return m_hasHeader; + } + + void normalize(); + + bool isNormalized() const + { + return m_normalized; + } + + void clear() { + m_normalized = false; + QList<TableRow>::clear(); + } + + private: + bool m_hasHeader; + bool m_normalized; + }; + + QtXmlToSphinx(DocGenerator* generator, const QString& doc, const QString& context = QString()); + + QString result() const + { + return m_result; + } + +private: + QString transform(const QString& doc); + + void handleHeadingTag(QXmlStreamReader& reader); + void handleParaTag(QXmlStreamReader& reader); + void handleItalicTag(QXmlStreamReader& reader); + void handleBoldTag(QXmlStreamReader& reader); + void handleArgumentTag(QXmlStreamReader& reader); + void handleSeeAlsoTag(QXmlStreamReader& reader); + void handleSnippetTag(QXmlStreamReader& reader); + void handleDotsTag(QXmlStreamReader& reader); + void handleLinkTag(QXmlStreamReader& reader); + void handleImageTag(QXmlStreamReader& reader); + void handleListTag(QXmlStreamReader& reader); + void handleTermTag(QXmlStreamReader& reader); + void handleSuperScriptTag(QXmlStreamReader& reader); + void handleQuoteFileTag(QXmlStreamReader& reader); + + // table tagsvoid QtXmlToSphinx::handleValueTag(QXmlStreamReader& reader) + + void handleTableTag(QXmlStreamReader& reader); + void handleRowTag(QXmlStreamReader& reader); + void handleItemTag(QXmlStreamReader& reader); + void handleRawTag(QXmlStreamReader& reader); + void handleCodeTag(QXmlStreamReader& reader); + + void handleIgnoredTag(QXmlStreamReader& reader); + void handleUnknownTag(QXmlStreamReader& reader); + void handleUselessTag(QXmlStreamReader& reader); + void handleAnchorTag(QXmlStreamReader& reader); + + typedef void (QtXmlToSphinx::*TagHandler)(QXmlStreamReader&); + QHash<QString, TagHandler> m_handlerMap; + QStack<TagHandler> m_handlers; + QTextStream m_output; + QString m_result; + + QStack<QString*> m_buffers; + + + Table m_currentTable; + bool m_tableHasHeader; + QString m_context; + DocGenerator* m_generator; + bool m_insideBold; + bool m_insideItalic; + QString m_lastTagName; + QString m_opened_anchor; + + QString readFromLocation(QString& location, QString& identifier); + void pushOutputBuffer(); + QString popOutputBuffer(); + void writeTable(Table& table); +}; + +inline QTextStream& operator<<(QTextStream& s, const QtXmlToSphinx& xmlToSphinx) +{ + return s << xmlToSphinx.result(); +} + +QTextStream& operator<<(QTextStream& s, const QtXmlToSphinx::Table &table); + +/** +* The DocGenerator generates documentation from library being binded. +*/ +class DocGenerator : public BoostPythonGenerator +{ +public: + virtual GeneratorType type() const + { + return DocumentationType; + } + + QString libSourceDir() const + { + return m_libSourceDir; + } + + virtual bool prepareGeneration(const QMap<QString, QString>& args); + + const char* name() const + { + return "DocGenerator"; + } + + QMap<QString, QString> options() const; + + QString codeSnippetDir() const + { + return m_codeSnippetDir; + } + +protected: + QString fileNameForClass(const AbstractMetaClass* cppClass) const; + void generateClass(QTextStream& s, const AbstractMetaClass* cppClass); + void finishGeneration(); +private: + void writeEnums(QTextStream& s, const AbstractMetaClass* cppClass); + + void writeFields(QTextStream &s, const AbstractMetaClass *cppClass); + void writeArguments(QTextStream &s, const AbstractMetaClass *cppClass, const AbstractMetaFunction *func); + void writeFunctionBrief(QTextStream &s, const AbstractMetaClass *cppClass, const AbstractMetaFunction *cppFunction); + void writeFunctionSignature(QTextStream& s, const AbstractMetaClass* cppClass, const AbstractMetaFunction* func); + void writeFunction(QTextStream& s, bool writeDoc, const AbstractMetaClass* cppClass, const AbstractMetaFunction* func); + void writeFunctionParametersType(QTextStream &s, const AbstractMetaClass *cppClass, const AbstractMetaFunction* func); + void writeFunctionList(QTextStream &se, const QString &content, const AbstractMetaClass *cppClass); + void writeParamerteType(QTextStream &s, const AbstractMetaClass *cppClass, const AbstractMetaArgument *arg); + + void writeConstructors(QTextStream &s, const AbstractMetaClass *cppClass); + void writeFormatedText(QTextStream& s, const Documentation& doc, const AbstractMetaClass* metaclass = 0); + void writeInjectDocumentation(QTextStream &s, DocModification::Mode mode, const AbstractMetaClass *cppClass, const AbstractMetaFunction *func); + void writeDocSnips(QTextStream &s, const CodeSnipList &codeSnips, CodeSnip::Position position, TypeSystem::Language language); + + + QString parseArgDocStyle(const AbstractMetaClass *cppClass, const AbstractMetaFunction *func); + QString parseFunctionDeclaration(const QString &data, const AbstractMetaClass *cppClass); + QString translateToPythonType(const AbstractMetaType *type, const AbstractMetaClass *cppClass); + + QString m_docDataDir; + QString m_libSourceDir; + QString m_codeSnippetDir; + QStringList m_functionList; + Documentation m_moduleDoc; +}; + +#endif // DOCGENERATOR_H diff --git a/hppgenerator.cpp b/hppgenerator.cpp new file mode 100644 index 000000000..4e7da1120 --- /dev/null +++ b/hppgenerator.cpp @@ -0,0 +1,219 @@ +/* + * This file is part of the Boost Python Generator project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * + * Contact: PySide team <contact@pyside.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ +#include "hppgenerator.h" +#include <apiextractor/reporthandler.h> + +#include <QtCore/QDir> +#include <QtCore/QTextStream> +#include <QtCore/QVariant> +#include <QtCore/QRegExp> +#include <QtCore/QDebug> + +static Indentor INDENT; + +QString HppGenerator::fileNameForClass(const AbstractMetaClass *cppClass) const +{ + return getWrapperName(cppClass) + QLatin1String(".hpp"); +} + +void HppGenerator::writeCopyCtor(QTextStream &s, const AbstractMetaClass *cppClass) +{ + s << INDENT << getWrapperName(cppClass) << "(const " << cppClass->qualifiedCppName() << "& self)" + << " : " << cppClass->qualifiedCppName() << "(self)" << endl + << INDENT << "{" << endl + << INDENT << "}" << endl; +} + +void HppGenerator::generateClass(QTextStream &s, const AbstractMetaClass *cppClass) +{ + ReportHandler::debugSparse("Generating header for " + cppClass->fullName()); + Indentation indent(INDENT); + + // write license comment + s << licenseComment() << endl; + + QString wrapperName = HppGenerator::getWrapperName(cppClass); + // Header + s << "#ifndef __" << wrapperName.toUpper() << "__" << endl; + s << "#define __" << wrapperName.toUpper() << "__" << endl << endl; + + s << "#include <pyside.hpp>" << endl; + //Includes + if (cppClass->typeEntry()->include().isValid()) + s << cppClass->typeEntry()->include().toString() << endl << endl; + + s << "using namespace PySide;" << endl << endl; + + if (!cppClass->isPolymorphic() || cppClass->hasPrivateDestructor() || cppClass->isNamespace()) + s << "namespace " << wrapperName << " {" << endl << endl; + + if (cppClass->isNamespace()) { + s << INDENT << "struct Namespace {};" << endl; + } else { + QString className; + bool create_wrapper = canCreateWrapperFor(cppClass); + // detect the held type + QString held_type = cppClass->typeEntry()->heldTypeValue(); + if (held_type.isEmpty() && create_wrapper) + held_type = "qptr"; + + writeCodeSnips(s, cppClass->typeEntry()->codeSnips(), + CodeSnip::Declaration, TypeSystem::NativeCode); + + if (cppClass->isPolymorphic() && !cppClass->hasPrivateDestructor()) { + if (!held_type.isEmpty()) { + s << "// held type forward decalration" << endl; + s << "template<typename T> class " << held_type << ';' << endl; + } + + // Class + s << "class PYSIDE_LOCAL " << wrapperName; + if (create_wrapper) { + s << " : public " << cppClass->qualifiedCppName() << ", public boost::python::wrapper<"; + s << cppClass->qualifiedCppName() << '>'; + } + s << endl; + s << "{" << endl; + } + + writeCodeSnips(s, cppClass->typeEntry()->codeSnips(), + CodeSnip::Declaration, TypeSystem::ShellDeclaration); + + if (cppClass->isPolymorphic() && !cppClass->hasPrivateDestructor()) { + s << endl << "private:" << endl; + + if (cppClass->hasPrivateDestructor()) + className = cppClass->qualifiedCppName(); + else + className = wrapperName; + } else { + className = cppClass->qualifiedCppName(); + } + + // print the huge boost::python::class_ typedef + s << INDENT << "typedef boost::python::class_< " << className; + + writeBaseClass(s, cppClass); + + if (!held_type.isEmpty()) + s << ", PySide::" << held_type << " < " << className << ", PySide::qptr_base::avoid_cache > "; + + if (!isCopyable(cppClass)) + s << ", boost::noncopyable"; + + s << " > class_type;" << endl; + + if (cppClass->isPolymorphic() && !cppClass->hasPrivateDestructor()) { + s << "public:" << endl; + + if (isCopyable(cppClass)) + writeCopyCtor(s, cppClass); + + foreach (AbstractMetaFunction *func, filterFunctions(cppClass)) + writeFunction(s, func); + + if (create_wrapper) { + //destructor + s << INDENT << "~" << wrapperName << "();" << endl; + + if (cppClass->isQObject() && (cppClass->name() != "QObject")) + s << INDENT << "using QObject::parent;" << endl; + } + } + + writeCodeSnips(s, cppClass->typeEntry()->codeSnips(), + CodeSnip::End, TypeSystem::ShellDeclaration); + + } + + QString staticKeyword = cppClass->isNamespace() ? QLatin1String("") : QLatin1String("static "); + s << INDENT; + if (cppClass->isPolymorphic() && !cppClass->hasPrivateDestructor()) { + s << "//static member used to export class" << endl; + s << INDENT << staticKeyword; + } + s << "void define_python_class() throw();" << endl << endl; + + writeCodeSnips(s, cppClass->typeEntry()->codeSnips(), + CodeSnip::PrototypeInitialization, TypeSystem::NativeCode); + + + s << "};" << endl << endl; + s << "#endif // __" << wrapperName.toUpper() << "__" << endl << endl; +} + +void HppGenerator::writeFunction(QTextStream &s, const AbstractMetaFunction* func) +{ + // pure virtual functions need a default implementation + if ((func->isPrivate() && !func->isConstructor()) || (func->isModifiedRemoved() && !func->isAbstract())) + return; + + // do not write copy ctors here. + if (func->isCopyConstructor()) + return; + + if (func->isConstructor() || func->isAbstract() || func->isVirtual()) { + if (func->isVirtual() && !func->isAbstract() && !func->isConstructor() + && !func->ownerClass()->hasPrivateDestructor() + && func->implementingClass() == func->ownerClass()) { + s << INDENT << "static " << signatureForDefaultVirtualMethod(func, "", "_default", Generator::SkipName) << ';' << endl; + } + + s << INDENT << functionSignature(func, "", "", Generator::OriginalTypeDescription | Generator::SkipName); + if (func->isModifiedRemoved() && func->isAbstract()) + writeDefaultImplementation(s, func); + else + s << ';' << endl; + } +} + +void HppGenerator::writeDefaultImplementation(QTextStream& s, const AbstractMetaFunction* func) +{ + QString returnValue; + if (func->type()) { + if (func->type()->isObject() || func->type()->isQObject() || func->type()->name() == "void") + returnValue = "0"; + else + returnValue = functionReturnType(func) + "()"; + } + s << " { return " << returnValue << "; }" << endl; +} + +void HppGenerator::writeBaseClass(QTextStream& s, const AbstractMetaClass* cppClass) +{ + if (!cppClass->isNamespace() && !cppClass->isInterface()) { + QStringList baseClass = getBaseClasses(cppClass); + + if (baseClass.isEmpty()) { + const ComplexTypeEntry *type = cppClass->typeEntry(); + if (cppClass->name() != type->defaultSuperclass()) { + QString sc = type->defaultSuperclass(); + if (!sc.isEmpty()) + s << ", python::bases< " << sc << "> "; + } + } else { + s << ", boost::python::bases< " << baseClass.join(", ") << " > "; + } + } +} + diff --git a/hppgenerator.h b/hppgenerator.h new file mode 100644 index 000000000..8e0f5f03b --- /dev/null +++ b/hppgenerator.h @@ -0,0 +1,51 @@ +/* + * This file is part of the Boost Python Generator project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * + * Contact: PySide team <contact@pyside.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#ifndef HPPGENERATOR_H +#define HPPGENERATOR_H + +#include "boostpythongenerator.h" + +/** +* The HppGenerator generate the declarations of boost::python bindings classes. +*/ +class HppGenerator : public BoostPythonGenerator +{ +protected: + QString fileNameForClass(const AbstractMetaClass* cppClass) const; + void generateClass(QTextStream& s, const AbstractMetaClass* cppClass); + void finishGeneration() {} + const char* name() const + { + return "HppGenerator"; + } +private: + void writeFunction(QTextStream& s, const AbstractMetaFunction* func); + void writePureVirtualEmptyImpl(QTextStream& , const AbstractMetaFunction* func); + void writeBaseClass(QTextStream& s, const AbstractMetaClass* cppClass); + void writeCopyCtor(QTextStream &s, const AbstractMetaClass* cppClass); + void writeDefaultImplementation(QTextStream& s, const AbstractMetaFunction* func); +}; + +#endif // HPPGENERATOR_H + diff --git a/main.cpp b/main.cpp new file mode 100644 index 000000000..9560effc6 --- /dev/null +++ b/main.cpp @@ -0,0 +1,52 @@ +/* + * This file is part of the Boost Python Generator project. + * + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). + * + * Contact: PySide team <contact@pyside.org> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ + +#include <QtCore/QCoreApplication> +#include <apiextractor/apiextractor.h> +#include "hppgenerator.h" +#include "cppgenerator.h" +#include "hppgenerator.h" +#include "convertergenerator.h" +#include "docgenerator.h" +#include "boostpythongeneratorversion.h" +#include <iostream> + +void showVersion(const char* apiextractor_version) { + using namespace std; + + cout << "BoostPythonGenerator v" BOOSTPYTHONGENERATOR_VERSION << " using " << apiextractor_version << endl; + cout << "Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)" << endl; +} + +int main(int argc, char *argv[]) +{ + QCoreApplication app(argc, argv); // needed by qxmlpatterns + + ApiExtractor extractor(argc, argv); + extractor.addGenerator(new HppGenerator); + extractor.addGenerator(new CppGenerator); + extractor.addGenerator(new ConverterGenerator); + extractor.addGenerator(new DocGenerator); + extractor.setVersionHandler(&showVersion); + return extractor.exec(); +} diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt new file mode 100644 index 000000000..9099adff8 --- /dev/null +++ b/tests/CMakeLists.txt @@ -0,0 +1,9 @@ +project(sphinxtabletest) + +# TODO +set(sphinxtabletest_SRC sphinxtabletest.cpp) +qt4_automoc(${sphinxtabletest_SRC}) +include_directories(${QT_INCLUDE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ${boostpythongenerator_SOURCE_DIR}) +add_executable(sphinxtabletest ${sphinxtabletest_SRC}) +target_link_libraries(sphinxtabletest ${QT_QTTEST_LIBRARY} ${APIEXTRACTOR_LIBRARY} libboostpythongenerator) +add_test("sphinxtable" sphinxtabletest) diff --git a/tests/Makefile b/tests/Makefile new file mode 100644 index 000000000..054d6f576 --- /dev/null +++ b/tests/Makefile @@ -0,0 +1,12 @@ +all: + (cd libfoo; $(MAKE)) + (cd foobinding; $(MAKE)) + + +test: + LD_LIBRARY_PATH=$(LD_LIBRARY_PATH):$(PWD)/libfoo PYTHONPATH=$(PYTHONPATH):$(PWD)/foobinding/foo python foo_test.py + +clean: + (cd libfoo; $(MAKE) clean) + (cd foobinding; $(MAKE) clean) + diff --git a/tests/foo_test.py b/tests/foo_test.py new file mode 100644 index 000000000..45b7e80e7 --- /dev/null +++ b/tests/foo_test.py @@ -0,0 +1,105 @@ + +'''Test cases for virtual methods called through generated bindings''' + +import unittest +try: + from foo import Foo, Bar +except: + import sys + print 'You need to set correct paths for libfoo and foo bindings' + import os + sys.exit(1) + + +class DerivedFoo(Foo): + + def __init__(self): + Foo.__init__(self) + + def pureVirtual(self): + print 'DerivedFoo.pureVirtual' + + +class VirtualMethods(unittest.TestCase): + '''Test case for virtual methods''' + + def setUp(self): + self.foo = Foo() + self.bar = Bar() + self.derivedfoo = DerivedFoo() + + def tearDown(self): + self.foo = None + self.bar = None + self.derivedfoo = None + + def testDerivedClassVirtualMethod(self): + '''Test reinplemented virtual methods from derived class''' + called = True + try: + self.bar.unpureVirtual() + self.bar.pureVirtual() + except: + called = False + self.assertTrue(called) + + def testBaseClassVirtualMethod(self): + '''Test virtual method from base class''' + called = True + try: + self.foo.unpureVirtual() + except: + called = False + self.assertTrue(called) + + + def testBaseClassPureVirtualMethod(self): + '''Test pure virtual method from base class''' + called = False + try: + self.foo.pureVirtual() + except: + called = False + self.assertFalse(called) + + def testBaseClassIndirectCallToUnpureVirtualMethod(self): + '''Test call to unpure virtual method from C++ to Python''' + called = True + try: + self.foo.unpureVirtual() + except: + called = False + self.assertTrue(called) + + def testDerivedClassIndirectCallToUnpureVirtualMethod(self): + '''Test call to unpure virtual method from C++ to Python''' + called = True + try: + self.bar.unpureVirtual() + except: + called = False + self.assertTrue(called) + + def testCppDerivedClassIndirectCallToPureVirtualMethod(self): + '''Test call to pure virtual method from C++ to Python''' + called = False + try: + self.bar.callPureVirtual() + except: + called = False + self.assertFalse(called) + + + def testDerivedClassIndirectCallToPureVirtualMethod(self): + '''Test call to pure virtual method from C++ to Python''' + called = False + try: + self.derivedfoo.callPureVirtual() + except: + called = False + self.assertFalse(called) + + +if __name__ == '__main__': + unittest.main() + diff --git a/tests/foobinding/Makefile b/tests/foobinding/Makefile new file mode 100644 index 000000000..30909aeeb --- /dev/null +++ b/tests/foobinding/Makefile @@ -0,0 +1,13 @@ +all: generate + (cd foo; $(MAKE)) + +generate: + boostpythongenerator --disable-named-arg global.h \ + --include-paths=`pwd`/../libfoo \ + --typesystem-paths=. --output-directory=. \ + typesystem_foo.xml + +clean: + rm *.log .preprocessed.tmp foo/*.hpp foo/*.cpp -rf + (cd foo; $(MAKE) clean) + diff --git a/tests/foobinding/foo/Makefile b/tests/foobinding/foo/Makefile new file mode 100644 index 000000000..4f6896f46 --- /dev/null +++ b/tests/foobinding/foo/Makefile @@ -0,0 +1,21 @@ +CXX_FLAGS=-DBOOST_PYTHON_NO_PY_SIGNATURES -g -fPIC -I/usr/include/python2.5 -I../../libfoo `pkg-config pyside --cflags` +CXX_LDFLAGS=-DBOOST_PYTHON_NO_PY_SIGNATURES -fPIC -shared -L../../libfoo -lfoo `pkg-config pyside --libs` + +all: foo_wrapper.o bar_wrapper.o foo_globals_wrapper.o foo_module_wrapper.o + g++ $(CXX_LDFLAGS) bar_wrapper.o foo_wrapper.o foo_globals_wrapper.o foo_module_wrapper.o -Wl,-soname,foo.so -o foo.so + +foo_wrapper.o: foo_wrapper.cpp foo_wrapper.hpp + g++ $(CXX_FLAGS) foo_wrapper.cpp -c + +bar_wrapper.o: bar_wrapper.cpp bar_wrapper.hpp + g++ $(CXX_FLAGS) bar_wrapper.cpp -c + +foo_globals_wrapper.o: foo_globals_wrapper.cpp + g++ $(CXX_FLAGS) foo_globals_wrapper.cpp -c + +foo_module_wrapper.o: foo_module_wrapper.cpp + g++ $(CXX_FLAGS) foo_module_wrapper.cpp -c + +clean: + rm *.o *.so -rf + diff --git a/tests/foobinding/global.h b/tests/foobinding/global.h new file mode 100644 index 000000000..a23601a31 --- /dev/null +++ b/tests/foobinding/global.h @@ -0,0 +1,2 @@ +#include "foo.h" +#include "bar.h" diff --git a/tests/foobinding/typesystem_foo.xml b/tests/foobinding/typesystem_foo.xml new file mode 100644 index 000000000..e4289e406 --- /dev/null +++ b/tests/foobinding/typesystem_foo.xml @@ -0,0 +1,6 @@ +<?xml version="1.0"?> +<typesystem package="foo"> + <object-type name="Foo"/> + <object-type name="Bar"/> +</typesystem> + diff --git a/tests/libfoo/Makefile b/tests/libfoo/Makefile new file mode 100644 index 000000000..eaf8f62f4 --- /dev/null +++ b/tests/libfoo/Makefile @@ -0,0 +1,15 @@ +all: foo.o bar.o + g++ -fPIC -shared foo.o bar.o -o libfoo.so + +foo.o: foo.h foo.cpp + g++ -fPIC foo.cpp -c + +bar.o: bar.h bar.cpp + g++ -fPIC bar.cpp -c + +test: main.cpp + g++ main.cpp -L. -lfoo -I. -o footest + +clean: + rm *.o *.so footest -rf + diff --git a/tests/libfoo/bar.cpp b/tests/libfoo/bar.cpp new file mode 100644 index 000000000..a8f9712a4 --- /dev/null +++ b/tests/libfoo/bar.cpp @@ -0,0 +1,15 @@ +#include <iostream> +#include "bar.h" + +using namespace std; + +void Bar::pureVirtual() +{ + cout << "Bar::pureVirtual()" << endl; +} + +void Bar::unpureVirtual() +{ + cout << "Bar::unpureVirtual()" << endl; +} + diff --git a/tests/libfoo/bar.h b/tests/libfoo/bar.h new file mode 100644 index 000000000..4a73c2deb --- /dev/null +++ b/tests/libfoo/bar.h @@ -0,0 +1,15 @@ +#ifndef BAR_H +#define BAR_H + +#include "foo.h" + +class Bar : public Foo +{ +public: + Bar() {} + virtual ~Bar() {} + virtual void pureVirtual(); + virtual void unpureVirtual(); +}; +#endif // BAR_H + diff --git a/tests/libfoo/foo.cpp b/tests/libfoo/foo.cpp new file mode 100644 index 000000000..22be35018 --- /dev/null +++ b/tests/libfoo/foo.cpp @@ -0,0 +1,17 @@ +#include <iostream> +#include "foo.h" + +using namespace std; + +void Foo::unpureVirtual() +{ + cout << "Foo::unpureVirtual()" << endl; +} + +void Foo::callPureVirtual() +{ + cout << "Foo::callPureVirtual() -- calling pureVirtual..." << endl; + this->pureVirtual(); + cout << " -- pureVirtual called." << endl; +} + diff --git a/tests/libfoo/foo.h b/tests/libfoo/foo.h new file mode 100644 index 000000000..585b844f7 --- /dev/null +++ b/tests/libfoo/foo.h @@ -0,0 +1,14 @@ +#ifndef FOO_H +#define FOO_H + +class Foo +{ +public: + Foo() {} + virtual ~Foo() {} + virtual void pureVirtual() = 0; + virtual void unpureVirtual(); + virtual void callPureVirtual(); +}; +#endif // FOO_H + diff --git a/tests/libfoo/main.cpp b/tests/libfoo/main.cpp new file mode 100644 index 000000000..6f410addb --- /dev/null +++ b/tests/libfoo/main.cpp @@ -0,0 +1,15 @@ +#include "foo.h" +#include "bar.h" + +int +main(int argv, char **argc) +{ + Bar bar; + + bar.unpureVirtual(); + bar.pureVirtual(); + bar.callPureVirtual(); + + return 0; +} + diff --git a/tests/sphinxtabletest.cpp b/tests/sphinxtabletest.cpp new file mode 100644 index 000000000..058a3b522 --- /dev/null +++ b/tests/sphinxtabletest.cpp @@ -0,0 +1,269 @@ +/* +* This file is part of the Boost Python Generator project. +* +* Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +* +* Contact: PySide team <contact@pyside.org> +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +* 02110-1301 USA +* +*/ + +#include "sphinxtabletest.h" +#include "docgenerator.h" +#include <QtTest/QTest> +#include <QDebug> + +QString SphinxTableTest::transformXml(const char* xml) +{ + return QtXmlToSphinx(m_generator, xml).result(); +} + +void SphinxTableTest::setUp() +{ + m_generator = new DocGenerator; +} + +void SphinxTableTest::tearDown() +{ + delete m_generator; +} + +void SphinxTableTest::testEmptyString() +{ + const char* xml = ""; + QCOMPARE(transformXml(xml), QString()); +} + +void SphinxTableTest::testSimpleTable() +{ + const char* xml = "\ +<table>\ + <header>\ + <item>\ + <para>Header 1</para>\ + </item>\ + <item>\ + <para>Header 2</para>\ + </item>\ + </header>\ + <row>\ + <item>\ + <para>1 1</para>\ + </item>\ + <item>\ + <para>1 2</para>\ + </item>\ + </row>\ + <row>\ + <item>\ + <para>2 1</para>\ + </item>\ + <item>\ + <para>2 2</para>\ + </item>\ + </row>\ +</table>"; + QCOMPARE(transformXml(xml), QString("\ + +--------+--------+\n\ + |Header 1|Header 2|\n\ + +--------+--------+\n\ + |1 1 |1 2 |\n\ + +--------+--------+\n\ + |2 1 |2 2 |\n\ + +--------+--------+\n\ +\n")); +} + +void SphinxTableTest::testColSpan() +{ + const char* xml = "\ +<table>\ + <header>\ + <item>\ + <para>Header 1</para>\ + </item>\ + <item>\ + <para>Header 2</para>\ + </item>\ + </header>\ + <row>\ + <item colspan=\"2\">\ + <para>I'm a big text!</para>\ + </item>\ + </row>\ + <row>\ + <item>\ + <para>2 1</para>\ + </item>\ + <item>\ + <para>2 2</para>\ + </item>\ + </row>\ +</table>"; + QCOMPARE(transformXml(xml), QString("\ + +---------------+--------+\n\ + |Header 1 |Header 2|\n\ + +---------------+--------+\n\ + |I'm a big text! |\n\ + +---------------+--------+\n\ + |2 1 |2 2 |\n\ + +---------------+--------+\n\ +\n")); +} + + +void SphinxTableTest::testRowSpan() +{ + const char* xml = "\ +<table>\ + <header>\ + <item>\ + <para>Header 1</para>\ + </item>\ + <item>\ + <para>Header 2</para>\ + </item>\ + </header>\ + <row>\ + <item rowspan=\"2\">\ + <para>1.1</para>\ + </item>\ + <item>\ + <para>1.2</para>\ + </item>\ + </row>\ + <row>\ + <item>\ + <para>2 2</para>\ + </item>\ + </row>\ +</table>"; + QCOMPARE(transformXml(xml), QString("\ + +--------+--------+\n\ + |Header 1|Header 2|\n\ + +--------+--------+\n\ + |1.1 |1.2 |\n\ + + +--------+\n\ + | |2 2 |\n\ + +--------+--------+\n\ +\n")); +} + + +void SphinxTableTest::testComplexTable() +{ + const char* xml = "\ +<table>\ + <header>\ + <item>\ + <para>Header 1</para>\ + </item>\ + <item>\ + <para>Header 2</para>\ + </item>\ + <item>\ + <para>Header 3</para>\ + </item>\ + </header>\ + <row>\ + <item rowspan=\"2\">\ + <para>1.1</para>\ + </item>\ + <item colspan=\"2\">\ + <para>1.2</para>\ + </item>\ + </row>\ + <row>\ + <item>\ + <para>2 2</para>\ + </item>\ + <item>\ + <para>2 3</para>\ + </item>\ + </row>\ +</table>"; + QCOMPARE(transformXml(xml), QString("\ + +--------+--------+--------+\n\ + |Header 1|Header 2|Header 3|\n\ + +--------+--------+--------+\n\ + |1.1 |1.2 |\n\ + + +--------+--------+\n\ + | |2 2 |2 3 |\n\ + +--------+--------+--------+\n\ +\n")); +} + +void SphinxTableTest::testRowSpan2() +{ + const char* xml = "\ +<table>\ + <header>\ + <item><para>h1</para></item>\ + <item><para>h2</para></item>\ + <item><para>h3</para></item>\ + <item><para>h4</para></item>\ + </header>\ + <row>\ + <item rowspan=\"6\"><para>A</para></item>\ + <item rowspan=\"6\"><para>B</para></item>\ + <item><para>C</para></item>\ + <item><para>D</para></item>\ + </row>\ + <row>\ + <item><para>E</para></item>\ + <item><para>F</para></item>\ + </row>\ + <row>\ + <item><para>E</para></item>\ + <item><para>F</para></item>\ + </row>\ + <row>\ + <item><para>E</para></item>\ + <item><para>F</para></item>\ + </row>\ + <row>\ + <item><para>E</para></item>\ + <item><para>F</para></item>\ + </row>\ + <row>\ + <item><para>E</para></item>\ + <item><para>F</para></item>\ + </row>\ +</table>"; + QCOMPARE(transformXml(xml), QString("\ + +--+--+--+--+\n\ + |h1|h2|h3|h4|\n\ + +--+--+--+--+\n\ + |A |B |C |D |\n\ + + + +--+--+\n\ + | | |E |F |\n\ + + + +--+--+\n\ + | | |E |F |\n\ + + + +--+--+\n\ + | | |E |F |\n\ + + + +--+--+\n\ + | | |E |F |\n\ + + + +--+--+\n\ + | | |E |F |\n\ + +--+--+--+--+\n\ +\n")); +} + + + +QTEST_APPLESS_MAIN( SphinxTableTest ) + +#include "sphinxtabletest.moc" diff --git a/tests/sphinxtabletest.h b/tests/sphinxtabletest.h new file mode 100644 index 000000000..163cc5337 --- /dev/null +++ b/tests/sphinxtabletest.h @@ -0,0 +1,48 @@ +/* +* This file is part of the Boost Python Generator project. +* +* Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +* +* Contact: PySide team <contact@pyside.org> +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License +* version 2 as published by the Free Software Foundation. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +* 02110-1301 USA +* +*/ + +#ifndef SPHINXTABLETEST_H +#define SPHINXTABLETEST_H + +#include <QObject> + +class DocGenerator; +class SphinxTableTest : public QObject { + Q_OBJECT + +private slots: + void setUp(); + void tearDown(); + void testEmptyString(); + void testSimpleTable(); + void testRowSpan(); + void testColSpan(); + void testComplexTable(); + void testRowSpan2(); +private: + DocGenerator* m_generator; + + QString transformXml(const char* xml); +}; + +#endif |