I have a makefile directive defined as follows:
OBJ = $(SRC:%.c=$(BUILDDIR)/%.o)
where $SRC is defined as
file1.c file2.c etc..
This works just fine when all files are at the same level as the makefile.
If they are in a directory i.e ./src/file1.c ./src/file2.c it does not.
It fails because it tries to append the source path to the build path i.e
gcc -o ./build/./src/file1.o src/file.c
.
I tried to use the nodir keyword but no luck.
I'm looking for the build command to look like this
gcc -o ./build/file1.o ./src/file.c
Any help is much appreciated
Let's try an experiment:
SRC = ./src/file1.c ./src/file2.c
OBJ = $(notdir $(SRC):%.c=$(BUILDDIR)/%.o)
apps: $(OBJ)
We get:
make: *** No rule to make target `file1.c', needed by `apps'. Stop.
Something's amiss here. Let's look at OBJ:
$(info $(OBJ))
We get:
file1.c %.o
Yikes! We constructed OBJ incorrectly. What if we break it up into smaller steps?
SIMPLE_SRC = $(notdir $(SRC))
OBJ = $(SIMPLE_SRC:%.c=$(BUILDDIR)/%.o)
$(info $(OBJ))
We get:
./build/file1.o ./build/file2.o
It turns out that substitution references of the form $(var:%a=%b) do not allow us to put functions in the var. At this point we should probably forgo them and write the full pattern substitution:
OBJ = $(patsubst %.c,$(BUILDDIR)/%.o,$(notdir $(SRC)))
$(info $(OBJ))
We get:
./build/file1.o ./build/file2.o
Related
I'm fairly new to Makefiles, and I am trying to create one for a C project I am building using gcc.
I am familiar with the error Makefile:<col>: *** missing separator. Stop. It has popped up before when I used spaces instead of tabs to precede rules in the Makefile. I just tried writing a Makefile for this particular project (being sure to use TAB character instead of spaces) and when I run the make command, I get a very nondescript error I do not understand how to fix: src/main.c:7: *** missing separator. Stop
My directory structure looks like this:
- projectfolder/
- Makefile
- bin/
- build/
- inc/
- src/
- main.c
- otherfolder/
- inc/
- common.h
- io.h
- src/
- io.c
main.c, which includes the main function, has the following imports:
#include <stdio.h>
#include <stdlib.h>
#include "common.h"
#include "io.h"
My goal is to make a bunch of .o and .d files from the files in both src/ and inc/ directories and put those into projectfolder/build/, so that they can then be used to make the final executable in projectfolder/bin/
Finally, here is the Makefile that is causing the issue:
# Compiler and linker
CC := gcc
# Target binary
TARGET := the-program
# File extensions
SRCEXT := c
# Directories
TARGETDIR := bin
BUILDDIR := build
SRCDIRS := src /home/myusername/otherfolder/src
INCDIRS := inc /home/myusername/otherfolder/inc
# gcc options
CCFLAGS := -Wall -Wextra -O3
#---------------------------------------------------------------------------------
#DO NOT EDIT BELOW THIS LINE
#---------------------------------------------------------------------------------
vpath %.$(SRCEXT) $(SRCDIRS)
vpath %.h $(INCDIRS)
CCFLAGS += $(addprefix -I,$(INCDIRS)) -MMD -MP
SRC := $(shell find $(SRCDIRS) -name *.$(SRCEXT))
OBJ := $(SRC:$(SRCDIRS)/%.$(SRCEXT)=$(BUILDDIR)/%.o)
DEP := $(OBJ:.o=.d)
TARGET := $(TARGETDIR)/$(TARGET)
# RULE: Default make
all: makedirs $(TARGET) clean
# RULE: Remake
remake: fullclean all
# RULE: Clean
clean:
rm -rf $(BUILDDIR)
# RULE: Full clean (objects and binaries)
fullclean: clean
rm -rf $(TARGETDIR)
# RULE: Make dirs
makedirs:
mkdir -p $(BUILDDIR)
mkdir -p $(TARGETDIR)
# RULE: Link
$(TARGET): $(OBJ)
$(CC) $(OBJ) -o $#
# RULE: Compile
$(OBJ): $(SRC)
$(CC) $(CCFLAGS) -c $< -o $#
# RULE: Non-file targets
.PHONY: all remake clean fullclean makedirs
# include dependencies
-include $(DEP)
What about this file would cause the described error? I am assuming that it is related to the Makefile itself rather than the C code actually contained in src/main.c since this does not appear to be a compilation error, but if I am wrong, let me know and I can change the post.
This error:
src/main.c:7: *** missing separator. Stop
is clearly being printed by make. Since we know the format of these messages is <makefile>:<linenumber>: <error>, we can see that make is trying to parse the file src/main.c as a makefile and obviously this cannot work.
How could make be doing such a thing? The obvious culprit is this line:
-include $(DEP)
If the variable DEP contains the file src/main.c, then make would try to include that as a makefile and parse it. So how is DEP set?
DEP := $(OBJ:.o=.d)
This changes all words in OBJ that end with .o to end with .d. Crucially, it should be noted that this makes no changes to words that do not end in .o. So, if OBJS contained src/main.c, this would pass it through unmodified to DEPS.
So how is OBJ set? Here are the relevant variables:
SRCDIRS := src /home/myusername/otherfolder/src
SRC := $(shell find $(SRCDIRS) -name *.$(SRCEXT))
OBJ := $(SRC:$(SRCDIRS)/%.$(SRCEXT)=$(BUILDDIR)/%.o)
Let's expand this: the SRC variable runs:
find src /home/myusername/otherfolder/src -name *.c
(you really should escape the *, either with backslash or quotes: it's very dangerous how you have this).
Now we'll say that SRC gets the value:
SRC := src/main.c /home/myusername/otherfolder/src/other.c
Now what does OBJ contain?
OBJ := $(SRC:src /home/myusername/otherfolder/src/%.$(SRCEXT)=build/%.o)
This clearly cannot work: you can't put multiple directories into SRCDIRS, but then treat it as if it contained only one word.
The problem is in the line
OBJ := $(SRC:$(SRCDIRS)/%.$(SRCEXT)=$(BUILDDIR)/%.o)
The pattern substitution works only where the pattern matches and leaves all other strings alone.
As a simple demonstration see this makefile (no rules, just variable assignments):
x := foo bar baz
y := $(x:ba%=gu%)
$(info $(x))
$(info $(y))
Output:
foo bar baz
foo gur guz
As you can see, foo still is there, unchanged although it didn't match the pattern ba%.
In your case you are passing an impossible to substitute pattern, the content of $(SRCDIRS), which is the two words: src /home/myusername/otherfolder/src to the substitution call, therefore main.c - which is either src/main.c or /home/myusername/otherfolder/src/main.c remains unchanged in your list, gets inadvertently flushed further into $(DEP) and is finally included as text with your last line -include $(DEP).
As a recommendation I want to point you to VPATH (see manual and here: https://www.cmcrossroads.com/article/basics-vpath-and-vpath), which is the better alternative to indicate the location of your sources to make.
I have a simple makefile that works fine, but it seems to perform
the all target even if no changes occurred. I would expect a
make: Nothing to be done for 'all'.
Message, but it keeps executing the target whenever I call make.
Here is my simple makefile:
BASEDIR = /home/someuser/STA
SRC_DIR = ${BASEDIR}/src
OBJ_DIR = ${BASEDIR}/obj
INC_DIR = ${BASEDIR}/inc
SRC_FILES = $(wildcard ${SRC_DIR}/*.cpp)
SRC_FILES_NOTDIR = $(notdir ${SRC_FILES})
OBJ_FILES_NOTDIR = $(patsubst %.cpp, %.cpp.o, ${SRC_FILES_NOTDIR})
OBJ_FILES = $(addprefix ${OBJ_DIR}/,${OBJ_FILES_NOTDIR})
INC_FILES = $(wildcard ${INC_DIR}/*.h)
all: ${OBJ_FILES}
g++ ${OBJ_FILES} -o program
${OBJ_DIR}/%.cpp.o: ${SRC_DIR}/%.cpp ${INC_FILES}
g++ -I${INC_DIR} -o $# -c $<
And here is what printed to terminal when I call make twice:
$ make
g++ <somedir/file1>.cpp.o <somedir/file2>.cpp.o -o program
$ make
g++ <somedir/file1>.cpp.o <somedir/file2>.cpp.o -o program
Replace all that is not a file and does not exist (reason why make tries to build it each time) by program, a real file that make can see. If you really want an all symbolic target, declare it as phony and add a rule without recipe to tell make that all depends on program:
.PHONY: all
all: program
I have a makefile that is trying to do the following: identify all files under the current directory (all sub-directories included) with .c and .s extensions, for each one compile a non-linked object file and put it into a directory. All C files end up in objects/c, all assembly files end up in objects/ass.
The makefile always works as expected on the first execution (all commands are called in the right order) and no errors are produced.
However if I call make again, half of the time i get "nothing to be done for 'all'.". Which is what you would expect, since no files have been modified. But the other half of the time, make is selecting a random assembly file and compiling that file. That is to say,if I keep doing "make" I sometimes compile file1.s sometimes file2.s. and it keeps randomly swapping between the assembly files add infinitum (it never reaches a "nothing to be done") state.
How is make exhibitting non deterministic behaviour?
This is the smallest makefile I could make that reproduces the error:
SRC_C = $(wildcard *.c) $(wildcard **/*.c)
SRC_ASS = $(wildcard *.s) $(wildcard **/*.s)
OBJECTS_C = $(addprefix $(OBJECT_DIR)c/, $(notdir $(SRC_C:.c=.o)))
OBJECTS_ASS = $(addprefix $(OBJECT_DIR)ass/, $(notdir $(SRC_ASS:.s=.o)))
OBJECTS = $(OBJECTS_C) $(OBJECTS_ASS)
OBJECT_DIR = objects/
all: $(OBJECTS)
%/:
mkdir $#
$(OBJECTS_C): $(OBJECT_DIR) $(OBJECT_DIR)c/
arm-none-eabi-gcc -O0 -march=armv8-a $(wildcard */$(#F:.o=.c)) -nostartfiles -c -o $#
$(OBJECTS_ASS): $(OBJECT_DIR) $(OBJECT_DIR)ass/
arm-none-eabi-as -march=armv8-a $(wildcard */$(#F:.o=.s)) -c -o $#
.PHONY: clean
clean:
rm -rf $(OBJECT_DIR)
You have many errors here.
The biggest is a conceptual one: By flattening all your object files into one directory, there's no way to express proper dependencies using pattern rules, so your object files do not really depend on their respective source files. I'd say: just don't do that! Having object directories is fine, but they should mirror the directory structure of the source tree.
Further errors:
directly depending on directories. This will not work as expected, directories should always be order-only dependencies, as already stated in the comments
Make doesn't support recursive wildcards -- if you really need that, you could write your own function or, assuming you're always building on *nix, just call find instead
Pattern rules for creating directories are not the best idea either -- I'd suggest to collect all needed directories in a variable and loop over that.
Stylistic improvements:
Assign variables that don't need deferred evaluation with :=
Assign variables influencing the build process with ?=, so the user can override them at the command line
Use "standard" variables like CC, AS, CROSS_COMPILE
declare all phony targets in .PHONY.
Your Makefile with these changes applied would look like this:
OBJECT_DIR ?= objects
C_OBJECT_DIR ?= $(OBJECT_DIR)/c
AS_OBJECT_DIR ?= $(OBJECT_DIR)/ass
SRC_C:= $(shell find -name \*.c)
SRC_ASS:= $(shell find -name \*.s)
OBJECTS_C:= $(addprefix $(C_OBJECT_DIR)/, $(SRC_C:.c=.o))
OBJECTS_ASS:= $(addprefix $(AS_OBJECT_DIR)/, $(SRC_ASS:.s=.o))
OBJECTS:= $(OBJECTS_C) $(OBJECTS_ASS)
OUTDIRS:= $(sort $(dir $(OBJECTS)))
CROSS_COMPILE ?= arm-none-eabi-
CC ?= gcc
AS ?= as
CFLAGS ?= -O0 -march=armv8-a -nostartfiles
ASFLAGS ?= -march=armv8-a
all: $(OBJECTS)
$(OUTDIRS):
$(foreach _dir,$#,mkdir -p $(_dir);)
$(C_OBJECT_DIR)/%.o: %.c | $(OUTDIRS)
$(CROSS_COMPILE)$(CC) -c -o $# $(CFLAGS) $<
$(AS_OBJECT_DIR)/%.o: %.s | $(OUTDIRS)
$(CROSS_COMPILE)$(AS) -c -o $# $(ASFLAGS) $<
clean:
rm -rf $(OBJECT_DIR)
.PHONY: all clean
Note there is one important thing missing: automatic dependencies. With this Makefile, each object file depends on its respective source file, but completely misses any headers included. For anything other than a simple toy, you should add that, google for "gnu make gcc automatic dependencies" or something similar (not the scope of this question).
I am trying to make one generic target in my makefile that will builds sources from mixed directories and output the object files to on single directory.
We have a source structure that is mixed in various directories (like said above, below is just an example)
SRCS = ../a/b/source1.c \
b/source2.c \
../c/source3.c
But I would like all of the object files to output to the directory ./objs (same directory level as 'b')
To do this I was trying the following
OBJS = $(addprefix objs/, $(notdir $(SRCS:.c=.o)))
$(OBJS): %.o : $(filter %/$(basename $(notdir %)).c, $(SRCS))
echo "dependencies: $^" # shows up empty
$(CC) $(filter %/$(basename $(notdir $#)).c, $(SRCS)) -o $# # This works and finds the proper source file
$(CC) $^, $(SRCS)) -o $# # I would like to use this, but as I said the dependencies show up blank
There is a weird problem with this however, and I don't understand where the problem is.
In the dependency it doesn't match anything, but in the recipe it does match properly.
Now the weird part (for me atleast). If I try and test out by hard coding one of the paths then it match for ALL files in that path
$(OBJS): %.o : $(filter ../a/b/$(basename $(notdir %)).c, $(SRCS)) # matches for all files in "../a/b" directory
But using SECONDEXPANSION and hardcoding the directory it works
.SECONDEXPANSION:
$(OBJS): %.o : $$(filter ../a/b/$$(basename $$(notdir %)).c, $(SRCS))
And also not using SECONDEXPANSION and hardcoding the source file name works
$(OBJS): %.o : $(filter %source1.c, $(SRCS)) # Hardcoding source1.c works for source1.c
But it seems like I can't combine to two do what I want for some reason. I have tried secondexpansion stuff (thoguht I'm not really sure why I would need it in this case) and could never get anything working that way either.
I am trying to avoid manually declaring targets for each file individually i.e.
objs/source1.o : ../a/b/source1.c
Because our real world example has tons of files and it would be nice to have less to maintain. I feel like I am very close to getting it.
I am using Cygwin with GNU Make 4.0.
After googling a few more times I finally came across the fix here:
http://lists.gnu.org/archive/html/help-make/2010-09/msg00062.html
I still don't know exactly why I needed to use the SECONDEXPANSION ($$-ness) at all but in practice it doesn't work without it. But basically I needed to create a variable for the '%' sign. Doing the following works for me.
SRCS = ../a/b/source1.c \
b/source2.c \
../c/source3.c
OBJS = $(addprefix objs/, $(notdir $(SRCS:.c=.o)))
.SECONDEXPANSION:
PERCENT = %
$(OBJS): %.o : $$(filter $$(PERCENT)/$$(notdir %).c, $(SRCS))
$(CC) $< -o $#
This now builds source1.c, source2.c, and source3.c and outputs the object files into the objs/ directory.
What I didn't mention in my question but I knew all along was that this will only work if you have unique file names for all source files. But we are okay with that limitation (obviously).
I am doing some Makefile refactoring and trying to figure out the most concise way to implement a Makefile that does the following:
Has one variable that has all the source files listed (can be both C and C++ files)
All object files are generated in OBJ_DIR
The object directory is created if it does not exist
Here is what I have so far:
...
OBJ_DIR = obj/
BIN_DIR = bin/
PROGRAM = program
SRCS = test1.cpp test2.c
OBJS = $(addprefix $(OBJ_DIR), \
$(patsubst %.cpp, %.o, \
$(patsubst %.c, %.o, $(SRCS))))
$(BIN_DIR)$(PROGRAM) : $(OBJS)
$(CREATE_OUT_DIR)
$(LINK)
$(OBJ_DIR)%.o : %.c
$(CREATE_OBJ_DIR)
$(CCOMPILE)
$(OBJ_DIR)%.o : %.cpp
$(CREATE_OBJ_DIR)
$(CPPCOMPILE)
...
I'd like to eliminate the call to $(CREATE_OBJ_DIR) for every .o compile. Anyone know how to do this? I tried adding this, but then it would not build the object files:
$(OBJS): | $(OBJ_DIR)
$(OBJ_DIR):
$(CREATE_OBJ_DIR)
You already seem to have solved your first point: Have them all in one variable (I shouldn't think you actually need to to separate them into TEMP1 and TEMP2 like you have, just have different build rules)
For the second point, you can tell the compiler where to output the object files (for g++ its like this:
g++ -c MySourceFile.cpp -o obj/MySourceFile.o
The make rule for this would look like:
obj/%.o: %.cpp
g++ -c $*.cpp -o obj/$*.o
And your third point is also easily solved, as you can have a build rule for it (Just put the directory name in the dependency list for the target, before all of the objects are listed), and the build rule would look like this
obj:
mkdir obj
Edit: or following your code examples:
$(BIN_DIR)$(PROGRAM) : $(BIN_DIR) $(OBJS)
$(LINK)
$(BIN_DIR):
$(CREATE_OUT_DIR)
As for your 3rd point: This question has been asked here before. Unfortunately there is no really good answer for this, and you need to find the least ugly hack from the answer. Personally, I vote for the marker file solution.
This is what I do:
$(OBJ_LOC)/%.o: $(SRC_LOC)/%.c
#[ -d $(OBJ_LOC) ] || mkdir -p $(OBJ_LOC)
g++ ...
But, I am looking at these other answers with great interest.