0

I'm trying to port my wayland compositor from make to scons, but I'm having trouble with the build order. I need xdg-shell-protocol to be generated with wayland-scanner and built before anything else. With make, something like this is all it takes:

WLSCAN_INFO =   @echo "  WLSCAN  " $@;
CC_INFO =   @echo "  CC      " $@;

CFLAGS= -g          \
    -Werror         \
    -I.         \
    -DWLR_USE_UNSTABLE

LIBS =  "-Lxdg-shell-protocol.h" \
    $(shell pkg-config --cflags --libs wlroots) \
    $(shell pkg-config --cflags --libs wayland-server) \
    $(shell pkg-config --cflags --libs xkbcommon) \

WAYLAND_PROTOCOLS=$(shell pkg-config --variable=pkgdatadir wayland-protocols)
WAYLAND_SCANNER=$(shell pkg-config --variable=wayland_scanner wayland-scanner)

XDG_SHELL_DEPS = xdg-shell-protocol.c xdg-shell-protocol.h

xdg-shell-protocol.h:
    $(WLSCAN_INFO)$(WAYLAND_SCANNER) server-header \
        $(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@

xdg-shell-protocol.c: xdg-shell-protocol.h
    $(WLSCAN_INFO)$(WAYLAND_SCANNER) private-code \
        $(WAYLAND_PROTOCOLS)/stable/xdg-shell/xdg-shell.xml $@

OBJS = \
    xdg-shell-protocol.o    \
    output.o        \
    renderer.o      \
    input.o         \
    xdg.o           \
    cursor.o        \
    keyboard.o      \
    main.o

%.o: %.c xdg-shell-protocol.h
    $(CC_INFO)$(CC) $(CFLAGS) -c $(LIBS) -o $@ $<

wlc: $(OBJS)
    $(CC_INFO)$(CC) $(CFLAGS) $(LIBS) -o $@ $(OBJS)

clean:
    rm -f wlc $(XDG_SHELL_DEPS) *.o

.DEFAULT_GOAL = wlc
.PHONY: wlc clean

With scons, I tried this:

CCFLAGS = "-fdiagnostics-color=always -g -Werror -DWLR_USE_UNSTABLE"
CPPPATH = ["./", "./include"]

env = Environment()

env.Append(CCFLAGS = CCFLAGS)
env.Append(CPPPATH = ["./", "./include"])

env.ParseConfig("pkg-config --cflags --libs wlroots")
env.ParseConfig("pkg-config --cflags --libs wayland-server")
env.ParseConfig("pkg-config --cflags --libs xkbcommon")

env.Command( source = "",
    target = "xdg-shell-protocol.h",
    action = "`pkg-config --variable=wayland_scanner wayland-scanner` server-header \
            `pkg-config --variable=pkgdatadir wayland-protocols`/stable/xdg-shell/xdg-shell.xml \
            $TARGET"
)

env.Command( source = "",
    target = "xdg-shell-protocol.c",
    action = "`pkg-config --variable=wayland_scanner wayland-scanner` private-code \
            `pkg-config --variable=pkgdatadir wayland-protocols`/stable/xdg-shell/xdg-shell.xml \
            $TARGET"
)

xdg_shell_protocol = env.Library(
    target = "xdg-shell-protocol",
    source = [
        "xdg-shell-protocol.h",
        "xdg-shell-protocol.c"
    ]
)

wlc = env.Program(
    target = "wlc",
    source = [
        Glob("input/*"),
        Glob("output/*"),
        Glob("shell/*"),
        "main.c",
    ],
    LIBS=[xdg_shell_protocol], LIBPATH="."
)
env.Depends(wlc, "xdg-shell-protocol.h")
)

But wlc always gets built before xdg_shell_protocol, and ends up failing because xdg-shell-protocol.h hasn't been generated yet. I also tried:

  • Defining an explicit dependency by adding env.Depends(wlc, "xdg-shell-protocol.h") or env.Depends(wlc, xdg_shell_protocol) at the end,
  • Setting LIBS = ["xdg-shell-protocol"] in wlc,
  • Not using Library and just adding xdg-shell-protocol.h and xdg-shell-protocol.c to the beginning of source in wlc. But main.c or some other source file always ends up being compiled first and fails because xdg-shell-protocol.h doesn't exist yet. What am I doing wrong?

EDIT:

  • Expanded ... above (note that the makefile is from before I moved source files to subdirectories, which was the main reason I decided to change build systems).
  • Output of $ scons --tree=prune
Tooniis
  • 123
  • 1
  • 9

3 Answers3

1

Please post the full file, the '...''s may be relevant.
Do any of your Command()'s specify the source argument?

What's line 1 of: include/shell/xdg.h ?

try adding this line

env.Depends('input/cursor.c', 'xdg-shell-protocol.h')

NOTE: This is not a good solution, but will help figure out what the issue is.

Now.. Try changing your Program(..) to this, and remove your explicit Depends().

cpppath = env['CPPPATH'] + ['/usr/include']
wlc = env.Program(
    target = "wlc",
    source = [
        Glob("input/*"),
        Glob("output/*"),
        Glob("shell/*"),
        "main.c",
    ],
    LIBS=[xdg_shell_protocol],
    CPPPATH=cpppath,
)
bdbaddog
  • 3,357
  • 2
  • 22
  • 33
  • both `Command()`s have `source = ""` since they don't need any input files. Changing `LIBS` to `LIBS=['xdg-shell-protocol']` did nothing (I already tried it, just with double quotes) – Tooniis Jul 20 '21 at 03:35
  • 1
    They do have input files.. pkg-config and the files it reads for such are the input files to those commands. But you can expect that the output files won't change assuming you're always running on the same system and that you don't update any of those sources in a way that changes anything you depend on. – bdbaddog Jul 20 '21 at 16:31
1

The problem is caused by the source scanner not seeing the dependency on xdg-shell-protocol.h because it comes from including /usr/include/wlr/types/wlr_xdg_shell.h, which wouldn't normally be scanned (this was the genesis of the suggestion above to add /usr/include to CPPPATH but that didn't seem to be good enough), and thus you don't get the order you would - forcing that header to get generated early - if it noticed that dependency. From your workaround, I think you can simplify to just this:

env.Depends("include/shell/xdg.h", "xdg-shell-protocol.h")

Which may still end up not being the prettiest answer...

Mats Wichmann
  • 800
  • 6
  • 6
0

Apparently I have to define the explicit dependency for each source file:

wlc_source = [
    "main.c",
    Glob("input/*.c"),
    Glob("output/*.c"),
    Glob("shell/*.c"),
]
for source in wlc_source:
    env.Depends(source, xdg_shell_protocol)

wlc = env.Program(
    target = "wlc",
    source = wlc_source
)

This fixes the issue, but I don't think this is the best solution.

Tooniis
  • 123
  • 1
  • 9