When building Souffle, I ran into an LTO issue with a library that contains a space in its filename (see https://github.com/souffle-lang/souffle/issues/2214). I've isolated the issue as follows (Fedora 35: gcc (GCC) 11.2.1 20220127 (Red Hat 11.2.1-9)): Makefile: CC=gcc CFLAGS=-fPIC CFLAGS:=$(CFLAGS) -flto=auto RM=rm -f all: ltomain "lib do it".so: doit.o $(CC) $(CFLAGS) $(LDFLAGS) -shared -Wl,-soname,"lib'do it'.so" -o "lib'do it'.so" doit.o ltomain: main.o "lib do it".so $(CC) $(CFLAGS) $(LDFLAGS) -o $@ main.o -L. -l"'do it'" clean: $(RM) *.o *.so ltomain doit.c: #include <stdio.h> void doit(void) { printf("Hello world!\n"); } void doit(); main.c: int main() { doit(); } This gives the following error: $ make clean all rm -f *.o *.so ltomain gcc -fPIC -flto=auto -c -o main.o main.c gcc -fPIC -flto=auto -c -o doit.o doit.c gcc -fPIC -flto=auto -shared -Wl,-soname,"lib'do it'.so" -o "lib'do it'.so" doit.o lto1: error: open it.so. failed: No such file or directory make[1]: *** [/tmp/ccetIqO9.mk:2: /tmp/ccIqDtkB.ltrans0.ltrans.o] Error 1 lto-wrapper: fatal error: make returned 2 exit status compilation terminated. /usr/bin/ld: error: lto-wrapper failed collect2: error: ld returned 1 exit status make: *** [Makefile:9: "lib] Error 1 Replacing '-flto=auto' by '-flto' works: $ make clean all rm -f *.o *.so ltomain gcc -fPIC -flto -c -o main.o main.c gcc -fPIC -flto -c -o doit.o doit.c gcc -fPIC -flto -shared -Wl,-soname,"lib'do it'.so" -o "lib'do it'.so" doit.o gcc -fPIC -flto -shared -Wl,-soname,"lib'do it'.so" -o "lib'do it'.so" doit.o gcc -fPIC -flto -shared -Wl,-soname,"lib'do it'.so" -o "lib'do it'.so" doit.o gcc -fPIC -flto -o ltomain main.o -L. -l"'do it'" $ LD_LIBRARY_PATH=. ./ltomain Hello world!
Compiling with '-v' shows the following differences: BAD: gcc -v -fPIC -flto=auto -shared -Wl,-soname,"lib'do it'.so" -o "lib'do it'.so" doit.o [...] COLLECT_GCC_OPTIONS='-v' '-fPIC' '-flto=auto' '-shared' '-o' 'lib'\''do it'\''.so' '-mtune=generic' '-march=x86-64' '-dumpdir' 'lib'\''do it'\''.so.' [...] COLLECT_GCC_OPTIONS='-c' '-fno-openmp' '-fno-openacc' '-fcf-protection=none' '-v' '-fPIC' '-shared' '-mtune=generic' '-march=x86-64' '-fltrans-output-list=/tmp/ccfiSKsT.ltrans.out' '-fwpa=16' '-fresolution=/tmp/ccOyShqf.res' '-flinker-output=dyn' [...] COLLECT_GCC_OPTIONS='-c' '-fno-openmp' '-fno-openacc' '-fcf-protection=none' '-v' '-fPIC' '-shared' '-mtune=generic' '-march=x86-64' '-fltrans-output-list=/tmp/ccfiSKsT.ltrans.out' '-fwpa=16' '-fresolution=/tmp/ccOyShqf.res' '-flinker-output=dyn' '-dumpdir' './lib'\''do it'\''.so.wpa.' make -f /tmp/ccNUrSeQ.mk -j16 all [...] COLLECT_GCC_OPTIONS='-c' '-fno-openmp' '-fno-openacc' '-fcf-protection=none' '-v' '-fPIC' '-shared' '-mtune=generic' '-march=x86-64' '-fltrans' '-o' '/tmp/ccfiSKsT.ltrans0.ltrans.o' '-dumpdir' './libdo-' /usr/libexec/gcc/x86_64-redhat-linux/11/lto1 -quiet -dumpdir ./libdo- -dumpbase ccfiSKsT.ltrans0.ltrans. -dumpbase-ext . -mtune=generic -march=x86-64 -version -fno-openmp -fno-openacc -fcf-protection=none -fPIC -fltrans it.so. it.so.ltrans0.ltrans /tmp/ccfiSKsT.ltrans0.o -o /tmp/ccCtIFo1.s [...] GOOD: gcc -v -fPIC -flto -shared -Wl,-soname,"lib'do it'.so" -o "lib'do it'.so" doit.o [...] COLLECT_GCC_OPTIONS='-v' '-fPIC' '-flto' '-shared' '-o' 'lib'\''do it'\''.so' '-mtune=generic' '-march=x86-64' '-dumpdir' 'lib'\''do it'\''.so.' [...] COLLECT_GCC_OPTIONS='-c' '-fno-openmp' '-fno-openacc' '-fcf-protection=none' '-v' '-fPIC' '-shared' '-mtune=generic' '-march=x86-64' '-fltrans-output-list=/tmp/ccMA9joX.ltrans.out' '-fwpa' '-fresolution=/tmp/cceTYxPV.res' '-flinker-output=dyn' [...] COLLECT_GCC_OPTIONS='-c' '-fno-openmp' '-fno-openacc' '-fcf-protection=none' '-v' '-fPIC' '-shared' '-mtune=generic' '-march=x86-64' '-fltrans-output-list=/tmp/ccMA9joX.ltrans.out' '-fwpa' '-fresolution=/tmp/cceTYxPV.res' '-flinker-output=dyn' '-dumpdir' './lib'\''do it'\''.so.wpa.' [...] COLLECT_GCC_OPTIONS='-c' '-fno-openmp' '-fno-openacc' '-fcf-protection=none' '-v' '-fPIC' '-shared' '-mtune=generic' '-march=x86-64' '-fltrans' '-o' '/tmp/ccMA9joX.ltrans0.ltrans.o' /usr/libexec/gcc/x86_64-redhat-linux/11/lto1 -quiet -dumpbase ./lib'do it'.so.ltrans0.ltrans -mtune=generic -march=x86-64 -version -fno-openmp -fno-openacc -fcf-protection=none -fPIC -fltrans @/tmp/ccpufIq0 -o /tmp/ccyVUMgZ.s The first three differences look ok: In the good case we have '-fwpa', and in the base case '-fwpa=16', which looks sane. In the last diff we can see a wrong behaviour: In the good case we have: * '-dumpbase ./lib'do it'.so.ltrans0.ltrans', and * '-fltrans it.so. it.so.ltrans0.ltrans /tmp/ccfiSKsT.ltrans0.o' In the bad case we have: * '-dumpdir ./libdo- -dumpbase ccfiSKsT.ltrans0.ltrans. -dumpbase-ext .' * '-fltrans @/tmp/ccpufIq0 -o /tmp/ccyVUMgZ.s'
Further analysis shows that '-flto=1' works as well and '-flto=16' fails as well. This brings us right to the spot: Bad: [...] make -f /tmp/ccyzs8VX.mk -j16 all Using built-in specs. [...] Good: [...] gcc @/tmp/cclqDb0Y Using built-in specs. [...] Let's look deeper: $ mkdir tmpdir $ export TEMP=$(pwd)/tmpdir/ $ gcc -v -fPIC -flto=16 -shared -Wl,-soname,"lib'do it'.so" -o "lib'do it'.so" doit.o -save-temps $ cat tmpdir/ccM8aNK8.mk ./lib'do it'.so.ltrans0.ltrans.o: @gcc '-xlto' '-c' '-fno-openmp' '-fno-openacc' '-fcf-protection=none' '-mtune=generic' '-march=x86-64' '-fPIC' '-v' '-fPIC' '-shared' '-save-temps' '-mtune=generic' '-march=x86-64' '-dumpdir' 'lib'do it'.so.' '-dumpbase' './lib'do it'.so.ltrans0.ltrans' '-fltrans' '-o' './lib'do it'.so.ltrans0.ltrans.o' './lib'do it'.so.ltrans0.o' .PHONY: all all: \ ./lib'do it'.so.ltrans0.ltrans.o The invocation of GCC will be: gcc '-xlto' '-c' '-fno-openmp' '-fno-openacc' '-fcf-protection=none' '-mtune=generic' '-march=x86-64' '-fPIC' '-v' '-fPIC' '-save-temps' '-shared' '-mtune=generic' '-march=x86-64' '-dumpdir' 'libdon't do it.so.' '-dumpbase' './libdon't do it.so.ltrans0.ltrans' '-fltrans' '-o' './libdon't do it.so.ltrans0.ltrans.o' './libdon't do it.so.ltrans0.o' And here we see the issue! The options are each quoted with '-characters. But the filename itself contains these characters as well, which will terminate the string. The space between the '-characters will therefore be interpreted as a separator. One thing to mention is that GNU Make has limitations how to handle spaces: http://savannah.gnu.org/bugs/?712
White spaces and even special characters will always be a problem with anything that interacts with make or the shell. I am not saying this is not a fixable issue, just fixing this might even require huge changes to way POSIX make works.
Confirmed (you analyzed it well). A fix would be welcome but not sure if it's easy enough to do - it's just arguments to a rule, not inputs / outputs so I think it should be possible to apply appropriate quoting somehow.