0

I'm trying to create a makefile that will find all existing .c and .cpp files then compile them.

I have used How to place object files in separate subdirectory as a template and combined it with How to make a makefile for C and C++, with sources in subdirectories. Assume I have defined all the variables (I just left them out since they are unnecessary).

The error I keep getting is make: *** No rule to make target 'obj/<randoCfile>.c', needed by '<target>'. Stop.

SOURCES := $(call rwildcard,$(SRCDIR),*.c)
SOURCES += $(call rwildcard,$(SRCDIR),*.cpp)
OBJECTS     := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:%.c=%.c.o))
OBJECTS     += $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:%.cpp=%.cpp.o))

#Default Make
all: $(TARGET)

#Remake
remake: cleaner all

#Make the Directories
directories:
    @mkdir -p $(TARGETDIR)
    @mkdir -p $(BUILDDIR)

#Clean only Objecst
clean:
    @$(RM) -rf $(BUILDDIR)

#Full Clean, Objects and Binaries
cleaner: clean
    @$(RM) -rf $(TARGETDIR)

#Link
$(TARGET): $(OBJECTS)
    $(CC) -o $(TARGETDIR)/$(TARGET) $^ $(LIB)

$(BUILDDIR)/%.c.o:
    $(CC) $(INC) $(CFLAGS) -c -o $@ $<

$(BUILDDIR)/%.cpp.o:
    $(CXX) $(INC) $(CXXFLAGS) -c -o $@ $<

#Non-File Targets
.PHONY: all remake clean cleaner resources

Any suggestions as to how to fix my problem? I'm running on Windows (which is why I'm using a wildcard as opposed to the shell(find...) that was in one of the examples I found.

kw-rad
  • 15
  • 5
  • 2
    You can't. You have to list every source file you want compiled. – S.S. Anne Feb 20 '20 at 22:50
  • You can't do what you're asking, because make files don't work using wildcards. Take the few minutes and create a proper makefile - you'd probably have it done and working in the time it took you to create this post. – Ken White Feb 20 '20 at 22:55
  • Looking at your rules, it appears that you are making a separate executable for each source file, as opposed to making a single executable from all of the source files. If that's the case, easiest solution is probably to just delete the Makefile and let make use defaults rules for everything. eg, something like `rm Makefile; make $(basename *.c *.cc | sed 's/\..*$//')` should do fine. It doesn't put object files in a different directory, but it's simple. Use the default rules; they exist to help. – William Pursell Feb 20 '20 at 23:03
  • 1
    It's really unclear what is your current situation. Please state *clearly* which files you have (and the current project hierarchy) and which files you want to produce from those. Also, show how you intend to invoke `make` from command line. – Marco Bonelli Feb 20 '20 at 23:03
  • Sounds like `cmake` is more likely to solve you task easier, you'll still have to generate a list of source files thought. Have you considered installing cygwin so you have linux tools like `find`? – Paul Evans Feb 20 '20 at 23:12

2 Answers2

2

You have a couple of problems. The most important is here:

SOURCES := $(call rwildcard,$(SRCDIR),*.c)
SOURCES += $(call rwildcard,$(SRCDIR),*.cpp)

Let's suppose that this results in the following value for SOURCES:

SOURCES := src/foo.c src/bar/bar.c src/biz/biz.cpp src/boz.cpp

Now what will OBJECTS be after the following?

OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:%.c=%.c.o))
OBJECTS += $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:%.cpp=%.cpp.o))

It will be (assuming BUILDDIR is obj):

OBJECTS := obj/foo.c.o obj/bar/bar.c.o obj/biz/biz.cpp obj/boz.cpp \
           obj/foo.c obj/bar/bar.c obj/biz/biz.cpp.o obj/boz.cpp.o

Why? Because a translation like $(SOURCES:%.c=%.c.o) doesn't return only the words that match the pattern... it returns ALL the words, and translates only the ones that match the pattern.

Since you're just adding the .o to the suffix rather than replacing the suffix, you can simplify this as:

SOURCES := $(call rwildcard,$(SRCDIR),*.c)
SOURCES += $(call rwildcard,$(SRCDIR),*.cpp)

OBJECTS := $(SOURCES:$(SRCDIR)/%=$(BUILDDIR)/%.o))

Also this rule is not right:

$(BUILDDIR)/%.c.o:
        $(CC) $(INC) $(CFLAGS) -c -o $@ $<

Here you've not declared any prerequisites. Maybe you do that somewhere else that you didn't show us, but better would be this instead:

$(BUILDDIR)/%.c.o: $(SRCDIR)/%.c
        $(CC) $(INC) $(CFLAGS) -c -o $@ $<

And ditto for the .cpp files of course.

MadScientist
  • 92,819
  • 9
  • 109
  • 136
  • Thank you for taking the type to teach rather than just criticize. Implementing what you've done here and a few other little tweaks has the makefile doing what I needed it to! – kw-rad Feb 21 '20 at 17:09
0

Make (any flavour) is a program that goes from the targets (the executables) to the sources, so you normally begin with the executable (that needs a list of object files to be built) and those objects depend on the source files they depend to be built.... you are thinking in the opposite direction... search for source files, and go in the opposite direction. While it is more dynamic, it is not the way make works, so most probably the solution needs to use another program that makes all the work to compile every source and finally end in something you probably cannot specify, and make will do nothing but being there to execute your search and compile program.

For that reason, the different flavours of Make (e.g. gnu make, or berkely make) have developed each incompatible ways to do the way back possible, using functions in gnu make, and having a powerfull macro feature in the case of berkeley make. Just to say that none of these is standard, and both require some training before being able to handle efficiently.

Luis Colorado
  • 10,974
  • 1
  • 16
  • 31