0
votes

I am trying to create a makefile for a new project. the project contains so far just some basic main func and some funcs declarations. my makefile makes objects from source files, but no executable is compiled. exit with error:

mkdir -p build/./src/app/
gcc -std=gnu99 -Wall  -I./src -I./src/app -I./src/include -I./src/lib  -c src/app/main.c -o build/./src/app/main.o
mkdir -p build/./src/app/
gcc -std=gnu99 -Wall  -I./src -I./src/app -I./src/include -I./src/lib  -c src/app/Emsg.c -o build/./src/app/Emsg.o
gcc -std=gnu99 -Wall  -I./src -I./src/app -I./src/include -I./src/lib   -o bin/Main
gcc: fatal error: no input files
compilation terminated.
Makefile:59: recipe for target 'all' failed
make: *** [all] Error 1

this is my make file:

CFLAGS := -std=gnu99 -Wall

ifeq ($(STRIP), yes)
    CFLAGS := $(CFLAGS) -s
endif

BUILD_DIR :=        ./build
BIN_DIR :=      ./bin

SRC_DIRS :=         ./
SRC_APPS :=         ./src
SRC_TESTS :=        ./test

SRCS_APPS :=        $(shell find $(SRC_APPS) -name '*.c')
SRCS_TESTS :=       $(shell find $(SRC_TESTS) -name '*.c')

OBJS_APPS :=        $(SRCS_APPS:%.c=$(BUILD_DIR)/%.o)
OBJS_TESTS :=       $(SRCS_TESTS:%.c=$(BUILD_DIR)/%.o)
OBJS_ALL :=     $(OBJS_APPS)
OBJS_ALL_TESTS :=   $(OBJS_ALL) $(OBJS_TESTS)

INC_APPS_DIRS :=    $(shell find ./src -type d)
INC_INCLUDES  :=    src/include
INC_TESTS_DIRS :=   test/

INC_APPS_FLAGS :=   $(addprefix -I,$(INC_APPS_DIRS))
INCLUDE_ALL :=      $(INC_APPS_FLAGS) 

CC :=           gcc

ifeq ($(TEST), yes)
    CFLAGS :=   $(CFLAGS) -D TEST 
    OBJECTS :=  $(OBJS_APPS) $(OBJS_TESTS)
    INCLUDE :=  $(INC_TESTS_LIBS_FLAGS) $(INC_TESTS_FLAGS) 
    DEPEND_LST :=   apps tests

    COMP_ARGS :=    $(CC) $(CFLAGS) $(INCLUDE) $(OBJECTS) -L$(INC_TEST_LIBS) -o bin/Test

else
    DEPEND_LST :=   apps
    COMP_ARGS :=    $(CC) $(CFLAGS)  $(INCLUDE_ALL) $(OBJECTS) -o bin/Main
endif

# All
all: $(DEPEND_LST)
    $(COMP_ARGS)

#Tests
tests: $(OBJS_TESTS)

$(BUILD_DIR)/%.o: %.c
    $(MKDIR_P) $(dir $@)
    $(CC) $(CFLAGS)  $(INCLUDE_ALL) -c $< -o $@

# Apps
apps: $(OBJS_APPS)

$(BUILD_DIR)/%.o: %.c
    $(MKDIR_P) $(dir $@)
    $(CC) $(CFLAGS)  $(INCLUDE_ALL) -c $< -o $@

# Clean
clean:
    $(RM) -r $(BUILD_DIR)

# not sure what these two lines do..
-include $(DEPS)

MKDIR_P ?= mkdir -p

I'm simply running make. files hierarchy is:

  • src dir
    • app dir (contains main.c and more files)
    • include dir (contains some .h files)
    • lib dir (empty)
  • test dir (contains another main.c file)
  • Makefile file
2
You seem to create build directory, and then inside of it src and src/app. Later on you're using ./src/app but you never cd-ed your location to inside build. Could this be a problem? - Rorschach
Your link command (macro COMPARGS) has no object files in non-test mode — which is what the compiler (linker) message says. You need to tell it which object files to link to build the executable by defining OBJECTS outside the if conditional. You should have a separate make target from all to build the executable so that your program is not linked even when it is all up to date. Add a target for bin/Main and list the object files as dependencies. You want your test and build systems to be as near identical as possible; you need to test what is released to customers. - Jonathan Leffler
ok, fixed the COMPARGS, but I don't understand what you mean in the second part about another target - user107761
You can call make with -d to get a whole bunch of debugging output. - the busybee

2 Answers

0
votes

Install GNU remake and run remake -X.

It will put you into a debugger and then you can run step to see step by step what the makefile is doing. Here is that applied to your Makefile:

$ remake -X 
Reading makefiles...
Updating makefiles...
Updating goal targets...
-> (/tmp/so/Makefile:45)
all: apps
remake<0> step
 File 'all' does not exist.
   File 'apps' does not exist.
  Must remake target 'apps'.
  Successfully remade target file 'apps'.
<- (/tmp/so/Makefile:56)
apps
remake<1> where
=>#0  apps at Makefile:56
  #1  all at Makefile:45
remake<3> x OBJS_APPS
Makefile:17 (origin: makefile) OBJS_APPS := ...

See the link for videos. Or https://github.com/rocky/remake for some screen shots

0
votes

Make's output presents the commands it runs. For a serial build, at least, this unambiguously communicates what command produced each diagnostic message emitted. In your case, the command that caused the error immediately preceeds it in the output:

gcc -std=gnu99 -Wall  -I./src -I./src/app -I./src/include -I./src/lib   -o bin/Main

So what's wrong with that? Why, exactly what the diagnostic says: it doesn't specify any input files to operate upon. No C source files to compile, no object files or libraries to link. Nothing from which to build the designated output file.

Supposing that you've presented a complete makefile that produces the problem for you, that command must come from an attempt to build target all via this rule:

all: $(DEPEND_LST)
    $(COMP_ARGS)

That's a bit suspicious on its face, because an all target typically provides only a prerequisite list, not a recipe. Each prerequisite that may need to be built would then have its own rule. But it's not inherently wrong to provide a recipe, and we need to consider the recipe itself to determine the nature of your problem. In this case, we have suspicious point #2: the recipe is specified entirely via a single variable. But I already knew that, because I had to trace through that to identify this rule as the source of the error in the first place.

In particular, the only place where the text bin/Main appears in the makefile is in this else block:

else
    DEPEND_LST :=   apps
    COMP_ARGS :=    $(CC) $(CFLAGS)  $(INCLUDE_ALL) $(OBJECTS) -o bin/Main
endif

That indeed provides the command line variable referenced by the all target (and by nothing else), and it matches up cleanly with the command that causes the error. And what do we find when we match the bits of the command line to the variables from which that version of COMP_ARGS is built? We find that all the bits are covered by variables other than OBJECTS, which evidently expands to nothing (you can even see the separate leading and trailing space characters around its empty value). And why does OBJECTS expand to an empty value? Because it is never set when that branch of the conditional is exercised.

Personally, I would be inclined to rewrite the whole makefile to be more idiomatic and to rely less on GNU make extensions, but the simplest way forward would probably be to put an appropriate definition of the OBJECTS variable in the else block I pointed out.