Make, problems with automatic variables

Hi there,
I am currently writing a Makefile and have run into Problems regarding the use of automatic variables when used in conjunction with ‘eval’. My project structure looks like this:
foo
|-> inc
| |-> header.h
|-> src
| |-> main.c

bar
|-> inc
| |-> header.h
|-> src
| |-> main.c

where foo, bar, inc and src are directories (hopefully its understandable). Now I want my Makefile to build ‘build/foo/main.o’ and ‘build/bar/main.o’. Here is what I’ve tried so far

TARGETS = foobar

BUILD_DIR = build
SRC_DIRS = foo bar
BUILD_SUB_DIRS = $(foreach D, $(SRC_DIRS), $(BUILD_DIR)/$D)
INC_DIRS = $(wildcard */inc)

OBJS = 	$(foreach D, $(SRC_DIRS), \
			$(foreach S, $(wildcard $D/src/*), \
				$(BUILD_DIR)/$D/$(notdir $(basename $S).o)))

CC = gcc
CC_FLAGS = -Wall -Wextra -Wpedantic -Werror -std=c99
LD_FLAGS = -lpthread
DEFINES =

define TARGET_template
$(1)/%.o : */src/%.c
	$(CC) -o $@ -c $^ $(CC_FLAGS) $(LD_FLAGS) $(DEFINES) \
		$(foreach D, $(INC_DIRS), -I$D) 
endef

all : $(BUILD_SUB_DIRS) $(OBJS) #$(BUILD_DIR)/$(TARGETS)

$(BUILD_DIR) : 
	mkdir $@

$(BUILD_SUB_DIRS) : $(BUILD_DIR)
	mkdir $@

$(foreach B, $(BUILD_SUB_DIRS), $(eval $(call TARGET_template, $B)))

test :
	@echo $(OBJS) $(BUILD_SUB_DIRS)

clean :
	rm -rf $(BUILD_DIR)

.PHONY : all clean test

now when i run make the automatic variables $@ and $^ don’t get properly expanded (in the way they would’ve worked had I not put them inside the TARGET_template). Any Ideas why that is the case and also how do I go about fixing this?

what are you trying to achieve? Maybe you don’t need the templates and evals.


also use this:

```
for code
```

it becomes

code

i.e.

int main(int argc, char** argv)
{
    return 0;
}

Oh thanks yeah edited the example. I actually got more than just foo and bar as directories and wanted a generic target and their rules that make figures out by evaluating inside the loop and calls the template. I basically wanted to avoid writing this

$(BUILD_SUB_DIRS)/foo/%.o : */src/%.c
	$(CC) -o $@ -c $^ $(CC_FLAGS) $(LD_FLAGS) $(DEFINES) \
		$(foreach D, $(INC_DIRS), -I$D) 
$(BUILD_SUB_DIRS)/bar/%.o : */src/%.c
	$(CC) -o $@ -c $^ $(CC_FLAGS) $(LD_FLAGS) $(DEFINES) \
		$(foreach D, $(INC_DIRS), -I$D) 

for every other directory I’ve got.

1 Like

Check this out:

https://bitbucket.org/snippets/redpandaua/7eM84a

This is how I build all C files inside all directories inside src. What I do, is I collect all the objs into one list and then just make the binary depend on them.

CSRCS     = $(shell find $(SRC_DIR) -type f -name "*.c")
OBJS      = $(subst $(SRC_DIR)/,$(OBJ_DIR)/, $(CSRCS:%.c=%_c.o))

You can add more dirs manually like so (I think, I haven’t tested):

CSRCS     = $(shell find $(SRC_DIR) -type f -name "*.c") \
            $(shell find $(FOO_DIR) -type f -name "*.c")
OBJS      = $(subst $(SRC_DIR)/,$(OBJ_DIR)/, $(CSRCS:%.c=%_c.o)) \
            $(subst $(FOO_DIR)/,$(OBJ_DIR)/, $(CSRCS:%.c=%_c.o))

TBH though, I would just put all the separate dirs into src dir, unless they are need to be built into separate binary.

They actually do build separate binaries. And thus I wanted the object files to live inside their respective subdir inside the build dir. And the problem I am facing is basically only cosmetic, in order to avoid copying some lines of code. The OBJS variable already holds all the required .o files that need to be created.

1 Like

I see now. I never used eval in Make so I don’t think i can help.

No problem, thanks for the effort anyway. For now I am just gonna copy the code for everything I need, not to hard after all and I also DO need to get stuff done :sweat_smile: . I was just hoping someone could help me understand this because it looks like another step forward towards my
‘almighty compile everything effortlessly with this one makefile’ Makefile.

1 Like

hahaha, I am slowly building towards that too. My other Makefile even grabs a cross compiler of ARM website for ya :wink:

Hope someone else can help ya!