Q:

Recommended approaches for making my code swiggable?

I'm currently refactoring a Tcl plugin library written in C++. Originally the code was hand-written. A second library exists that does the same thing for Java.
The refactored library will be a single C++ library that can be used to create bindings to different languages.
My first tests with SWIG are promising. However, a lot of junk is generated as well. Various base classes and utilities are all exported. These don't make sense from the scripting point of view and only increase clutter.
Possible solutions that I can think of are:

Use #ifndef SWIG in the original codebase to filter out unneeded code
Create a SWIG-compatible wrapper around the API classes.
Differentiate between public and private headers. Public headers are pure abstract base classes that contain no implementation. The private headers inherit and implement them. Only SWIG the public headers.
The opposite of the above solution: inherit a SWIG-compatible class for each API class.

I'm currently leaning towards solution 3 at the moment. However, I'm not really certain so I'd like to know the SO community's opinion on this. Feel free to share your thoughts.
Update
I forgot to list one solution:

Code that should not exported by SWIG should probably not be in the public section of your class.

Perhaps this is the answer. I'll have another look on Monday.
Update
I settled with a solution. See my answer.

A:

Any approach that means that the C++ library becomes less useful to the C++ user is not the ideal solution.

#ifdef SWIG in the middle of .hpp files: Muddies up your C++ with unnecessary cruft, so it's not ideal
SWIG Specific Interface: This is a viable option, but only makes sense if the code you want to expose to SWIG is significantly higher level then the base C++ API.
Public vs Private interface: Might make sense, but again you have to ask at what cost to the C++ user of the API? Are you limiting the public interface too much? Who has access to the private interface? Should the pImpl idiom be considered instead?
SWIG Compatible Class for each interface: Probably more work than necessary.

First and foremost, to keep your SWIG related code separate from the rest of the API.
You probably don't want to import the .hpp files directly into SWIG (if SWIG wasn't considered during the initial design of the library), but if you do, you want to use a SWIG .i file to help you clean up the mess. There are three basic approaches we use, each with different use cases.
First, direct inclusion. This is useful if you know your API is nice and clean and well suited for parsing by SWIG:
// MyClass.i
%{
  #include "MyClass.hpp" // included for the generated .cxx file
%}

%include "MyClass.hpp" // included and parsed directly by SWIG

The second case is for code that is most of the way there. This is code that had SWIG taken into consideration, but really needed some stuff for the C++ user that we didn't want to expose to SWIG:
// MyClass.i
%{
  #include "MyClass.hpp" // included for the generated .cxx file
%}

%ignore MyClass::someFunction(); // This function really just causes us problems
%include "MyClass.hpp" // included and parsed directly by SWIG

The third case, and probably the one you want to use, is to directly choose which functions you want to expose to SWIG.
// MyClass.i
%{
  #include "MyClass.hpp" // included for the generated .cxx file
%}

// With this example we provide exactly as much information to SWIG as we want
// it to have. Want it to know the base class? Add it. Don't want it to know about
// a function? Leave it out. want to add a new function? %extend it.
class MyClass
{
  void importantFunction();
  void importantFunction2();
}

