Makefile: Can VPATH variable is applied to assigning Makefile variable? - makefile

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)

Related

Understanding and modifying slightly this makefile

I have been editing this makefile but it's mostly trial and error.
Basically I have n .c files in the same directory. I want the first one (that has a fixed name) to be compiled and linked using my makefile hacks, that incorporate different .o files in the linking step, and all the other ones to be compiled and linked using only the LIBS (without the other .o files).
This is the 'main' makefile:
MAKEFILE_BASE = ./Build-Assets/Makefile
MAKEFILE_CONTROLLERS = ./Controllers/Makefile
.PHONY: default clean release release-clean
default: release
clean: release-clean
release:
$(MAKE) -f $(MAKEFILE_CONTROLLERS) # This generates the .o files, and it works well
$(MAKE) -f $(MAKEFILE_BASE).Release
release-clean:
$(MAKE) -f $(MAKEFILE_BASE).Release clean
And this is the 'Makefile.Release' that handles the compilation/linking of those .c files.
TARGET = $(notdir $(shell pwd))
LIBS = -lm -lev3dev-c -pthread
D_BIN = Build-Assets
ifeq ($(OS),Windows_NT)
LIBS := $(LIBS) -lws2_32
D_BIN := $(D_BIN)/mingw
endif
D_H = ../../source/ev3
CFLAGS = $(addprefix -I, $(D_H)) -O2 -std=gnu99 -W -Wall -Wno-comment
ifeq ($(OS),Windows_NT)
CC = gcc
else
CC = arm-linux-gnueabi-gcc
endif
ifeq ($(OS),Windows_NT)
E_BIN = .exe
else
E_BIN =
endif
F_BIN = $(TARGET)$(E_BIN)
OBJECTS = $(addprefix $(D_BIN)/, $(patsubst %.c, %.o, $(wildcard *.c))) $(addprefix $(D_BIN)/, $(patsubst %.c, %.o, $(wildcard Controllers/*.c)))
.PHONY: default all clean
default: $(F_BIN)
all: default
$(OBJECTS): $(D_BIN)/%.o: %.c
$(CC) $(CFLAGS) -c $< -o $#
.PRECIOUS: $(F_BIN) $(OBJECTS)
$(F_BIN): $(OBJECTS)
$(info VAR is $#)
$(CC) $(OBJECTS) -Wall $(LIBS) -o $#
clean:
-rm -f $(D_BIN)/*.o
-rm -f $(F_BIN)
This also gives the output file the name of the main folder (though I don't understand where he does that?).
When linking this throws the 'multiple main' error (I don't have the ARM device at hand, so I can't provide the full error).
This is the folder hierarchy so that hopefully I can solve all your doubts..
# Main folder (This is the name that the compiled exe has)
## Controllers
-- .c & .h files
-- Makefile
## Build-Assets
-- all .o go here to clean up the folders
- Makefile (The one I call)
- main.c (this needs to be compiled with the .o in build-assets, name can be either main or main folder)
- gcheck.c (this needs to be compiled with only the LIBS, name of executable should be filename)
- ... other .c files, same as gcheck.c
Regarding "where the target name as the name of the directory" comes from, it's here:
TARGET = $(notdir $(shell pwd))
This runs the shell command pwd to get the full path of the current directory, then uses notdir to strip off the parent directory. Then the rule to link the executable uses this:
F_BIN = $(TARGET)$(E_BIN)
...
$(F_BIN): $(OBJECTS)
Regarding why you get multiple main errors, it's because you added your new .c file with the new main to the same directory and rather than the makefile listing a specific set of source files to compile and link, it uses wildcard to grab all the source files:
OBJECTS = $(addprefix $(D_BIN)/, $(patsubst %.c, %.o, $(wildcard *.c))) $(addprefix $(D_BIN)/, $(patsubst %.c, %.o, $(wildcard Controllers/*.c)))
These $(wildcard *.c) functions will expand to all the *.c files in these directories including any new ones you added. Then they will all be linked into the target, which gives you two different object files containing main.
You'll have to change this to list just the files you want, or put your files somewhere else, or remove your files from the list using make's filter-out function, or something like that.

Makefile file matching sources from different subfolders into single build folder

I want to create a make file that takes all files in several src subdirectories and compiles them each directly into one single build directory.
I.e. i have e.g.
src/main.c
src/i2c/i2c.c
src/i2c/i2c.h
and as output i want the object files as well as the final binary
- build/main.o
- build/i2c.o
- build/release.elf
I manage to get all source files as a list with their respective subdirectory paths into a variable and I also manage to get a list of all output files but when i try to create a target to build all .o files in that build directory it does not match the corresponding .c files with the .o files. Here i am just not sure how to link these two.
It fails while trying to match main.o with i2c.c.
Here is "relevant" part of the Makefile:
TARGET = $(lastword $(subst /, ,$(CURDIR)))
BUILD_DIR := buildDir
SOURCES = $(wildcard src/*.c src/*/*.c)
BROKENOBJECTS = $(SOURCES:.c=.o)
LESSBROKEN = $(notdir $(BROKENOBJECTS))
OBJECT_FILES = $(addprefix $(BUILD_DIR)/, $(LESSBROKEN))
$(BUILD_DIR)/%.o: $(SOURCES) $(BUILD_DIR)
$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c -o $# $<
$(BUILD_DIR)/$(TARGET).elf: $(OBJECT_FILES)
$(CC) $(LDFLAGS) $(TARGET_ARCH) $^ $(LDLIBS) -o $#
$(BUILD_DIR) :
mkdir -p $#
compile : $(BUILD_DIR)/$(TARGET).elf
How would I go about this, running the recipe for each .c file from $(SOURCES) and just create the corresponding .o file in buildDir/ ?
You could make use of make's vpath mechanism. So, rather than specifying possible source paths using...
SOURCES = $(wildcard src/*.c src/*/*.c)
you would have...
# Build a list of directories under src
#
SOURCE_DIRS := $(shell find src -type d)
# Use the list in $(SOURCE_DIRS) as a search path for .c files.
#
vpath %.c $(SOURCE_DIRS)
Now, when attempting to update i2c.o (for example), the rule...
$(BUILD_DIR)/%.o: %.c $(BUILD_DIR)
$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c -o $# $<
will cause make to automatically search through the list of source directories for the dependency i2c.c.
Note: For obvious reasons multiple files with the same name under different source directories will cause problems here. Hence my original question (in the comments) regarding the uniqueness of source file names under different directories.
Assuming you use GNU make and your C source files are all *.c that can be found in the current directory and all its subdirectories (up to any depth), this should be close to what you want:
BUILDDIR := build
SRC := $(shell find . -type f -name '*.c')
# Convert C source file name(s) to object file name(s)
# $(1): C source file name(s)
define c2o
$(patsubst %.c,$(BUILDDIR)/%.o,$(notdir $(1)))
endef
OBJ := $(call c2o,$(SRC))
.PHONY: all
all: $(OBJ)
# Compilation rule for a C source file (use echo for testing)
# $(1): C source file name
define MY_rule
$$(call c2o,$(1)): $(1)
#echo $$(CC) $$(CFLAGS) $$(CPPFLAGS) $$(TARGET_ARCH) -c -o $$# $$<
endef
# Instantiate compilation rules for all C source files
$(foreach s,$(SRC),$(eval $(call MY_rule,$(s))))
Demo:
host> tree .
.
├── Makefile
├── a.c
├── b
│   └── b.c
└── c
└── c
└── c.c
host> make
cc -c -o build/a.o a.c
cc -c -o build/c.o c/c/c.c
cc -c -o build/b.o b/b.c
Note the use of $$ in the definition of MY_rule. It is needed because it gets expanded twice: one time when expanding the parameters of the eval function and a second time when make parses the result as regular make syntax.
As explained in other comments and answers this works only if you don't have several C source files with the same base name. There is a way to detect this situation and issue an error if it is encountered. The make sort function sorts its word list parameter but it also removes duplicates. So, if the word count before and after sorting differ, you have duplicates. Add the following just after the definition of OBJ:
SOBJ := $(sort $(OBJ))
ifneq ($(words $(OBJ)),$(words $(SOBJ)))
$(error Found multiple C source files with same base name)
endif
Demo:
host> touch c/c/a.c
host> make
Makefile:13: *** Found multiple C source files with same base name. Stop.
Here is a modified snippet that should do what you want, though I didn't find a solution without specifying each subdirectory in src/ manually.
SOURCES = $(wildcard src/*.c)
SUBSOURCES = $(wildcard src/*/*.c)
OBJECTS = $(addprefix $(BUILD_DIR)/, $(notdir $(SOURCES:.c=.o)))
SUBOBJECTS = $(addprefix $(BUILD_DIR)/, $(notdir $(SUBSOURCES:.c=.o)))
compile : $(BUILD_DIR)/$(TARGET).elf
$(BUILD_DIR)/$(TARGET).elf: $(OBJECTS) $(SUBOBJECTS)
$(CC) $(LDFLAGS) $(TARGET_ARCH) $^ $(LDLIBS) -o $#
# save some typing for the rules below
COMPILE = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c -o $# $<
$(OBJECTS): $(BUILD_DIR)/%.o: src/%.c | $(BUILD_DIR)
$(COMPILE)
$(BUILD_DIR)/%.o: src/i2c/%.c | $(BUILD_DIR)
$(COMPILE)
$(BUILD_DIR)/%.o: src/someOtherSubdir/%.c | $(BUILD_DIR)
$(COMPILE)
As #G.M. suggested in the comments, you must make sure that source file names are unique across subdirectories. Note also that I turned $(BUILD_DIR) into an order only prerequisite, which should reflect your intention more precisely.

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: search for files in subdirectories

So I have a GCC command for which I want to use a SIMPLE makefile. Never worked on makefile before and still having problems after referring the tutorial.
So the command on terminal is
link4#link4-VirtualBox:~/link4/G2/G2 module/src$ gcc -I.src/L4COMM -I.src/L4SERIAL -I.src/L4SYSTEM -I.src/main.c -I.src/L4COMM/l4comm.c -I.src/L4SERIAL/l4serial.c ./src/bypass.c ./src/input.c
This works fine, but when I create a makefile, I'm unable to make it search for the files 'l4comm.c and l4serial.c' which are in src/L4COMM and src/L4SERIAL respectively.
This is what my makefile looks like:
CC =gcc
INCLUDE = -I/src/L4COMM \
-I/src/L4SERIAL
VPATH = -I/src/L4COMM \
-I/src/L4SERIAL
cfiles := $(patsubst %.c, %.o, $(wildcard *.c))
hfiles := $(patsubst %.h, %.o, $(wildcard *.h))
g2make: $(cfiles)
$(CC) $(INCLUDE) -o main.c l4comm.c l4serial.c bypass.c input.c
Want the makefile to look for files in the sub directories
Just as I used the 'cfiles/hfiles' to check for changes, I want to wildcard to also check for the files in the sub directories.
Help appreciated! :)
You can use this g2make:
$(CC) $(INCLUDE) -o .src/main.c ./src/L4COMM/l4comm.c ./src/L4SERIAL/l4serial.c ./src/bypass.c ./src/input.c

Generating a makefile target dependency from the filename in a stem

Hi I have a makefile I am creating where each .o is represented as a relative path to another directory and has a dependency on a .cpp file in the local directory. My understanding of the problem is that I can't use functions in a rule definition so the rule:
%.o: %.cpp
results in a prerequisite .cpp that is in the same directory as the .o which is not where the cpp is actually located. For example:
../../Tmp/MyClass.o: ../../Tmp/MyClass.cpp <--- WRONG, result of %.o: %.cpp
../../Tmp/MyClass.o: MyClass.cpp <--- RIGHT, how do I do this in an automatic way?
Lastly the output, which is in yet another directory, has a dependency on the .o's so they must all have full relative path information from the beginning:
OBJS := $(addprefix ../../../Tmp/XCode/${PLATFORM}/${CONFIGURATION}/, $(addsuffix .o, $(basename ${SRCS})))
${OUTPUT}: ${OBJS} ; ${AR} $# ${OBJS}
Thanks!
I think kristi's solution will work, but here's another way to do the same thing:
# Here's how you do it:
OBJS := $(addprefix ../../../Tmp/XCode/${PLATFORM}/${CONFIGURATION}/, $(addsuffix .o, $(basename ${SRCS})))
# Here's a slightly cleaner way:
BASEPATH = ../../../Tmp/XCode/$(PLATFORM)/$(CONFIGURATION)
OBJS := $(patsubst %.cc,$(BASEPATH)/%.o,$(SRCS))
# And here's the rule:
$(OBJS): $(BASEPATH)/%.o: %.cc
whatever...
This should work
../../Tmp/%.o: %.cpp
Or use a variable
builddir := ../../Tmp
$(builddir)/%.o: %.cpp

Resources