Wednesday, June 26, 2013

vim plugin

Recently for no good reason I decided to build a vim plugin. Being a C++ enthusiast the target will obviously be some sort of compiled binary plugin. Scripting vim is kind of tricky- this article is going to go from start to finish in how to build the vim plugin stub. Hopefully it will help someone else since the documentation on the world wide internets can be skimpy when dealing with this topic; the reason it's skimpy is that it just works.

The first step is to write a small program that's in a library:

#include <iostream>
#include <dlfcn.h>

extern "C" 
{

const int libexp95plugin_load(const char* libname)
{
    return (long) dlopen(libname, RTLD_LAZY);
}

const char* libexp95plugin_call(const char* context)
{
    std::cout << "HELLO WORLD!" << std::endl;
    return "Hello";
}

}

Step by step:

#include <iostream>

extern "C"
{

I see this all the time in code- this tells the compiler that the function names included should have 'C' linkage. This allows any other base program (such as vim) a universal way to load this library and also know how to call it.

const char* libexp95plugin_call(const char* context)
{
    std::cout << "HELLO WORLD!" << std::endl;
    return "Hello";
}

}

The final portion of the code is self explanatory. To build this library (I put the code above into a file called exp95.cpp), I use a tool called premake4. Honestly, you could just as easily use straight command line to do it too, but premake4 is easier to read:

solution "exp95"
configurations { "Debug", "Release" }

project "exp95plugin"
kind "SharedLib"
language "C++"
files { "exp95.cpp" }
buildoptions { "-fPIC" }
linkoptions { "-fPIC" }


That's all. The -fPIC flag is the most important since it enables Placement Independent Code. After the plugin is build (inside of libexp95plugin.so), to the following:

> cd ~
> cd .vim
> vim exp95.vim

Inside of exp95.vim add the following:

function! Exp95Function()
    call libcall( "absolute-path-to-libexp95plugin.so", "libexp95plugin_call", "SOMETHING")
endfunction

command Exp95 call Exp95Function()

That's all! I got hung up for awhile because I didn't use the "call" keyword in front of libcall. The lesson there is that if you are not storing the return value from a function call in vim, you must use the call keyword in front. Otherwise you'd get the error:

E492: Not an editor command: ^Ilibcall( ... )

Yeah, not so good. To invoke your new command, all you have to do is fire up vim and execute. From within vim:

:Exp95

Your hello message should pop right up!





Monday, June 24, 2013

std::map insert, stuff I should have already known

Spot the error in the code:

typedef std::map<std::string, CacheEntry*> CacheMap;
typedef CacheMap::iterator CacheIterator;

void doSomething(CacheMap& cacheMap, std::string const& id)
{
    CacheIterator iter = cacheMap.find(id);
    if (iter != cacheMap.end())
    {
        CacheEntry* originalEntry = iter->second;

        CacheEntry* switchedCacheEntry = convertEntry(iter->second);

        delete originalEntry;

        cacheMap.insert(std::make_pair(id, switchedCacheEntry));

    }
}

There are actually a few errors in this code snippet if you are taking into account exception safety. The first error regarding exception safety is performing a delete before keeping the state of the map intact. In C++, destructors can never throw exceptions; therefore deleting the originalEntry is not a big deal. BUT what if the delete succeeds and then the cacheMap.insert throws? The cacheMap is left in an errant state because the entry in the map points at a deleted object. That's not good. The remedy for that error is simple, rearrange the order of the insertion and deletion. There is still another exception safety problem with this in that the switchedCacheEntry object will be dangling but that could be fixed by other means.

The big error that I uncovered when writing code like this was the use of std::map::insert. To me insert means that the element being inserted overwrites the contents in the map; but this is NOT THE CASE [1]. 


"Because element keys in a map are unique, the insertion operation checks whether each inserted element has a key equivalent to the one of an element already in the container, and if so, the element is not inserted, returning an iterator to this existing element (if the function returns a value)."


So there it is. In this case, it will be more efficient to just overwrite the entry in the map rather than attempt an insert. Using an insert in this case will cause us to keep the original entry object in the map instead of our switchedCacheEntry. 


REFERENCES


Friday, June 7, 2013

Why I Don't Like Qt Open Source Projects (typically)

I'm porting a version of the QtCreator libraries from using qmake to premake4. Long long ago I did the same thing with QtCreator 2.5.0 and it turned my love for qmake into pure hatred. Before I had started that project I was firmly in the qmake camp because of it's simple syntax and portability with Qt projects. Then I started having to read other developer's pro files. Maybe I'll dig into qmake's more bizarre features after this blogpost; but what is really grinding my gears about Qt Open source projects right now is the private implementation mechanism they use.

Full disclaimer: private implementations are great. I love the pattern because it allows us to do lazy evaluation, fast swapping, binary compatibility, etc. It's a necessary implementation technique. With that being said, the way that Qt Open source projects do it is RIDICULOUS. Here's an example from the utils library from QtCreator:

#ifndef TIPS_H
#define TIPS_H

...

namespace Utils {
class TipContent;
}

#ifndef Q_MOC_RUN
namespace Utils {
namespace Internal {
#endif

class QTipLabel : public QLabel
{
    Q_OBJECT
...
};

#endif

Then inside of the cpp file:

#include "tips.h"
...

namespace Utils {
namespace Internal {

QTipLabel::QTipLabel() {
...
}

#include "moc_tips.cpp"

} // namespace Internal
} // namespace Utils

Okay, I've seen this pattern before with Qt projects where we will perform a moc-step and then include the resulting moc file at the bottom. I actually think it's a neat idea, most of the time the files have a .moc extension (meaning that the moc app was run on a cpp file). That's not the case here.

What this code is doing is running moc on tips.h, which will process QTipLabel. Because the namespace declarations for Utils and Internal are inside of Q_MOC_RUN, they are not going to be processed in the moc generated code. In other words, if you look at moc_tips.cpp there will be no mention of Utils/Internal. That allows us to nicely include it at the end of the cpp file.

Why go to this much trouble?! I understand wanting to be efficient and using the tools you have but don't twist the use of the tools (moc) to fit these really specific cases. Developers probably would say, "Well it works, so why care?" The reason you want to care and SHOULD care is that this is now the bar that new developers have to rise above to start contributing to your code base. It's code like this that kills projects and causes wasted time in understanding and refactoring. Just use something simple and consistent.

That's the end of my rant about Qt open source for today. Join my rant tomorrow when I continue to not take my meds...