[Kde-bindings] Progress report on Py*5 binding generation

Shaheed Haque srhaque at theiet.org
Thu Apr 21 23:29:26 UTC 2016


Hi Steve,

On 21 April 2016 at 23:29, Stephen Kelly <steveire at gmail.com> wrote:

> Shaheed Haque wrote:
>
> >> To that end, in addition to sip/kselectionproxymodel.sip I now have:
> >>
> >>  $ cat sip/kitemmodelsmod.sip
> >>
> >>  %Module PyKDE5.kitemmodels
> >>
> >>  %ModuleHeaderCode
> >>  #pragma GCC visibility push(default)
> >>  %End
> >>
> >>  %Import QtCore/QtCoremod.sip
> >>
> >>  %Include kselectionproxymodel.sip
> >>
> >>
> >> Is this what I am supposed to do? Here is the output I get when
> >> attempting to use it:
> >
> > Yeeessss...it is a bit tricky...
> >
> > First, if you use the "-v" flag to the sip_compiler.py, it will show you
> > the exact command like for SIP and later the C++ compiler/linker. That
> > might help you see what is going on.
>
> Yes, that's good, thanks.
>
> > The %Feature thing you may be able to ignore. It is used along with the
> > SIP compiler's -x (lower case X) option to try to work around the problem
> > where in KF5, you often get AAAmod.sip and BBBmod.sip which need to
> import
> > each other
>
> You have alluded to this several times, but you have never stated which
> modules form a cycle like this. Which KF5 libraries have this cycle?
>

I think there are many of these. One example is this one:

sip/KIOCore/KIOCoremod.sip:%Import KIOCore/kio/kiomod.sip
sip/KIOCore/kio/kiomod.sip:%Import KIOCore/KIOCoremod.sip

This was the first one I happened on, and there are others.  I have not
tried to track down the exact root cause but I guess that this does not
often show up in normal C++ development because of the effect of header
guard macros.


> > ...I used the SIP compiler's -X (upper case X) option to extract the
> > %Extract data, and generate the "-I foo -I bar" paths for the C++
> > compiler. So, you can just put a %Extract section like this into your
> > file:
> >
> > %Extract(id=includes)
> > /usr/include/KF5/KDBusAddons
> > /usr/include/x86_64-linux-gnu/qt5/QtCore
> > /usr/include/x86_64-linux-gnu/qt5/QtDBus
> > %End
>
> As the file might be generated by cmake, this might work, but it seems
> easier to pass the include directories on the command line.  The includes
> will be different on each platform.
>

That is correct, but AFAIK, this is just a build time dependency. Once the
modules are built, nobody will care. However, I'm sensitive that my
ignorance about how CMake is used by packagers might make the current
approach suboptimal.


> After hacking the sip_compiler a bit I can do this:
>
>  ./sip_compiler.py -v --includes "/usr/include/x86_64-linux-
>  gnu/qt5,/usr/include/x86_64-linux-gnu/qt5/QtCore" --select
>  @kitemmodelsmod.sip sip cxx
>
>
> My hacking is quite dirty, but you can extract feature requests from it,
> namely, don't require the include/extract stuff.
>

For me, and for now at least, it is important to be able to run on a large
body of code without generating anything by hand so generating xxxmod.sip
files by hand (with or without the %Extract) is not practical. Perhaps a
CLI option would be acceptable?


> The makefile manipulation stuff can be ignored, because the SIP generated
> makefiles won't play nicely with cmake, but should be easily able to
> generate our own makefiles/ninja build files.
>

OK. Once we get there, then maybe some of the stuff above might be worth
reconsidering too.


> diff --git a/sip_generation/sip_compiler.py
> b/sip_generation/sip_compiler.py
> index 057dfe9..715f9c4 100755
> --- a/sip_generation/sip_compiler.py
> +++ b/sip_generation/sip_compiler.py
> @@ -133,20 +133,23 @@ class CxxDriver(object):
>                          if line.startswith("%Module"):
>                              feature_list = os.path.join(self.input_dir,
> "modules.features")
>                              tmp = set()
> -                            with open(feature_list, "rU") as f:
> -                                for feature in f:
> -                                    if feature not in tmp:
> -                                        tmp.add(feature)
> -                                        o.write(feature)
> +                            # with open(feature_list, "rU") as f:
> +                            #     for feature in f:
> +                            #         if feature not in tmp:
> +                            #             tmp.add(feature)
> +                            #             o.write(feature)
>              logger.debug(modified_source)
>              feature = sip_file.replace(os.path.sep, "_").replace(".", "_")
> -            cmd = [self.sipconfig.sip_bin, "-c", full_output, "-b",
> build_file, "-x", feature, "-X",
> -                   INCLUDES_EXTRACT + ":" + module_includes] +
> self.pyqt_sip_flags + sip_roots + [modified_source]
> +            cmd = [self.sipconfig.sip_bin, "-c", full_output, "-b",
> build_file, "-x", feature] + self.pyqt_sip_flags + sip_roots +
> [modified_source]
>              self._run_command(cmd)
>              #
>              # Create the Makefile.
>              #
> -            module_includes = self.includes + open(module_includes,
> "rU").read().split("\n")
> +            module_includes = self.includes
> +            try:
> +              module_includes += open(module_includes,
> "rU").read().split("\n")
> +            except:
> +              pass
>              self.sipconfig._macros["INCDIR"] = " ".join(module_includes)
>              makefile = sipconfig.SIPModuleMakefile(self.sipconfig,
> build_file, makefile=make_file)
>              #
> @@ -155,6 +158,9 @@ class CxxDriver(object):
>              # ".dll" extension on Windows).
>              #makefile.extra_libs = ["KParts"]
>              #
> +            makefile.extra_cxxflags = ["-std=c++14"]
> +            makefile.extra_lflags = ["-std=c++14", "-Wl,--fatal-warnings",
> "-Wl,--no-undefined"]
> +            makefile.extra_libs = ["m /usr/lib/x86_64-linux-
> gnu/libQt5Core.so /usr/lib/x86_64-linux-gnu/libKF5ItemModels.so
> /usr/lib/x86_64-linux-gnu/libpython2.7.so"]
>              makefile.generate()
>              self._run_command(["make", "-f", os.path.basename(make_file)],
> cwd=full_output)
>          except Exception as e
>
>
> With that done here is my output:
>
> $ ./sip_compiler.py -v --includes "/usr/include/x86_64-linux-
> gnu/qt5,/usr/include/x86_64-linux-gnu/qt5/QtCore" --select
> @kitemmodelsmod.sip sip cxx
> 2016-04-22 00:23:01,282 __main__ INFO: Creating cxx/
> 2016-04-22 00:23:01,283 __main__ DEBUG: cxx/kitemmodelsmod.sip.tmp
> 2016-04-22 00:23:01,283 __main__ INFO: /usr/bin/sip -c cxx/ -b
> cxx/module.sbf -x kitemmodelsmod_sip -x VendorID -t WS_X11 -t Qt_5_4_2 -x
> Py_v3 -I/usr/share/sip/PyQt5 -Isip cxx/kitemmodelsmod.sip.tmp
> 2016-04-22 00:23:01,728 __main__ INFO: make -f module.Makefile
> g++ -c -std=c++14  -g -O2 -fstack-protector-strong -Wformat -Werror=format-
> security  -D_FORTIFY_SOURCE=2 -fPIC -Wall -W -DNDEBUG -I. -
> I/usr/include/x86_64-linux-gnu/qt5 -I/usr/include/x86_64-linux-
> gnu/qt5/QtCore -I/usr/include/python2.7 -o sipkitemmodelscmodule.o
> sipkitemmodelscmodule.cpp
> g++ -c -std=c++14  -g -O2 -fstack-protector-strong -Wformat -Werror=format-
> security  -D_FORTIFY_SOURCE=2 -fPIC -Wall -W -DNDEBUG -I. -
> I/usr/include/x86_64-linux-gnu/qt5 -I/usr/include/x86_64-linux-
> gnu/qt5/QtCore -I/usr/include/python2.7 -o
> sipkitemmodelsKSelectionProxyModel.o sipkitemmodelsKSelectionProxyModel.cpp
> g++ -std=c++14 -Wl,--fatal-warnings -Wl,--no-undefined  -Wl,-Bsymbolic-
> functions -Wl,-z,relro -shared -Wl,--version-script=kitemmodels.exp -o
> kitemmodels.so sipkitemmodelscmodule.o sipkitemmodelsKSelectionProxyModel.o
> -lm /usr/lib/x86_64-linux-gnu/libQt5Core.so /usr/lib/x86_64-linux-
> gnu/libKF5ItemModels.so /usr/lib/x86_64-linux-gnu/libpython2.7.so
>
> That created the cxx/kitemmodels.so library
>
> $ ls cxx/
> kitemmodels.exp         sipAPIkitemmodels.h
> kitemmodelsmod.sip.tmp  sipkitemmodelscmodule.cpp
> kitemmodels.so*         sipkitemmodelscmodule.o
> module.Makefile         sipkitemmodelsKSelectionProxyModel.cpp
> module.sbf              sipkitemmodelsKSelectionProxyModel.o
> pythontest.py*
>
> $ cat cxx/pythontest.py
> #!/usr/bin/env python
>
> from PyQt5 import QtCore
>
> import kitemmodels
>
> $ ./cxx/pythontest.py
> Traceback (most recent call last):
>   File "./cxx/pythontest.py", line 5, in <module>
>     import kitemmodels
> SystemError: dynamic module not initialized properly
>
>
> Is there some other step to take before that import will work?
>

Only to pick up the code I pushed earlier tonight [1]. This brings a slight
change the in the CLI for the sip_compiler.py. The second argument ("cxx"
above) is now optional and defaulted from the project rules "project_name".
For KF5, the latter is PyKF5, and the net effect of the changes is that you
get the following by default:

- a directory PyKF5
- containing a __init__.py
- and all the .so files such as KItemModels.so
- and a disposable tmp directory

so that you can then just say "from PyKF5 import KItemModels". You'll
notice that in support of this, there is a temporary list of hardcoded
libraries to link against (a quick hack just to get us going).

Thanks, Shaheed

[1] See
https://www.riverbankcomputing.com/pipermail/pyqt/2016-April/037331.html
for the details.



> Thanks,
>
> Steve.
> _______________________________________________
> Kde-bindings mailing list
> Kde-bindings at kde.org
> https://mail.kde.org/mailman/listinfo/kde-bindings
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.kde.org/pipermail/kde-bindings/attachments/20160422/15a962e4/attachment-0001.html>


More information about the Kde-bindings mailing list