clinker-errorsundefined-referencegobject

Do I need to implement the "new" method myself when writing GObject classes in C?


I'm trying to follow the GObject Tutorial to implement my first GObject class. So far, I've come up with this code:

train.h:

#pragma once

#include <glib-object.h>

G_BEGIN_DECLS

#define EXAMPLE_TYPE_TRAIN example_train_get_type ()
G_DECLARE_DERIVABLE_TYPE (ExampleTrain, example_train, EXAMPLE, TRAIN, GObject)

struct _ExampleTrainClass
{
  GObjectClass parent_class;

  void (* get_route) (ExampleTrain *train);
};

ExampleTrain *example_train_new (void);

G_END_DECLS

train.c:

#include "train.h"

typedef struct {
  char *origin;
} ExampleTrainPrivate;

G_DEFINE_TYPE_WITH_PRIVATE (ExampleTrain, example_train, G_TYPE_OBJECT)

static void
example_train_class_init (ExampleTrainClass *klass)
{

}

static void
example_train_init (ExampleTrain *self)
{
  ExampleTrainPrivate *priv = example_train_get_instance_private (self);
}

Of course, it doesn't really do anything yet, but it compiles and so I thought I could try to instantiate it. Given that in the header I prototype example_train_new (), I presumed that I then could use this in my main.c file to instantiate this class, but no dice:

[1/2] Compiling C object src/gobject-inheritance.p/main.c.o
../../../../../gobject-inheritance/src/main.c: In function ‘main’:
../../../../../gobject-inheritance/src/main.c:13:17: warning: unused variable ‘train_one’ [-Wunused-variable]
   13 |   ExampleTrain *train_one = example_train_new ();
      |                 ^~~~~~~~~
[2/2] Linking target src/gobject-inheritance
FAILED: src/gobject-inheritance 
cc  -o src/gobject-inheritance src/gobject-inheritance.p/fruit.c.o src/gobject-inheritance.p/main.c.o src/gobject-inheritance.p/train.c.o -L/app/lib -Wl,--as-needed -Wl,--no-undefined -Wl,--start-group /usr/lib/x86_64-linux-gnu/libglib-2.0.so /usr/lib/x86_64-linux-gnu/libgobject-2.0.so -Wl,--end-group
/usr/lib/gcc/x86_64-unknown-linux-gnu/14.2.0/../../../../x86_64-unknown-linux-gnu/bin/ld: src/gobject-inheritance.p/main.c.o: in function `main':
/mnt/storage/Programming/.gnome-builder/projects/gobject-inheritance/builds/org.gnome.Example.json-flatpak-org.freedesktop.Platform-24.08-x86_64-main/../../../../../gobject-inheritance/src/main.c:13:(.text+0x10): undefined reference to `example_train_new'
collect2: error: ld returned 1 exit status
ninja: build stopped: subcommand failed.

If I'm reading this error right, the problem seems to be that the linker can't find any definition for example_train_new (). While it might seem sensible to just define it myself, in the linked tutorial I don't see this done anywhere.

What am I doing wrong here? Should I implement the "new" method myself?


Solution

  • I ended up looking at some implementations in the GTK 4 source code for how to do this. Specifically, gtk/gtkstack.c.

    For the case above, a simple constructor like this seems to suffice:

    ExampleTrain *
    example_train_new (void)
    {
      return g_object_new (EXAMPLE_TYPE_TRAIN, NULL);
    }
    

    However, if one also for example wants to set the private origin property from the example above in the constructor, you can do this:

    ExampleTrain *
    example_train_new (const char *origin)
    {
      ExampleTrain *self = g_object_new (EXAMPLE_TYPE_TRAIN, NULL);
      ExampleTrainPrivate *priv = example_train_get_instance_private (self);
      priv->origin = origin;
    
      return self;
    }
    

    If you wanted to set a public property, you would do the same as the above but instead use self in place of priv. So, the whole example_train_get_instance_private (self) part could be removed if you don't have any private properties to set.