Thursday, December 15, 2011

execve under OSX Snow Leopard

Background:

A colleague and I are developing a piece of code (called pbsmake) in python that ends up interpreting something that looks like a Makefile. We will use pbsmake to help distribute jobs to a local scheduler (each makefile target gets its own job) but we found that we may want to use the pbsmake interpreter as a shell interpreter itself so we can simply execute certain commands (which are really like makefiles) with a target.

Most of our development has been under GNU/Linux and this works just fine. However, as soon as we do this under OSX Snow Leopard, the top-level makefile starts being executed as if it were a bash script.

How to replicate:


  1. create a simple interpreter that is a shell script itself:
    1. /Users/imoverclocked/simple-interp.sh:
      1. #!/bin/cat
      2. This is my simple interpreter, it simply spits the file onto STDOUT
  2. create a script that uses this interpreter:
    1. /Users/imoverclocked/simple-script.sh:
      1. #!/Users/imoverclocked/simple/interp.sh
      2. This is a simple script that is interpreted (really, just spit out by cat)
  3. try and execute the simple-script.sh
    1. ./simple-script.sh
      1. Badly placed ()'s.
  4. change the interpreter to first invoke /usr/bin/env as a work-around
    1. /Users/imoverclocked/simple-script.sh:
      1. #!/usr/bin/env /Users/imoverclocked/simple/interp.sh
      2. This is a simple script that is interpreted (really, just spit out by cat)
  5. executing the script now gives the same output as on other unix-like architectures.
    1. $ ./simple-script.sh 
      #!/bin/cat
      This is my simple interpreter, it simply spits the file onto STDOUT
      #!/home/pirl/tims/sh/simple-interp.sh
      This is a simple script that is interpreted (really, just spit out by cat)

My guess to what is happening is that execv* can't handle the case where a script calls a script to interpret a script. One work-around is to use /usr/bin/env in the "simple-script.sh" header which works since /usr/bin/env is a binary executable which then invokes the script in it's own execvp call.

Apparently this works under Lion but we can't quite make the plunge across our infrastructure yet. Hope this helps someone else out there! Maybe Apple is listening?