Scala-native: Expose argv[0] since it is missing in the entrypoint: def main(args: Array[String])

Created on 5 Aug 2016  路  4Comments  路  Source: scala-native/scala-native

Context

C programmers (and even bash programmers) are used to do tricks with command line arguments. A very common trick is testing argv[0] (this is C!) in order to assume certain defaults. For example, grep, egrep and fgrep are all the same executable really, which behaves differently depending on how it is invoked.

The entry point of a C application is:

int main(int argc, void* argv[])

So, when you invoke fgrep abc file.txt, this is what the application sees:

argc = 3
argv[0] = "fgrep"
argv[1] = "abc"
argv[2] = "file.txt"

Now compare with Scala Native. The entry point of a Scala application is:

def main(args: Array[String]): Unit

If you invoke `fgrep-out abc file.txt``, this is what the application sees:

args(0) = "abc"
args(1) = "file.txt"

Discussion

I suggest that Scala Native somehow passes the name of the executable to the program.

Possibly the runtime enviroment could simply expose a variable which contains the argv[0] which was ignored when args was populated. Something like exposing...

private var argv0 = ""
def program: String = argv0

... and initializing argv0 like this:

argv0 = argv(0)

just before:

     82     while (c < argc-1) {
     83       // use the default Charset (UTF_8 atm)
     84       args(c) = fromCString(argv(c+1))
     85       c += 1
     86     }

Ideas? Thanks

feature interop

Most helpful comment

I vote for a dual entry point. The programmer choose which one in build.sbt:

JVM style, the default:

def main(args: Array[String]): Unit

C style, if some configuration is set in build.sbt

def main(argc: Int, argv: Ptr[CString]): Int

As a side effect, this solution supports better the case where the application uses the Scala syntax but calls only C functions as it doesn't introduce unused dependencies on java.lang.String and scala.Array

All 4 comments

At this point, scala-bindgen simply fakes argv(0) like shown below:

def main(args: Array[String]): Unit = {
  val argc = args.length + 1
  val argv: Ptr[CString] = malloc(sizeof[CString] * argc).cast[Ptr[CString]]
  argv(0) = "bindgen" //FIXME: https://github.com/scala-native/scala-native/issues/266
  args.zipWithIndex.foreach { case (arg, idx) => argv(idx+1) = args(idx) }
  System.exit( main(argc, argv) )
}

I vote for a dual entry point. The programmer choose which one in build.sbt:

JVM style, the default:

def main(args: Array[String]): Unit

C style, if some configuration is set in build.sbt

def main(argc: Int, argv: Ptr[CString]): Int

As a side effect, this solution supports better the case where the application uses the Scala syntax but calls only C functions as it doesn't introduce unused dependencies on java.lang.String and scala.Array

We should probably do something along the lines of JSApp from Scala.js to expose an alternative C-style entry point.

I volunteer for implementing this. Thanks.

Was this page helpful?
0 / 5 - 0 ratings