0

I have been recently been trying to get started with GTKmm on my MacBook, and I have installed lots of the dependencies using Homebrew. However, when I go to compile my program, I get this error:

Undefined symbols for architecture x86_64:
  "HelloWorld::HelloWorld()", referenced from:
      _main in main-88dc5e.o
  "HelloWorld::~HelloWorld()", referenced from:
      _main in main-88dc5e.o
  "Gtk::Application::run(Gtk::Window&)", referenced from:
      _main in main-88dc5e.o
  "Gtk::Application::create(int&, char**&, Glib::ustring const&, Gio::ApplicationFlags)", referenced from:
      _main in main-88dc5e.o
  "Glib::ustring::ustring(char const*)", referenced from:
      _main in main-88dc5e.o
  "Glib::ustring::~ustring()", referenced from:
      _main in main-88dc5e.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

My program is this:

helloworld.h:

#ifndef GTKMM_EXAMPLE_HELLOWORLD_H
#define GTKMM_EXAMPLE_HELLOWORLD_H

#include <gtkmm-3.0/gtkmm/button.h>
#include <gtkmm-3.0/gtkmm/window.h>

class HelloWorld : public Gtk::Window {
    public:
        HelloWorld();
        virtual ~HelloWorld();

    protected:
        //Signal handlers:
        void on_button_clicked();

        //Member widgets:
        Gtk::Button m_button;
};

#endif

helloworld.cpp:

#include "helloworld.h"
#include <iostream>

HelloWorld::HelloWorld()
: m_button("Hello World")   // creates a new button with label "Hello World".
{
    // Sets the border width of the window.
    set_border_width(10);

    // When the button receives the "clicked" signal, it will call the
    // on_button_clicked() method defined below.
    m_button.signal_clicked().connect(sigc::mem_fun(*this,
              &HelloWorld::on_button_clicked));

    // This packs the button into the Window (a container).
    add(m_button);

    // The final step is to display this newly created widget...
    m_button.show();
}

main.cpp:

#include "helloworld.h"
#include <gtkmm-3.0/gtkmm/application.h>

int main (int argc, char *argv[]) {
    auto app = Gtk::Application::create(argc, argv, "org.gtkmm.example");

    HelloWorld helloworld;

    //Shows the window and returns when it is closed.
    return app->run(helloworld);
}

...which comes from here.

I am using a Makefile to include all of the Homebrew-installed libraries:

# the Makefile for the helloworld GTK+ example
cellar=/usr/local/Cellar
inc_dir=/usr/local/include

gtk_inc=$(cellar)/gtk+3/3.24.25/include/gtk-3.0
gtk_lib=$(cellar)/gtk+3/3.24.25/lib

gtkmm_inc=$(cellar)/gtkmm3/3.24.3_3/include/gtkmm-3.0
gtkmm_lib_inc=$(cellar)/gtkmm3/3.24.3_3/lib/gtkmm-3.0/include
gtkmm_lib=$(cellar)/gtkmm3/3.24.3_3/lib

glibmm_inc=$(cellar)/glibmm@2.66/2.66.0/include/glibmm-2.4
glibmm_lib_inc=$(cellar)/glibmm@2.66/2.66.0/lib/glibmm-2.4/include
glibmm_lib=$(cellar)/glibmm@2.66/2.66.0/lib

glib_inc=$(cellar)/glib/2.66.7/include/glib-2.0
glib_lib_inc=$(cellar)/glib/2.66.7/lib/glib-2.0/include
glib_lib=$(cellar)/glib/2.66.7/lib

sigcpp_inc=$(cellar)/libsigc++@2/2.10.6/include/sigc++-2.0/sigc++
sigcpp_inc_parent=$(cellar)/libsigc++@2/2.10.6/include/sigc++-2.0
sigcpp_lib_inc=$(cellar)/libsigc++@2/2.10.6/lib/sigc++-2.0/include
sigcpp_lib=$(cellar)/libsigc++@2/2.10.6/lib

gdkmm_inc=$(cellar)/gtkmm3/3.24.3_3/include/gdkmm-3.0
gdkmm_lib_inc=$(cellar)/gtkmm3/3.24.3_3/lib/gdkmm-3.0/include
gdlmm_lib=$(cellar)/gtkmm3/3.24.3_3/lib

pango_inc=$(cellar)/pango/1.48.2/include/pango-1.0
#pango_lib_inc=$(cellar)/pango/1.48.2/lib
pango_lib=$(cellar)/pango/1.48.2/lib

pangomm_inc=$(cellar)/pangomm@2.46/2.46.0/include/pangomm-1.4
pangomm_lib_inc=$(cellar)/pangomm@2.46/2.46.0/lib/pangomm-1.4/include
pangomm_lib=$(cellar)/pangomm@2.46/2.46.0/lib

harfbuzz_inc=$(cellar)/harfbuzz/2.7.4/include/harfbuzz
harfbuzz_lib=$(cellar)/harfbuzz/2.7.4/lib

cairo_inc=$(cellar)/cairo/1.16.0_4/include/cairo
cairo_lib=$(cellar)/cairo/1.16.0_4/lib

cairomm_inc=$(cellar)/cairomm@1.14/1.14.2/include/cairomm-1.0
cairomm_lib_inc=$(cellar)/cairomm@1.14/1.14.2/lib/cairomm-1.0/include
cairomm_lib=$(cellar)/cairomm@1.14/1.14.2/lib

freetype_inc=$(cellar)/freetype/2.10.4/include/freetype2
freetype_lib=$(cellar)/freetype/2.10.4/lib

atk_inc=$(cellar)/atk/2.36.0/include/atk-1.0
atk_lib=$(cellar)/atk/2.36.0/lib

atkmm_inc=$(cellar)/atkmm@2.28/2.28.1_1/include/atkmm-1.6
atkmm_lib_inc=$(cellar)/atkmm@2.28/2.28.1_1/lib/atkmm-1.6/include
atkmm_lib=$(cellar)/atkmm@2.28/2.28.1_1/lib

gdk-pixbuf_inc=$(cellar)/gdk-pixbuf/2.42.2/include/gdk-pixbuf-2.0
gdk-pixbuf_lib=$(cellar)/gdk-pixbuf/2.42.2/lib

giomm_inc=$(cellar)/glibmm@2.66/2.66.0/include/giomm-2.4
giomm_lib_inc=$(cellar)/glibmm@2.66/2.66.0/lib/giomm-2.4/include
giomm_lib=$(cellar)/glibmm@2.66/2.66.0/lib

INC_LIST=$(gtk_inc) \
    $(gtkmm_inc) \
    $(gtkmm_lib_inc) \
    $(glibmm_inc) \
    $(glibmm_lib_inc) \
    $(glib_inc) \
    $(glib_lib_inc) \
    $(sigcpp_inc) \
    $(sigcpp_inc_parent) \
    $(sigcpp_lib_inc) \
    $(gdkmm_inc) \
    $(gdkmm_lib_inc) \
    $(pango_inc) \
    $(pangomm_inc) \
    $(pangomm_lib_inc) \
    $(harfbuzz_inc) \
    $(cairo_inc) \
    $(cairomm_inc) \
    $(cairomm_lib_inc) \
    $(freetype_inc) \
    $(atk_inc) \
    $(atkmm_inc) \
    $(atkmm_lib_inc) \
    $(gdk-pixbuf_inc) \
    $(giomm_inc) \
    $(giomm_lib_inc)

INC=$(foreach d, $(INC_LIST), -I$d)

LIB_LIST=$(gtk_lib) \
    $(gtkmm_lib) \
    $(glibmm_lib) \
    $(glib_lib) \
    $(sigcpp_lib) \
    $(gdkmm_lib) \
    $(pango_lib) \
    $(pangomm_lib) \
    $(harfbuzz_lib) \
    $(cairo_lib) \
    $(cairomm_lib) \
    $(freetype_lib) \
    $(atk_lib) \
    $(atkmm_lib) \
    $(gdk-pixbuf_lib) \
    $(giomm_lib)

LIB=$(foreach d, $(LIB_LIST), -L$d)

default: main
    
main: main.cpp
    g++ -std=c++17 $(INC) $(LIB) main.cpp -o helloworld
    
clean:
    rm helloworld

I don't really understand this error. What does it mean? What do I need to do to solve it?

Thank you for your help.

Update: Tried linking the library .dylib files, but I am still getting the same exact error.

scriptor6
  • 196
  • 3
  • 12
  • It means you are not linking with the library that implements these functions. – drescherjm Feb 24 '21 at 16:02
  • 1
    "Including a header file" with `-I` is not the same thing as linking a library. A header file gives you a description of the interface needed to use things, so your code can know how to call functions etc. The library gives you the actual implementation of those things, which is needed to run the program. – MadScientist Feb 24 '21 at 16:33
  • It's weird that all your `_lib` variables point to yet more `include` directories. Also, is it really the case that there both `include/pangomm-1.4` and also `lib/pangomm-1.4/include` directories (as an example) in these packages? That's very strange, but I never underestimate strange things on MacOS. – MadScientist Feb 24 '21 at 16:35
  • @MadScientist the `_lib` variables point to more `include` directories because a lot of them contain `[library]config.h`. I am going to rename these for greater clarity. – scriptor6 Feb 24 '21 at 16:50

1 Answers1

2

You are missing helloworld.cpp in your Makefile. It should be next to main.cpp

arved
  • 4,401
  • 4
  • 30
  • 53
  • What do you mean? Doesn't including the header file also link the `cpp` implementation? – scriptor6 Feb 25 '21 at 16:12
  • no, you have to specify, what you want to link. This doesn't end with your object files but also libraries. You have not specified any libray -lfoo in your Makefile. I suggest using pkg-config to specify compiler and linker flags for your gtkmm app – arved Feb 26 '21 at 12:10
  • 1
    I think you should reread how a compiler works. helloworld.cpp is your source file. you need to speficy it in your Makefile, so that it is translated into an object file by the compiler. Then all object files are linked together by the linker. make has default rules how to do this, but you still have to specify which sources it should work on, and which libraries it should use – arved Feb 27 '21 at 18:49