After some days recovering from a septoplasty I got some time to put love on my new pet, not a dog, not a cat, just something non-organic, i.e. yet another pet project. This time it’s a plugin to add Ruby language support on QtCreator, a C++/Qml IDE.
Why?
Because I want to would be enough, but as I’m in a good mood let me explain in a single paragraph:
I use QtCreator for C++, It’s faster and code navigation, auto-completion and refactoring works as expected. I want to have these features when doing Ruby programming, besides it’s fun to write this kind of stuff.
So the project is hosted on github, I’m working on it when I can, however it already have some features:
Project Manager
QtCreator is a project oriented IDE, however I dislike the bureaucracy related to project setups on most IDEs, so I went to the simpler approach: open a .rb file and all .rb files under the directory will be added to the project, later I plan to add the many extensions used on Ruby and Ruby related files like .rhtml, .ru, etc.
A project manager means you can type “Ctrl+K” on QtCreator to open any project files.
Basic syntax highlight
It’s working, just need to be improved a bit to recognize regexes, in string variables, symbols, etc. It’s very easy to add this, but as the basic stuff is working I’ll concentrate on other things and improve the highlight as I need it.
Basic code navigation
Basic code navigation is working too via the “Ctrl+K menu”, you can see (and navigate) all methods of the current file (“. “ shortcut) or all project methods (“m “ shortcut).
The backend for this is based on regular expressions, my first attempt was using a Ruby-based Ruby parser but it was too slow for the task taking 6 seconds to parse a 20K lines files while my simple C++ version took 385 miliseconds, still slow but is enough for now.
Indentation
This is simple, type: “def foobar”, hit enter and see the cursor when you expect it to be.
The future
The features I want to write ASAP are:
Type "def foobar", "if foobar", etc, hit enter and the "end" keyword is written for you.
(done!)
Variable use highlight: leave the cursor on a local variable and all local variables in the scope are highlighted.
Basic auto-completion, for attributes is easy, but for method invocations some times is impossible due to the nature of the Ruby language.
(done!)
Code navigation via F2: hit F2 when the cursor is on a method and go to the method. As sometimes is impossible to know the instance type, a small combo would appear like happens when this feature is triggered on a virtual method in C++.
(done!)
How to install and test?
Hmmm, there’s no docs at all, so consider the next lines as a documentation:
Clone the QtCreator sources and go to the tag v3.1.0.
I didn’t write a install procedure, so you need to manually copy the files on QtCreator plugins directory, the files are: libRubySupport.so and RubySupport.pluginspec located under the build directory. On my system the plugins directory is /usr/lib/qtcreator/plugins/.
Conclusion
This is it, if you want to help me on this just mail me, leave a comment or ping me on IRC.
I started to write my own build system for C++ years ago, at my own pace, one line at the time… and sometimes no lines at all. Last months I did work a bit more on it and nowadays I would consider it in a pretty good shape, so it’s time for a benchmark!
The motivations behind of benchmarking meique (BTW this is the project name) was the most pure act of human curiosity, mainly after read about the tup benchmak.
Meique is slower than tup, on the other hand it doesn’t need the “complicated” tup setup, run with suid, etc. So my comparison here is with 2 other contenders: CMake/make and CMake/ninja.
Metodology
The metodology is very similar to the one used by the tup benchmak, just the code generator differ, so there’s a dummy C project with 4 shared libraries, and a main.c that uses them all, the number of files per shared libraries increase in each round, first 10 then 100, 1000 and 10000. i.e. 41, 401, 4001 and a 40001 files project. On each round the following operations are done:
Clean build.
Touch a header, then trigger a build.
Touch a .c file, then trigger a build.
Do nothing, then trigger a build.
Except for clean build, all other operations are repeated 3 times and the mean is used as result, there are also some other details that you can check in the run-test.sh script.
The computer used was a 8 cores intel i7 machine with 16GB on a hardware enabled RAID 0, make was ran with -j9.
Results
For my surprise, meique is faster than CMake/make and as expected it’s slower than CMake/ninja. Since speed is a concern but not the meique main focus as it’s on ninja I consider the results very good.
Ninja isn’t showing in the results due to a bug, it can’t link a shared library with 10000 files due to the very long argument list, meique had this very same bug, now fixed.
1.95x faster on the 40K files project! And I don’t know why because clean build is the most simple task.
There are still much room for improvements on meique, so the next goal is simple: to be faster than a ninja! ;-)
I’m writing this as a reminder to myself, first of all because there is no documentation about how to embedded Ruby into a C++ application besides the Ruby interpreter source files, secondly because when you start a sentence saying “first..” you need a second sentence saying “secondly…”.
The fast way to explain what you need to do:
ruby_options receive argc/argv as parameters, they are used like the Ruby interpreter would do, a void pointer is returned. The void pointer returned is a Node, it represents the Ruby code compiled and ready to run.
Notice “-enil”, if you don’t pass any argument the Ruby VM will crash without further explanation. In my example I want to execute some Ruby code located into a string, not a separated file, so I can’t pass the file path into options array because there’s no file, so -enil says “Execute this code: ‘nil’“.
You can use the void pointer returned by ruby_options into two functions, ruby_run_node and ruby_exec_node, the difference is that ruby_run_node executes the node then clean up the VM, so any other call to the Ruby C-API will cause a crash, ruby_exec_node just execute the node and keeps the VM alive for a future use.
Now with all in place, you can call rb_eval_string_protect to execute some ruby code and all other rb_* functions found on ruby.h to do whatever do you want, at least those rb_* functions have some documentation into README.EXT file found on Ruby source code.
After some months I finally got the committer rights on WebKit project :-), my first commit of course was the most traditional one, add myself on commiters.py :-P, hope to do more useful commits in a near future :-).
Don’t include myself in this group, I’m a long time KDE user and I don’t hate it despite of some annoying bugs, but I’m a heavy icecream user anyway :-).
What I have to say isn’t exactly about icecream, but about icemon, the nice GUI used to monitor icecream networks. But what’s wrong with it? Nothing! I’m a KDE user and the KDE dependency doesn’t bother me at all, but days ago tired of listen people (non-KDE users) complaining about the KDE dependency I decided to stop with all this and strip the KDE dependency from icemon even if the final result wont provide much difference to me.
After 1 hour of work I could finally say: “Mission accomplished!” and went to tell some coworkers at INdT that they owe me some beers. Some commits later to polish the fork and done… the Qt version is identical to the KDE one but without the kdelibs dependency.
This new baby is now called Iceberg and lives happy on Git-Hub, the name was a suggestion from setanta, just a word similar to icemon, nothing special.
So if you use icecream and don’t want to install kdelibs to see your icecream network, enjoy!