1

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?

3
  • "Should I implement the "new" method myself?" Just ask yourself: Who would you expect to provide that function for you? Do you expect some of the macros you are using, to expand to such a _new function? How would anyone except you know what needs to be done in such a constructer function? Also "Given that in the header I prototype" that is not some GTK specific thing. If you provide a prototype you onla make a promise that there is some function out there that looks like you declar in the prototype. It is up to you to keep the promise and provide the implementation as well. Commented Dec 2, 2024 at 7:57
  • @Gerhardh I'm already providing two "init" functions, so I thought perhaps it somehow would expand to something utilising one of those? I also don't really know what such a function would look like given that I can't find any section in the guide that talks about it. I know that in general, if you provide a prototype in a header, you should implement it yourself, but GObject does a lot of macro things that I don't understand. Commented Dec 2, 2024 at 10:40
  • The GObject macros all document exactly what functions/macros they expand out to produce. None of them can produce a ‘new’ function for you, because none of them know which properties (if any) you’d like to expose as arguments to the ‘new’ function. Commented Dec 2, 2024 at 13:56

1 Answer 1

0

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.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.