2

I'm trying to run the makefile, shown in this repo, which is a simple Wayland client. But when I run make, it seems that the output of $(WAYLAND) is blank, and it fails to compile due to not being able to find the necessary wayland-client.h header file. cc (GCC) version 5.3.1 on Fedora 23 in bash.

Below are some details. My question is, what mistake am I making with my environment that is preventing this makefile from working for me as intended?

Contents of makefile:

WAYLAND=`pkg-config wayland-client --cflags --libs`
CFLAGS?=-std=c11 -Wall -Werror -O3 -fvisibility=hidden

hello_wayland: hello_wayland.o helpers.o helpers.h images.bin
    $(CC) -o hello_wayland *.o $(WAYLAND) -lrt

images.bin: images/convert.py images/window.png images/fish.png
    images/convert.py
    cat window.bin fish.bin > images.bin

clean:
    $(RM) *.o fish.bin window.bin hello_wayland

Output of make:

cc -std=c11 -Wall -Werror -O3 -fvisibility=hidden -c -o hello_wayland.o hello_wayland.c hello_wayland.c:6:28: fatal error: wayland-client.h: No such file or directory

Notice how the options to cc above seem to be missing the output of $(WAYLAND) specified in makefile. If I manually execute cc like this:

cc -std=c11 -Wall -Werror -O3 -fvisibility=hidden -c -o hello_wayland.o hello_wayland.c \
-I/home/me/install/include -L/home/me/install/lib -lwayland-client

The compilation succeeds.

Output of pkg-config wayland-client --cflags --libs:

-I/home/me/install/include -L/home/me/install/lib -lwayland-client

Contents of ~/.bash_profile:

source ~/.profile
source ~/.bashrc

Relevant contents of ~/.bashrc:

export WLD=$HOME/install
export LD_LIBRARY_PATH=$WLD/lib
export PKG_CONFIG_PATH=$WLD/lib/pkgconfig/:$WLD/share/pkgconfig/
export PATH=$WLD/bin:$PATH
export ACLOCAL_PATH=$WLD/share/aclocal
export ACLOCAL="aclocal -I $ACLOCAL_PATH"

Thanks for pointing out something that should probably be totally obvious to me.

  • regarding the line setting CFLAGS, this part: CFLAGS?=-std=c11 should be: CFLAGS := -std=c11 – user3629249 Mar 20 '16 at 21:02
2

the posted makefile is missing some details

Note: it is (almost) always best to separate the compile step from the link step

The following makefile corrects those details

Note: <tab> means to use the tab key in the actual makefile

RM             := /usr/bin/rm

LFLAGS         += `pkg-config wayland-client --libs`

CFLAGS         := -std=c11 -Wall -Werror -O3 -fvisibility=hidden
CFLAGS         += `pkg-config wayland-client --cflags`

OBJS           := hello_wayland.o helpers.o
HDRS           := helpers.h

TARGET         := hello_wayland

.PHONY: all
all: $(TARGET)

$(TARGET): $(OBJS) images.bin
<tab>$(CC) -o hello_wayland *.o $(LFLAGS) -lrt

%.o:%.c $(HDRS)
<tab>$(CC) $(CFLAGS)-c $< -o $@ -I.

images.bin: images/convert.py images/window.png images/fish.png
<tab>images/convert.py
<tab>cat window.bin fish.bin > images.bin

.PHONY: clean
clean:
<tab>$(RM) *.o fish.bin window.bin hello_wayland

You ask what is wrong with the original makefile:

here are some observations:

-- macros in a make file are of two types:
   those evaluated only once using `:=`
   those evaluated every time they are referenced `=`

WAYLAND=`pkg-config wayland-client --cflags --libs`
== WAYLAND will be re-evaluated every time referenced

CFLAGS?=-std=c11 -Wall -Werror -O3 -fvisibility=hidden
== invalid format for macro.  `?=` should be `:=`

== in a makefile,  typical usage is `make all`  but this makefile is missing that target (which should be the first target so `make` by itself, will execute the first target)
== `targets` for a link step should not be the actual file name
==== but rather a macro name where that macro contains the target name
==== This usage of a macro also makes it easy to set the resulting executable file name at the invocation of `make`
==== while either way will work, for flexability it is best to create a macro
==== this is expecially true when writing a recursive makefile or multiple different executables
hello_wayland: hello_wayland.o helpers.o helpers.h images.bin

== this is a link step, with hidden compiles, using the default recipe, which knows nothing about any specific header file
==== so the hidden compiles will not be done if the header file changes
== and a header file `helpers.h` should never be in a link step
== the `*.o` is a `glob` operation, which should not be used in makefiles
==== instead use the make facilties:

SRC := $(wildcard *.c)
OBJ := $(SRC:.c=.o)

== the 'target' is properly referenced by `$@` and there can be no keypunch errors if the `$@` is used.
    $(CC) -o hello_wayland *.o $(WAYLAND) -lrt

images.bin: images/convert.py images/window.png images/fish.png
    images/convert.py
    cat window.bin fish.bin > images.bin

== when a `target` is not the name of a produced file,
==== especially in older versions of `make`
==== then the target needs to be preceeded by a 

.PHONY: <list of target names that produce no actual output file>

== using  a `glob` operation in a makefile is a bad idea
==== instead use the appropriate macro
==== like the $(OBJS) macro listed above
clean:
    $(RM) *.o fish.bin window.bin hello_wayland

So, why did the original makefile not work? a combination of things that accumulate into a make failure. Here are the more obvious reasons:

1) the incorrect setting of the CFLAGS macro
2) the combining of the link operation with the compile operations
3) the missing .PHONY: statement
4) the use of the `glob` statements
  • Thanks, this makefile works without issue. But I'm still curious about why the original fails to utilize the output of pkg-config via the original WAYLAND variable. – ybakos Mar 21 '16 at 13:18
  • Whoah, awesome edit, thanks for taking the time to explain! – ybakos Mar 21 '16 at 19:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.