diff --git a/README.rst b/README.rst
index 662c1b5626d234a621bbd17b98dc82aa2718d861..abb838902203b2ba491cb33fbd2bf780c4214b1d 100644
--- a/README.rst
+++ b/README.rst
@@ -18,3 +18,7 @@ Comments
 * particles: initialization of multistep solvers is done with lower
   order methods, so don't be surprised if direct convergence tests fail.
 
+* I am using this code mainly with Python 3.4, but Python 2.7
+  compatibility should be kept since mayavi (well, vtk actually) only
+  works on Python 2.
+
diff --git a/bfps/__init__.py b/bfps/__init__.py
index 08532a02b43e6a74b5ae94c643f15c6b7a075a21..248b5a75570bdafb1dad2c57e571b6981abbd13e 100644
--- a/bfps/__init__.py
+++ b/bfps/__init__.py
@@ -38,10 +38,10 @@ try:
     if not here.startswith(os.path.join(dist_loc, 'bfps')):
         # not installed, but there is another version that *is*
         header_dir = os.path.join(os.path.dirname(here), 'cpp')
-        lib_dir = os.path.join(os.path.dirname(here), os.pardir)
+        lib_dir = os.path.dirname(here)
         raise DistributionNotFound
     header_dir = os.path.join(os.path.join(dist_loc, 'bfps'), 'cpp')
-    lib_dir = _dist.location
+    lib_dir = os.path.join(dist_loc, 'bfps')
     __version__ = _dist.version
 except DistributionNotFound:
     __version__ = ''
@@ -49,7 +49,7 @@ except DistributionNotFound:
 install_info = pickle.load(
         open(os.path.join(os.path.dirname(here),
                           'install_info.pickle'),
-             'r'))
+             'rb'))
 
 from .code import code
 from .fluid_converter import fluid_converter
diff --git a/bfps/base.py b/bfps/base.py
index 528db8260fc561890481feaba56a116a29902abb..1301fe65d465066134755c1e10d6b72d707c3236 100644
--- a/bfps/base.py
+++ b/bfps/base.py
@@ -25,6 +25,7 @@
 
 
 import os
+import sys
 import numpy as np
 import h5py
 import bfps
@@ -48,8 +49,7 @@ class base(object):
         self.simname = simname
         return None
     def cdef_pars(self):
-        key = self.parameters.keys()
-        key.sort()
+        key = sorted(list(self.parameters.keys()))
         src_txt = ''
         for i in range(len(key)):
             if type(self.parameters[key[i]]) == int:
@@ -60,21 +60,18 @@ class base(object):
                 src_txt += 'double ' + key[i] + ';\n'
         return src_txt
     def cread_pars(self):
-        key = self.parameters.keys()
-        key.sort()
+        key = sorted(list(self.parameters.keys()))
         src_txt = ('int read_parameters(hid_t data_file_id)\n{\n'
                  + 'hid_t dset, memtype, space;\n'
                  + 'hsize_t dims[1];\n'
-                 + 'char *string_data;\n'
-                 + 'std::string tempstr;\n')
+                 + 'char *string_data;\n')
         for i in range(len(key)):
             src_txt += 'dset = H5Dopen(data_file_id, "parameters/{0}", H5P_DEFAULT);\n'.format(key[i])
             if type(self.parameters[key[i]]) == int:
                 src_txt += 'H5Dread(dset, H5T_NATIVE_INT, H5S_ALL, H5S_ALL, H5P_DEFAULT, &{0});\n'.format(key[i])
             elif type(self.parameters[key[i]]) == str:
                 src_txt += ('space = H5Dget_space(dset);\n' +
-                            'memtype = H5Tcopy(H5T_C_S1);\n' +
-                            'H5Tset_size(memtype, H5T_VARIABLE);\n' +
+                            'memtype = H5Dget_type(dset);\n' +
                             'H5Sget_simple_extent_dims(space, dims, NULL);\n' +
                             'string_data = (char*)malloc(dims[0]*sizeof(char));\n' +
                             'H5Dread(dset, memtype, H5S_ALL, H5S_ALL, H5P_DEFAULT, &string_data);\n' +
@@ -88,8 +85,7 @@ class base(object):
         src_txt += 'return 0;\n}\n' # finishing read_parameters
         return src_txt
     def cprint_pars(self):
-        key = self.parameters.keys()
-        key.sort()
+        key = sorted(list(self.parameters.keys()))
         src_txt = ''
         for i in range(len(key)):
             if type(self.parameters[key[i]]) == int:
@@ -104,7 +100,14 @@ class base(object):
             os.makedirs(self.work_dir)
         ofile = h5py.File(os.path.join(self.work_dir, self.simname + '.h5'), 'w-')
         for k in self.parameters.keys():
-            ofile['parameters/' + k] = self.parameters[k]
+            if (type(self.parameters[k]) == str) and (sys.version[0] == 3):
+                ofile.create_dataset('parameters/' + k,
+                                     (1,),
+                                     dtype = 'S10')
+                #ofile['parameters/' + k] = self.parameters[k].encode('ascii', 'ignore')
+                #print (ofile['parameters/' + k])
+            else:
+                ofile['parameters/' + k] = self.parameters[k]
         ofile['iteration'] = int(iter0)
         for k in bfps.install_info.keys():
             ofile['install_info/' + k] = str(bfps.install_info[k])
diff --git a/bfps/code.py b/bfps/code.py
index 478ef8ad9b61c6f3e1d76bdb2c650f9060787103..e8baced47d29812354974f3b8f44cda896b5ff67 100644
--- a/bfps/code.py
+++ b/bfps/code.py
@@ -24,10 +24,11 @@
 
 
 
-import h5py
-import subprocess
 import os
+import sys
 import shutil
+import subprocess
+import h5py
 from datetime import datetime
 import math
 import bfps
@@ -139,7 +140,8 @@ class code(base):
             raise IOError('header not there:\n' +
                           '{0}\n'.format(os.path.join(bfps.header_dir, 'base.hpp')) +
                           '{0}\n'.format(bfps.dist_loc))
-        libraries = ['bfps'] + bfps.install_info['libraries']
+        libraries = ['bfps']
+        libraries += bfps.install_info['libraries']
 
         command_strings = ['g++']
         command_strings += [self.name + '.cpp', '-o', self.name]
diff --git a/bfps/cpp/fftw_tools.cpp b/bfps/cpp/fftw_tools.cpp
index c9e685268c1fda92881798670933ca0c455f6420..f6eacbf1dfe2dfe31e603e9239c42d4639327d3d 100644
--- a/bfps/cpp/fftw_tools.cpp
+++ b/bfps/cpp/fftw_tools.cpp
@@ -28,9 +28,7 @@
 #include "base.hpp"
 #include "fftw_tools.hpp"
 
-//#ifdef NDEBUG
-//#undef NDEBUG
-//#endif//NDEBUG
+#define NDEBUG
 
 template <class rnumber>
 int clip_zero_padding(
diff --git a/bfps/cpp/field_descriptor.cpp b/bfps/cpp/field_descriptor.cpp
index 87f25a169accb92d185cbda8dbed4753846cba14..b5025835903a37ea5384cb4102c716f527aabfe5 100644
--- a/bfps/cpp/field_descriptor.cpp
+++ b/bfps/cpp/field_descriptor.cpp
@@ -22,10 +22,9 @@
 *                                                                     *
 **********************************************************************/
 
-// code is generally compiled via setuptools, therefore NDEBUG is present
-//#ifdef NDEBUG
-//#undef NDEBUG
-//#endif//NDEBUG
+
+
+#define NDEBUG
 
 #include <stdlib.h>
 #include <algorithm>
diff --git a/bfps/cpp/fluid_solver.cpp b/bfps/cpp/fluid_solver.cpp
index 04b4aa5a1c88ee40bc70b0ad62b88f6d35935280..880d4f695fc513ddd6d4d931bf08ff83e2a5f5d6 100644
--- a/bfps/cpp/fluid_solver.cpp
+++ b/bfps/cpp/fluid_solver.cpp
@@ -22,10 +22,9 @@
 *                                                                     *
 **********************************************************************/
 
-// code is generally compiled via setuptools, therefore NDEBUG is present
-//#ifdef NDEBUG
-//#undef NDEBUG
-//#endif//NDEBUG
+
+
+#define NDEBUG
 
 #include <cassert>
 #include <cmath>
diff --git a/bfps/cpp/fluid_solver_base.cpp b/bfps/cpp/fluid_solver_base.cpp
index d570f80f98d3be1a990c56592b192fc97478e21a..7f191f88da6cee5bfbd23b423e5b956dd2a3906a 100644
--- a/bfps/cpp/fluid_solver_base.cpp
+++ b/bfps/cpp/fluid_solver_base.cpp
@@ -22,10 +22,9 @@
 *                                                                     *
 **********************************************************************/
 
-// code is generally compiled via setuptools, therefore NDEBUG is present
-//#ifdef NDEBUG
-//#undef NDEBUG
-//#endif//NDEBUG
+
+
+#define NDEBUG
 
 #include <cassert>
 #include <cmath>
diff --git a/bfps/cpp/slab_field_particles.cpp b/bfps/cpp/slab_field_particles.cpp
index 3988659a0caba5eb46fd2070b178f68a5694a343..15fa363f6d277d34c6081fd545c4578e1f735929 100644
--- a/bfps/cpp/slab_field_particles.cpp
+++ b/bfps/cpp/slab_field_particles.cpp
@@ -22,10 +22,9 @@
 *                                                                     *
 **********************************************************************/
 
-// code is generally compiled via setuptools, therefore NDEBUG is present
-//#ifdef NDEBUG
-//#undef NDEBUG
-//#endif//NDEBUG
+
+
+#define NDEBUG
 
 
 #include <cmath>
diff --git a/bfps/cpp/tracers.cpp b/bfps/cpp/tracers.cpp
index 5e0e106ea658741fdf1b1bb209e100b22474504c..3d9fbfb6a1e357d70452466b6cc901659444539d 100644
--- a/bfps/cpp/tracers.cpp
+++ b/bfps/cpp/tracers.cpp
@@ -22,10 +22,9 @@
 *                                                                     *
 **********************************************************************/
 
-// code is generally compiled via setuptools, therefore NDEBUG is present
-//#ifdef NDEBUG
-//#undef NDEBUG
-//#endif//NDEBUG
+
+
+#define NDEBUG
 
 
 #include <cmath>
diff --git a/bfps/fluid_converter.py b/bfps/fluid_converter.py
index b448d8db870303bc7b8822277711b7db198a527a..04f113c4ed44d99fb020d4a782bb7d28ae09adbb 100644
--- a/bfps/fluid_converter.py
+++ b/bfps/fluid_converter.py
@@ -37,12 +37,14 @@ class fluid_converter(bfps.fluid_base.fluid_particle_base):
             name = 'fluid_converter',
             work_dir = './',
             simname = 'test',
-            fluid_precision = 'single'):
+            fluid_precision = 'single',
+            use_fftw_wisdom = True):
         super(fluid_converter, self).__init__(
                 name = name,
                 work_dir = work_dir,
                 simname = simname,
-                dtype = fluid_precision)
+                dtype = fluid_precision,
+                use_fftw_wisdom = use_fftw_wisdom)
         self.parameters['write_rvelocity']  = 1
         self.parameters['write_rvorticity'] = 1
         self.parameters['fluid_name'] = 'test'
diff --git a/bfps/fluid_resize.py b/bfps/fluid_resize.py
index c022627931c29534c24f26934504712def959e90..5c4e6c5ed001c9ca698d19824677c335a6a0ff53 100644
--- a/bfps/fluid_resize.py
+++ b/bfps/fluid_resize.py
@@ -35,12 +35,14 @@ class fluid_resize(bfps.fluid_base.fluid_particle_base):
             name = 'fluid_resize',
             work_dir = './',
             simname = 'test',
-            dtype = np.float32):
+            dtype = np.float32,
+            use_fftw_wisdom = False):
         super(fluid_resize, self).__init__(
                 name = name,
                 work_dir = work_dir,
                 simname = simname,
-                dtype = dtype)
+                dtype = dtype,
+                use_fftw_wisdom = use_fftw_wisdom)
         self.parameters['src_simname'] = 'test'
         self.parameters['dst_iter'] = 0
         self.parameters['dst_nx'] = 32
diff --git a/done.txt b/done.txt
new file mode 100644
index 0000000000000000000000000000000000000000..11abcd19add0332fa2b7a91b4dc24fde68c17b57
--- /dev/null
+++ b/done.txt
@@ -0,0 +1 @@
+x 2015-12-04 make code py3 compatible                                @python3
diff --git a/setup.py b/setup.py
index ae97c93421499a46f260781ed8a1b0722ec2b42a..5ef07d2904e9fd111aba3f105bc87f27f53a9f3a 100644
--- a/setup.py
+++ b/setup.py
@@ -31,6 +31,7 @@ import pickle
 AUTHOR = 'Cristian C Lalescu'
 AUTHOR_EMAIL = 'Cristian.Lalescu@ds.mpg.de'
 
+import os
 import datetime
 import subprocess
 from subprocess import CalledProcessError
@@ -61,8 +62,8 @@ src_file_list = ['field_descriptor',
 
 header_list = ['cpp/base.hpp'] + ['cpp/' + fname + '.hpp' for fname in src_file_list]
 
-# not sure we need the MANIFEST.in file, but I might as well
 #with open('MANIFEST.in', 'w') as manifest_in_file:
+#    manifest_in_file.write('include libbfps.a\n')
 #    for fname in ['bfps/cpp/' + fname + '.cpp' for fname in src_file_list] + header_list:
 #        manifest_in_file.write('include {0}\n'.format(fname))
 
@@ -83,22 +84,45 @@ pickle.dump(
         open('bfps/install_info.pickle', 'wb'),
         protocol = 2)
 
-from setuptools import setup, Extension
-
-libbfps = Extension(
-        'libbfps',
-        sources = ['bfps/cpp/' + fname + '.cpp' for fname in src_file_list],
-        include_dirs = include_dirs,
-        libraries = libraries,
-        extra_compile_args = extra_compile_args,
-        library_dirs = library_dirs)
+from distutils.command.build import build as DistutilsBuild
+
+class CustomBuild(DistutilsBuild):
+    def run(self):
+        # compile bfps library
+        if not os.path.isdir('obj'):
+            os.makedirs('obj')
+        for fname in src_file_list:
+            ifile = 'bfps/cpp/' + fname + '.cpp'
+            ofile = 'obj/' + fname + '.o'
+            if not os.path.exists(ofile):
+                need_to_compile = True
+            else:
+                need_to_compile = (datetime.datetime.fromtimestamp(os.path.getctime(ofile)) <
+                                   datetime.datetime.fromtimestamp(os.path.getctime(ifile)))
+            if need_to_compile:
+                command_strings = ['g++', '-c']
+                command_strings += ['bfps/cpp/' + fname + '.cpp']
+                command_strings += ['-o', 'obj/' + fname + '.o']
+                command_strings += extra_compile_args
+                command_strings += ['-I' + idir for idir in include_dirs]
+                command_strings.append('-Ibfps/cpp/')
+                print(' '.join(command_strings))
+                subprocess.call(command_strings)
+        command_strings = ['ar', 'rvs', 'bfps/libbfps.a']
+        command_strings += ['obj/' + fname + '.o' for fname in src_file_list]
+        print(' '.join(command_strings))
+        subprocess.call(command_strings)
+        DistutilsBuild.run(self)
+
+from setuptools import setup
 
 setup(
         name = 'bfps',
         packages = ['bfps'],
         install_requires = ['numpy>=1.8', 'h5py>=2.2.1'],
-        ext_modules = [libbfps],
+        cmdclass={'build': CustomBuild},
         package_data = {'bfps': header_list + ['../machine_settings.py',
+                                               'libbfps.a',
                                                'install_info.pickle']},
 ########################################################################
 # useless stuff folows
diff --git a/tests/test_convergence.py b/tests/test_convergence.py
index 0b27504d10c275c79fabb4aa5df8fb715758a1b9..636dea9bc9487241b62166d35ac7367272e513b3 100755
--- a/tests/test_convergence.py
+++ b/tests/test_convergence.py
@@ -71,7 +71,9 @@ def convergence_test(
             code_class = code_class,
             tracer_state_file = h5py.File(os.path.join(c0.work_dir, c0.simname + '.h5'), 'r'))
     # get real space fields
-    converter = bfps.fluid_converter(fluid_precision = opt.precision)
+    converter = bfps.fluid_converter(
+            fluid_precision = opt.precision,
+            use_fftw_wisdom = False)
     converter.write_src()
     converter.set_host_info({'type' : 'pc'})
     for c in [c0, c1, c2]:
diff --git a/tests/test_plain.py b/tests/test_plain.py
index 596eb0e9323c81e4d0c8c504b093aa2b1c95b0f9..a4f032ccf535057e4a89ef0cac7080d4673beff2 100755
--- a/tests/test_plain.py
+++ b/tests/test_plain.py
@@ -46,12 +46,12 @@ def plain(opt):
     assert(opt.niter_todo % 3 == 0)
     opt.work_dir = wd + '/N{0:0>3x}_2'.format(opt.n)
     opt.njobs *= 2
-    opt.niter_todo /= 2
+    opt.niter_todo = opt.niter_todo//2
     c1 = launch(opt, dt = c0.parameters['dt'])
     c1.compute_statistics()
     opt.work_dir = wd + '/N{0:0>3x}_3'.format(opt.n)
-    opt.njobs = 3*opt.njobs/2
-    opt.niter_todo = 2*opt.niter_todo/3
+    opt.njobs = 3*opt.njobs//2
+    opt.niter_todo = 2*opt.niter_todo//3
     c2 = launch(opt, dt = c0.parameters['dt'])
     c2.compute_statistics()
     # plot energy and enstrophy
diff --git a/todo.txt b/todo.txt
index 41973e4e1db5181dcde4bed763ea8e3d54288075..c25b79d183a098e3384e324612b4255696157c12 100644
--- a/todo.txt
+++ b/todo.txt
@@ -1,6 +1,5 @@
 (B) use less memory                                         @optimization
 (C) code overview                                           @documentation
-(C) make code py3 compatible                                @python3
 (C) test involving hydrodynamic similarity                  @tests
 (C) use HDF5 io for fields                                  @HDF5 +I/O
 (D) test anisotropic grids                                  @tests
diff --git a/tox_convergence.ini b/tox_convergence.ini
index 447e32fe9a7ffa2fc7adbcd9e07ca464785b8700..39a368ff0d1954cb841cbaab41e5a8d98bb68031 100644
--- a/tox_convergence.ini
+++ b/tox_convergence.ini
@@ -1,6 +1,7 @@
 [tox]
-envlist = py27
+envlist = py34
 [testenv]
+deps = matplotlib
 whitelist_externals =
     echo
     cp
diff --git a/tox_io.ini b/tox_io.ini
index 994d35525286ef31df4a896a341f796287c3ba2e..de8c2fc5d0bb5fa7498527ecb4b96b32ca000c69 100644
--- a/tox_io.ini
+++ b/tox_io.ini
@@ -1,6 +1,7 @@
 [tox]
-envlist = py27
+envlist = py27, py34
 [testenv]
+deps = matplotlib
 whitelist_externals =
     echo
     cp
diff --git a/tox_plain.ini b/tox_plain.ini
index 1af8e3cd72aeb99524d339dbf9cd13ca306d1f2a..ad816b8378eab61dcfcc679f9704bffa09e6cb78 100644
--- a/tox_plain.ini
+++ b/tox_plain.ini
@@ -1,6 +1,7 @@
 [tox]
-envlist = py27
+envlist = py34
 [testenv]
+deps = matplotlib
 whitelist_externals =
     echo
     cp