Make: wildcard to use all object files - makefile

I have a Makefile that looks like this:
CC=cc
CFLAGS=-g -std=c99 -Wfatal-errors
OBJS=$(wildcard *.o)
all: main.o cmdargs.o io.o
$(CC) -o app $(OBJS)
main.o: main.c
$(CC) -c main.c $(CFLAGS)
cmdargs.o: cmdargs.c
$(CC) -c cmdargs.c $(CFLAGS)
io.o: io.c
$(CC) -c io.c $(CFLAGS)
clean:
#rm -rf app $(OBJS)
Whenever I run make all after a clean, there's an error saying
cc -o
undefined reference to `main'
But when I run it a second time everything works as expected. What is wrong with the script, and how can we fix it?

The previous respondents gave good answers but not complete. So let me post one too.
First of all, it is a bad idea to use wildcard in makefiles. It is much better to not be lazy and list your files explicitly.
If you must be lazy, the way to use wildcard is, as shawncorey writes, to use it for sources.
Also, do not have a recipe for phony targets such as all. In your example, the recipe for all will always run, which is inefficient.
CC := gcc
SRCS := $(wildcard *.c)
OBJS := $(SRCS:c=o)
.PHONY: all clean
all: app
app: $(OBJS) Makefile
$(CC) -o $# $(OBJS)
$(OBJS): %.o: %.c Makefile
$(CC) -c $< $(CFLAGS)
clean:
#rm -rf app $(OBJS)

You can automatically create the names of the objects files if you're careful about including all the source files.
# --------------------------------------
# list all source files
CPP_SOURCES := $(wildcard *.cpp)
C_SOURCES := $(wildcard *.c)
# other source files here
# consolidate all sources
SOURCES := $(CPP_SOURCES) $(C_SOURCES)
# --------------------------------------
# list all object files
CPP_OBJECTS := $(CPP_SOURCES:.cpp=.o)
C_OBJECTS := $(C_SOURCES:.c=.o)
# other object files here
# consolidate all objects
OBJECTS := $(CPP_OBJECTS) $(C_OBJECTS)
all:
echo $(SOURCES)
echo $(OBJECTS)
PS: A more compact makefile:
# list all source files
SOURCES := $(wildcard *.cpp) $(wildcard *.c)
# determine all object files
OBJECTS := $(addsuffix .o, $(basename $(notdir $(SOURCES))))
all:
echo $(SOURCES)
echo $(OBJECTS)

The statement
OBJS=$(wildcard *.o)
collects all the *.o files currently in the file system, but it doesn't know about any object files that might be created in the future.
When you run make for the first time, there are no .o files around, so the variable OBJS will be an empty string and the final linking command does not get passed into the command that would tell it which object files to use. But all the other compilation steps are run nevertheless. Upon the second invocation make will skip the compilation phases, because the object files are already there, but because linking failed and the final binary is missing, it will run that step, which will now produce something, because there have been files to collect by the wildcard.
Lesson learned: Don't use file system wildcards in Makefile, it's just causing trouble. Instead learn about implicit rules if you want to save yourself from work.

Related

Makefile does not find rules despire of available files

Currently I am trying to get a rather big project of mine to work with a Makefile. I used Make before but in a rather crude way and not really "dynamic", this means I am pretty new to good Makefiles.
My Makefile looks like this:
INCLUDE_DIR = /inc
SOURCE_DIR = /src
BUILD_DIR = /build
BUILD_NAME = build
CC = arm-none-eabi-gcc
CFLAGS = -I$(INCLUDE_DIR)
_INCLUDES = main.h pfc.h
INCLUDES = $(patsubst %, $(INCLUDE_DIR)/%, $(_INCLUDES))
_OBJ = main.o pfc.o
OBJ = $(patsubst %, $(BUILD_DIR)/%, $(_OBJ))
$(BUILD_DIR)/%.o: $(SOURCE_DIR)/%.c $(INCLUDES)
$(CC) -c -o $# $< $(CFLAGS)
$(BUILD_NAME): $(OBJ)
$(CC) -o $# $^ $(CFLAGS)
all: $(BUILD_NAME)
.PHONY: clean
clean:
rm -rf $(BUILD_DIR)/*
When I make the file I get this:
make: *** No rule to make target '/build/main.o', needed by 'build'. Stop.
I guess it is an error in this recipe:
$(BUILD_DIR)/%.o: $(SOURCE_DIR)/%.c $(INCLUDES)
$(CC) -c -o $# $< $(CFLAGS)
Sadly I am not able to get this done on my own.
All files a available in the correct folders.
I really appreciate all the help!
Tristan
You have a few issues here that I can see. But first off - just check (just incase) that all your rules are only indented with tabs and not spaces..... this can be a real "silent" killer of makefiles as they give crap error messages.
Ok so - lets assume you have:
INCLUDE_DIR = inc
SOURCE_DIR = src
BUILD_DIR = build
instead of /src etc.. as mentioned in the comments.
Do you really have inc/main.h and inc/pfc.h?
I copied and pasted your makefile added your src and inc folders (but I used gcc instead of arm-none-eabi-gcc. It did the compile lines correctly, but failed at the linker stage because you are trying to build an output file called build when there is already a folder called build (not allowed in linux - maybe ok for windows but I don't recommend).
I made an answer for another question - but it might be a better start point then you have here in the case where you have nested src/inc directories and you want to be able to clean your output folders - ill put it here for convenience:
# Get your source list (use wildcard or what ever, but just for clarity you should end up with a list of files with full paths to start with):
# Output folders/targets
SRC_DIR = src
OBJ_DIR = obj
BIN_DIR = bin
OUTPUT_FILE = output
# Generate list of source files - this is a linux command - but you can do this in pure make using wildcard and such).
SOURCES := $(shell find $(SOURCEDIR) -name '*.c')
# Create your objects list in the obj directory
OBJECTS = $(addprefix $(OBJ_DIR)/,$(addsuffix .o,$(basename $(SOURCES))))
# Create list of unique folders to create
DIRS = $(sort $(dir $(OBJECTS))) $(BIN_DIR)
# Create list of include paths
INCS = $(addprefix -I,$(sort $(dir $(SOURCES))))
# Main target rule
$(BIN_DIR)/$(OUTPUT_FILE): $(OBJECTS) | $(DIRS)
#echo linker: gcc $(OBJECTS) -o $#
#touch $#
# Rule to build your object file - ensure that the folders are created first (also create a dummy obj file) - note this works for parallel builds too (make -j
$(OBJ_DIR)/%.o: %.c | $(DIRS)
#echo compile: gcc $(INCS) -c $? -o $#
#touch $#
# Create your directories here
$(DIRS):
#echo Creating dir: $#
#mkdir -p $#
# Clean if needed
.PHONY: clean
clean:
rm -rf $(OBJ_DIR) $(BIN_DIR)
Note this is just a template, you still need to fill in the gcc/makefile flags - but its a decent start point...
Debugging
$(info ...) is your friend - for example you could do:
$(info OBJ = $(OBJ))
$(info objrule = $(BUILD_DIR)/%.o: $(SOURCE_DIR)/%.c $(INCLUDES))
To print our what make has expanded these variables / lines to be - this can yield useful debug.
Here is another version of your makefile with automatic dependency generation:
INCLUDE_DIR := inc
SOURCE_DIR := src
BUILD_DIR := build
CC := arm-none-eabi-gcc
CPPFLAGS := -I$(INCLUDE_DIR)
exes := build
build.obj := main.o pfc.o
all : ${exes:%=${BUILD_DIR}/%}
.SECONDEXPANSION:
${BUILD_DIR}:
mkdir -p $#
# Rule to link all exes.
${exes:%=${BUILD_DIR}/%} : ${BUILD_DIR}/% : $$(addprefix ${BUILD_DIR}/,$${$$*.obj}) | $${#D}
${CC} -o $# ${LDFLAGS} $^ ${LDLIBS}
# Rule to compile C sources. And generate header dependencies.
${BUILD_DIR}/%.o : ${SOURCE_DIR}/%.c | $${#D}
${CC} -o $# -c ${CPPFLAGS} ${CFLAGS} -MD -MP $<
# Include automatically generated header dependencies.
ifneq ($(MAKECMDGOALS),clean)
-include $(foreach exe,${exes},$(patsubst %.o,${BUILD_DIR}/%.d,${${exe}.obj}))
endif
clean:
rm -rf $(BUILD_DIR)
.PHONY: all clean
To add another executable target do:
exes += another
another.obj := another_main.o another_pfc.o

Evolving a Makefile From Flat Directory Structure to Sub-Directory Structure

SEE UPDATES BELOW
Research Done: I'm finding learning how to evolve Makefiles from one situation to another is difficult. There are a ton of questions and answers out there but few of them actually show how a Makefile can evolve as your project changes. They also all seem to use various different techniques and idioms of Makefiles so translating between one question and another can be tricky when you are learning Makefiles for the first time, as I am.
Problem: My problem is that I have a project that started at as a flat directory structure but then is migrating to a structure with sub-directories. What I can't do is get my Makefile to along for the ride.
First I'll show what I created that works and then I show how I want it to evolve and how that doesn't work.
Flat Directory Structure, Working Makefile
I have project directory that has all my C files and one header file plus my Makefile:
project
Makefile
c8_asm.c
c8_dasm.c
c8_terp.c
chip8.h
Here is my Makefile (which works just fine):
CC = gcc
CFLAGS += -c -Wall -std=c99
CFLAGS += -D_POSIX_C_SOURCE=200809L
LDLIBS += -lm
# Targets
all: c8_dasm c8_asm c8_terp
c8_dasm: c8_dasm.o
$(CC) $(LDLIBS) c8_dasm.o -o $#
c8_asm: c8_asm.o
$(CC) $(LDLIBS) c8_asm.o -o $#
c8_terp: c8_terp.o
$(CC) $(LDLIBS) c8_terp.o -o $#
# Using implicit rules for updating an '.o' file from a correspondingly
# named '.c' file.
c8_dasm.o: chip8.h
c8_asm.o: chip8.h
c8_terp.o: chip8.h
.PHONY: clean
clean:
rm c8_dasm c8_asm c8_terp c8_dasm.o c8_asm.o c8_terp.o
I get all my .o files and my executables are created in the project directory.
Evolving The Project
But what I wanted to do is have my sources files (all .c and .h) in a src directory. I wanted to build into an obj directory and have the executables go in a bin directory. So my project would look like this:
project
src
c8_asm.c
c8_dasm.c
c8_terp.c
chip8.h
Makefile
Sub-Directory Structure, Makefile NOT Working
To accommodate the above, I changed my Makefile accordingly:
CC = gcc
CFLAGS += -c -Wall -std=c99
CFLAGS += -D_POSIX_C_SOURCE=200809L
LDLIBS += -lm
SRC_DIR = src
OBJ_DIR = obj
BIN_DIR = bin
SOURCES := $(wildcard $(SRC_DIR)/*.c)
OBJECTS := $(SOURCES:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
MKDIR_P ?= mkdir -p
# Targets
all: $(BIN_DIR)/c8_dasm $(BIN_DIR)/c8_asm $(BIN_DIR)/c8_terp
$(BIN_DIR)/c8_dasm: $(OBJ_DIR)/c8_dasm.o
$(CC) $(LDLIBS) $(OBJ_DIR)/c8_dasm.o -o $#
$(BIN_DIR)/c8_asm: $(OBJ_DIR)/c8_asm.o
$(CC) $(LDLIBS) $(OBJ_DIR)/c8_asm.o -o $#
$(BIN_DIR)/c8_terp: $(OBJ_DIR)/c8_terp.o
$(MKDIR_P) $(dir $#)
$(CC) $(LDLIBS) $(OBJ_DIR)/c8_terp.o -o $#
$(OBJECTS): $(OBJ_DIR)/%.o : $(SRC_DIR)/%.c
$(MKDIR_P) $(dir $#)
$(CC) $< -o $(OBJ_DIR)/$#
# Using implicit rules for updating an '.o' file from a correspondingly
# named '.c' file.
$(OBJ_DIR)/c8_dasm.o: $(SRC_DIR)/chip8.h
$(OBJ_DIR)/c8_asm.o: $(SRC_DIR)/chip8.h
$(OBJ_DIR)/c8_terp.o: $(SRC_DIR)/chip8.h
.PHONY: clean
clean:
rm -r $(BUILD_DIR)
rm $(OBJECTS)
Upon running this I get the following:
mkdir -p obj/obj/
gcc src/c8_dasm.c -o obj/c8_dasm.o
gcc -lm obj/c8_dasm.o -o bin/c8_dasm
ld: can't link with a main executable file 'obj/c8_dasm.o' for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [bin/c8_dasm] Error 1
I wanted to stop here and get some assistance because I fear I'm making this Makefile for complicated than it need be and I'm trying to avoid getting into bad habits.
I'm hoping to hear opinions about what I'm not conceptualizing correctly here.
FIRST UPDATE
I managed to take it bit by bit and get it mostly working. Here is what I ended up with:
CC = gcc
CFLAGS += -c -Wall -std=c99
CFLAGS += -D_POSIX_C_SOURCE=200809L
LDLIBS += -lm
# Directories.
SRC_DIR = src
BIN_DIR = bin
$(shell mkdir -p $(BIN_DIR))
# Patterns for files.
SOURCES := $(wildcard $(SRC_DIR)/*.c)
OBJECTS := $(SOURCES:$(SRC_DIR)/%.c=$(SRC_DIR)/%.o)
EXECUTABLES := c8_dasm c8_asm c8_terp
# Targets
all: $(EXECUTABLES)
c8_dasm: $(SRC_DIR)/c8_dasm.o
$(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$#
#echo "C8 Disassembler Built"
c8_asm: $(SRC_DIR)/c8_asm.o
$(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$#
#echo "C8 Assembler Built"
c8_terp: $(SRC_DIR)/c8_terp.o
$(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$#
#echo "C8 Interpreter Built"
# Using implicit rules for updating an '.o' file from a correspondingly
# named '.c' file.
c8_dasm.o: $(SRC_DIR)/chip8.h
c8_asm.o: $(SRC_DIR)/chip8.h
c8_terp.o: $(SRC_DIR)/chip8.h
.PHONY: clean
clean:
rm $(OBJECTS)
rm -r $(BIN_DIR)
Of course, as I'm finding with Make this leads to other obscure problems. For example doing this:
make
make clean
works fine. Meaning all files are generated and the files are cleaned, including the bin directory.
However, if I do this:
make c8_dasm
make clean
This builds fine. But the clean fails to delete the bin directory (although it does delete the object files). This happens regardless of what individual executable I try to build.
No amount of searching is helping me find out why that is.
SECOND UPDATE
I found that problem was solved as well. It just required using the "-f" for the rm statements in the clean target.
THIRD UPDATE
To get the object file directory part working, I tried (from this: path include and src directory makefile) to construct my Makefile as follows:
CC = gcc
CFLAGS += -c -Wall -std=c99
CFLAGS += -D_POSIX_C_SOURCE=200809L
LDLIBS += -lm
SRC_DIR = src
OBJ_DIR = obj
BIN_DIR = bin
$(shell mkdir -p $(BIN_DIR))
$(shell mkdir -p $(OBJ_DIR))
SOURCES := $(wildcard $(SRC_DIR)/*.c)
OBJECTS := $(SOURCES:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
EXECUTABLES := c8_dasm c8_asm c8_terp
all: $(EXECUTABLES)
c8_dasm: $(SRC_DIR)/c8_dasm.o
$(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$#
#echo "C8 Disassembler Built"
c8_asm: $(SRC_DIR)/c8_asm.o
$(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$#
#echo "C8 Assembler Built"
c8_terp: $(SRC_DIR)/c8_terp.o
$(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$#
#echo "C8 Interpreter Built"
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c
$(CC) $(CFLAGS) -c $< -o $(BIN_DIR)/$#
.PHONY: clean
clean:
rm -rf $(BIN_DIR)
rm -f $(OBJECTS)
I was able to condense the original three lines using chip8.h into one target but I have no way to know if that's correct. It compiles at least. I also changed the OBJECTS line to reflect the new OBJ_DIR I created.
However, this doesn't put the object files in the right place. It still puts them in the src directory rather than the obj directory.
This is why it makes sense to not do anything complicated with Makefiles. Just put the actual directory names in your commands. Never rely on wildcards.
People using C and C++ and using Makefiles spend too much time trying to get those to work rather than just actually getting things done. That's why you see so many of the questions that you see and why the answers vary so much.
In your specific case, your targets don't always have to contain the directory and that's part of the problem. The rules getting generated don't have an actual target in your file because of the directories you are prepending to everything. You have to think in terms of what is getting generated by each target: meaning, the output. So if c8_dasm is getting output, that's your target. The directory has nothing to do with that. So you need to remove all of your directory substitutions where they aren't needed.
But before doing that, ask yourself this: if your first solution was working, why change it? It's better to not even do directories when you're using Make. Just have everything in the same directory as you started off with. You can even see that this allows your Makefile to be much cleaner.
I believe I may have figured this out. Below is my Makefile. It seems to do what I want. It does the following:
Compiles all object files into the obj directory.
Compiles and links so that executables are generated in the bin directory.
Recognizes if any .c files are changed and recompiles accordingly.
Recognizes if the .h file is changed and recompiles all C files that reference it.
This seems to satisfy all the criteria but I can't tell if I've painted myself into some corner that I can't see yet.
CC = gcc
CFLAGS += -c -Wall -std=c99
CFLAGS += -D_POSIX_C_SOURCE=200809L
LDLIBS += -lm
SRC_DIR = src
OBJ_DIR = obj
BIN_DIR = bin
$(shell mkdir -p $(BIN_DIR))
$(shell mkdir -p $(OBJ_DIR))
SOURCES := $(wildcard $(SRC_DIR)/*.c)
OBJECTS := $(SOURCES:$(SRC_DIR)/%.c=$(OBJ_DIR)/%.o)
EXECUTABLES := c8_dasm c8_asm c8_terp
all: $(EXECUTABLES)
c8_dasm: $(OBJ_DIR)/c8_dasm.o
$(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$#
#echo "C8 Disassembler Built"
c8_asm: $(OBJ_DIR)/c8_asm.o
$(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$#
#echo "C8 Assembler Built"
c8_terp: $(OBJ_DIR)/c8_terp.o
$(CC) $^ $(LDLIBS) -o $(BIN_DIR)/$#
#echo "C8 Interpreter Built"
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c $(SRC_DIR)/chip8.h
$(CC) $(CFLAGS) -c $< -o $#
.PHONY: clean
clean:
rm -rf $(BIN_DIR)
rm -rf $(OBJ_DIR)
Stackoverflow is whining about too many comments, so I'll make this another "answer." After our back-and-forth to my original comment, your last comment is correct. That's what I wanted you to see.
Understand that you can't use Make to do what you want to do exactly.
So here's really the answer: You can't create multiple executables AND with only some of the object files applying to each one AND while using a directory structure. Make is in no way capable of handling that.
Right now you're trying to use Make in a way that it wasn't intended for which is why you're running into so many problems. If you keep playing around you're going to run into is a series of errors that say "duplicate symbol" because you will be compiling each of your files multiple times for each executable, assuming you follow most of the advice you'll find.
Check out this How can I create a Makefile for C projects with SRC, OBJ, and BIN subdirectories? to see what I mean. That one works because all object files are being used to create a single executable. But as you've stated, that's not going to be the case for you. And that's what Make can't handle. That's why you're not finding an answer to that.
And while your chip8.h file is now not going to cause problems in terms of allowing you to compile, your Makefile with that third update would not recognize when the chip8.h file itself has changed. You would have to change a .c file to force a recompile so that changes to your .h were recognized. So you either have to stick with your second update or use something other than Make.

How to have a sometimes empty dependency in makefiles?

I have the following rule:
EXECS = $(sort $(patsubst %.cpp,%$(EXESUFFIX), $(patsubst %.c,%$(EXESUFFIX), $(filter-out $(IGNORESRCS), $(EXECSRCS)))))
SRCS = $(sort $(filter-out $(EXECSRCS), $(filter-out $(IGNORESRCS), $(wildcard *.c) $(wildcard *.cpp) $(foreach DIR,$(SUBDIRS),$(wildcard $(DIR)/*.cpp) $(wildcard $(DIR)/*.c) ) )))
#OBJS = $(addprefix $(OBJDIR), $(patsubst %.cpp,%$(OBJSUFFIX), $(patsubst %.c,%$(OBJSUFFIX), $(SRCS))))
OBJS = $(patsubst %.cpp,%$(OBJSUFFIX), $(patsubst %.c,%$(OBJSUFFIX), $(SRCS)))
RESOURCE_SRCS= $(sort $(filter-out $(IGNORESRCS), $(wildcard *.rc) $(foreach DIR,$(SUBDIRS),$(wildcard $(DIR)/*.rc) ) ))
RESOURCES = $(patsubst %.rc,%$(OBJSUFFIX), $(RESOURCE_SRCS))
%$(EXESUFFIX) : %.cpp $(LIBS) $(RESOURCES)
$(CXX) $(DEFINES) $(CFLAGS) $(INCLUDES) $(LIBPATH) -o $(BINDIR)/$* $< $(RESOURCES) $(LIBINCLUDES)
The problem is that $(RESOURCES) doesnt exist for all platforms. The %$(EXESUFFIX) : %.cpp rule doesnt run, instead it tries to run g++ exec.cpp -o exec which as far as I can tell isnt a rule that I declared anywhere.
How do I get the rule to still build despite the fact that it is empty (and build the resources if it is not empty)?
If the variable is empty it has no effect on the rule. It should just work as written. What is the actual error you're seeing?
ETA:
Your question is very unclear in what, exactly, you mean by $(RESOURCES) doesn't exist. My answer was assuming you meant that the variable was empty. But given your comment below about how the makefile behaves, I now suspect what you mean is that the variable is still set to a list of files, but that those files are not present.
Because they're not there, and make doesn't know how to build them, make decides that this pattern rule cannot be used at all and it chooses a different rule.
If you want these files to only have any impact if they exist, then you can use the $(wildcard ...) function to expand only to those files that exist:
%$(EXESUFFIX) : %.cpp $(LIBS) $(wildcard $(RESOURCES))
$(CXX) ...
One critical point here: the contents of $(RESOURCES) MUST be source files. They cannot be derived files (files that are supposed to be created by make). If they are derived, the situation is far more complex.

Makefile mirror build directory

I need to create Makefile that compiles .c files with a lot of subdirs (sources directory goes in around 5 level depth) and I need to place the object files in the mirrored build directory. So far, I have created this Makefile:
CC := gcc.exe
AS := as.exe
CFLAGS = -DCORE_SW_VERSION='"$(CORE_SW_VERSION)"' -Wall -mA6 -c -fmessage-length=0 -Hsdata0
CFLAGS += -fgnu89-inline -mno-volatile-cache $(INCLUDE) -Hon=each_function_in_own_section -Xcrc -std=c99 -O1
CORE_SW_VERSION:=CORE.07.01.04.01.03.01.R
HAL_SW_VERSION:=16.01.06.01.06.00
MODE_CORE := dev
MODE_HAL := dev
OBJDIR := $(shell pwd)/$(TARGET12) #TARGET12 is a make parameter
INCLUDE := $(shell cat ./$(TARGET12)_include.txt)
SOURCEDIR := ../sources
CSRC := $(shell find $(SOURCEDIR) -name '*.c')
EXCLUDES := $(shell cat ./$(TARGET12)_exclude.txt)
OBJ := $(CSRC:.c=.o)
OBJS := $(patsubst ../%.c,$(OBJDIR)/%.o,$(CSRC))
.PHONY: $(TARGET12)
$(TARGET12): $(OBJS)
$(AR) -r $(CORE_SW_VERSION).a $(OBJS)
$(OBJS): $(CSRC)
mkdir -p $(dir $#)
$(CC) $(CFLAGS) $< -o $(patsubst ../%,$(OBJDIR)/%,$#)
If I define rule for $(OBJS) this way, $< is always the first .c file in $(CSRC).
If I define $(OBJS) this way:
$(OBJS): %.o: %.c
mkdir -p $(dir $#)
$(CP) $< $#
I get error that there is no rule to make target for .c file. But I see that make is looking for .c file in build mirrored directory, and it should look at the source dir. Do you maybe know how this could be arranged?
Thanks you in advance!
The rule $(OBJS): %.o: %.c means something like this: when trying to create a .o file, use this rule if the corresponding .c file exists. For example: when make is looking for a way to create $(OBJDIR)/foo.o, it will look for $(OBJDIR)/foo.c.
In your case this file does not exists, so the rule is ignored.
What you want is rather something like this:
$(OBJS): $(OBJDIR)/%.o: $(SOURCEDIR)/%.c
mkdir -p $(dir $#)
$(CP) $< $#
The first rule for $(OBJS) you tried, states that every object file individually depends on all source files. Surely that's not correct.
Your second attempt is better, although the recipe is weird. Fix that and use VPATH to make make find the sources.

How to place object files in separate subdirectory

I'm having trouble with trying to use make to place object files in a separate subdirectory, probably a very basic technique. I have tried to use the information in this page:
http://www.gnu.org/software/hello/manual/make/Prerequisite-Types.html#Prerequisite-Types
I get the following output from make:
make: *** No rule to make target `ku.h', needed by `obj/kumain.o'. Stop.
However ku.h is a dependency not a target (although it's obviously #included within the c source files). When I don't try to use a subdirectory for object files (i.e. miss out the OBJDIR parts) it works fine. Why does make think ku.h is a target?
my makefile is this: (the style is after reading various sources of information)
.SUFFIXES:
.SUFFIXES: .c .o
CC=gcc
CPPFLAGS=-Wall
LDLIBS=-lhpdf
VPATH=%.c src
VPATH=%.h src
VPATH=%.o obj
OBJDIR=obj
objects= $(addprefix $(OBJDIR)/, kumain.o kudlx.o kusolvesk.o kugetpuz.o kuutils.o \
kurand.o kuASCboard.o kuPDFs.o kupuzstrings.o kugensud.o \
kushapes.o )
ku : $(objects)
$(CC) $(CPPFLAGS) -o ku $(objects) $(LDLIBS)
$(objects) : ku.h kudefines.h kuglobals.h kufns.h | $(OBJDIR)
$(OBJDIR):
mkdir $(OBJDIR)
.PHONY: clean
clean :
rm $(objects)
Edit:
I applied the change to use the vpath directive. My version was a bad mixture of VPATH=xxx and vpath %.c xxx. However I now get another problem (which was the original problem before I added the wrong vpath). This is now the output:
gcc -o ku -lhpdf obj/kumain.o obj/kudlx.o obj/kusolvesk.o ..etc
gcc: obj/kumain.o: No such file or directory
gcc: obj/kudlx.o: No such file or directory
gcc: obj/kusolvesk.o: No such file or directory
gcc: obj/kugetpuz.o: No such file or directory
gcc: obj/kuutils.o: No such file or directory
gcc: obj/kurand.o: No such file or directory
gcc: obj/kuASCboard.o: No such file or directory
gcc: obj/kuPDFs.o: No such file or directory
gcc: obj/kupuzstrings.o: No such file or directory
gcc: obj/kugensud.o: No such file or directory
gcc: obj/kushapes.o: No such file or directory
make: *** [ku] Error 1
It appears that make is not applying the implicit rule for an object file although the manual says
"Implicit rules tell make how to use customary techniques so that you do not have to specify them in detail when you want to use them. For example, there is an implicit rule for C compilation. File names determine which implicit rules are run. For example, C compilation typically takes a .c file and makes a .o file. So make applies the implicit rule for C compilation when it sees this combination of file name endings." and also "The search through the directories specified in VPATH or with vpath also happens during consideration of implicit rules (see Using Implicit Rules)."
Again here "For example, when a file foo.o has no explicit rule, make considers implicit rules, such as the built-in rule to compile foo.c if that file exists. If such a file is lacking in the current directory, the appropriate directories are searched for it. If foo.c exists (or is mentioned in the makefile) in any of the directories, the implicit rule for C compilation is applied."
Any assistance in getting implicit rules to work for my makefile would be greatly appreciated.
Edit no 2:
Thanks to Jack Kelly I have made an explicit rule to compile the .c files since I couldn't get anywhere trying to use implicit rules. Also thanks to al_miro for the vpath info.
Here is the working makfile:
.SUFFIXES:
.SUFFIXES: .c .o
CC=gcc
CPPFLAGS=-Wall
LDLIBS=-lhpdf
OBJDIR=obj
vpath %.c src
vpath %.h src
objects = $(addprefix $(OBJDIR)/, kumain.o kudlx.o kusolvesk.o kugetpuz.o kuutils.o \
kurand.o kuASCboard.o kuPDFs.o kupuzstrings.o kugensud.o \
kushapes.o )
ku : $(objects)
$(CC) $(CPPFLAGS) -o ku $(objects) $(LDLIBS)
$(OBJDIR) obj/%.o : %.c ku.h kudefines.h kuglobals.h kufns.h
$(CC) -c $(CPPFLAGS) $< -o $#
.PHONY : clean
clean :
rm $(objects)
Since you're using GNUmake, use a pattern rule for compiling object files:
$(OBJDIR)/%.o: %.c
$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $# $<
This is the makefile that I use for most of my projects,
It permits putting source files, headers and inline files in subfolders, and subfolders of subfolders and so-forth, and will automatically generate a dependency file for each object This means that modification of headers and inline files will trigger recompilation of files which are dependent.
Source files are detected via shell find command, so there is no need to explicitly specify, just keep coding to your hearts content.
It will also copy all files from a 'resources' folder, into the bin folder when the project is compiled, which I find handy most of the time.
To provide credit where it is due, the auto-dependencies feature was based largely off Scott McPeak's page that can be found HERE, with some additional modifications / tweaks for my needs.
Example Makefile
#Compiler and Linker
CC := g++-mp-4.7
#The Target Binary Program
TARGET := program
#The Directories, Source, Includes, Objects, Binary and Resources
SRCDIR := src
INCDIR := inc
BUILDDIR := obj
TARGETDIR := bin
RESDIR := res
SRCEXT := cpp
DEPEXT := d
OBJEXT := o
#Flags, Libraries and Includes
CFLAGS := -fopenmp -Wall -O3 -g
LIB := -fopenmp -lm -larmadillo
INC := -I$(INCDIR) -I/usr/local/include
INCDEP := -I$(INCDIR)
#---------------------------------------------------------------------------------
#DO NOT EDIT BELOW THIS LINE
#---------------------------------------------------------------------------------
SOURCES := $(shell find $(SRCDIR) -type f -name *.$(SRCEXT))
OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:.$(SRCEXT)=.$(OBJEXT)))
#Defauilt Make
all: resources $(TARGET)
#Remake
remake: cleaner all
#Copy Resources from Resources Directory to Target Directory
resources: directories
#cp $(RESDIR)/* $(TARGETDIR)/
#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)
#Pull in dependency info for *existing* .o files
-include $(OBJECTS:.$(OBJEXT)=.$(DEPEXT))
#Link
$(TARGET): $(OBJECTS)
$(CC) -o $(TARGETDIR)/$(TARGET) $^ $(LIB)
#Compile
$(BUILDDIR)/%.$(OBJEXT): $(SRCDIR)/%.$(SRCEXT)
#mkdir -p $(dir $#)
$(CC) $(CFLAGS) $(INC) -c -o $# $<
#$(CC) $(CFLAGS) $(INCDEP) -MM $(SRCDIR)/$*.$(SRCEXT) > $(BUILDDIR)/$*.$(DEPEXT)
#cp -f $(BUILDDIR)/$*.$(DEPEXT) $(BUILDDIR)/$*.$(DEPEXT).tmp
#sed -e 's|.*:|$(BUILDDIR)/$*.$(OBJEXT):|' < $(BUILDDIR)/$*.$(DEPEXT).tmp > $(BUILDDIR)/$*.$(DEPEXT)
#sed -e 's/.*://' -e 's/\\$$//' < $(BUILDDIR)/$*.$(DEPEXT).tmp | fmt -1 | sed -e 's/^ *//' -e 's/$$/:/' >> $(BUILDDIR)/$*.$(DEPEXT)
#rm -f $(BUILDDIR)/$*.$(DEPEXT).tmp
#Non-File Targets
.PHONY: all remake clean cleaner resources
The VPATH lines are wrong, they should be
vpath %.c src
vpath %.h src
i.e. not capital and without the = . As it is now, it doesn't find the .h file and thinks it is a target to be made.
In general, you either have to specify $(OBJDIR) on the left hand side of all the rules that place files in $(OBJDIR), or you can run make from $(OBJDIR).
VPATH is for sources, not for objects.
Take a look at these two links for more explanation, and a "clever" workaround.
http://mad-scientist.net/make/vpath.html
http://mad-scientist.net/make/multi-arch.html
Build from the output directory
Instead of building from the top-level directory, build from the output directory. You can access the source directories by setting the vpath. This option has the advantage that the built-in rules can be used.
build.sh
#!/bin/bash
mkdir -p obj
cp Makefile.template obj/Makefile
cd obj
make "$*"
Makefile
.SUFFIXES:
.SUFFIXES: .c .o
CC=gcc
CPPFLAGS=-Wall
LDLIBS=-lhpdf
VPATH=%.c ../src
VPATH=%.h ../src
objects=kumain.o kudlx.o kusolvesk.o kugetpuz.o kuutils.o \
kurand.o kuASCboard.o kuPDFs.o kupuzstrings.o kugensud.o \
kushapes.o
ku : $(objects)
$(objects) : ku.h kudefines.h kuglobals.h kufns.h
.PHONY: clean
clean :
rm $(objects)
The disadvantage is that error messages do not match the CWD. This can be solved by skipping build.sh and directly building from the obj directory.
Another advantage of this approach is that it's somewhat popular. cmake works in a similar fashion.
Create Rule based on output option
The following solution isn't nice in my opinion, as I really love the built-in rules. However, GNU make doesn't support something like vpath for output directories. And the built-in rules cannot match, as the % in %.o would match obj/foo of obj/foo.o, leaving make with a search in vpath %.c src/ for stuff like src/obj/foo.c, but not src/foo.c.
But this is as close to the built-in rules as you can get, and therefore to my best knowledge the nicest solution that's available.
$(OBJDIR)/%.o: %.c
$(COMPILE.c) $(OUTPUT_OPTION) $<
Explanation: $(COMPILE.c) $(OUTPUT_OPTION) $< actually is how .c.o is implemented, see http://git.savannah.gnu.org/cgit/make.git/tree/default.c (and it's even mentioned in the manual)
Besides, if $(OBJDIR) would only ever contain auto-gererated files, you could create it on-the-fly with an order-only prerequisite, making the clean rule slightly simpler:
$(OBJDIR):
mkdir -p $(OBJDIR)
$(OBJDIR)/%.o: %.c | $(OBJDIR)
$(COMPILE.c) $(OUTPUT_OPTION) $<
.PHONY: clean
clean:
$(RM) -r $(OBJDIR)
This requires that the feature order-only is available, which you can check using $(filter order-only, $(.FETAURES)). I've checked on Kubuntu 14.04 GNU make 3.81 and OpenSUSE 13.1 GNU make 3.82. Both were built with order-only enabled, and am now left puzzled why Kubuntu 14.04 comes with an older version of GNU make than OpenSUSE 13.1. Anyways, gonna download make 4.1 now :)
For anyone that is working with a directory style like this:
project
> src
> pkgA
> pkgB
...
> bin
> pkgA
> pkgB
...
The following worked very well for me. I made this myself, using
the GNU make manual as my main reference; this, in particular, was extremely helpful for my last rule, which ended up being the most important one for me.
My Makefile:
PROG := sim
CC := g++
ODIR := bin
SDIR := src
MAIN_OBJ := main.o
MAIN := main.cpp
PKG_DIRS := $(shell ls $(SDIR))
CXXFLAGS = -std=c++11 -Wall $(addprefix -I$(SDIR)/,$(PKG_DIRS)) -I$(BOOST_ROOT)
FIND_SRC_FILES = $(wildcard $(SDIR)/$(pkg)/*.cpp)
SRC_FILES = $(foreach pkg,$(PKG_DIRS),$(FIND_SRC_FILES))
OBJ_FILES = $(patsubst $(SDIR)/%,$(ODIR)/%,\
$(patsubst %.cpp,%.o,$(filter-out $(SDIR)/main/$(MAIN),$(SRC_FILES))))
vpath %.h $(addprefix $(SDIR)/,$(PKG_DIRS))
vpath %.cpp $(addprefix $(SDIR)/,$(PKG_DIRS))
vpath $(MAIN) $(addprefix $(SDIR)/,main)
# main target
#$(PROG) : all
$(PROG) : $(MAIN) $(OBJ_FILES)
$(CC) $(CXXFLAGS) -o $(PROG) $(SDIR)/main/$(MAIN)
# debugging
all : ; $(info $$PKG_DIRS is [${PKG_DIRS}])#echo Hello world
%.o : %.cpp
$(CC) $(CXXFLAGS) -c $< -o $#
# This one right here, folks. This is the one.
$(OBJ_FILES) : $(ODIR)/%.o : $(SDIR)/%.h
$(CC) $(CXXFLAGS) -c $< -o $#
# for whatever reason, clean is not being called...
# any ideas why???
.PHONY: clean
clean :
#echo Build done! Cleaning object files...
#rm -r $(ODIR)/*/*.o
By using $(SDIR)/%.h as a prerequisite for $(ODIR)/%.o, this forced make to look in source-package directories for source code instead of looking in the same folder as the object file.
I hope this helps some people. Let me know if you see anything wrong with what I've provided.
BTW: As you may see from my last comment, clean is not being called and I am not sure why. Any ideas?
For all those working with implicit rules (and GNU MAKE). Here is a simple makefile which supports different directories:
#Start of the makefile
VPATH = ./src:./header:./objects
OUTPUT_OPTION = -o objects/$#
CXXFLAGS += -Wall -g -I./header
Target = $(notdir $(CURDIR)).exe
Objects := $(notdir $(patsubst %.cpp,%.o,$(wildcard src/*.cpp)))
all: $(Target)
$(Target): $(Objects)
$(CXX) $(CXXFLAGS) -o $(Target) $(addprefix objects/,$(Objects))
#Beware of -f. It skips any confirmation/errors (e.g. file does not exist)
.PHONY: clean
clean:
rm -f $(addprefix objects/,$(Objects)) $(Target)
Lets have a closer look (I will refer to the current Directory with curdir):
This line is used to get a list of the used .o files which are in curdir/src.
Objects := $(notdir $(patsubst %.cpp,%.o,$(wildcard src/*.cpp)))
#expands to "foo.o myfoo.o otherfoo.o"
Via variable the output is set to a different directory (curdir/objects).
OUTPUT_OPTION = -o objects/$#
#OUTPUT_OPTION will insert the -o flag into the implicit rules
To make sure the compiler finds the objects in the new objects folder, the path is added to the filename.
$(Target): $(Objects)
$(CXX) $(CXXFLAGS) -o $(Target) $(addprefix objects/,$(Objects))
# ^^^^^^^^^^^^^^^^^^^^
This is meant as an example and there is definitly room for improvement.
For additional Information consult:
Make documetation. See chapter 10.2
Or:
Oracle: Programming Utilities Guide
You can specify the -o $# option to your compile command to force the output of the compile command to take on the name of the target. For example, if you have:
sources: cpp/class.cpp and cpp/driver.cpp
headers: headers/class.h
...and you want to place the object files in:
objects: obj/class.o obj/driver.o
...then you can compile cpp/class.cpp and cpp/driver.cpp separately into obj/class.o and obj/driver.o, and then link, with the following Makefile:
CC=c++
FLAGS=-std=gnu++11
INCS=-I./headers
SRC=./cpp
OBJ=./obj
EXE=./exe
${OBJ}/class.o: ${SRC}/class.cpp
${CC} ${FLAGS} ${INCS} -c $< -o $#
${OBJ}/driver.o: ${SRC}/driver.cpp ${SRC}/class.cpp
${CC} ${FLAGS} ${INCS} -c $< -o $#
driver: ${OBJ}/driver.o ${OBJ}/class.o
${CC} ${FLAGS} ${OBJ}/driver.o ${OBJ}/class.o -o ${EXE}/driver
None of these answers seemed simple enough - the crux of the problem is not having to rebuild:
makefile
OBJDIR=out
VPATH=$(OBJDIR)
# make will look in VPATH to see if the target needs to be rebuilt
test: moo
touch $(OBJDIR)/$#
example use
touch moo
# creates out/test
make test
# doesn't update out/test
make test
# will now update test
touch moo
make test

Resources