Consider this makefile:
srcs = 1.src
%.compiled: create_srcs $(srcs)
#echo $# depends on: $^
create_srcs:
$(eval srcs = $(srcs) 2.src)
#echo srcs: $(srcs)
%.src:
#echo src: $#
If executed it outputs:
c:\>make file.compiled
srcs: 1.src 2.src
src: 1.src
file.compiled depends on create_srcs 1.src
How do I make %.compiled depend on 2.src also?
Also, if it matters, in my real makefile create_srcs unpacks some zips which may contain sources and 'srcs' variable is defined as srcs = $(shell find ...). %.compiled is not the final target, though create_srcs is the first one.
Related
I am new to Makefile.
I have a string of multiple directories and I want to compile all the .c files in them.
The number of paths in that string can change (it is received as an argument from a script).
For example:
DIRS = path1 path2...
I will be happy to receive help with building a mechanism that can go over DIRS and compile each and every .c file in each path.
I am not sure if this is the right way, but I got this so far:
DIRS = path1 path2
define generateRules
SOURCES := $(wildcard $(path)/*.c)
%.o: $(SOURCES)
echo "path is $(path)";
$(CC) $(CFLAGS) ${INCS} ${DEFS} -c $< -o ${BUILD}/$#
endef
$(foreach path,$(DIRS),$(info $(generateRules)))
Thank you
Let's start with generating a list of the source files.
DIRS = path1 path2
SOURCES := $(wildcard $(addsuffix /*.c,$(DIRS)))
From this we can generate a list of targets:
TARGETS = $(patsubst %.c,$(BUILD)/%.o,$(notdir $(SOURCES)))
The simplest way to get the effect you want is by use of the vpath directive and a static pattern rule:
vpath %.c $(DIRS)
$(TARGETS): $(BUILD)/%.o: %.c
#echo building $# from $<
$(CC) $(CFLAGS) ${INCS} ${DEFS} -c $< -o $#
If you want to generate a rule for each source directory -- or each source file -- you can, but that requires a few more advanced techniques. I advise you to get the simple approach working first.
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
i've tried to write simple makefile for practice.
I have two directories 1. srcs(.c), 2.include(.h)
and try to define SRCS variable that would contain all .c files
in current directory and srcs directory.
and below is my Makefile
CURDIR = $(shell pwd)
OBJDIR = $(CURDIR)/objdir
VPATH = $(CURDIR)/srcs
SRCS = $(wildcard *.c)
OBJS = $(patsubst %.c, %.o, $(SRCS))
all: main
main: $(OBJS)
gcc -o $# $^
$(OBJS): $(SRCS) | $(OBJDIR)
gcc -c -o $# $<
$(OBJDIR):
mkdir objdir
I designate current/src directory as a VPATH to make find
all *.c files in current directory and current/srcs but
it cannot find *.c files in /srcs directory.
May be make cannot us VPATH when it defines the variable in Makefile
right? if it's right please let me know better approach :)
Thanks.
VPATH is for directories make should search to find prerequisites.
It doesn't change where $(wildcard) searches.
VPATH lets you use foo.c (either explicitly or implicitly) in the prerequisite list of a rule and have make look in the current directory and the VPATH directories for the file for it.
If you want SRCS to contain the .c files from the srcs directory then you need to include srcs/*.c in an additional $(wildcard) call in the SRCS assignment.
SRCS = $(wildcard *.c) $(wildcard srcs/*.c)
I've written a simple make to test with pattern rule. Here it is:
default:
echo This is default target
%.o:%.c
gcc -c $< -o $#
clean:
rm -f *.o
I have a three *.c files in pwd. After make command I have:
echo This is default target
This is default target
but I expected that any *.c file in pwd will be compiled.
The first target in the makefile is the one that is built when you do not specify a specific target name.
In your makefile, default is first, so it is created.
Often, you'll create a target all as the first target, and list the programs that should be built by some more or less devious means.
.PHONY: default all clean
default:
#echo "You must specify which program you want built (or specify all)"
SRCS = $(wildcard *.c)
PROGS = ${SRCS:.c=}
all: ${PROGS}
%.o:%.c
gcc -c $< -o $#
clean:
rm -f *.o
The .PHONY target specifies that default, all and clean are not real files but phony targets.
I have a directory with many source files in it, and I have a default rule similar to the above as the first target, but I also have an all target so that make all works sensibly.
I prefer to use the ${...} notation around make variables, which make has always accepted; many people use $(...) notation the whole time.
I think default is your program target, but it did not link any objects? see my makefile:
SRCS = $(wildcard *.c)
OBJS = $(patsubst %.c, %.o, $(SRCS))
default:
#echo This is default target
Program: $(OBJS)
gcc $^ -o $#
$(OBJS): $(SRCS)
gcc -c $^
clean:
rm -f $(OBJS) $(Program)
if you type make, it just echo This is default target, if you want to make real target, you can type make Program
This is a kind of silly question, but this is first time I am using Makefile.
I am having trouble with selecting files. When I used this command,
target1:
$(CC) -o target *.c
it worked well.
But this doesn't work,
SRCS = dir1/*.c
target1:
$(CC) -o target $(SRCS)
and spits this error.
clang: error: no such file or directory: 'dir1/*.c'
Obviously this because my variable SRCS is escaped before passed.
How can I make Makefile pass the string as is? Or is there another conventional/designed way to do this? (selecting file by pattern)
You can use the wildcard keyword to select all the files matching a certain pattern like this:
SRCS = $(wildcard dir1/*.c)
target1:
$(CC) -o target $(SRCS)
SRCS := $(shell echo dir1/*.c)
target1:
$(CC) -o target $(SRCS)