Search code examples
c++cmakefilebuildgnu-make

Makefile objects in different folders with wildcard & headers (modular compile)?


UPDATE#04:

Got everything compiling. Will keep the answer concise so here are some intermediary steps.

Basically the Rules only partially worked because the objects were being made in their own folder still. After creating new local object Rules it compiled. However since they were now in their own directory the modular compile could not assemble the objects & work properly (programs will error when run).

The answer is a new patsubst pattern (of course), but I finally found one by trial & error that will allow output with wildcard + the original Rules + Recipes (for modular compiling with multiple targets). See the answer below.

UPDATE#03:

Modular wildcard compile now works for the Client by trying patterns & rules in the order below & only changing them if they fail. However, I'm now unable to compile the Server from the Client objects & getting a bunch of .c:(.text+0xb28): undefined reference to My_Func_Call type errors. I've sorta given up on trying to move the objects to another path because Make just refuses to follow the rules properly or compile (will come back to that later).

Anyone know why objects/refs can't be reused now from the Client for the Server or any ideas on what might work?

# Pattern 1:
CODE = $(wildcard $(PATH)/*.c)
OBJS += $(CODE)

# Pattern 2:
CODE = $(wildcard $(PATH)/*.c)
CODE_OBJS = $(CODE:%.c=%.o)
OBJS += $(CODE_OBJS)

# Pattern 2 & Rule:
CODE = $(wildcard $(PATH)/*.c)
CODE_OBJS = $(CODE:%.c=%.o)
OBJS += $(CODE_OBJS)

$(BPATH)/%.o: $(PATH)/%.c $(PATH)/%.h $(COMMON_PATH)/%.h 
  %.o: %.c 
  $(DO_CC)

UPDATE#02:

I continued to implement this pattern of wildcarding other sub dirs & just ignored where the objects are stored, but now the new compiled sub dirs seem to be causing conflicts. The previous header vars are missing (even though I changed nothing in the previous compiled code). This is caused by having multiple nested %o: %c rules I'm guessing (so that means I can't do anymore sub dirs argh).

I'm very open to someone pointing me towards some pattern or resources that might be in the area of this issue? Most of what I've seen are these simple Makefiles that have the same solutions over & over (non-modular compiles).

Otherwise, I think I'm going to go download GNU Make & start going line by line commenting it to figure out what is going on with the data. One thing is reading about stems & another is knowing what syntax or structure that Make actually needs to not break.

UPDATE#01:

Need a Makefile with objects in different folders & working with headers. I have it working in one path setup, but with a different path it's requiring more code to find the headers & not able to place the objects in a different folder.

This is basically what is happening in a minimal example -- any ideas?:

CODE00 = $(wildcard $(PATH00)/*.c)
OBJ00 = $(CODE00:%.c=%.o)

OBJS = $(OBJ00)

CODE = $(wildcard $(PATH)/*.c)
HEADER = $(wildcard $(PATH)/*.h) $(wildcard $(COMMON_PATH)/*.h) # Alt header.
#OBJ = $(patsubst %.c, %.o, $(CODE)) # Also works.
OBJ = $(CODE:%.c=%.o)

OBJS += $(OBJ)

############
# RULES:
############

# Works:
$(BPATH00)/%.o: $(PATH00)/%.c $(PATH00)/%.h $(PATH01)/%.h # Objs in folder/headers work.
    $(DO_CC)

# Broken:
$(BPATH)/%.o: $(PATH)/%.c $(PATH)/%.h $(COMMON_PATH)/%.h # Requires more before DO_CC?
  #%.o: %.c # Works but .o in source folder, fails without.
  #%.o: %.c ${HEADER} # Works but .o in source folder, fails without.
  $(BPATH)/%.o: %.c # Fails with missing header vars.
  #$(BPATH)/%.o: %.c ${HEADER} # Fails with missing header vars.
    $(DO_CC)

############
# LINK:
############

define DO_CC
gcc $(OBJS) $(CFLAGS) -o $@ -c $< 
endef

Solution

  • Here is the working pattern for wildcard & modular compiles with multiple targets.

    NOTE: You will have to remove header includes or conflicting %.o: %o.c Rules needed for same folder objects. Otherwise it will cause lots of weird missing target errors that change when you alter the Rule order (which just wastes your time & is confusing).

    HOST_CODE      := $(wildcard $(HOST_PATH)/*.c)
    HOST_OBJECTS    = $(patsubst $(HOST_PATH)/%.c, $(HOST_BPATH)/%.o, $(HOST_CODE))
    CLIENT_OBJECTS  = $(patsubst $(HOST_PATH)/%.c, $(CLIENT_BPATH)/%.o, $(HOST_CODE))
    
    # Or to append:
    
    HOST_CODE      := $(wildcard $(HOST_PATH)/*.c)
    HOST_OBJECTS   += $(patsubst $(HOST_PATH)/%.c, $(HOST_BPATH)/%.o, $(HOST_CODE))
    CLIENT_OBJECTS += $(patsubst $(HOST_PATH)/%.c, $(CLIENT_BPATH)/%.o, $(HOST_CODE))
    
    # Rules (includes/headers will break your compile):
    
    $(HOST_BPATH)/%.o: $(HOST_PATH)/%.c
        $(DO_HOST_CC)
    
    $(CLIENT_BPATH)/%.o: $(HOST_PATH)/%.c
        $(DO_CLIENT_CC)
    
    
    

    You won't need header include Rules. But if you want to test to see if your headers are working I recommend this non-conflicting pattern (many patterns easily conflict & break your Makefile, so you need to be VERY careful):

    INCLUDES = $(shell find . -name '*.d')
    
    include $(INCLUDES)