0.25 version is out FINALLY

edited November 2017 in General

Hi all,

I just released 0.25. Finally that's done after promising it many times ...

KLayout is now compatible with Qt5. It's build system and major parts of the code structure was overhauled entirely. With this and the GitHub based development, I am able to do continuous integration and deployment on a Jenkins instance. I am using Docker slaves to build the RPM's and DEB's for some selected distributions. Some Docker images (for example CentOS6, OpenSuSE 42.3) did not work out of the box because of missing prerequisites. As I become able to provide them, I'll add packages for these distributions too.

Some highlights with more visibility are:

  • A package manager for easier distribution of add-ons (see [The Package Chookbook}(http://www.klayout.de/staging/package_cookbook.html)
  • More display styles (line styles, cross fill for rectangles)
  • Some functionality is available as "buddy" tools - small binaries that can be used standalone. See the Release Notes for a list of tools.
  • Single-click measurement rules (my personal favourite)
  • Visual XOR progress
  • Enhancements to the macro development IDE

Please see Release Notes for some more details.

The script API has received many enhancements, but also some deprecated concepts were dropped. Please see Script Migration from 0.24 to 0.25.

The final challenge was to provide signed binaries for Windows installation. They are available now, so I was finally able to release.

Please find the download links in the Usual Place.

Enjoy. I'll fetch myself a release beer now.



  • edited November -1

    Fantastic! Starting to play with the package manager now.

    I did observe something unusual during installation though. On Windows 10 64 bit, in the past if version 0.x.y was installed (in the default location of C:\Program Files\KLayout) and you wanted to install 0.x.y+1 or whatever, you'd just run the installer and the older installation would be replaced with a newer one.

    However this time when I installed, it left the 0.24.10 installed in C:\Program Files\KLayout, and installed a separate version 0.25.0 in C:\Program Files (x86)\KLayout. I am indeed installing the 64-bit version (klayout-0.25-win64-install.exe). Is this intentional?

  • edited November -1

    Another few minor issues:

    1) You've added new rulers (Cross, Measure, Ellipse, Box). However rather than appending to my existing list of rulers that I use, it overwrote them. Not a big deal as I can set them up again but worth noting.

    2) In Settings > Rulers and Annotations > Templates, clicking on the "See here for a description of the properties" does nothing. I can right-click and choose "Copy link location" but it points to "int:/manual/ruler_properties.xml"

    3) I've always thought the default ruler formats were a little strange. Maybe I'm wrong, but most users will I think be using the default database unit of 1nm, however the ruler formats such as $D will print out seven decimal places! Like 0.1234567 um, which is 123.4567 nanometers. I think that represents precision corresponding to approximately the size of an atomic nucleus! In my own work I've either had the ruler snap to grid (which is not always desired) or used the following bulky workarounds:

    Either replace $D with $(sprintf('%.3f',D)) for a simple fix (or similar for $X, $Y, ...)

    Or, replace it with the following ugly thing for a nicer fix (which hides trailing zeros which many times simplifies the number): $((sprintf('%.0f',D) + '.000')==(sprintf('%.3f',D)) ? (sprintf('%.0f',D)) : (sprintf('%.3f',D)))

    However it starts to get even more bulky when you want to simply do "$X, $Y". In that case my preferred solution above becomes $((sprintf('%.0f',U) + '.000')==(sprintf('%.3f',U)) ? (sprintf('%.0f',U)) : (sprintf('%.3f',U))), $((sprintf('%.0f',V) + '.000')==(sprintf('%.3f',V)) ? (sprintf('%.0f',V)) : (sprintf('%.3f',V)))

    4) I like the Back/Forward buttons. One minor thing I noticed is that I intuitively expect when I right click on a cell in the tree and do Show As New Top, then click Back, that it will go back to showing the other cell as top. Instead nothing happens (because any zoom level changes were done with the other cell as top.) Just a suggestion for a future version.

    5) In the package manager it tells me I can add dependencies but I can't see how to add them, and don't see an empty tag in the .xml file (which I would otherwise manually fill). Am I missing something obvious..? In newly-created Packages there is a default script file, with this comment:

    # In order [to] pull in classes from other packages, just specify these classes
    # in the dependencies of this package. Provided those packages contain macros
    # which are marked as "autorun-early", the will be loaded before this package
    # and their modules and classes will be available.

    Does this mean that instead of putting "import XXX" or "include XXX" etc, at the top of the script file, you list the dependency in the .xml file?

    Secondly, it mentions using autorun-early for dependencies -- how does it handle the following case?: Imagine we have File1 which depends on File2 (which is autorun-early) and then File2 depends on File3 which is also autorun-early. Does File3 always get run before File2 (so, do dependencies between all macros get checked and respected at startup)?



  • edited November 2017

    Hi David,

    Thanks for your feedback. I see you took your time to try out :-)

    Regarding the first question:

    I am using the default location suggested by NSIS - I wasn't aware that it would pick C:\Program Files (x86) for 64bit. Apparently that's because NSIS itself is a 32bit version and functionality wise it does not make a difference (although it's not quite clean). I was using the same installer for 0.24.10, so I can't tell why 0.24.10 would be installed differently, but I guess that overwriting 64bit with another 64bit should remove the old version.

    I personally prefer to run the installer as a local user. In this case, the installation will be made in your personal profile and not use C:\Program Files ... at all.

    I'll keep that in mind.

    Regarding the other points:


    I'm aware of this - but I wasn't able to find a good solution other than this. This will happen only
    once - on the next upgrade, your personal rulers will be kept. Technically the issue is figuring out
    whether the rulers are yours or mine. The new ruler templates will carry a flag telling me. So I can
    update mine and leave yours alone. Sorry for the inconvenience.


    Strange - that works for me. But it may take some time (up to a minute) on the first call after
    installation (there is a progress bar in the main window). This is because it will create the help
    index initially. There is also a slight delay when the help dialog opens because the help index
    needs to be read. On the other hand, KLayout starts faster this way. But I admit it lacks a busy
    cursor which would reduce confusion.


    Oh yes ... The default format is basically worst case. Database units of 0.25nm are common today,
    so 5 trailing digits digits are required. But if you snap to grid, I'd suggest using
    sprintf("%.12g",..) which implies sufficient precision but without imposing a specific number
    of digits after the dot. If you don't use grid snap, the numbers will get long however (like


    I see the point. So you think it makes sense to record the cell path too, right? The back/forth
    button basically uses the bookmark system. Will it make sense to record the cell path for
    bookmarks too?


    Dependencies are specified in the Package Properties, under "Depends On" (Click on the "Edit"
    button at the right upper corner of the package properties page). The dependencies then go into
    the mentioned section of the "grain.xml" file.

    But first of all, you need packages yours depends on. The main intention is to enable providing
    Ruby or Python libraries, you package will be based on. Such libraries can be built either as
    ".lym" macros or as a collection of ".rb" or ".py" files. Both differ in the way they are loaded
    by KLayout:

    • ".lym" files are handled by KLayout: KLayout will scan the package folders and load ".lym" files. It will execute the text contained in these files when the "autorun" or "autorun-early" flag is set. ".lym" files are richer and allow easy integration of macros into the menus, but they cannot be included in other Ruby/Python files through the standard "require/import" scheme. Hence, ".lym" files a best suited for "entry point" macros.
    • ".rb"/".py" files are not handled by KLayout, but if you include them in the package inside a "ruby" or "python" folder, these files can be loaded using "require" or "import". This scheme does provide or require autorun-early. This is the preferred way to building a library hierarchy as the one you mentioned. Nesting isn't an issue - "require" or "import" will take care of that.

    I hope this gets a little clearer this way. Bottom line is:

    • If you want to create nested Ruby/Python libraries, use the Ruby or /Python library template and put your files into the "ruby" or "python" folder. This allows rich libraries consisting of many classes and files to be created and allows for additional dependencies.

    • Only if you really need to make one ".lym" file dependent on another - because the other defines a class needed by the first one for example - you should to use "autorun-early" for the dependencies. Otherwise, KLayout cannot guarantee loading of the first one before the second. But as you rightly noticed, this scheme has severe limitation so I'd propose to target for a clean separation into library code (".rb"/".py") and entrance code (".lym").

    Packages can contain many different things, you can use dependencies for other purposes too, like
    requiring special text fonts for a certain macro or similar. In this case, dependencies rather mean
    "ensure it's installed together".

    And just a friendly reminder:

    You are very welcome to raise your concerns by creating issues on the GitHub Project. By doing so, these issues get noticed by others and I can easily refer to them in a commit. That increases transparency, enables feedback on a solution and allows tracking and prioritization. I may even be able to encourage others to get involved.

    Thanks and best regards,


  • edited November -1

    Thanks Matthias,

    Yep I can create issues on the GitHub project in future for things like this. I didn't realize that was the preferred method but it makes sense.

    2) Weird -- still doesn't work for me. No big deal, let me poke around some more and see if there are other similar links that don't open, then maybe we can find a pattern

    4) Yeah, I guess my initial assumption was that the Back and Forward buttons were moving back and forward with what you are viewing in the viewport.. but it's not a big deal either way. As for bookmarks, I've actually never used them so can't comment

    5) Ah, I did not see the pencil icon / Edit button. That solves it!

    This is fantastic, thanks Matthias


  • edited November -1
    Hi Matthias:

    I found an issue with the $KLAYOUT_PYTHONPATH variable in Windows. When I set the variable to, e.g.:
    the app starts OK.

    However, when I add another (existing) path element
    SET KLAYOUT_PYTHONPATH=%KLAYOUT_PYTHONPATH%;C:\Users\nxa11113\PycharmProjects\Layout\LayerMap
    then the app doesn't start, with a Runtime Error:
    Fatal Python error: Py_Initialize: unable to load the file system codec
    ImportError: No module named 'encodings'

    which I think means that Python can't find its usual path (the first element of the path).

    Also, using an additional path with the "-j" option always appends "python" to the path. I think it would be better not to do that to have full flexibility.

    Thanks for your good work, I'll keep debugging...

    Best regards, Erwin
  • edited December 2017
    Disregard this comment. I had an issue with the build system not seeing the correct Qt version as we have several installed. Our config system conflicts with the build system (qmake etc.).
  • edited November -1
    Hi Matthias, FYI, I was able to build 0.25 with Qt 4.8.3.

    By the way, is there a "make clean" command of some sort? Looks like before each build I have to start from the tar.gz ball to make sure I have nothing conflicting when I change Qt versions.

    Best regards, Erwin
  • edited November -1

    Hi Erwin,

    To "make clean" you can simply remove the build directory (which is usually called "build-release" or similar). If you experiment with different settings, you can use different build directories. Use

    build.sh -bin <binary-dir> -build <build-dir>

    "-bin" specifies the name of the directory where the final binaries will be put to. "-build" specifies the build directory. For example:

    build.sh -bin bin-qt4.8.7-release -build build-qt4.8.7-release

    Everything goes into these two directories - if you use different names there won't be any interaction. If you delete them, everything is gone. You can also do a clean by changing into the build directory and using

    make clean


  • edited November -1
    Hi Matthias, thanks for the clarification. Best regards, Erwin
  • edited December 2017
    I compiled 0.25 and run a regression on our previous generated python scripts.
    in the new release I received a message std::bad_alloc in Region.insert(Class RuntimeError) executing:

    myBox = [pya.Point(-bw,-hw), pya.Point(bw,-hw), pya.Point(bw,hw), pya.Point(-bw, hw)]
    xBox = pya.Polygon(myBox).move(cx,cy)
    pR3.insert(xBox) #Error occur here

    Was there a change in the Region command? I can't find one in the documemtation.

    Second issue I can't resolve is the ruler p1. I checked the annotation class example in ruby and it works but not for python anymore.
    Caught the following exception:
    'NoneType' object has no attribute 'p1' (Class AttributeError)

    ant = pya.Annotation.new()
    ant.p1 = pya.DPoint.new(x1, y1) # issue occur here
    ant.p2 = pya.DPoint.new(x_+x1, y_+y1)
    ant.style = pya.Annotation.StyleRuler


  • edited November -1

    Hi Andy,

    regarding the first issue: the problem is not related to Region but to Polygon#move or rather the thing that this method returns.

    The problem is this:

    pya.Polygon(myBox).move(cx, cy)

    Polygon#move returns a reference to self. In case of pya.Polygon(myBox).move(cx, cy), self is the polygon just created. But the call travels through C++, so the reference is not a Python reference, but a pointer and as soon as pya.Polygon(myBox) gets discarded, the returned reference becomes invalid and memory corruption happens.

    That's why this

    poly = pya.Polygon(myBox)
    xBox = poly.move(cx,cy)

    works: "poly" does not get discarded because it's kept in a variable.

    Nevertheless I'd recommend the action out-of-place operation:

    pya.Polygon(myBox).moved(cx, cy)

    (note the "moved" instead of "move"). This method returns a copy

    Maybe there was some magic in the 0.24 implementation which prevented this issue, but I'd rather guess this worked by coincidence. But I opened a ticket on GitHub to cover this case: https://github.com/klayoutmatthias/klayout/issues/40.

    Regarding the second issue:

    The right way to create an object in Python is not new: use

    ant = pya.Annotation()

    Frankly, I don't know why "new" works and what it does - I'll check that.



  • edited November -1
    Thanks a lot Matthias for your appriciated feedback,
    in case you require the complete scripts please let me know.

    Best Regards,
  • edited November -1

    Hi Andy,

    Thanks for the offer. I'd include these scripts into the unit tests if you think they are of general interest and can be published as GPL. The more tests, the better :-)

    Best regards,


Sign In or Register to comment.