Saturday, February 14, 2009

Notes on Eclipse CDT

It has been a while since I last tried out Eclipse CDT. I've been using Eclipse at work recently for Java and RCP stuff, so I thought I'd give CDT another go. I prefer Vim, but I don't mind trying new things. So I thought I'd try it out for my homebrew stuff.

Eclipse for Java is actually pretty good. When you write Eclipse plug-ins you usually have to implement a load of seemingly random interfaces. There are project wizards in Eclipse that generate all the necessary stubs and what-not for you. Then once your project is underway, the editor has all sorts of auto-completion and javadoc "hints" to help you figure out the API. The facetious among you may say that all these crutches are necessary because the Eclipse API is not discoverable enough. I might not argue with you, but I've seen some terrible C++ libraries in my time too.

Now I am not a big Java coder. I mostly write C++, with a bit of Python. In Vim I can emulate a lot of what Eclipse does for Java, but for C++. Exuberant CTAGS is a marvelous help for doing this. Coupled with Vim's omni-complete, you can have a lot of context sensitive auto-completion for C++ code. The completion in Vim also gracefully degrades to just regular context-insensitive completion. So even if it doesn't complete your class based on its available member variables and methods, Vim completes based on the contents of the current buffer, or loaded buffers, or included files. Most of the time this achieves what you want.

By the way, to set up omni-completion in Vim for C++ you need to do a couple of things. First you need a modern Vim. Version 7.1 or so should do. Then you need to either pass these flags to ctags, or create a $HOME/.ctags file:
--c++-kinds=+p
--fields=+iaS
--extra=+q
Now run "ctags -R ." in your source code tree. That creates a tags file with the index that Vim uses to auto complete. Armed with that knowledge, you can create tags files for the STL to have auto-completed vectors, lists, strings and so on. Using g] in Vim it jumps to methods, variables and defines.

OK, back to the story. I'm trying to use Eclipse CDT for C++ to see how it compares to my Vim setup. This article from IBM describes how to compile UNIX software from Eclipse using the C++ IDE. Instead of using make directly, it recommends using ant to call configure and then make. That's quite novel and it "works" insomuch that your code compiles, but it isn't very good for proper coding. The main issue is that the errors from ant are not parsed into clickable quick fix errors. In other words, if you screw up and your code doesn't compile the errors are not highlighted in the editor as they should be.

Aha! But I don't use make. I use waf for bunjalloo. The waf interface is almost identical to make. In Vim I use "set makeprg=waf" so that running ":make" compiles my code. I realised that I could do the same thing in Eclipse, and here's how.

Before starting anything I did what I normally do to install new programs on Ubuntu; I opened up Synaptic. Sadly Ubunutu 8.04 has an ancient version of Eclipse (3.2.2! That's from the middle ages, held together with wattle and daub). I made like I was using Windows and went off to the Eclipse web site to download the latest release, which is 3.4.1 at the time of writing. Excellently this is just a big fat tarball, so you can unpack it in /opt or wherever you like and it runs. No dependencies and with batteries included.

Now I had to get my code into Eclipse. There's a bit of irritation involved with this. Eclipse insists on copying your files into its own workspace, even if you already have a perfectly good space for working available. My plan here was to create a new workspace, use the import tools to copy the code there, then manually copy the secret Eclipse project files back to my regular directory. I could then import the original directory as an already existing project. Convoluted, but I just don't trust Eclipse not to bork up my files while it whispers softly "it's for your own good..."

Step 1. Start Eclipse and tell it the workspace to use
eclipse -data /tmp/workspace
This was a throwaway workspace that I wouldn't use once the project files had been created.

Step 2. Create a new C++ project in Eclipse. This has to be an empty Makefile project.
Create empty C+ projectThis created an empty project that would not be managed by Eclipse's internal builder. Eclipse just calls "make all" and crosses its fingers.

Step 3. Add the source code. I used the Import > General > File System option.
Import Files
This copied all the code into the /tmp/workspace/project folder.

Step 4. Set up waf as an alternative to make

To do this, I only needed to change "make" to "waf", and change the default incremental build target to be "build" instead of "all". This is done from the Project > Properties > C/C++ Build. In Builder Settings, uncheck "use default command" and change "make" to "waf". From the Behaviours tab, change the "all" target to "build".




At this point I was almost done. However first I had to add the configuration step in. Waf, like autotools, first configures the environment to see where your compilers, libraries and other tools are installed. This is done by running "waf configure" from the command line. I added a new Make target "configure" to do this. That's right click on the project > Make Targets > Create... In the dialog, I added "configure" in both the target fields.

I ran the "configure" target first, then ran "build" as normal. With this done, the whole thing was compiled.

Now that everything was set up, I could use the project files created by Eclipse. These are called .project and .cproject. The .project file is pretty light weight and describes the project basics. But the .cproject file is a mess. 276 lines of incomprehensible XML, with all sorts of redundant and machine-specific configuration information encrusted in it. Yuck. It also changes "randomly" when you alter minor details in the project. This makes it really unsuitable for storing in version control, but without it the whole CDT project is useless. A hairy dilemma, and one that doesn't occur in the Eclipse Java IDE, where the .project file is pretty stable.

I just completely ignored this problem and I copied the project metadata files to the original location of the project in $HOME/src/ndsdev/ anyway. This is to make sure I can re-import the project using just these files. I restarted Eclipse, using a different workspace now (the default $HOME/workspace), and used the "import existing project" option. This all went well. I now had all my code in Eclipse in its original location, compiling, running, and so on.

I then wanted to fiddle around, see what Eclipse could do with C++. The first problem I hit was a lot of "unresolved inclusion" errors. This occurs when the #include files cannot be found. As I wasn't using Eclipse's managed build, my project compiles OK but Eclipse is ignorant to the actual internal paths my Makefiles, er, wscripts use. To fix this, I had to add the project include paths using the Properties > C/C++ General > Paths and Symbols setup page.

Next up, I thought I'd try out the auto completion. What a disappointment! Compared to the Java equivalent, which has an almost 6th sense ability to guess what you are trying to write, the CDT version is hobbled. My Vim+CTAGS solution works much better. As an example, say we have this code:
class Test {
public:
Test();
int getValue() const {
return m_
}
private:
int m_value;
};



the cursor is at the end of "m_" and I press Ctrl+Space to auto-complete, but I get told that there are no proposals. What about that m_value just 4 lines down, eh? Gah. You can "fix" this by placing the definition of m_value above where we were trying to use it, but that's just silly.

Another niggle I have is with the cut and paste mechanism. In Vim, yy, dd and pp all copy, cut and paste entire lines - from the very left of the screen to the end of the line. In Eclipse however, the keyboard shortcut for cutting a line is not enabled by default, copying a line with ctrl-alt-down results in a copy directly below where the line was, which you can then ctrl-x cut. But pasting is awkward - the cursor jumps about unexpectedly to an indented place, and it is very easy to add unwanted blanks at the end of text. Perhaps this just requires getting used to, but it feels weird and icky.

The other nice feature in Java is the documentation hints for filling out constructors and functions. There's an option to support Doxygen (Properties>C++ General), but it doesn't seem to make any difference. I've Doxygenized most of my headers, and Woopsi also uses the convention, but when I hover over a method that has documentation it just shows the implementation and leading comment. Fair enough, you get some idea of what is needed, but it'd be nicer if it showed the actual documentation.

Finally I tried some of that cool refactoring that the hip kids are all talking about. I found method that was looking a bit full, selected a portion of code and hit Refactor > Extract function. This was in a class method and the code used member variables. Ideally refactor would create a new method and add the prototype to the header file (no chance!). The dialog was disconcerting:



The dialog says Function Name, the text entry says Method name. Which is it? Function or method? A function is a named section of code. A method is a function that is part of a class. I had a bad feeling about this. Rather surprisingly, it did what I expected! It extracted the code, placed it in a new method and added the prototype to the header. Wow! Unfortunately the header file got a bit mangled, with all the comments stripped out. I tracked down a minimal bit of code that causes this and opened a bug report. It does mean that you probably have to be extra careful about using this feature blindly, but it's better than nothing. UPDATE: The bug has been fixed in record time! I opened it on the 12th, and it was marked fixed on the 17th.

Eclipse has a lot of other cool features - I haven't mentioned mylyn or the debugger integration here - but the C++ IDE itself is still a bit rough around the edges. This is probably to be expected if we consider that it's a C++ editor written in Java. That isn't meant as Java bashing, let me explain. The people who write the Java IDE version of Eclipse undoubtedly use this Java IDE to edit the Java code. The people writing the C++ IDE also need to write Java code. They don't necessarily need to write C++ though. Likewise, the users of the Java IDE edition of Eclipse are presumably capable Java coders, so it is more likely that they would be able to investigate the code and provide patches for bugs they find. Users of the C++ IDE are coders who probably know Java, but there are no guarantees, and it may not be their preferred language. They are less likely to dig into the guts of the editor to add functionality or fix bugs. Maybe. It's the dog food thing again.

Another factor is the size of the target audience. In the case of the C++ IDE, this is a lot smaller. According to the eclipse download page, there have been around 4.5 million downloads of the various Java flavours of the IDE, but less than 700,000 downloads of the C++ version. That doesn't take into account updates of the Java version to the C++ equivalent, but the opposite is also true (updates of the C++ IDE to add Java components) so it's probably a pretty accurate reflection. The Java IDE is more than 6 times as popular. More eyes means more bug fixes and polish.

So will I use Eclipse for C++ from now on? Probably not. I'll check back when the next release comes out, as the improvement over the last CDT release is major - the indexer hung last time I tried to load the bunjalloo code base into it and refactoring now has more than rename variable. Hopefully the next release will fix more niggles and add more features. But I've used Vim for years and it is an extremely optimal way to edit text once you get used to the interface. :wq

Saturday, February 07, 2009

WIP Woopsi screenshot

I've started the port to Woopsi now and it's going alright-ish. There are still a lot of bugs to iron out and old features to re-implement, but I think being able to view 2 web pages at the same time is going to make a huge difference. This screenshot shows a test page and the Google code hosting site. The page title is shown on the screen title bar. Each web page is a borderless window gadget. Clicking a link opens it in the same window. Shift-clicking (clicking with the stylus while holding a shoulder button) opens the web page on the opposite screen. So you can have 2 web pages open at once. This is an artificial limit, but given the memory limits I think is a good compromise.

Now for some technical crap! I'm using git's submodule support here to track Woopsi's development on sourceforge (via git svn...). Sounds complicated, but it's not really. And in the end it means I get bug fixes for free, but can also add my own hacks on top of the main Woopsi code. I've added my own build scripts for example, but most of the rest of my bug fixes have been committed by ant to his svn repository. Nice!

The main issues I've seen so far are to do with my "meta-gadget" that keeps track of all the text and image gadgets. There are some scrolling issues and position problems there. The other problem is with unicode of course, but I knew that was going to be a sticking point when I started.

I still need to figure out how I'm going to add in the back-forward-stop buttons. I think these will have to be in a separate window, but I get the feeling that that would be awkward. I'll probably end up adding them to each window under the main display. It'll cut off some screen space, but not too much. In the current version the buttons are shown on top of the text and are slightly transparent. This is a bit ugly though and you can't really read the text underneath anyway. Woopsi's gadget heirachy means that it might be easier to add these as separate controls and forget about it.