0

I've tried to use the Freeglut library in a Swift 4 Project. When the

void glutInit(int *argcp, char **argv);

function is shifted to Swift, its declaration is

func glutInit(_ pargc: UnsafeMutablePointer<Int32>!, _ argv: UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>!)

Since I don't need the real arguments from the command line I want to make up the two arguments. I tried to define **argv in the Bridging-Header.h file

#include <OpenGL/gl.h>
#include <GL/glut.h>

char ** argv[1] = {"t"};

and use them in main.swift

func main() {
    var argcp: Int32 = 1
    glutInit(&argcp, argv!)  // EXC_BAD_ACCESS
    glutInitDisplayMode(UInt32(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH));
    glutCreateWindow("my project")
    glutDisplayFunc(display)
    initOpenGL()
    glutMainLoop()

but with that I get Thread 1: EXC_BAD_ACCESS (code=1, address=0x74) at the line with glutInit().

How can I initialize glut properly? How can I get an UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>! so that it works?

genpfault
  • 51,148
  • 11
  • 85
  • 139
oliver_p
  • 3
  • 2
  • 1
    I'm not a Swift guy, but it sure looks like it ought to be "char * argv[1] = {"t"};" rather than "char ** argv[1] = {"t"};" (note the single star rather than the double). Not an answer since I'm just guessing... – Drew Hall Jul 19 '18 at 18:48
  • When I delete one `*` then it won't even compile because the argument is wrapped in two UnsafeMutablePointers which is represented by the two `*` I guess – oliver_p Jul 19 '18 at 18:55

1 Answers1

0

The reason the right code in C char * argv[1] = {"t"}; does not work is because Swift imports fixed size C-array as a tuple, not a pointer to the first element.

But your char ** argv[1] = {"t"}; is completely wrong. Each Element of argv needs to be char **, but you assign char * ("t"). Xcode must have shown you a warning at first build:

warning: incompatible pointer types initializing 'char **' with an expression of type 'char [2]'

You should better take incompatible pointer types warning as error, unless you know what you are doing completely.

Generally, you should better not write some codes generating actual code/data like char * argv[1] = {"t"}; in a header file.


You can try it with Swift code.

As you know, when you want to pass a pointer to single element T, you declare a var of type T and pass &varName to the function you call.

As argcp in your code.

As well, when you want to pass a pointer to multiple element T, you declare a var of type [T] (Array<T>) and pass &arrName to the function you call.

(Ignoring immutable case to simplify.)

The parameter argv matches this case, where T == UnsafeMutablePointer<Int8>?.

So declare a var of type [UnsafeMutablePointer<Int8>?].

func main() {
    var argc: Int32 = 1
    var argv: [UnsafeMutablePointer<Int8>?] = [
        strdup("t")
    ]
    defer { argv.forEach{free($0)} }

    glutInit(&argc, &argv)
    //...
}

But I wonder if you really want to pass something to glutInit().

You can try something like this:

func main() {
    var argc: Int32 = 0 //<- 0

    glutInit(&argc, nil)
    //...
}

I'm not sure if freeglut accept this, but you can find some articles on the web saying that this works in some implementation of Glut.

OOPer
  • 47,149
  • 6
  • 107
  • 142