Makefile with directory for object files - makefile

I have the following structure for a project and I am just starting to introduce a Makefile to build the software:
├── Makefile
├── README.md
├── cg
│   └── cg.c
└── utilities
├── utilities.c
└── utilities.h
I am trying to put object files in a directory called obj yet I can't seem to get it working.
My makefile looks like:
CC=mpicc
CFLAGS=-O3 -std=c99
LIBS=
MKDIR_P = mkdir -p
make_build_dir:
#mkdir -p obj/
utilities.o: utilities/utilities.c
$(CC) $(CFLAGS) -o ./obj/$# -c $<
cg.o: cg/cg.c
$(CC) $(CFLAGS) -o ./obj/$# -c $<
.PHONY: make_build_dir
cg.exe: make_build_dir utilities.o cg.o
$(CC) $(CFLAGS) -o $# $<
clean:
rm -fr obj
rm cg.exe
Yet this generates the following error:
a#a:b/b ‹master*›$ make cg.exe
mpicc -O3 -std=c99 -o ./obj/utilities.o -c utilities/utilities.c
mpicc -O3 -std=c99 -o ./obj/cg.o -c cg/cg.c
cg/cg.c:133:3: warning: implicit declaration of function 'decompose' is invalid in C99
[-Wimplicit-function-declaration]
decompose(num_chunks, chunks_per_rank,me, &settings);
^
1 warning generated.
mpicc -O3 -std=c99 -o cg.exe make_build_dir
clang: error: no such file or directory: 'make_build_dir'
make: *** [cg.exe] Error 1
How can I get it to generate the object files in the obj directory and then an executable in the top-level directory?

This linking part of the makefile
cg.exe: make_build_dir utilities.o cg.o
$(CC) $(CFLAGS) -o $# $<
has two issues. First, $< refers to the first prerequesite of the target cg.exe, and that is make_build_dir. Declaring it as .PHONY doesn't help here, it's simply passed to $(CC). Second, utilities.o cg.o both don't exist at this location. You can change the rule to
cg.exe: obj/utilities.o obj/cg.o
$(CC) $(CFLAGS) -o $# $^
Note the automatic variable $^ which refers to all prerequisites. Additionally, the object file targets should be
obj/cg.o: cg/cg.c
$(CC) $(CFLAGS) -o $# -c $<
(identical for utilities.o).

First of all, you need to make_build_dir before making any *.o or make won't have a place to put them.
And you can make the Makefile more generic.
.PHONY: all clean info
.DEFAULT_GOAL := all
SRC_DIRS = cg utilities
OBJ_DIR = obj
EXE = cg.exe
SOURCES = $(foreach path, $(SRC_DIRS), $(wildcard $(path)/*.c))
OBJECTS = $(addprefix $(OBJ_DIR)/, $(notdir $(SOURCES:%.c=%.o)))
$(OBJ_DIR)/%.o: */%.c
$(CC) $(CFLAGS) -o $# -c $<
all: make_build_dir $(EXE)
info:
$(info SOURCES=$(SOURCES))
$(info OBJECTS=$(OBJECTS))
make_build_dir:
#mkdir -p $(OBJ_DIR)
$(EXE): $(OBJECTS)
$(CC) $(CFLAGS) -o $# $^
With this Makefile, you can add more source directories to SRC_DIRS and it will automatically compile sources in them.
What does it do? Run make with the -n option to see:
$ make -n
mkdir -p obj
cc -o obj/cg.o -c cg/cg.c
cc -o obj/utilities.o -c utilities/utilities.c
cc -o cg.exe obj/cg.o obj/utilities.o
You can also display the info on the variables by:
$ make info
SOURCES= cg/cg.c utilities/utilities.c
OBJECTS=obj/cg.o obj/utilities.o

Related

How to let avr-gcc output *.o to separate folder in Makefile with `%.o: %.c`?

As showed in first screenshot, my ideal AVR project structure is that:
*.o, *.elf and *.hex files are in build folder.
PomoScheler.c and pinDefines.h as main files are in root folder, while other *.c and *.h are in src folder.
But *.o are always generated at the same folder as *.c like showed in second screenshot, no matter how.
(I attached my endeavors and whole Makefile below the screenshots)
Firstly, I tried build/ before $#, in vain. The terminal still the same.
# My first Makefile endeavor
%.o: %.c $(HEADERS)
$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o build/$#
# Terminal command generated by Makefile (Look at the end: *.o path still same as *.c)
avr-gcc -Os -g -std=gnu99 -Wall -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -ffunction-sections -fdata-sections -DF_CPU=1000000UL -DBAUD=9600UL -I. -I~/Developer/bin/avr8-gnu-toolchain-darwin_x86_64/avr/include -mmcu=atmega328p -c -o src/RotaryEncoder.o src/RotaryEncoder.c
Secondly, I tried to add mv $# build to explicitly move it to build folder. But nothing happened. Even echo are not displayed in Terminal.
# My second Makefile endeavor
%.o: %.c $(HEADERS)
$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o $#
mv $# build
echo ---------Hello---------
Thirdly, I delete $(HEADERS) and replace $< with $^ just to have a try. The mv is executed. But it cannot find *.o file this time even though I have VPATH = src:build in Makefile.
# My third Makefile endeavor
%.o: %.c
$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $^ -o $#
mv $# build
# Terminal error
Assembler messages:
Fatal error: can't create build/src/RotaryEncoder.o: No such file or directory
And my whole Makefile is here. Please help me out.
# My whole Makefile
MCU = atmega328p
F_CPU = 1000000UL
BAUD = 9600UL
LIBDIR = ~/Developer/bin/avr8-gnu-toolchain-darwin_x86_64/avr/include
PROGRAMMER_TYPE = usbtiny
PROGRAMMER_ARGS =
CC = avr-gcc
OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
AVRSIZE = avr-size
AVRDUDE = avrdude
##########------------------------------------------------------##########
VPATH = ./src:./build
TARGET = $(lastword $(subst /, ,$(CURDIR)))
SOURCES=$(wildcard *.c src/*.c $(LIBDIR)/*.c)
OBJECTS=$(SOURCES:.c=.o)
HEADERS=$(SOURCES:.c=.h)
CPPFLAGS = -DF_CPU=$(F_CPU) -DBAUD=$(BAUD) -I. -I$(LIBDIR)
CFLAGS = -Os -g -std=gnu99 -Wall
CFLAGS += -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
CFLAGS += -ffunction-sections -fdata-sections
LDFLAGS = -Wl,-Map,build/$(TARGET).map
LDFLAGS += -Wl,--gc-sections
TARGET_ARCH = -mmcu=$(MCU)
%.o: %.c $(HEADERS)
$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $< -o build/$#
$(TARGET).elf: $(OBJECTS)
$(CC) $(LDFLAGS) $(TARGET_ARCH) $^ $(LDLIBS) -o build/$#
%.hex: %.elf
$(OBJCOPY) -j .text -j .data -O ihex build/$< build/$#
all: $(TARGET).hex
size: $(TARGET).elf
$(AVRSIZE) -C --mcu=$(MCU) $(TARGET).elf
clean:
rm -f $(TARGET).elf $(TARGET).hex $(TARGET).obj \
$(TARGET).o $(TARGET).d $(TARGET).eep $(TARGET).lst \
$(TARGET).lss $(TARGET).sym $(TARGET).map $(TARGET)~ \
$(TARGET).eeprom
flash: $(TARGET).hex
$(AVRDUDE) -c $(PROGRAMMER_TYPE) -p $(MCU) $(PROGRAMMER_ARGS) -U flash:w:$<
This is clearly not right:
OBJECTS = $(SOURCES:.c=.o)
because the object files you want to create are not foo.o etc. which is what this will expand to; the object files are build/foo.o etc. So this has to be:
OBJECTS = $(patsubst %.c,build/%.o)
All of your attempts to trick make by telling it your recipe will build one target (foo.o) but actually building a totally different target (build/foo.o) are doomed to fail, regardless of whether you have the compiler do it directly, you use mv, or any other method.
If you just tell make what your recipe actually does, you will have a much simpler time of it:
build/%.o: %.c
mkdir -p $(#D)
$(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $^ -o $#
Probably you have similar issues with the other rules that you want to put into other directories.
You can't do this by trying to hide it from make. Make has to know where the files actually are.
BTW, VPATH cannot help here. VPATH is for finding source files, it cannot be used for finding generated files. So you could use VPATH to find your .c files but not your .o files.

Makefile: Unable to add .h files from folder using a .mk file

I'm trying to link a .h file from a folder into a Makefile using a .mk file. Folder with .h file (include) is in the same folder as Makefile.
When I run from terminal: make memory.o or make memory.o PLATFORM=MSP432 I get the following error
make: *** No rule to make target '-I./include', needed by 'memory.o'. Stop.
My .mk folder looks like this:
# Add your Source files to this variable
SOURCES = \
./main.c \
./memory.c
# Add your include paths to this variable
INCLUDES =-I./include
My Make file looks like this:
include sources.mk
# Platform Overrides
PLATFORM =
# Architectures Specific Flags
LINKER_FILE = msp432p401r.lds
CPU = cortex-m0plus
ARCH = thumb
SPECS = nosys.specs
# Compiler Flags and Defines
CC = arm-none-eabi-gcc
LD = arm-none-eabi-ld
TARGET= c1m2
LDFLAGS = -Wl, -Map=$(TARGET).map -T $(LINKER_FILE)
CFLAGS = -Wall -Werror -g -O0 -std=c99 -mcpu=$(CPU) -m$(ARCH) --specs=$(SPECS)
CPPFLAGs =
ifeq ($(PLATFORM),MSP)
CPU=cortex-m4
CC=arm-none-eabi-gcc
endif
ifeq ($(PLATFORM),HOST)
CC=gcc
endif
OBJS = $(SOURCES:.c=.o)
%.o : %.c $(INCLUDES)
$(CC) -c $< $(CFLAGS) -o $#
.PHONY: build
build: all
.PHONY: all
all: $(TARGET).out
$(TARGET).out: $(OBJS) $(INCLUDES)
$(CC) $(OBJS) $(CFLAGS) $(LDFLAGS) -o $#
.PHONY: clean
clean:
rm -f $(OBJS) $(TARGET).out $(TARGET).map
Can anybody help?
You shouldn't put $(INCLUDES) as a prerequisite of your .o file. This is not right:
%.o : %.c $(INCLUDES)
$(CC) -c $< $(CFLAGS) -o $#
INCLUDES contains options that need to be passed to the compiler (-I...). Prerequisites of targets need to be files that are used during the build. I suppose you want this:
%.o : %.c
$(CC) -c $< $(CFLAGS) $(INCLUDES) -o $#

How to compile source objects into another directory and then build an executable?

Good day. I am in a directory, where is Makefile and folders src and bin. How can I compile object files into bin folder and then build an executable file?
I read some instructions and added $(BIN) before %.o, but it didn't helped, object files appear in folder with makefile. Where is the problem?
CC = arm-linux-gnueabihf-gcc
CXX = arm-linux-gnueabihf-g++
CPPFLAGS = -I .
CFLAGS =-g -std=gnu99 -O1 -Wall
CXXFLAGS = -g -std=gnu++11 -O1 -Wall
LDFLAGS = -lrt -lpthread
SRCDIR = src
BIN = bin
SOURCES = $(wildcard $(SRCDIR)/*.cpp) $(wildcard $(SRCDIR)/*.c)*
...
OBJECTS += $(filter %.o,$(SOURCES:%.c=%.o))
OBJECTS += $(filter %.o,$(SOURCES:%.cpp=%.o))
#$(warning OBJECTS=$(OBJECTS))
ifeq ($(filter %.cpp,$(SOURCES)),)
LINKER = $(CC)
LDFLAGS += $(CFLAGS) $(CPPFLAGS)
else
LINKER = $(CXX)
LDFLAGS += $(CXXFLAGS) $(CPPFLAGS)
endif
$(BIN)/%.o:%.c
$(CC) $(CFLAGS) -c $<
$(BIN)/%.o:%.cpp
$(CXX) $(CXXFLAGS) -c $<
all: $(TARGET_EXE)
$(TARGET_EXE): $(OBJECTS)
$(LINKER) $(LDFLAGS) -L. $^ -o $#
.PHONY : dep all run copy-executable debug
dep: depend
depend: $(SOURCES) *.h
echo '# autogenerat`enter code here`ed dependencies' > depend
ifneq ($(filter %.c,$(SOURCES)),)
$(CC) $(CFLAGS) $(CPPFLAGS) -w -E -M $(filter %.c,$(SOURCES)) \
>> depend
endif
ifneq ($(filter %.cpp,$(SOURCES)),)
$(CXX) $(CXXFLAGS) $(CPPFLAGS) -w -E -M $(filter %.cpp,$(SOURCES)) \
>> depend
endif
clean:
rm -f *.o *.a $(OBJECTS) $(TARGET_EXE) connect.gdb depend
...
It's not clear to me how this makefile can works as well as it does, given that you haven't told it where to find the source files (unless you do so in one of the elided sections).
In these rules:
$(BIN)/%.o:%.c
$(CC) $(CFLAGS) -c $<
$(BIN)/%.o:%.cpp
$(CXX) $(CXXFLAGS) -c $<
you tell the compiler to build object files, but you don't specify where to build them, and the default is to build them in the working directory. You can override that with the -o option:
$(BIN)/%.o:%.c
$(CC) $(CFLAGS) -c $< -o $#
$(BIN)/%.o:%.cpp
$(CXX) $(CXXFLAGS) -c $< -o $#
Once you have the object files where you want them (bin/), you must ensure that the linking rule:
$(TARGET_EXE):$(OBJECTS)
$(LINKER) $(LDFLAGS) -L. $^ -o $#
can find them. The best way to do that is to ensure that OBJECTS contains the correct paths to the object files. I'm not sure how to advise you to do that, since from the look of your makefile that variable might not contain what you think it does.
EDIT:
Let's take this in stages.
Suppose we have on source file, src/foo.c. What we want is:
src/foo.c -> bin/foo.o
bin/foo.o -> foo
This requires two rules, which we can write like this:
$(BIN)/%.o: src/%.c
$(CC) $(CFLAGS) -c $< -o $#
$(TARGET_EXE): bin/foo.o
$(LINKER) $(LDFLAGS) -L. $^ -o $#
We actually have many source files, some of which are C++ files. So we must have a rule for them:
$(BIN)/%.o: src/%.cpp
$(CXX) $(CXXFLAGS) -c $< -o $#
and construct a longer list of objects:
OBJECTS := bin/foo.o bin/bar.o bin/baz.o bin/quartz.o...
$(TARGET_EXE): $(OBJECTS)
$(LINKER) $(LDFLAGS) -L. $^ -o $#
(Mixing C and C++ seems unhealthy to me, but never mind.)
And how do we construct that list of objects? We must start with the list of sources which wildcard can produce:
SRC := src
C_SOURCES := $(wildcard $(SRC/*.c)
# this is src/foo.c src/bar.c
SRC := src
CPP_SOURCES := $(wildcard $(SRC/*.cpp)
# this is src/baz.cpp src/quartz.cpp
and then convert them to the object file names we actually want:
BIN := bin
OBJECTS := $(patsubst $(SRC)/%.cpp,$(BIN)/%.o, $(CPP_SOURCES))
OBJECTS += $(patsubst $(SRC)/%.c,$(BIN)/%.o, $(C_SOURCES))
# this is bin/foo.o bin/bar.o bin/baz.o bin/quartz.o
That should give you the effect you want, and if you understand it you will understan why your old makefile did not.

No rule to make target (make project in different directories)

Excuse me for asking simple questions, but I can't find where the problem is.
I have an src directory, contains makefile and obj folder. An include folder and a lib one. The codes have provided here.
IDIR =../include
CC=gcc
CFLAGS=-I$(IDIR)
ODIR=obj
LDIR =../lib
LIBS=-lm
_DEPS = hellomake.h
DEPS = $(patsubst %,$(IDIR)/%,$(_DEPS))
_OBJ = hellomake.o hellofunc.o
OBJ = $(patsubst %,$(ODIR)/%,$(_OBJ))
$(ODIR)/%.o: %.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)
hellomake: $(OBJ)
gcc -o $# $^ $(CFLAGS) $(LIBS)
.PHONY: clean
clean:
rm -f $(ODIR)/*.o *~
it gives me the following error:
gcc -c -o obj/hellomake.o hellomake.c -I../include
make: *** No rule to make target 'obj/hellofunc.o', needed by 'hellomake'. Stop.
It uses the same rule for creating .o files and hellomake file. but the last one does not work.
Thanks for any comment or guide.
You have a src directory, but you don't tell Make about it. Make is complaining that there is no hellofunc.c. (There is asrc/hellofunc.c, but Make didn't know to look there.) Try this:
SRC := src
$(ODIR)/%.o: $(SRC)/%.c $(DEPS)
$(CC) -c -o $# $< $(CFLAGS)

gcc cannot specify -o with -c or -S with Multiple files

Whenever I am trying to build something like this in my Makefile -
gcc -o main.o -IStarterWare_Files -c main.c StarterWare_Files/test.h StarterWare_Files/add.h
It throws me error that gcc: cannot specify -o with -c or -S with multiple files. Basically I want my makefile to build the target again if I change for example some macro in one of my header files. My current Makefile is -
EXE = nextgenrsm
CC = gcc
LIBS = StarterWare_Files/
CPPFLAGS = _IStarterWare_Files/
MAIN_OBS = $(patsubst %.c,%.o,$(wildcard *.c))
LIB_OBS = $(patsubst %.c,%.o,$(wildcard StarterWare_Files/*.c))
all: $(EXE)
$(EXE): $(MAIN_OBS) $(LIB_OBS)
$(CC) -o $# $(LDFLAGS) $(MAIN_OBS) $(LIB_OBS) $(LDLIBS)
%.o: %.c
$(CC) -o $# -MD -MP $(CPPFLAGS) $(CFLAGS) -c $^
ALL_DEPS = $(patsubst %.o,%.d,$(MAIN_OBS), $(LIB_OBS))
-include $(ALL_DEPS)
clean:
rm -f $(LIB_OBS) $(EXE) $(MAIN_OBS) $(ALL_DEPS)
.PHONY: all clean
I can't figure out what changes to make to build my executable again if one of the header files is modified. I don't want to do make clean and make again.
The way the automake system handles this is to not use %.o: %.c but instead list the C file and all of the headers in the C file.
So for example:
main.o: main.c StarterWare_Files/test.h StarterWare_Files/add.h
$(CC) -o $# -MD -MP $(CPPFLAGS) $(CFLAGS) -c $^
See makedepends for a tool that will read C files and figure out the make dependencies.

Resources