diff -r d0296183eeeb cx_Freeze/__init__.py
--- a/cx_Freeze/__init__.py	Mon Feb 13 22:16:40 2012 +0000
+++ b/cx_Freeze/__init__.py	Mon Feb 20 17:20:29 2012 +0100
@@ -4,6 +4,8 @@
 from cx_Freeze.dist import *
 if sys.platform == "win32" and sys.version_info[:2] >= (2, 5):
     from cx_Freeze.windist import *
+if sys.platform == "darwin":
+    from cx_Freeze.macdist import *
 from cx_Freeze.finder import *
 from cx_Freeze.freezer import *
 from cx_Freeze.main import *
diff -r d0296183eeeb cx_Freeze/dist.py
--- a/cx_Freeze/dist.py	Mon Feb 13 22:16:40 2012 +0000
+++ b/cx_Freeze/dist.py	Mon Feb 20 17:20:29 2012 +0100
@@ -350,6 +350,8 @@
     if sys.platform == "win32":
         if sys.version_info[:2] >= (2, 5):
             _AddCommandClass(commandClasses, "bdist_msi", cx_Freeze.bdist_msi)
+    elif sys.platform == "darwin":
+        _AddCommandClass(commandClasses, "bdist_mac", cx_Freeze.bdist_mac)
     else:
         _AddCommandClass(commandClasses, "bdist_rpm", cx_Freeze.bdist_rpm)
     _AddCommandClass(commandClasses, "build", build)
diff -r d0296183eeeb cx_Freeze/macdist.py
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/cx_Freeze/macdist.py	Mon Feb 20 17:20:29 2012 +0100
@@ -0,0 +1,115 @@
+from distutils.core import Command
+import distutils.errors
+import distutils.util
+import os, stat
+import subprocess
+
+__all__ = [ "bdist_mac" ]
+
+plist_template = \
+"""<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleIconFile</key>
+	<string>%(bundle_iconfile)s</string>
+	<key>CFBundleDevelopmentRegion</key>
+	<string>English</string>
+	<key>CFBundleExecutable</key>
+	<string>%(bundle_executable)s</string>
+</dict>
+</plist>
+"""
+
+class bdist_mac(Command):
+    description = "create a Mac application bundle an possibly a DMG disk image"
+    
+    user_options = [
+        ('build-dmg=', None, 'build a DMG disk image containing the application bundle'),
+        ('dmg-size=', None, 'Size (in MB) of the DMG disk image (before it is compressed)'),
+        ('bundle-iconfile=', None, 'Name of the application bundle icon file as stored in the Info.plist file'),
+    ]
+    
+    boolean_options = [ 'build-dmg' ]
+    
+    negative_opts = ['no-build-dmg' ]
+    
+    def initialize_options(self):
+        self.dmg_size = 100
+        self.build_dmg = False
+        self.bundle_iconfile = 'icon.icns'
+        
+    def finalize_options(self):
+        print ('finalize options ', self.dmg_size, self.build_dmg)
+    
+    def create_plist(self):
+        """Create the Contents/Info.plist file"""
+        plist = open(os.path.join(self.contentsDir, 'Info.plist'),'w')
+        plist.write(plist_template % self.__dict__)
+        plist.close()
+    
+    def setRelativeReferencePaths(self):
+        """ For all files in Contents/MacOS, check if they are binaries
+        with references to other files in that dir. If so, make those references
+        relative. The appropriate commands are applied to all files; they will
+        just fail for files on which they do not apply."""
+        files = os.listdir(self.binDir)
+        
+        for file in files:
+            filepath = os.path.join(self.binDir, file)
+            
+            #Ensure write permissions
+            mode = os.stat(filepath).st_mode
+            if not (mode & stat.S_IWUSR):
+                os.chmod(filepath, mode | stat.S_IWUSR)
+            
+            
+            #Let the file itself know its place
+            subprocess.call(('install_name_tool','-id','@executable_path/'+file,filepath))
+            
+            #Find the references: call otool -L on the file and read lines [1:]
+            otool = subprocess.Popen(('otool','-L', filepath),stdout=subprocess.PIPE)
+            references = otool.stdout.readlines()[1:]
+            
+            for reference in references:
+                # Find the actual referenced file name
+                referencedFile = reference.decode().strip().split()[0]
+                
+                if referencedFile.startswith('@'):
+                    #The referencedFile is already a relative path
+                    continue
+                
+                path, name = os.path.split(referencedFile)
+                
+                # See if we provide the referenced file, if so, change the reference
+                if name in files:
+                    newReference='@executable_path/'+name
+                    subprocess.call(('install_name_tool','-change',referencedFile,newReference,filepath))
+    
+    def run(self):
+        self.run_command('build')
+        build = self.get_finalized_command('build')
+        
+        # Define the paths within the application bundle
+        self.bundleDir = os.path.join(build.build_base, self.distribution.get_fullname()+".app")
+        self.contentsDir = os.path.join(self.bundleDir, 'Contents')
+        self.resourcesDir = os.path.join(self.contentsDir, 'Resources')
+        self.binDir = os.path.join(self.contentsDir, 'MacOS')
+
+        #Find the executable name
+        executable = self.distribution.executables[0].targetName
+        _, self.bundle_executable=os.path.split(executable)
+
+        # Build the app directory structure
+        self.mkpath(self.resourcesDir)
+        self.mkpath(self.binDir)
+        
+        self.copy_tree(build.build_exe, self.binDir)
+
+        # Create the Info.plist file
+        self.execute(self.create_plist,())
+        
+        # Make all references to libraries relative
+        self.execute(self.setRelativeReferencePaths,())
+
+
diff -r d0296183eeeb samples/PyQt4/setup.py
--- a/samples/PyQt4/setup.py	Mon Feb 13 22:16:40 2012 +0000
+++ b/samples/PyQt4/setup.py	Mon Feb 20 17:20:29 2012 +0100
@@ -21,5 +21,6 @@
         name = "simple_PyQt4",
         version = "0.1",
         description = "Sample cx_Freeze PyQt4 script",
+        options = {"build_exe": {"includes": "atexit"}},
         executables = [Executable("PyQt4app.py", base = base)])
 
