pingus-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Pingus-Devel] Pingus on Mac OS X


From: Dave Vasilevsky
Subject: [Pingus-Devel] Pingus on Mac OS X
Date: Sat, 13 Oct 2007 23:33:08 -0400

Hi,

I'm thrilled that Pingus now uses SDL. ClanLib never worked particularly
well on the Mac, but now it's pretty easy to get Pingus HEAD working on
Mac OS X.

My patch for better Mac support is appended to this mail, changes include:

* src/pingus_main.cpp: Declare CoreFoundation functions and types. It would be
        nicer to just include CoreFoundation.h, but there are some
name conflicts
        between it and Pingus.

* SConstruct:
        - Check whether ICONV_CONST should be 'const' or blank. Also
check whether
                libiconv needs to be linked in or not.

        - Passing command line options to 'scons configure' didn't work well
                before, since all values were treated as strings. Now
treat values as
                booleans or space-separated lists, as appropriate.

        - On Mac and Windows (and other platforms) the SDL headers
#define 'main'
                to 'SDL_main', so they can do some initialization
early in the startup
                sequence. But SDL_main doesn't automatically have C
linkage the way
                main does, which can make tests for SDL_image and
SDL_mixer fail.
                Replace them with a custom test for SDL libraries.

A few build features I'd like to add eventually, but not right away:
* Build a Universal Binary (PPC and Intel)
* Build a self-contained Mac OS X application bundle
* Link to SDL 'frameworks' instead of libraries.
* Auto-detect sensible defaults for linuxusbmouse and linuxevdev.
        (Would platform.system() == 'Linux' be the right test for this?)

Unfortunately there are still some performance problems on my old Mac. Once
the settings dialog is implemented, hopefully I'll be able to turn off
some of the eye candy and music so I can get better FPS. Other than that
Pingus runs very well, I've played several levels with no problems at all.

Thanks very much to the Pingus authors and other contributors!

Cheers,
Dave Vasilevsky


Index: src/pingus_main.cpp
===================================================================
--- src/pingus_main.cpp (revision 3277)
+++ src/pingus_main.cpp (working copy)
@@ -35,6 +35,21 @@
 #include "string_util.hpp"
 #include "sexpr_file_reader.hpp"

+#if defined(__APPLE__)
+/* Can't use the include, some type names conflict.
+#include <CoreFoundation/CoreFoundation.h>
+*/
+extern "C" {
+       typedef unsigned char UInt8;
+       typedef void* CFTypeRef;
+       typedef CFTypeRef CFURLRef;
+       CFURLRef CFBundleGetMainBundle(void);
+       CFURLRef CFBundleCopyResourcesDirectoryURL(CFTypeRef);
+       bool CFURLGetFileSystemRepresentation(CFURLRef, bool, UInt8*, int);
+       void CFRelease(CFTypeRef);
+}
+#endif
+
 #include "SDL.h"

 #ifdef ENABLE_BINRELOC
Index: SConstruct
===================================================================
--- SConstruct  (revision 3277)
+++ SConstruct  (working copy)
@@ -20,6 +20,7 @@
 ##  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

 import sys, os
+import SCons.Util

 pingus_sources = [
 # # 'gui/buffer_graphic_context.cpp',
@@ -293,28 +294,112 @@
 'src/worldobjs/woodthing.cpp',
 'lib/binreloc/binreloc.c'
 ]
-
+
+class _SpaceListOptionClass:
+   """An option type for space-separated lists with arbitrary elements."""
+   def CheckDir(self, val):
+      if not os.path.isdir(val):
+         raise SCons.Errors.UserError("No directory at %s" % val)
+
+   def _convert(self, key, val, env):
+      if SCons.Util.is_List(val): # prefer val if it's already a list
+         return val
+      elif len(val) > 0 and val[0] == '[' and val[-1] == ']':
+         # or a repr of a list
+         return eval(val)
+      elif env: # otherwise, use whatever's in env
+         val = env[key]
+         if not SCons.Util.is_List(val):
+            val = val.split(None)
+         return val
+      else: # val was substituted into a string, losing its structure
+         # We'll be called again with env, hopefully that's more useful
+         raise TypeError("try again with the environment")
+
+   def _validate(self, val, env, check, converter):
+      for i in converter(val, env):
+         if check(i):
+            return True
+      return False
+
+   def __call__(self, key, help, check=None, default=[]):
+      def converter(val, env = None):
+         return self._convert(key, val, env)
+
+      validator = None
+      if check is not None:
+         validator = lambda k, v, e: self._validate(v, e, check, converter)
+      return (key, help, default, validator, converter)
+
+SpaceListOption = _SpaceListOptionClass()
+
+
 def DefineOptions(filename, args):
    opts = Options(filename, args)
-   opts.Add('CPPPATH', 'Additional preprocessor paths', [])
-   opts.Add('CPPFLAGS', 'Additional preprocessor flags', [])
-   opts.Add('CPPDEFINES', 'defined constants', [])
-   opts.Add('LIBPATH', 'Additional library paths', [])
-   opts.Add('LIBS', 'Additional libraries', [])
-   opts.Add('CCFLAGS', 'C Compiler flags', [])
-   opts.Add('LINKFLAGS', 'Linker Compiler flags', [])
+   opts.Add(SpaceListOption('CPPPATH', 'Additional preprocessor paths',
+      SpaceListOption.CheckDir))
+   opts.Add(SpaceListOption('CPPFLAGS', 'Additional preprocessor flags'))
+   opts.Add(SpaceListOption('CPPDEFINES', 'defined constants'))
+   opts.Add(SpaceListOption('LIBPATH', 'Additional library paths',
+      SpaceListOption.CheckDir))
+   opts.Add(SpaceListOption('LIBS', 'Additional libraries'))
+   opts.Add(SpaceListOption('CCFLAGS', 'C Compiler flags'))
+   opts.Add(SpaceListOption('LINKFLAGS', 'Linker Compiler flags'))
    opts.Add('CC', 'C Compiler', 'gcc')
    opts.Add('CXX', 'C++ Compiler', 'g++')
 #   opts.Add('debug', 'Build with debugging options', 0)
 #   opts.Add('profile', 'Build with profiling support', 0)
-   opts.Add('with_xinput', 'Build with Xinput support', False)
-   opts.Add('with_linuxusbmouse', 'Build with Linux USB mouse support', True)
-   opts.Add('with_linuxevdev', 'Build with Linux evdev support', True)
-   opts.Add('with_wiimote', 'Build with Wiimote support', False)
-   opts.Add('ignore_errors', 'Ignore any fatal configuration errors', False)
+   opts.Add(BoolOption('with_xinput', 'Build with Xinput support', False))
+   opts.Add(BoolOption('with_linuxusbmouse',
+      'Build with Linux USB mouse support', True))
+   opts.Add(BoolOption('with_linuxevdev',
+      'Build with Linux evdev support', True))
+   opts.Add(BoolOption('with_wiimote', 'Build with Wiimote support', False))
+   opts.Add(BoolOption('ignore_errors',
+      'Ignore any fatal configuration errors', False))
    opts.Add('optional_sources', 'Additional source files', [])
    return opts

+def CheckSDLLib(context, sdllib):
+   """
+   On some platforms, SDL does this ugly redefine-main thing, that can
+   interact badly with CheckLibWithHeader.
+   """
+   lib = "SDL_%s" % sdllib
+   context.Message('Checking for %s...' % lib)
+   text = """
+#include "SDL.h"
+#include "%s.h"
+int main(int argc, char* argv[]) { return 0; }
+""" % lib
+   context.AppendLIBS(lib)
+   if context.BuildProg(text, ".cpp"):
+      context.Result("failed")
+      return False
+   else:
+      context.Result("ok")
+      return True
+
+def CheckIconv(context):
+   text = """
+#include <iconv.h>
+int main() {
+   %s char *foo;
+   (void)iconv((iconv_t)0, &foo, (size_t*)0, (char**)0, (size_t*)0);
+   return 0;
+}
+"""
+   config.CheckLibWithHeader('iconv', 'iconv.h', 'c++') # Ok to fail
+   context.Message('Check how to call iconv...')
+
+   for i in ['', 'const']:
+      if config.TryCompile(text % i, ".cpp"):
+         context.Result("ok")
+         return i
+   context.Result("failed")
+   return False
+
+
 def CheckMyProgram(context, prgn):
    context.Message('Checking for %s...' % prgn)
    for i in context.env['ENV']['PATH'].split(":"):
@@ -347,7 +432,11 @@

     config_h_defines = []

-    config = env.Configure(custom_tests = {'CheckMyProgram' : CheckMyProgram})
+    config = env.Configure(custom_tests = {
+       'CheckMyProgram' : CheckMyProgram,
+       'CheckSDLLib': CheckSDLLib,
+       'CheckIconv': CheckIconv,
+    })
     fatal_error = ""
     reports = ""

@@ -396,14 +485,16 @@

     if config.CheckMyProgram('sdl-config'):
        env.ParseConfig('sdl-config  --cflags --libs')
-       for lib in ['SDL_image', 'SDL_mixer']:
-          if not config.CheckLibWithHeader(lib, lib + ".h", 'c++'):
-             fatal_error += "  * library '%s' not found\n" % lib
-          else:
-             env['LIBS'] += [lib]
+       for sdllib in ['image', 'mixer']:
+          if not config.CheckSDLLib(sdllib):
+             fatal_error += "  * SDL library '%s' not found\n" % sdllib
     else:
        fatal_error += "  * couldn't find sdl-config, SDL missing\n"

+    iconv_const = config.CheckIconv()
+    if not iconv_const:
+       fatal_error += "  * can't call iconv\n"
+
     env = config.Finish()
     opts.Save("config.py", env)

@@ -421,7 +512,7 @@
     config_h = open('config.h', 'w')
     config_h.write('#define VERSION "0.7.1"\n')
     config_h.write('#define ENABLE_BINRELOC 1\n')
-    config_h.write('#define ICONV_CONST\n') # FIXME: make a check for this
+    config_h.write('#define ICONV_CONST %s\n' % iconv_const)
     for (v,k) in config_h_defines:
         config_h.write('#define %s %s\n' % (v, k))
     config_h.close()

reply via email to

[Prev in Thread] Current Thread [Next in Thread]