5

I am writing a C++ program using gtkmm as the window library and autotools as my build system. In my Makefile.am, I install the icon as follows:

icondir = $(datadir)/icons/hicolor/scalable/apps
icon_DATA = $(top_srcdir)/appname.svg

EDIT: changed from prefix to datadir

This results in appname.svg being copied to $(datadir)/icons/hicolor/scalable/apps when the program is installed. In my C++ code, I would like to access the icon at runtime for a window decoration:

string iconPath = DATADIR + "/icons/hicolor/scalable/apps/appname.svg";
// do stuff with the icon

I am unsure how to go about obtaining DATADIR for this purpose. I could use relative paths, but then moving the binary would break the icon, which seems evident of hackery. I figure that there should be a special way to handle icons separate from general data, since people can install 3rd party icon packs. So, I have two questions:

  1. What is the standard way of installing and using icons with autotools/C++/gtkmm?

Edit: gtkmm has an IconTheme class that is the standard way to use icons in gtkmm. It appears that I add_resource_path() (for which I still need the installation prefix), and then I can use the library to obtain the icon by name.

  1. What is the general method with autotools/C++ to access the autotools installation prefix?
Nathan Vance
  • 605
  • 1
  • 5
  • 21
  • 2
    Sorry, edited out the C references because `string iconPath = PREFIX + "/icons/hicolor/scalable/apps/appname.svg";` is not C, and there is no "C/C++" language. – Weather Vane Jul 15 '18 at 22:32
  • To do things the way you envision I believe you need to read `PREFIX` and [possibly] `DESTDIR` from the environment. `PREFIX` is usually relative like `../../share/...`. I'm not sure what you can do about staging and `DESTDIR`. Maybe Bollinger will have an answer. He usually answers my non-trivial questions. – jww Jul 16 '18 at 01:58
  • Can I rely on an environment variable to stay consistent? The main problem is that I have a different prefix if I compile manually, in an IDE, or turn it into a flatpak. Now what I could do is write a build hook to modify my code and edit it in, but that's basically a macro (or a pragma? Directive?), and I find it hard to believe that such a thing isn't already standardized. – Nathan Vance Jul 16 '18 at 14:12
  • You should either define a preprocessor symbol (eg -DPREFIX=...) in the Makefile, or write something in config.h – William Pursell Jul 16 '18 at 16:25
  • Which autotools are you using ? autoconf ? automake ? both ? – Yann Droneaud Jul 16 '18 at 17:14
  • @YannDroneaud: I'm using both; there is a directory of m4 files (autoconf I think) and the autogen.sh, configure.ac, and Makefile.am that are part of automake (correct me if I'm wrong). These were all generated by an IDE (gnome-builder), and it's all sorcery to me :/ – Nathan Vance Jul 16 '18 at 17:33
  • 1
    The usual place to install an icon would be `$(datadir)/icons/hicolor/scalable/apps`. That would be something like `/usr/local/share/icons/...`. Are you *sure* that's not where you really want to put it? – John Bollinger Jul 16 '18 at 18:55
  • configure.ac is not part of automake. configure.ac is used only by autoconf to generate the configure script. The Makefile.am is used by autoconf to generate Makefile.in, which is used by the configure script to generate the Makefile. – William Pursell Jul 16 '18 at 20:28

2 Answers2

2

In your Makefile.am, use the following

AM_CPPFLAGS = -DPREFIX='"$(prefix)"'

See Defining Directories in autoconf's manual.

Yann Droneaud
  • 5,277
  • 1
  • 23
  • 39
2

To convey data determined by configure to your source files, the primary methods available are to write them in a header that your sources #include or to define them as macros on the compiler command line. These are handled most conveniently via the AC_DEFINE Autoconf macro. Under some circumstances, you might also consider converting source files to templates for configure to process, but except inasmuch as Autoconf itself uses an internal version of that technique to build config.h (when that is requested), I wouldn't normally recommend it.

HOWEVER, the installation prefix and other installation directories are special cases. They are not finally set until you actually run make. Even if you set them via the configure's command-line options, you can still override that by specifying different values on the make command line. Thus, it is not safe to rely on AC_DEFINE for this particular purpose, and in fact, doing so may not work at all (will not work for prefix itself).

Instead, you should specify the appropriate macro definition in a command-line option that is evaluated at make time. You can do this for all targets being built by setting the AM_CPPFLAGS variable in your Makefile.am files, as demonstrated in another answer. That particular example sets the specified symbol to be a macro that expands to a C string literal containing the prefix. Alternatively, you could consider defining the whole icon directory as a symbol. If you need it only for one target out of several then you might prefer setting the appropriate onetarget_CPPFLAGS variable.

As an aside, do note that $(prefix)/icons/hicolor/scalable/apps is a nonstandard choice for the installation directory for your icon. That will typically resolve to something like /usr/local/icons/hicolor/scalable/apps. The conventional choice would be $(datadir)/icons/hicolor/scalable/apps, which will resolve to something like /usr/local/share/icons/hicolor/scalable/apps.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
  • Marking this one correct for completeness. Thanks for pointing out the difference between `prefix` and `datadir`; I ended up adding `CPPFLAGS = -DDATADIR='"$(datadir)"' @CPPFLAGS@` to my `Makefile.am` and referencing it in my code as `DATADIR`. – Nathan Vance Jul 16 '18 at 21:04
  • 1
    Better use `AM_CPPFLAGS` or `yourprogram_CPPFLAGS` instead of `CPPFLAGS`. It is intended use and entirely normal for the person building your program to run `make CPPFLAGS=-Dfoo=bar` for building which will override your `CPPFLAGS` definition and thus build without `DATADIR` being defined. – ndim Aug 03 '18 at 21:25