So I'm trying to write this makefile and I'm having some issues getting it working, in fact I'm having issues getting makefiles in general working (no doubt due to user error).
make output:
$ make -v
GNU Make 4.2.1
Built for x86_64-unknown-linux-gnu
Copyright (C) 1988-2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
$ make clean all
rm -rf a.out bin
rm -rf obj
g++ -lm -o bin/a.out
/usr/lib/gcc/x86_64-pc-linux-gnu/8.1.0/../../../../lib/Scrt1.o: In function `_start':
(.text+0x20): undefined reference to `main'
collect2: error: ld returned 1 exit status
make: *** [makefile:32: bin/a.out] Error 1
makefile:
CXX := g++
LXX := g++
CXXFLAGS := -m64 -std=gnu++14 -fno-enforce-eh-specs -fno-rtti -fpermissive -O3 -funswitch-loops -w
CXXDEBUG := -ggdb3 -pg
LDFLAGS := -lm
EXE := a.out
SRC_DIR := src
BIN_DIR := bin
OBJ_DIR := obj
INCLUDE := $(addprefix -I, include)
SOURCES := $(foreach sdir, $(SRC_DIR), $(wildcard $(sdir)/*.cpp))
OBJECTS := $(pathsubst src/%.cpp, obj/%.o, $(SOURCES))
vpath %.cpp $(SRC_DIR)/
define make-goal
$1/%.o: %.cpp
$(CXX) $(INCLUDE) $(CXXFLAGS) -c $$< -o $$@
endef
.PHONY: clean all checkdirs $(BIN_DIR)/a.out
.SECONDARY:
default: all
all: checkdirs $(BIN_DIR)/a.out
$(BIN_DIR)/a.out: $(OBJECTS)
$(LXX) $(LDFLAGS) $^ -o $@
checkdirs: $(BIN_DIR) $(OBJ_DIR)
$(BIN_DIR):
@mkdir -p $@
$(OBJ_DIR):
@mkdir -p $@
clean:
rm -rf $(EXE) $(OBJECTS) bin
@find . -name "*~" -exec rm {} \;
@find . -name "*.o" -exec rm {} \;
rm -rf obj
$(foreach odir,$(OBJ_DIR),$(eval $(call make-goal,$(odir))))
My theory is that the $(foreach ...) at the end is never executed OR that the implicit pattern rules created are not executed (come to think of it I could never get %.o: %.c rules working either)
But honestly? I have no idea, the manual didn't provide any help - at least not that I could find (or, possibly, understand).
What I do understand is that no object files are output, ergo ld fails because it's not finding a main function.
This much is obvious and (painfully) clear to me. (I'm testing this with a very simple example: hello world, it compiles cleanly and executes as expected with g++ world.cpp -o a.out so it's not a g++ sanity issue I think).
Am I using GNU extensions wrong? I know call is a GNU extension.
the expected output would be:
├── bin
│ └── a.out
├── makefile
├── obj
│ └── world.o
└── src
└── world.cpp
This makefile is very similiar to other makefiles I've seen floating around on SO, e.g https://stackoverflow.com/a/2484343/2717116 - however this makefile when copied verbatim also does not appear to work for me - verbatim output:
make all
g++ -o build/test.exe
g++: fatal error: no input files
compilation terminated.
as expected the same issue is faced, namely that make-goal is never reached for one reason or another.